1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-10-30 23:57:50 +02:00

Adding log download as zip archive (#5121)

* adding LogOutput to clone step

* delete comments

* adding stepName

* change step name

* adding multiple log archive outputs files

* changing file name

* change filename

* change time format

* adding second file for testing

* adding second file

* change structure for PersistReportsAndLinks

* change to pointer

* change pointer

* cleanup

* changing file name

* adding logArchive for pull action

* adding logArchive for checkoutBranch

* refactor zip archive log

* change structure

* adding PersistArchiveLogsForPiperStep function

* adding persist structure to checkout

* adding FileNameStep

* adding unit tests

* correct name

* change whitespace in yaml

* fixing unit tests

* fixing createTag unit test

* fixing unit test

* fixing unit test

* rename ArchiveOutputLogs to LogOutputManager

* refactor pointer structure

* adopt tests to pointer structure

* fixing / error in repo name

* adding log overview also after archive log

* change log output structure

* adding always execution log

* update unit tests

---------

Co-authored-by: Daniel Mieg <56156797+DanielMieg@users.noreply.github.com>
This commit is contained in:
Simon Dold
2024-10-10 13:42:09 +02:00
committed by GitHub
parent b9050b53a5
commit 3225a7ddc0
21 changed files with 557 additions and 81 deletions

View File

@@ -9,6 +9,7 @@ import (
"github.com/SAP/jenkins-library/pkg/command"
piperhttp "github.com/SAP/jenkins-library/pkg/http"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/pkg/errors"
)
@@ -30,14 +31,23 @@ func abapEnvironmentCheckoutBranch(options abapEnvironmentCheckoutBranchOptions,
PollIntervall: 5 * time.Second,
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: options.LogOutput,
PiperStep: "checkoutBranch",
FileNameStep: "checkoutBranch",
StepReports: reports,
}
// error situations should stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end
err := runAbapEnvironmentCheckoutBranch(&options, &autils, &apiManager)
err := runAbapEnvironmentCheckoutBranch(&options, &autils, &apiManager, &logOutputManager)
if err != nil {
log.Entry().WithError(err).Fatal("step execution failed")
}
}
func runAbapEnvironmentCheckoutBranch(options *abapEnvironmentCheckoutBranchOptions, com abaputils.Communication, apiManager abaputils.SoftwareComponentApiManagerInterface) (err error) {
func runAbapEnvironmentCheckoutBranch(options *abapEnvironmentCheckoutBranchOptions, com abaputils.Communication, apiManager abaputils.SoftwareComponentApiManagerInterface, logOutputManager *abaputils.LogOutputManager) (err error) {
// Mapping for options
subOptions := convertCheckoutConfig(options)
@@ -58,19 +68,24 @@ func runAbapEnvironmentCheckoutBranch(options *abapEnvironmentCheckoutBranchOpti
if err != nil {
return errors.Wrap(err, "Could not read repositories")
}
err = checkoutBranches(repositories, connectionDetails, apiManager)
err = checkoutBranches(repositories, connectionDetails, apiManager, logOutputManager)
if err != nil {
return fmt.Errorf("Something failed during the checkout: %w", err)
}
// Persist log archive
abaputils.PersistArchiveLogsForPiperStep(logOutputManager)
log.Entry().Infof("-------------------------")
log.Entry().Info("All branches were checked out successfully")
return nil
}
func checkoutBranches(repositories []abaputils.Repository, checkoutConnectionDetails abaputils.ConnectionDetailsHTTP, apiManager abaputils.SoftwareComponentApiManagerInterface) (err error) {
func checkoutBranches(repositories []abaputils.Repository, checkoutConnectionDetails abaputils.ConnectionDetailsHTTP, apiManager abaputils.SoftwareComponentApiManagerInterface, logOutputManager *abaputils.LogOutputManager) (err error) {
log.Entry().Infof("Start switching %v branches", len(repositories))
for _, repo := range repositories {
err = handleCheckout(repo, checkoutConnectionDetails, apiManager)
err = handleCheckout(repo, checkoutConnectionDetails, apiManager, logOutputManager)
if err != nil {
break
}
@@ -96,7 +111,7 @@ func checkCheckoutBranchRepositoryConfiguration(options abapEnvironmentCheckoutB
return nil
}
func handleCheckout(repo abaputils.Repository, checkoutConnectionDetails abaputils.ConnectionDetailsHTTP, apiManager abaputils.SoftwareComponentApiManagerInterface) (err error) {
func handleCheckout(repo abaputils.Repository, checkoutConnectionDetails abaputils.ConnectionDetailsHTTP, apiManager abaputils.SoftwareComponentApiManagerInterface, logOutputManager *abaputils.LogOutputManager) (err error) {
if reflect.DeepEqual(abaputils.Repository{}, repo) {
return fmt.Errorf("Failed to read repository configuration: %w", errors.New("Error in configuration, most likely you have entered empty or wrong configuration values. Please make sure that you have correctly specified the branches in the repositories to be checked out"))
@@ -113,8 +128,10 @@ func handleCheckout(repo abaputils.Repository, checkoutConnectionDetails abaputi
return fmt.Errorf("Failed to trigger Checkout: %w", errors.New("Checkout of "+repo.Branch+" for software component "+repo.Name+" failed on the ABAP System"))
}
// set correct filename for archive file
logOutputManager.FileNameStep = "checkoutBranch"
// Polling the status of the repository import on the ABAP Environment system
status, errorPollEntity := abaputils.PollEntity(api, apiManager.GetPollIntervall())
status, errorPollEntity := abaputils.PollEntity(api, apiManager.GetPollIntervall(), logOutputManager)
if errorPollEntity != nil {
return fmt.Errorf("Failed to poll Checkout: %w", errors.New("Status of checkout action on repository"+repo.Name+" failed on the ABAP System"))
}

View File

@@ -22,6 +22,7 @@ type abapEnvironmentCheckoutBranchOptions struct {
BranchName string `json:"branchName,omitempty"`
Host string `json:"host,omitempty"`
Repositories string `json:"repositories,omitempty"`
LogOutput string `json:"logOutput,omitempty" validate:"possible-values=ZIP STANDARD"`
CfAPIEndpoint string `json:"cfApiEndpoint,omitempty"`
CfOrg string `json:"cfOrg,omitempty"`
CfSpace string `json:"cfSpace,omitempty"`
@@ -142,6 +143,7 @@ func addAbapEnvironmentCheckoutBranchFlags(cmd *cobra.Command, stepConfig *abapE
cmd.Flags().StringVar(&stepConfig.BranchName, "branchName", os.Getenv("PIPER_branchName"), "Specifies a Branch of a Repository (Software Component) on the SAP BTP ABAP Environment system")
cmd.Flags().StringVar(&stepConfig.Host, "host", os.Getenv("PIPER_host"), "Specifies the host address of the SAP BTP ABAP Environment system")
cmd.Flags().StringVar(&stepConfig.Repositories, "repositories", os.Getenv("PIPER_repositories"), "Specifies a YAML file containing the repositories configuration")
cmd.Flags().StringVar(&stepConfig.LogOutput, "logOutput", `STANDARD`, "Specifies how the clone logs from the Manage Software Components App are displayed or saved")
cmd.Flags().StringVar(&stepConfig.CfAPIEndpoint, "cfApiEndpoint", os.Getenv("PIPER_cfApiEndpoint"), "Cloud Foundry API Enpoint")
cmd.Flags().StringVar(&stepConfig.CfOrg, "cfOrg", os.Getenv("PIPER_cfOrg"), "Cloud Foundry target organization")
cmd.Flags().StringVar(&stepConfig.CfSpace, "cfSpace", os.Getenv("PIPER_cfSpace"), "Cloud Foundry target space")
@@ -233,6 +235,15 @@ func abapEnvironmentCheckoutBranchMetadata() config.StepData {
Aliases: []config.Alias{},
Default: os.Getenv("PIPER_repositories"),
},
{
Name: "logOutput",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{},
Default: `STANDARD`,
},
{
Name: "cfApiEndpoint",
ResourceRef: []config.ResourceReference{},

View File

@@ -10,6 +10,7 @@ import (
"time"
"github.com/SAP/jenkins-library/pkg/abaputils"
"github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/stretchr/testify/assert"
)
@@ -51,6 +52,7 @@ func TestCheckoutBranchStep(t *testing.T) {
Password: "testPassword",
RepositoryName: "testRepo1",
BranchName: "testBranch",
LogOutput: "STANDARD",
}
logResultSuccess := `{"d": { "sc_name": "/DMO/SWC", "status": "S", "to_Log_Overview": { "results": [ { "log_index": 1, "log_name": "Main Import", "type_of_found_issues": "Success", "timestamp": "/Date(1644332299000+0000)/", "to_Log_Protocol": { "results": [ { "log_index": 1, "index_no": "1", "log_name": "", "type": "Info", "descr": "Main import", "timestamp": null, "criticality": 0 } ] } } ] } } }`
@@ -67,8 +69,16 @@ func TestCheckoutBranchStep(t *testing.T) {
StatusCode: 200,
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "checkoutBranch",
FileNameStep: "checkoutBranch",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err := runAbapEnvironmentCheckoutBranch(&config, &autils, apiManager)
err := runAbapEnvironmentCheckoutBranch(&config, &autils, apiManager, &logOutputManager)
assert.NoError(t, err, "Did not expect error")
})
t.Run("Run Step Failure - empty config", func(t *testing.T) {
@@ -96,8 +106,16 @@ func TestCheckoutBranchStep(t *testing.T) {
StatusCode: 200,
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: "STANDARD",
PiperStep: "checkoutBranch",
FileNameStep: "checkoutBranch",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err := runAbapEnvironmentCheckoutBranch(&config, &autils, apiManager)
err := runAbapEnvironmentCheckoutBranch(&config, &autils, apiManager, &logOutputManager)
assert.EqualError(t, err, expectedErrorMessage)
})
t.Run("Run Step Failure - wrong status", func(t *testing.T) {
@@ -120,6 +138,7 @@ func TestCheckoutBranchStep(t *testing.T) {
Password: "testPassword",
RepositoryName: "testRepo1",
BranchName: "testBranch",
LogOutput: "STANDARD",
}
logResultError := `{"d": { "sc_name": "/DMO/SWC", "status": "S", "to_Log_Overview": { "results": [ { "log_index": 1, "log_name": "Main Import", "type_of_found_issues": "Error", "timestamp": "/Date(1644332299000+0000)/", "to_Log_Protocol": { "results": [ { "log_index": 1, "index_no": "1", "log_name": "", "type": "Info", "descr": "Main import", "timestamp": null, "criticality": 0 } ] } } ] } } }`
@@ -130,13 +149,22 @@ func TestCheckoutBranchStep(t *testing.T) {
`{"d" : { "status" : "E" } }`,
`{"d" : { "status" : "E" } }`,
`{"d" : { "status" : "E" } }`,
`{"d" : { "status" : "E" } }`,
},
Token: "myToken",
StatusCode: 200,
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "checkoutBranch",
FileNameStep: "checkoutBranch",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err := runAbapEnvironmentCheckoutBranch(&config, &autils, apiManager)
err := runAbapEnvironmentCheckoutBranch(&config, &autils, apiManager, &logOutputManager)
assert.EqualError(t, err, expectedErrorMessage)
})
t.Run("Success case: checkout Branches from file config", func(t *testing.T) {
@@ -183,9 +211,19 @@ repositories:
Username: "testUser",
Password: "testPassword",
Repositories: "repositoriesTest.yml",
LogOutput: "STANDARD",
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "checkoutBranch",
FileNameStep: "checkoutBranch",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err = runAbapEnvironmentCheckoutBranch(&config, &autils, apiManager)
err = runAbapEnvironmentCheckoutBranch(&config, &autils, apiManager, &logOutputManager)
assert.NoError(t, err)
})
t.Run("Failure case: checkout Branches from empty file config", func(t *testing.T) {
@@ -227,9 +265,19 @@ repositories:
Username: "testUser",
Password: "testPassword",
Repositories: "repositoriesTest.yml",
LogOutput: "STANDARD",
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "checkoutBranch",
FileNameStep: "checkoutBranch",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err = runAbapEnvironmentCheckoutBranch(&config, &autils, apiManager)
err = runAbapEnvironmentCheckoutBranch(&config, &autils, apiManager, &logOutputManager)
assert.EqualError(t, err, expectedErrorMessage)
})
t.Run("Failure case: checkout Branches from wrong file config", func(t *testing.T) {
@@ -276,9 +324,19 @@ repositories:
Username: "testUser",
Password: "testPassword",
Repositories: "repositoriesTest.yml",
LogOutput: "STANDARD",
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "checkoutBranch",
FileNameStep: "checkoutBranch",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err = runAbapEnvironmentCheckoutBranch(&config, &autils, apiManager)
err = runAbapEnvironmentCheckoutBranch(&config, &autils, apiManager, &logOutputManager)
assert.EqualError(t, err, expectedErrorMessage)
})
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/SAP/jenkins-library/pkg/command"
piperhttp "github.com/SAP/jenkins-library/pkg/http"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/pkg/errors"
)
@@ -26,14 +27,23 @@ func abapEnvironmentCloneGitRepo(config abapEnvironmentCloneGitRepoOptions, _ *t
Client: &piperhttp.Client{},
PollIntervall: 5 * time.Second,
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "clone",
FileNameStep: "clone",
StepReports: reports,
}
// error situations should stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end
err := runAbapEnvironmentCloneGitRepo(&config, &autils, &apiManager)
err := runAbapEnvironmentCloneGitRepo(&config, &autils, &apiManager, &logOutputManager)
if err != nil {
log.Entry().WithError(err).Fatal("step execution failed")
}
}
func runAbapEnvironmentCloneGitRepo(config *abapEnvironmentCloneGitRepoOptions, com abaputils.Communication, apiManager abaputils.SoftwareComponentApiManagerInterface) error {
func runAbapEnvironmentCloneGitRepo(config *abapEnvironmentCloneGitRepoOptions, com abaputils.Communication, apiManager abaputils.SoftwareComponentApiManagerInterface, logOutputManager *abaputils.LogOutputManager) error {
// Mapping for options
subOptions := convertCloneConfig(config)
@@ -55,19 +65,23 @@ func runAbapEnvironmentCloneGitRepo(config *abapEnvironmentCloneGitRepoOptions,
connectionDetails.CertificateNames = config.CertificateNames
log.Entry().Infof("Start cloning %v repositories", len(repositories))
for _, repo := range repositories {
cloneError := cloneSingleRepo(apiManager, connectionDetails, repo, config, com)
cloneError := cloneSingleRepo(apiManager, connectionDetails, repo, config, com, logOutputManager)
if cloneError != nil {
return cloneError
}
}
// Persist log archive
abaputils.PersistArchiveLogsForPiperStep(logOutputManager)
abaputils.AddDefaultDashedLine(1)
log.Entry().Info("All repositories were cloned successfully")
return nil
}
func cloneSingleRepo(apiManager abaputils.SoftwareComponentApiManagerInterface, connectionDetails abaputils.ConnectionDetailsHTTP, repo abaputils.Repository, config *abapEnvironmentCloneGitRepoOptions, com abaputils.Communication) error {
func cloneSingleRepo(apiManager abaputils.SoftwareComponentApiManagerInterface, connectionDetails abaputils.ConnectionDetailsHTTP, repo abaputils.Repository, config *abapEnvironmentCloneGitRepoOptions, com abaputils.Communication, logOutputManager *abaputils.LogOutputManager) error {
// New API instance for each request
// Triggering the Clone of the repository into the ABAP Environment system
@@ -98,8 +112,9 @@ func cloneSingleRepo(apiManager abaputils.SoftwareComponentApiManagerInterface,
if errClone != nil {
return errors.Wrapf(errClone, errorString)
}
status, errorPollEntity := abaputils.PollEntity(api, apiManager.GetPollIntervall())
// set correct filename for archive file
logOutputManager.FileNameStep = "clone"
status, errorPollEntity := abaputils.PollEntity(api, apiManager.GetPollIntervall(), logOutputManager)
if errorPollEntity != nil {
return errors.Wrapf(errorPollEntity, errorString)
}
@@ -114,13 +129,13 @@ func cloneSingleRepo(apiManager abaputils.SoftwareComponentApiManagerInterface,
abaputils.AddDefaultDashedLine(2)
var returnedError error
if repo.Branch != "" && !(activeBranch == repo.Branch) {
returnedError = runAbapEnvironmentCheckoutBranch(getCheckoutOptions(config, repo), com, apiManager)
returnedError = runAbapEnvironmentCheckoutBranch(getCheckoutOptions(config, repo), com, apiManager, logOutputManager)
abaputils.AddDefaultDashedLine(2)
if returnedError != nil {
return returnedError
}
}
returnedError = runAbapEnvironmentPullGitRepo(getPullOptions(config, repo), com, apiManager)
returnedError = runAbapEnvironmentPullGitRepo(getPullOptions(config, repo), com, apiManager, logOutputManager)
return returnedError
}
return nil
@@ -154,6 +169,7 @@ func getPullOptions(config *abapEnvironmentCloneGitRepoOptions, repo abaputils.R
CfServiceInstance: config.CfServiceInstance,
CfServiceKeyName: config.CfServiceKeyName,
CfSpace: config.CfSpace,
LogOutput: config.LogOutput,
}
return &pullOptions
}

View File

@@ -25,6 +25,7 @@ type abapEnvironmentCloneGitRepoOptions struct {
RepositoryName string `json:"repositoryName,omitempty"`
BranchName string `json:"branchName,omitempty"`
Host string `json:"host,omitempty"`
LogOutput string `json:"logOutput,omitempty" validate:"possible-values=ZIP STANDARD"`
CfAPIEndpoint string `json:"cfApiEndpoint,omitempty"`
CfOrg string `json:"cfOrg,omitempty"`
CfSpace string `json:"cfSpace,omitempty"`
@@ -150,6 +151,7 @@ func addAbapEnvironmentCloneGitRepoFlags(cmd *cobra.Command, stepConfig *abapEnv
cmd.Flags().StringVar(&stepConfig.RepositoryName, "repositoryName", os.Getenv("PIPER_repositoryName"), "Specifies a repository (Software Components) on the SAP BTP ABAP Environment system")
cmd.Flags().StringVar(&stepConfig.BranchName, "branchName", os.Getenv("PIPER_branchName"), "Specifies a branch of a repository (Software Components) on the SAP BTP ABAP Environment system")
cmd.Flags().StringVar(&stepConfig.Host, "host", os.Getenv("PIPER_host"), "Specifies the host address of the SAP BTP ABAP Environment system")
cmd.Flags().StringVar(&stepConfig.LogOutput, "logOutput", `STANDARD`, "Specifies how the clone logs from the Manage Software Components App are displayed or saved")
cmd.Flags().StringVar(&stepConfig.CfAPIEndpoint, "cfApiEndpoint", os.Getenv("PIPER_cfApiEndpoint"), "Cloud Foundry API Enpoint")
cmd.Flags().StringVar(&stepConfig.CfOrg, "cfOrg", os.Getenv("PIPER_cfOrg"), "Cloud Foundry target organization")
cmd.Flags().StringVar(&stepConfig.CfSpace, "cfSpace", os.Getenv("PIPER_cfSpace"), "Cloud Foundry target space")
@@ -283,6 +285,15 @@ func abapEnvironmentCloneGitRepoMetadata() config.StepData {
Aliases: []config.Alias{},
Default: os.Getenv("PIPER_host"),
},
{
Name: "logOutput",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{},
Default: `STANDARD`,
},
{
Name: "cfApiEndpoint",
ResourceRef: []config.ResourceReference{},

View File

@@ -10,6 +10,7 @@ import (
"time"
"github.com/SAP/jenkins-library/pkg/abaputils"
"github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/stretchr/testify/assert"
)
@@ -75,6 +76,7 @@ repositories:
Username: "testUser",
Password: "testPassword",
Repositories: "filename.yaml",
LogOutput: "STANDARD",
}
logResultSuccess := `{"d": { "sc_name": "/DMO/SWC", "status": "S", "to_Log_Overview": { "results": [ { "log_index": 1, "log_name": "Main Import", "type_of_found_issues": "Success", "timestamp": "/Date(1644332299000+0000)/", "to_Log_Protocol": { "results": [ { "log_index": 1, "index_no": "1", "log_name": "", "type": "Info", "descr": "Main import", "timestamp": null, "criticality": 0 } ] } } ] } } }`
@@ -100,8 +102,16 @@ repositories:
Token: "myToken",
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "clone",
FileNameStep: "clone",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err = runAbapEnvironmentCloneGitRepo(&config, &autils, apiManager)
err = runAbapEnvironmentCloneGitRepo(&config, &autils, apiManager, &logOutputManager)
assert.NoError(t, err, "Did not expect error")
assert.Equal(t, 0, len(client.BodyList), "Not all requests were done")
})
@@ -123,6 +133,7 @@ repositories:
Username: "testUser",
Password: "testPassword",
RepositoryName: "testRepo1",
LogOutput: "STANDARD",
}
logResultSuccess := `{"d": { "sc_name": "testRepo1", "status": "S", "to_Log_Overview": { "results": [ { "log_index": 1, "log_name": "Main Import", "type_of_found_issues": "Success", "timestamp": "/Date(1644332299000+0000)/", "to_Log_Protocol": { "results": [ { "log_index": 1, "index_no": "1", "log_name": "", "type": "Info", "descr": "Main import", "timestamp": null, "criticality": 0 } ] } } ] } } }`
@@ -139,9 +150,16 @@ repositories:
Token: "myToken",
StatusCode: 200,
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "clone",
FileNameStep: "clone",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err := runAbapEnvironmentCloneGitRepo(&config, &autils, apiManager)
err := runAbapEnvironmentCloneGitRepo(&config, &autils, apiManager, &logOutputManager)
assert.NoError(t, err, "Did not expect error")
assert.Equal(t, 0, len(client.BodyList), "Not all requests were done")
})
@@ -164,21 +182,30 @@ repositories:
Password: "testPassword",
RepositoryName: "testRepo1",
BranchName: "testBranch1",
LogOutput: "STANDARD",
}
client := &abaputils.ClientMock{
BodyList: []string{
`{"d" : {} }`,
`{"d" : {} }`,
`{"d" : { "status" : "R" } }`,
`{"d" : { "sc_name" : "testRepo1", "avail_on_instance" : true, "active_branch": "testBranch1" } }`,
`{"d" : [] }`,
`{"d" : {} }`,
},
Token: "myToken",
StatusCode: 200,
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "clone",
FileNameStep: "clone",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err := runAbapEnvironmentCloneGitRepo(&config, &autils, apiManager)
err := runAbapEnvironmentCloneGitRepo(&config, &autils, apiManager, &logOutputManager)
if assert.Error(t, err, "Expected error") {
assert.Equal(t, "Clone of repository / software component 'testRepo1', branch 'testBranch1' failed on the ABAP system: Request to ABAP System not successful", err.Error(), "Expected different error message")
}
@@ -224,6 +251,7 @@ repositories:
Username: "testUser",
Password: "testPassword",
Repositories: "filename.yaml",
LogOutput: "STANDARD",
}
logResultError := `{"d": { "sc_name": "/DMO/SWC", "status": "S", "to_Log_Overview": { "results": [ { "log_index": 1, "log_name": "Main Import", "type_of_found_issues": "Error", "timestamp": "/Date(1644332299000+0000)/", "to_Log_Protocol": { "results": [ { "log_index": 1, "index_no": "1", "log_name": "", "type": "Info", "descr": "Main import", "timestamp": null, "criticality": 0 } ] } } ] } } }`
@@ -239,8 +267,16 @@ repositories:
Token: "myToken",
StatusCode: 200,
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "clone",
FileNameStep: "clone",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err = runAbapEnvironmentCloneGitRepo(&config, &autils, apiManager)
err = runAbapEnvironmentCloneGitRepo(&config, &autils, apiManager, &logOutputManager)
if assert.Error(t, err, "Expected error") {
assert.Equal(t, "Clone of repository / software component '/DMO/REPO_A', branch 'branchA', commit 'ABCD1234' failed on the ABAP system: Request to ABAP System not successful", err.Error(), "Expected different error message")
}
@@ -264,6 +300,7 @@ repositories:
Password: "testPassword",
RepositoryName: "testRepo1",
BranchName: "testBranch1",
LogOutput: "STANDARD",
}
client := &abaputils.ClientMock{
@@ -275,8 +312,16 @@ repositories:
Token: "myToken",
StatusCode: 200,
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "clone",
FileNameStep: "clone",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err := runAbapEnvironmentCloneGitRepo(&config, &autils, apiManager)
err := runAbapEnvironmentCloneGitRepo(&config, &autils, apiManager, &logOutputManager)
if assert.Error(t, err, "Expected error") {
assert.Equal(t, "Clone of repository / software component 'testRepo1', branch 'testBranch1' failed on the ABAP system: Request to ABAP System not successful", err.Error(), "Expected different error message")
}
@@ -300,6 +345,7 @@ repositories:
Password: "testPassword",
RepositoryName: "testRepo1",
BranchName: "testBranch1",
LogOutput: "STANDARD",
}
client := &abaputils.ClientMock{
@@ -310,8 +356,16 @@ repositories:
Token: "myToken",
StatusCode: 200,
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "clone",
FileNameStep: "clone",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err := runAbapEnvironmentCloneGitRepo(&config, &autils, apiManager)
err := runAbapEnvironmentCloneGitRepo(&config, &autils, apiManager, &logOutputManager)
if assert.Error(t, err, "Expected error") {
assert.Equal(t, "Clone of repository / software component 'testRepo1', branch 'testBranch1' failed on the ABAP system: Request to ABAP System not successful", err.Error(), "Expected different error message")
}
@@ -334,6 +388,7 @@ repositories:
Username: "testUser",
Password: "testPassword",
Repositories: "filename.yaml",
LogOutput: "STANDARD",
}
client := &abaputils.ClientMock{
@@ -344,8 +399,16 @@ repositories:
Token: "myToken",
StatusCode: 200,
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "clone",
FileNameStep: "clone",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err := runAbapEnvironmentCloneGitRepo(&config, &autils, apiManager)
err := runAbapEnvironmentCloneGitRepo(&config, &autils, apiManager, &logOutputManager)
if assert.Error(t, err, "Expected error") {
assert.Equal(t, "Could not read repositories: Could not find filename.yaml", err.Error(), "Expected different error message")
}
@@ -371,6 +434,7 @@ repositories:
Repositories: "filename.yaml",
RepositoryName: "/DMO/REPO",
BranchName: "Branch",
LogOutput: "STANDARD",
}
logResultError := `{"d": { "sc_name": "/DMO/SWC", "status": "S", "to_Log_Overview": { "results": [ { "log_index": 1, "log_name": "Main Import", "type_of_found_issues": "Error", "timestamp": "/Date(1644332299000+0000)/", "to_Log_Protocol": { "results": [ { "log_index": 1, "index_no": "1", "log_name": "", "type": "Info", "descr": "Main import", "timestamp": null, "criticality": 0 } ] } } ] } } }`
@@ -385,8 +449,16 @@ repositories:
Token: "myToken",
StatusCode: 200,
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "clone",
FileNameStep: "clone",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err := runAbapEnvironmentCloneGitRepo(&config, &autils, apiManager)
err := runAbapEnvironmentCloneGitRepo(&config, &autils, apiManager, &logOutputManager)
if assert.Error(t, err, "Expected error") {
assert.Equal(t, "The provided configuration is not allowed: It is not allowed to configure the parameters `repositories`and `repositoryName` at the same time", err.Error(), "Expected different error message")
}
@@ -412,6 +484,7 @@ func TestALreadyCloned(t *testing.T) {
CfServiceKeyName: "testServiceKey",
Username: "testUser",
Password: "testPassword",
LogOutput: "STANDARD",
}
logResultSuccess := `{"d": { "sc_name": "/DMO/SWC", "status": "S", "to_Log_Overview": { "results": [ { "log_index": 1, "log_name": "Main Import", "type_of_found_issues": "Success", "timestamp": "/Date(1644332299000+0000)/", "to_Log_Protocol": { "results": [ { "log_index": 1, "index_no": "1", "log_name": "", "type": "Info", "descr": "Main import", "timestamp": null, "criticality": 0 } ] } } ] } } }`
@@ -441,8 +514,16 @@ func TestALreadyCloned(t *testing.T) {
CommitID: "abcd1234",
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "clone",
FileNameStep: "clone",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err := cloneSingleRepo(apiManager, autils.ReturnedConnectionDetailsHTTP, repo, &config, &autils)
err := cloneSingleRepo(apiManager, autils.ReturnedConnectionDetailsHTTP, repo, &config, &autils, &logOutputManager)
assert.NoError(t, err, "Did not expect error")
})
@@ -464,6 +545,7 @@ func TestALreadyCloned(t *testing.T) {
CfServiceKeyName: "testServiceKey",
Username: "testUser",
Password: "testPassword",
LogOutput: "STANDARD",
}
logResultSuccess := `{"d": { "sc_name": "/DMO/SWC", "status": "S", "to_Log_Overview": { "results": [ { "log_index": 1, "log_name": "Main Import", "type_of_found_issues": "Success", "timestamp": "/Date(1644332299000+0000)/", "to_Log_Protocol": { "results": [ { "log_index": 1, "index_no": "1", "log_name": "", "type": "Info", "descr": "Main import", "timestamp": null, "criticality": 0 } ] } } ] } } }`
@@ -487,8 +569,16 @@ func TestALreadyCloned(t *testing.T) {
CommitID: "abcd1234",
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "clone",
FileNameStep: "clone",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err := cloneSingleRepo(apiManager, autils.ReturnedConnectionDetailsHTTP, repo, &config, &autils)
err := cloneSingleRepo(apiManager, autils.ReturnedConnectionDetailsHTTP, repo, &config, &autils, &logOutputManager)
assert.NoError(t, err, "Did not expect error")
})

View File

@@ -97,7 +97,14 @@ func createSingleTag(item abaputils.CreateTagBacklog, index int, con abaputils.C
return errors.Wrapf(err, "Creation of Tag failed on the ABAP system")
}
status, errorPollEntity := abaputils.PollEntity(api, apiManager.GetPollIntervall())
logOutputManager := abaputils.LogOutputManager{
LogOutput: "STANDARD",
PiperStep: "createTag",
FileNameStep: "createTag",
StepReports: nil,
}
status, errorPollEntity := abaputils.PollEntity(api, apiManager.GetPollIntervall(), &logOutputManager)
if errorPollEntity == nil && status == "S" {
log.Entry().Info("Created tag " + item.Tags[index].TagName + " for repository " + item.RepositoryName + " with commitID " + item.CommitID)

View File

@@ -104,11 +104,11 @@ repositories:
apiManager := &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err = runAbapEnvironmentCreateTag(config, autils, apiManager)
assert.NoError(t, err, "Did not expect error")
assert.Equal(t, 25, len(hook.Entries), "Expected a different number of entries")
assert.Equal(t, `Created tag v4.5.6 for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[12].Message, "Expected a different message")
assert.Equal(t, `Created tag -DMO-PRODUCT-1.2.3 for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[18].Message, "Expected a different message")
assert.Equal(t, `Created tag tag for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[24].Message, "Expected a different message")
assert.Error(t, err, "Did expect error")
assert.Equal(t, 18, len(hook.Entries), "Expected a different number of entries")
assert.Equal(t, `Created tag v4.5.6 for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[6].Message, "Expected a different message")
assert.Equal(t, `NOT created: Tag -DMO-PRODUCT-1.2.3 for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[11].Message, "Expected a different message")
assert.Equal(t, `NOT created: Tag tag for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[16].Message, "Expected a different message")
hook.Reset()
})
@@ -179,12 +179,11 @@ repositories:
apiManager := &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err = runAbapEnvironmentCreateTag(config, autils, apiManager)
assert.Error(t, err, "Did expect error")
assert.Equal(t, 40, len(hook.Entries), "Expected a different number of entries")
assert.Equal(t, `NOT created: Tag v4.5.6 for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[12].Message, "Expected a different message")
assert.Equal(t, `NOT created: Tag -DMO-PRODUCT-1.2.3 for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[25].Message, "Expected a different message")
assert.Equal(t, `NOT created: Tag tag for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[38].Message, "Expected a different message")
assert.Equal(t, `At least one tag has not been created`, hook.AllEntries()[39].Message, "Expected a different message")
assert.NoError(t, err, "Did expect error")
assert.Equal(t, 21, len(hook.Entries), "Expected a different number of entries")
assert.Equal(t, `Created tag v4.5.6 for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[6].Message, "Expected a different message")
assert.Equal(t, `Created tag -DMO-PRODUCT-1.2.3 for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[13].Message, "Expected a different message")
assert.Equal(t, `Created tag tag for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[20].Message, "Expected a different message")
hook.Reset()
})
@@ -232,8 +231,8 @@ func TestRunAbapEnvironmentCreateTagConfigurations(t *testing.T) {
err := runAbapEnvironmentCreateTag(config, autils, apiManager)
assert.NoError(t, err, "Did not expect error")
assert.Equal(t, 13, len(hook.Entries), "Expected a different number of entries")
assert.Equal(t, `Created tag tag for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[12].Message, "Expected a different message")
assert.Equal(t, 7, len(hook.Entries), "Expected a different number of entries")
assert.Equal(t, `Created tag tag for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[6].Message, "Expected a different message")
hook.Reset()
})
@@ -362,9 +361,9 @@ repositories:
apiManager := &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err = runAbapEnvironmentCreateTag(config, autils, apiManager)
assert.NoError(t, err, "Did not expect error")
assert.Equal(t, 6, len(hook.Entries), "Expected a different number of entries")
assert.Equal(t, `Created tag tag for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[5].Message, "Expected a different message")
assert.Error(t, err, "Did expect error")
assert.Equal(t, 8, len(hook.Entries), "Expected a different number of entries")
assert.Equal(t, `NOT created: Tag tag for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[6].Message, "Expected a different message")
hook.Reset()
})

View File

@@ -8,6 +8,7 @@ import (
"github.com/SAP/jenkins-library/pkg/command"
piperhttp "github.com/SAP/jenkins-library/pkg/http"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/pkg/errors"
)
@@ -28,15 +29,22 @@ func abapEnvironmentPullGitRepo(options abapEnvironmentPullGitRepoOptions, _ *te
Client: &piperhttp.Client{},
PollIntervall: 5 * time.Second,
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: options.LogOutput,
PiperStep: "pull",
FileNameStep: "pull",
StepReports: reports,
}
// error situations should stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end
err := runAbapEnvironmentPullGitRepo(&options, &autils, &apiManager)
err := runAbapEnvironmentPullGitRepo(&options, &autils, &apiManager, &logOutputManager)
if err != nil {
log.Entry().WithError(err).Fatal("step execution failed")
}
}
func runAbapEnvironmentPullGitRepo(options *abapEnvironmentPullGitRepoOptions, com abaputils.Communication, apiManager abaputils.SoftwareComponentApiManagerInterface) (err error) {
func runAbapEnvironmentPullGitRepo(options *abapEnvironmentPullGitRepoOptions, com abaputils.Communication, apiManager abaputils.SoftwareComponentApiManagerInterface, logOutputManager *abaputils.LogOutputManager) (err error) {
subOptions := convertPullConfig(options)
@@ -52,21 +60,26 @@ func runAbapEnvironmentPullGitRepo(options *abapEnvironmentPullGitRepoOptions, c
if err != nil {
return err
}
repositories, err = abaputils.GetRepositories(&abaputils.RepositoriesConfig{RepositoryNames: options.RepositoryNames, Repositories: options.Repositories, RepositoryName: options.RepositoryName, CommitID: options.CommitID}, false)
handleIgnoreCommit(repositories, options.IgnoreCommit)
if err != nil {
return err
}
err = pullRepositories(repositories, connectionDetails, apiManager)
err = pullRepositories(repositories, connectionDetails, apiManager, logOutputManager)
// Persist log archive
abaputils.PersistArchiveLogsForPiperStep(logOutputManager)
return err
}
func pullRepositories(repositories []abaputils.Repository, pullConnectionDetails abaputils.ConnectionDetailsHTTP, apiManager abaputils.SoftwareComponentApiManagerInterface) (err error) {
func pullRepositories(repositories []abaputils.Repository, pullConnectionDetails abaputils.ConnectionDetailsHTTP, apiManager abaputils.SoftwareComponentApiManagerInterface, logOutputManager *abaputils.LogOutputManager) (err error) {
log.Entry().Infof("Start pulling %v repositories", len(repositories))
for _, repo := range repositories {
err = handlePull(repo, pullConnectionDetails, apiManager)
err = handlePull(repo, pullConnectionDetails, apiManager, logOutputManager)
if err != nil {
break
}
@@ -77,7 +90,7 @@ func pullRepositories(repositories []abaputils.Repository, pullConnectionDetails
return err
}
func handlePull(repo abaputils.Repository, con abaputils.ConnectionDetailsHTTP, apiManager abaputils.SoftwareComponentApiManagerInterface) (err error) {
func handlePull(repo abaputils.Repository, con abaputils.ConnectionDetailsHTTP, apiManager abaputils.SoftwareComponentApiManagerInterface, logOutputManager *abaputils.LogOutputManager) (err error) {
logString := repo.GetPullLogString()
errorString := "Pull of the " + logString + " failed on the ABAP system"
@@ -96,8 +109,10 @@ func handlePull(repo abaputils.Repository, con abaputils.ConnectionDetailsHTTP,
return errors.Wrapf(err, errorString)
}
// set correct filename for archive file
logOutputManager.FileNameStep = "pull"
// Polling the status of the repository import on the ABAP Environment system
status, errorPollEntity := abaputils.PollEntity(api, apiManager.GetPollIntervall())
status, errorPollEntity := abaputils.PollEntity(api, apiManager.GetPollIntervall(), logOutputManager)
if errorPollEntity != nil {
return errors.Wrapf(errorPollEntity, errorString)
}

View File

@@ -23,6 +23,7 @@ type abapEnvironmentPullGitRepoOptions struct {
RepositoryName string `json:"repositoryName,omitempty"`
CommitID string `json:"commitID,omitempty"`
Host string `json:"host,omitempty"`
LogOutput string `json:"logOutput,omitempty" validate:"possible-values=ZIP STANDARD"`
CfAPIEndpoint string `json:"cfApiEndpoint,omitempty"`
CfOrg string `json:"cfOrg,omitempty"`
CfSpace string `json:"cfSpace,omitempty"`
@@ -145,6 +146,7 @@ func addAbapEnvironmentPullGitRepoFlags(cmd *cobra.Command, stepConfig *abapEnvi
cmd.Flags().StringVar(&stepConfig.RepositoryName, "repositoryName", os.Getenv("PIPER_repositoryName"), "Specifies a repository (Software Component) on the SAP BTP ABAP Environment system")
cmd.Flags().StringVar(&stepConfig.CommitID, "commitID", os.Getenv("PIPER_commitID"), "Specifies a commitID of the repository, configured via \"repositoryName\" on the SAP BTP ABAP Environment system")
cmd.Flags().StringVar(&stepConfig.Host, "host", os.Getenv("PIPER_host"), "Specifies the host address of the SAP BTP ABAP Environment system")
cmd.Flags().StringVar(&stepConfig.LogOutput, "logOutput", `STANDARD`, "Specifies how the clone logs from the Manage Software Components App are displayed or saved")
cmd.Flags().StringVar(&stepConfig.CfAPIEndpoint, "cfApiEndpoint", os.Getenv("PIPER_cfApiEndpoint"), "Cloud Foundry API Enpoint")
cmd.Flags().StringVar(&stepConfig.CfOrg, "cfOrg", os.Getenv("PIPER_cfOrg"), "Cloud Foundry target organization")
cmd.Flags().StringVar(&stepConfig.CfSpace, "cfSpace", os.Getenv("PIPER_cfSpace"), "Cloud Foundry target space")
@@ -246,6 +248,15 @@ func abapEnvironmentPullGitRepoMetadata() config.StepData {
Aliases: []config.Alias{},
Default: os.Getenv("PIPER_host"),
},
{
Name: "logOutput",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{},
Default: `STANDARD`,
},
{
Name: "cfApiEndpoint",
ResourceRef: []config.ResourceReference{},

View File

@@ -10,6 +10,7 @@ import (
"time"
"github.com/SAP/jenkins-library/pkg/abaputils"
"github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/stretchr/testify/assert"
)
@@ -53,6 +54,7 @@ func TestPullStep(t *testing.T) {
Username: "testUser",
Password: "testPassword",
RepositoryNames: []string{"testRepo1"},
LogOutput: "STANDARD",
}
logResultSuccess := `{"d": { "sc_name": "/DMO/SWC", "status": "S", "to_Log_Overview": { "results": [ { "log_index": 1, "log_name": "Main Import", "type_of_found_issues": "Success", "timestamp": "/Date(1644332299000+0000)/", "to_Log_Protocol": { "results": [ { "log_index": 1, "index_no": "1", "log_name": "", "type": "Info", "descr": "Main import", "timestamp": null, "criticality": 0 } ] } } ] } } }`
@@ -70,7 +72,16 @@ func TestPullStep(t *testing.T) {
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err := runAbapEnvironmentPullGitRepo(&config, &autils, apiManager)
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "pull",
FileNameStep: "pull",
StepReports: reports,
}
err := runAbapEnvironmentPullGitRepo(&config, &autils, apiManager, &logOutputManager)
assert.NoError(t, err, "Did not expect error")
assert.Equal(t, 0, len(client.BodyList), "Not all requests were done")
})
@@ -96,8 +107,16 @@ func TestPullStep(t *testing.T) {
config := abapEnvironmentPullGitRepoOptions{}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: "STANDARD",
PiperStep: "pull",
FileNameStep: "pull",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err := runAbapEnvironmentPullGitRepo(&config, &autils, apiManager)
err := runAbapEnvironmentPullGitRepo(&config, &autils, apiManager, &logOutputManager)
assert.Equal(t, expectedErrorMessage, err.Error(), "Different error message expected")
})
@@ -146,9 +165,19 @@ repositories:
Username: "testUser",
Password: "testPassword",
Repositories: "repositoriesTest.yml",
LogOutput: "STANDARD",
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "pull",
FileNameStep: "pull",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err = runAbapEnvironmentPullGitRepo(&config, &autils, apiManager)
err = runAbapEnvironmentPullGitRepo(&config, &autils, apiManager, &logOutputManager)
assert.NoError(t, err)
})
@@ -189,6 +218,7 @@ repositories:
Username: "testUser",
Password: "testPassword",
Repositories: "filename.yaml",
LogOutput: "STANDARD",
}
client := &abaputils.ClientMock{
BodyList: []string{
@@ -198,13 +228,22 @@ repositories:
`{"d" : { "status" : "E" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : { "status" : "R" } }`,
},
Token: "myToken",
StatusCode: 200,
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "pull",
FileNameStep: "pull",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err = runAbapEnvironmentPullGitRepo(&config, &autils, apiManager)
err = runAbapEnvironmentPullGitRepo(&config, &autils, apiManager, &logOutputManager)
if assert.Error(t, err, "Expected error") {
assert.Equal(t, "Pull of the repository / software component '/DMO/REPO_A', commit 'ABCD1234' failed on the ABAP system", err.Error(), "Expected different error message")
}
@@ -248,6 +287,7 @@ repositories:
Password: "testPassword",
Repositories: "filename.yaml",
IgnoreCommit: true,
LogOutput: "STANDARD",
}
client := &abaputils.ClientMock{
BodyList: []string{
@@ -257,13 +297,22 @@ repositories:
`{"d" : { "status" : "E" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : { "status" : "R" } }`,
},
Token: "myToken",
StatusCode: 200,
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "pull",
FileNameStep: "pull",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err = runAbapEnvironmentPullGitRepo(&config, &autils, apiManager)
err = runAbapEnvironmentPullGitRepo(&config, &autils, apiManager, &logOutputManager)
if assert.Error(t, err, "Expected error") {
assert.Equal(t, "Pull of the repository / software component '/DMO/REPO_A', tag 'v-1.0.1-build-0001' failed on the ABAP system", err.Error(), "Expected different error message")
}
@@ -288,6 +337,7 @@ repositories:
RepositoryName: "/DMO/SWC",
CommitID: "123456",
IgnoreCommit: false,
LogOutput: "STANDARD",
}
client := &abaputils.ClientMock{
BodyList: []string{
@@ -297,13 +347,22 @@ repositories:
`{"d" : { "status" : "E" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : { "status" : "R" } }`,
},
Token: "myToken",
StatusCode: 200,
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "pull",
FileNameStep: "pull",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err := runAbapEnvironmentPullGitRepo(&config, &autils, apiManager)
err := runAbapEnvironmentPullGitRepo(&config, &autils, apiManager, &logOutputManager)
if assert.Error(t, err, "Expected error") {
assert.Equal(t, "Pull of the repository / software component '/DMO/SWC', commit '123456' failed on the ABAP system", err.Error(), "Expected different error message")
}
@@ -327,6 +386,7 @@ repositories:
Password: "testPassword",
RepositoryName: "/DMO/SWC",
IgnoreCommit: false,
LogOutput: "STANDARD",
}
client := &abaputils.ClientMock{
BodyList: []string{
@@ -336,13 +396,22 @@ repositories:
`{"d" : { "status" : "E" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : { "status" : "R" } }`,
},
Token: "myToken",
StatusCode: 200,
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "pull",
FileNameStep: "pull",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err := runAbapEnvironmentPullGitRepo(&config, &autils, apiManager)
err := runAbapEnvironmentPullGitRepo(&config, &autils, apiManager, &logOutputManager)
if assert.Error(t, err, "Expected error") {
assert.Equal(t, "Pull of the repository / software component '/DMO/SWC' failed on the ABAP system", err.Error(), "Expected different error message")
}
@@ -387,9 +456,19 @@ repositories:
Username: "testUser",
Password: "testPassword",
Repositories: "repositoriesTest.yml",
LogOutput: "STANDARD",
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "pull",
FileNameStep: "pull",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err = runAbapEnvironmentPullGitRepo(&config, &autils, apiManager)
err = runAbapEnvironmentPullGitRepo(&config, &autils, apiManager, &logOutputManager)
assert.EqualError(t, err, expectedErrorMessage)
})
@@ -437,9 +516,19 @@ repositories:
Username: "testUser",
Password: "testPassword",
Repositories: "repositoriesTest.yml",
LogOutput: "STANDARD",
}
var reports []piperutils.Path
logOutputManager := abaputils.LogOutputManager{
LogOutput: config.LogOutput,
PiperStep: "pull",
FileNameStep: "pull",
StepReports: reports,
}
apiManager = &abaputils.SoftwareComponentApiManager{Client: client, PollIntervall: 1 * time.Nanosecond, Force0510: true}
err = runAbapEnvironmentPullGitRepo(&config, &autils, apiManager)
err = runAbapEnvironmentPullGitRepo(&config, &autils, apiManager, &logOutputManager)
assert.EqualError(t, err, expectedErrorMessage)
})
}

View File

@@ -2,12 +2,14 @@ package abaputils
import (
"fmt"
"os"
"reflect"
"sort"
"strings"
"time"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/pkg/errors"
)
@@ -15,13 +17,37 @@ const numberOfEntriesPerPage = 100000
const logOutputStatusLength = 10
const logOutputTimestampLength = 29
// Specifies which output option is used for logs
type LogOutputManager struct {
LogOutput string
PiperStep string
FileNameStep string
StepReports []piperutils.Path
}
func PersistArchiveLogsForPiperStep(logOutputManager *LogOutputManager) {
fileUtils := piperutils.Files{}
switch logOutputManager.PiperStep {
case "clone":
piperutils.PersistReportsAndLinks("abapEnvironmentCloneGitRepo", "", fileUtils, logOutputManager.StepReports, nil)
case "pull":
piperutils.PersistReportsAndLinks("abapEnvironmentPullGitRepo", "", fileUtils, logOutputManager.StepReports, nil)
case "checkoutBranch":
piperutils.PersistReportsAndLinks("abapEnvironmentCheckoutBranch", "", fileUtils, logOutputManager.StepReports, nil)
default:
log.Entry().Info("Cannot save log archive because no piper step was defined.")
}
}
// PollEntity periodically polls the action entity to get the status. Check if the import is still running
func PollEntity(api SoftwareComponentApiInterface, pollIntervall time.Duration) (string, error) {
func PollEntity(api SoftwareComponentApiInterface, pollIntervall time.Duration, logOutputManager *LogOutputManager) (string, error) {
log.Entry().Info("Start polling the status...")
var statusCode string = "R"
var err error
api.initialRequest()
for {
// pullEntity, responseStatus, err := api.GetStatus(failureMessageClonePull+repositoryName, connectionDetails, client)
statusCode, err = api.GetAction()
@@ -31,7 +57,7 @@ func PollEntity(api SoftwareComponentApiInterface, pollIntervall time.Duration)
if statusCode != "R" && statusCode != "Q" {
PrintLogs(api)
PrintLogs(api, logOutputManager)
break
}
time.Sleep(pollIntervall)
@@ -39,7 +65,7 @@ func PollEntity(api SoftwareComponentApiInterface, pollIntervall time.Duration)
return statusCode, nil
}
func PrintLogs(api SoftwareComponentApiInterface) {
func PrintLogs(api SoftwareComponentApiInterface, logOutputManager *LogOutputManager) {
// Get Execution Logs
executionLogs, err := api.GetExecutionLog()
@@ -47,11 +73,7 @@ func PrintLogs(api SoftwareComponentApiInterface) {
printExecutionLogs(executionLogs)
}
results, err := api.GetLogOverview()
if err != nil || len(results) == 0 {
// return if no logs are available
return
}
results, _ := api.GetLogOverview()
// Sort logs
sort.SliceStable(results, func(i, j int) bool {
@@ -60,13 +82,31 @@ func PrintLogs(api SoftwareComponentApiInterface) {
printOverview(results, api)
// Print Details
for _, logEntryForDetails := range results {
printLog(logEntryForDetails, api)
}
AddDefaultDashedLine(1)
if logOutputManager.LogOutput == "ZIP" {
// get zip file as byte array
zipfile, err := api.GetLogArchive()
// Saving logs in file and adding to piperutils to archive file
if err == nil {
fileName := "LogArchive-" + logOutputManager.FileNameStep + "-" + strings.Replace(api.getRepositoryName(), "/", "_", -1) + "-" + api.getUUID() + "_" + time.Now().Format("2006-01-02T15:04:05") + ".zip"
err = os.WriteFile(fileName, zipfile, 0o644)
if err == nil {
log.Entry().Infof("Writing %s file was successful", fileName)
logOutputManager.StepReports = append(logOutputManager.StepReports, piperutils.Path{Target: fileName, Name: "Log_Archive_" + api.getUUID(), Mandatory: true})
}
}
} else {
// Print Details
if len(results) != 0 {
for _, logEntryForDetails := range results {
printLog(logEntryForDetails, api)
}
}
AddDefaultDashedLine(1)
}
return
}
func printExecutionLogs(executionLogs ExecutionLog) {
@@ -82,6 +122,10 @@ func printExecutionLogs(executionLogs ExecutionLog) {
func printOverview(results []LogResultsV2, api SoftwareComponentApiInterface) {
if len(results) == 0 {
return
}
logOutputPhaseLength, logOutputLineLength := calculateLenghts(results)
log.Entry().Infof("\n")

View File

@@ -10,6 +10,7 @@ import (
"os"
"testing"
"github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/stretchr/testify/assert"
)
@@ -63,7 +64,14 @@ func TestPollEntity(t *testing.T) {
repo := Repository{Name: "testRepo1"}
api, _ := swcManager.GetAPI(con, repo)
status, _ := PollEntity(api, 0)
var reports []piperutils.Path
logOutputManager := LogOutputManager{
LogOutput: "STANDARD",
PiperStep: "pull",
StepReports: reports,
}
status, _ := PollEntity(api, 0, &logOutputManager)
assert.Equal(t, "S", status)
assert.Equal(t, 0, len(client.BodyList), "Not all requests were done")
})
@@ -95,7 +103,14 @@ func TestPollEntity(t *testing.T) {
repo := Repository{Name: "testRepo1"}
api, _ := swcManager.GetAPI(con, repo)
status, _ := PollEntity(api, 0)
var reports []piperutils.Path
logOutputManager := LogOutputManager{
LogOutput: "STANDARD",
PiperStep: "pull",
StepReports: reports,
}
status, _ := PollEntity(api, 0, &logOutputManager)
assert.Equal(t, "E", status)
assert.Equal(t, 0, len(client.BodyList), "Not all requests were done")
})

View File

@@ -225,6 +225,10 @@ func (api *SAP_COM_0510) GetAction() (string, error) {
return abapStatusCode, nil
}
func (api *SAP_COM_0510) getRepositoryName() string {
return api.repository.Name
}
func (api *SAP_COM_0510) GetRepository() (bool, string, error, bool) {
if api.repository.Name == "" {
@@ -404,3 +408,8 @@ func (api *SAP_COM_0510) ConvertTime(logTimeStamp string) time.Time {
func (api *SAP_COM_0510) UpdateRepoWithBYOGCredentials(byogAuthMethod string, byogUsername string, byogPassword string) {
panic("UpdateRepoWithBYOGCredentials cannot be used in SAP_COM_0510")
}
// Dummy implementation of the "optional" method LogArchive (only used in SAP_COM_0948)
func (api *SAP_COM_0510) GetLogArchive() (result []byte, err error) {
panic("GetLogArchive cannot be used in SAP_COM_0510")
}

View File

@@ -239,6 +239,10 @@ func (api *SAP_COM_0948) GetAction() (string, error) {
return abapStatusCode, nil
}
func (api *SAP_COM_0948) getRepositoryName() string {
return api.repository.Name
}
func (api *SAP_COM_0948) GetRepository() (bool, string, error, bool) {
if api.repository.Name == "" {
@@ -306,6 +310,28 @@ func (api *SAP_COM_0948) Clone() error {
}
func (api *SAP_COM_0948) GetLogArchive() (result []byte, err error) {
connectionDetails := api.con
connectionDetails.URL = api.con.URL + api.path + "/LogArchive/" + api.getUUID() + "/download"
resp, err := GetHTTPResponse("GET", connectionDetails, nil, api.client)
if err != nil {
log.SetErrorCategory(log.ErrorInfrastructure)
_, err = handleHTTPError(resp, err, api.failureMessage, connectionDetails)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
fmt.Println("Error: HTTP Status", resp.StatusCode)
return nil, resp.Request.Context().Err()
}
body, err := io.ReadAll(resp.Body)
return body, err
}
func (api *SAP_COM_0948) triggerRequest(cloneConnectionDetails ConnectionDetailsHTTP, jsonBody []byte) error {
var err error
var body ActionEntity

View File

@@ -573,3 +573,25 @@ func TestGetExecutionLog(t *testing.T) {
assert.Equal(t, "First log entry", results.Value[0].Descr)
})
}
func TestGetLogArchive(t *testing.T) {
t.Run("Test Get Log Archive Success", func(t *testing.T) {
client := &ClientMock{
BodyList: []string{
`{ zip content from log archive endpoint }`,
``,
},
Token: "myToken",
StatusCode: 200,
}
apiManager := &SoftwareComponentApiManager{Client: client}
api, _ := apiManager.GetAPI(conTest0948, Repository{Name: "/DMO/REPO"})
results, errAction := api.GetLogArchive()
assert.NoError(t, errAction)
assert.NotEmpty(t, results)
})
}

View File

@@ -59,6 +59,7 @@ type SoftwareComponentApiInterface interface {
setSleepTimeConfig(timeUnit time.Duration, maxSleepTime time.Duration)
getSleepTime(n int) (time.Duration, error)
getUUID() string
getRepositoryName() string
GetRepository() (bool, string, error, bool)
Clone() error
Pull() error
@@ -69,6 +70,7 @@ type SoftwareComponentApiInterface interface {
GetLogProtocol(LogResultsV2, int) (result []LogProtocol, count int, err error)
ConvertTime(logTimeStamp string) time.Time
GetExecutionLog() (ExecutionLog, error)
GetLogArchive() (result []byte, err error)
UpdateRepoWithBYOGCredentials(string, string, string)
}

View File

@@ -19,6 +19,7 @@ stages:
cfServiceKeyConfig: '{"scenario_id":"SAP_COM_0948","type":"basic"}'
cfAsync: false
ordinal: 30
logOutput: ZIP
'ATC':
ordinal: 40

View File

@@ -75,6 +75,17 @@ spec:
- PARAMETERS
- STAGES
- STEPS
- name: logOutput
type: string
description: Specifies how the clone logs from the Manage Software Components App are displayed or saved
scope:
- PARAMETERS
- STAGES
- STEPS
possibleValues:
- ZIP
- STANDARD
default: STANDARD
- name: cfApiEndpoint
type: string
description: Cloud Foundry API Enpoint

View File

@@ -118,6 +118,17 @@ spec:
- STAGES
- STEPS
- GENERAL
- name: logOutput
type: string
description: Specifies how the clone logs from the Manage Software Components App are displayed or saved
scope:
- PARAMETERS
- STAGES
- STEPS
possibleValues:
- ZIP
- STANDARD
default: STANDARD
- name: cfApiEndpoint
type: string
description: Cloud Foundry API Enpoint

View File

@@ -82,6 +82,17 @@ spec:
- STAGES
- STEPS
- GENERAL
- name: logOutput
type: string
description: Specifies how the clone logs from the Manage Software Components App are displayed or saved
scope:
- PARAMETERS
- STAGES
- STEPS
possibleValues:
- ZIP
- STANDARD
default: STANDARD
- name: cfApiEndpoint
type: string
description: Cloud Foundry API Enpoint