You've already forked sap-jenkins-library
							
							
				mirror of
				https://github.com/SAP/jenkins-library.git
				synced 2025-10-30 23:57:50 +02:00 
			
		
		
		
	Add commit to clone and pull (#2258)
* commit ID for clone * commit ID for clone * Remove old default values * Add commitID to Pull * Print http response on debug level * Fix tests * Adapt tests * Shorten sleep * Fix clone tests * Add ignore commit option * Adapt tests * Adapt docu * Implement feedback * fix codeclimate issue
This commit is contained in:
		| @@ -30,10 +30,6 @@ func abapEnvironmentCheckoutBranch(options abapEnvironmentCheckoutBranchOptions, | ||||
|  | ||||
| 	client := piperhttp.Client{} | ||||
|  | ||||
| 	// for http calls import  piperhttp "github.com/SAP/jenkins-library/pkg/http" | ||||
| 	// and use a  &piperhttp.Client{} in a custom system | ||||
| 	// Example: step checkmarxExecuteScan.go | ||||
|  | ||||
| 	// error situations should stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end | ||||
| 	err := runAbapEnvironmentCheckoutBranch(&options, telemetryData, &autils, &client) | ||||
| 	if err != nil { | ||||
| @@ -44,16 +40,7 @@ func abapEnvironmentCheckoutBranch(options abapEnvironmentCheckoutBranchOptions, | ||||
| func runAbapEnvironmentCheckoutBranch(options *abapEnvironmentCheckoutBranchOptions, telemetryData *telemetry.CustomData, com abaputils.Communication, client piperhttp.Sender) (err error) { | ||||
|  | ||||
| 	// Mapping for options | ||||
| 	subOptions := abaputils.AbapEnvironmentOptions{} | ||||
|  | ||||
| 	subOptions.CfAPIEndpoint = options.CfAPIEndpoint | ||||
| 	subOptions.CfServiceInstance = options.CfServiceInstance | ||||
| 	subOptions.CfServiceKeyName = options.CfServiceKeyName | ||||
| 	subOptions.CfOrg = options.CfOrg | ||||
| 	subOptions.CfSpace = options.CfSpace | ||||
| 	subOptions.Host = options.Host | ||||
| 	subOptions.Password = options.Password | ||||
| 	subOptions.Username = options.Username | ||||
| 	subOptions := convertCheckoutConfig(options) | ||||
|  | ||||
| 	//  Determine the host, user and password, either via the input parameters or via a cloud foundry service key | ||||
| 	connectionDetails, errorGetInfo := com.GetAbapCommunicationArrangementInfo(subOptions, "/sap/opu/odata/sap/MANAGE_GIT_REPOSITORY/") | ||||
| @@ -93,7 +80,7 @@ func runAbapEnvironmentCheckoutBranch(options *abapEnvironmentCheckoutBranchOpti | ||||
| } | ||||
|  | ||||
| func checkoutBranches(repositories []abaputils.Repository, checkoutConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, pollIntervall time.Duration) (err error) { | ||||
| 	log.Entry().Infof("Start switching of %v branches", len(repositories)) | ||||
| 	log.Entry().Infof("Start switching %v branches", len(repositories)) | ||||
| 	for _, repo := range repositories { | ||||
| 		err = handleCheckout(repo, checkoutConnectionDetails, client, pollIntervall) | ||||
| 		if err != nil { | ||||
| @@ -122,9 +109,9 @@ func triggerCheckout(repositoryName string, branchName string, checkoutConnectio | ||||
| 	defer resp.Body.Close() | ||||
|  | ||||
| 	// workaround until golang version 1.16 is used | ||||
| 	time.Sleep(1 * time.Second) | ||||
| 	time.Sleep(100 * time.Millisecond) | ||||
|  | ||||
| 	log.Entry().WithField("StatusCode", resp.Status).WithField("ABAP Endpoint", checkoutConnectionDetails.URL).Info("Authentication on the ABAP system was successful") | ||||
| 	log.Entry().WithField("StatusCode", resp.Status).WithField("ABAP Endpoint", checkoutConnectionDetails.URL).Debug("Authentication on the ABAP system was successful") | ||||
| 	uriConnectionDetails.XCsrfToken = resp.Header.Get("X-Csrf-Token") | ||||
| 	checkoutConnectionDetails.XCsrfToken = uriConnectionDetails.XCsrfToken | ||||
|  | ||||
| @@ -139,7 +126,7 @@ func triggerCheckout(repositoryName string, branchName string, checkoutConnectio | ||||
| 		return uriConnectionDetails, err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 	log.Entry().WithField("StatusCode", resp.StatusCode).WithField("repositoryName", repositoryName).WithField("branchName", branchName).Info("Triggered checkout of branch") | ||||
| 	log.Entry().WithField("StatusCode", resp.StatusCode).WithField("repositoryName", repositoryName).WithField("branchName", branchName).Debug("Triggered checkout of branch") | ||||
|  | ||||
| 	// Parse Response | ||||
| 	var body abaputils.PullEntity | ||||
| @@ -217,3 +204,17 @@ func finishCheckoutLogs(branchName string, repositoryName string) { | ||||
| 	log.Entry().Infof("Checkout of branch %v on repository %v was successful", branchName, repositoryName) | ||||
| 	log.Entry().Info("--------------------------------") | ||||
| } | ||||
|  | ||||
| func convertCheckoutConfig(config *abapEnvironmentCheckoutBranchOptions) abaputils.AbapEnvironmentOptions { | ||||
| 	subOptions := abaputils.AbapEnvironmentOptions{} | ||||
|  | ||||
| 	subOptions.CfAPIEndpoint = config.CfAPIEndpoint | ||||
| 	subOptions.CfServiceInstance = config.CfServiceInstance | ||||
| 	subOptions.CfServiceKeyName = config.CfServiceKeyName | ||||
| 	subOptions.CfOrg = config.CfOrg | ||||
| 	subOptions.CfSpace = config.CfSpace | ||||
| 	subOptions.Host = config.Host | ||||
| 	subOptions.Password = config.Password | ||||
| 	subOptions.Username = config.Username | ||||
| 	return subOptions | ||||
| } | ||||
|   | ||||
| @@ -30,10 +30,6 @@ func abapEnvironmentCloneGitRepo(config abapEnvironmentCloneGitRepoOptions, tele | ||||
|  | ||||
| 	client := piperhttp.Client{} | ||||
|  | ||||
| 	// for http calls import  piperhttp "github.com/SAP/jenkins-library/pkg/http" | ||||
| 	// and use a  &piperhttp.Client{} in a custom system | ||||
| 	// Example: step checkmarxExecuteScan.go | ||||
|  | ||||
| 	// error situations should stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end | ||||
| 	err := runAbapEnvironmentCloneGitRepo(&config, telemetryData, &autils, &client) | ||||
| 	if err != nil { | ||||
| @@ -43,7 +39,7 @@ func abapEnvironmentCloneGitRepo(config abapEnvironmentCloneGitRepoOptions, tele | ||||
|  | ||||
| func runAbapEnvironmentCloneGitRepo(config *abapEnvironmentCloneGitRepoOptions, telemetryData *telemetry.CustomData, com abaputils.Communication, client piperhttp.Sender) error { | ||||
| 	// Mapping for options | ||||
| 	subOptions := convertConfig(config) | ||||
| 	subOptions := convertCloneConfig(config) | ||||
|  | ||||
| 	// Determine the host, user and password, either via the input parameters or via a cloud foundry service key | ||||
| 	connectionDetails, errorGetInfo := com.GetAbapCommunicationArrangementInfo(subOptions, "/sap/opu/odata/sap/MANAGE_GIT_REPOSITORY/Clones") | ||||
| @@ -71,33 +67,39 @@ func runAbapEnvironmentCloneGitRepo(config *abapEnvironmentCloneGitRepoOptions, | ||||
|  | ||||
| 	log.Entry().Infof("Start cloning %v repositories", len(repositories)) | ||||
| 	for _, repo := range repositories { | ||||
|  | ||||
| 		commitString := "" | ||||
| 		if repo.CommitID != "" { | ||||
| 			commitString = ", commit '" + repo.CommitID + "'" | ||||
| 		} | ||||
|  | ||||
| 		log.Entry().Info("-------------------------") | ||||
| 		log.Entry().Info("Start cloning " + repo.Name + " with branch " + repo.Branch) | ||||
| 		log.Entry().Info("Start cloning " + repo.Name + ", branch " + repo.Branch + commitString) | ||||
| 		log.Entry().Info("-------------------------") | ||||
|  | ||||
| 		// Triggering the Clone of the repository into the ABAP Environment system | ||||
| 		uriConnectionDetails, errorTriggerClone := triggerClone(repo.Name, repo.Branch, connectionDetails, client) | ||||
| 		uriConnectionDetails, errorTriggerClone := triggerClone(repo, connectionDetails, client) | ||||
| 		if errorTriggerClone != nil { | ||||
| 			return errors.Wrapf(errorTriggerClone, "Clone of '%s' with branch '%s' failed on the ABAP System", repo.Name, repo.Branch) | ||||
| 			return errors.Wrapf(errorTriggerClone, "Clone of '%s', branch '%s'%s failed on the ABAP System", repo.Name, repo.Branch, commitString) | ||||
| 		} | ||||
|  | ||||
| 		// Polling the status of the repository import on the ABAP Environment system | ||||
| 		status, errorPollEntity := abaputils.PollEntity(repo.Name, uriConnectionDetails, client, com.GetPollIntervall()) | ||||
| 		if errorPollEntity != nil { | ||||
| 			return errors.Wrapf(errorPollEntity, "Clone of '%s' with branch '%s' failed on the ABAP System", repo.Name, repo.Branch) | ||||
| 			return errors.Wrapf(errorPollEntity, "Clone of '%s', branch '%s'%s failed on the ABAP System", repo.Name, repo.Branch, commitString) | ||||
| 		} | ||||
| 		if status == "E" { | ||||
| 			return errors.New("Clone of '" + repo.Name + "' with branch '" + repo.Branch + "' failed on the ABAP System") | ||||
| 			return errors.New("Clone of '" + repo.Name + "', branch '" + repo.Branch + "'" + commitString + " failed on the ABAP System") | ||||
| 		} | ||||
|  | ||||
| 		log.Entry().Info(repo.Name + " with branch  " + repo.Branch + " was cloned successfully") | ||||
| 		log.Entry().Info(repo.Name + ", branch  " + repo.Branch + commitString + " was cloned successfully") | ||||
| 	} | ||||
| 	log.Entry().Info("-------------------------") | ||||
| 	log.Entry().Info("All repositories were cloned successfully") | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func triggerClone(repositoryName string, branchName string, cloneConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender) (abaputils.ConnectionDetailsHTTP, error) { | ||||
| func triggerClone(repo abaputils.Repository, cloneConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender) (abaputils.ConnectionDetailsHTTP, error) { | ||||
|  | ||||
| 	uriConnectionDetails := cloneConnectionDetails | ||||
| 	uriConnectionDetails.URL = "" | ||||
| @@ -112,24 +114,27 @@ func triggerClone(repositoryName string, branchName string, cloneConnectionDetai | ||||
| 	defer resp.Body.Close() | ||||
|  | ||||
| 	// workaround until golang version 1.16 is used | ||||
| 	time.Sleep(1 * time.Second) | ||||
| 	time.Sleep(100 * time.Millisecond) | ||||
|  | ||||
| 	log.Entry().WithField("StatusCode", resp.Status).WithField("ABAP Endpoint", cloneConnectionDetails.URL).Info("Authentication on the ABAP system successful") | ||||
| 	log.Entry().WithField("StatusCode", resp.Status).WithField("ABAP Endpoint", cloneConnectionDetails.URL).Debug("Authentication on the ABAP system successful") | ||||
| 	uriConnectionDetails.XCsrfToken = resp.Header.Get("X-Csrf-Token") | ||||
| 	cloneConnectionDetails.XCsrfToken = uriConnectionDetails.XCsrfToken | ||||
|  | ||||
| 	// Trigger the Clone of a Repository | ||||
| 	if repositoryName == "" { | ||||
| 	if repo.Name == "" { | ||||
| 		return uriConnectionDetails, errors.New("An empty string was passed for the parameter 'repositoryName'") | ||||
| 	} | ||||
| 	jsonBody := []byte(`{"sc_name":"` + repositoryName + `", "branch_name":"` + branchName + `"}`) | ||||
|  | ||||
| 	commitQuery, commitString := abaputils.GetCommitStrings(repo.CommitID) | ||||
|  | ||||
| 	jsonBody := []byte(`{"sc_name":"` + repo.Name + `", "branch_name":"` + repo.Branch + `"` + commitQuery + `}`) | ||||
| 	resp, err = abaputils.GetHTTPResponse("POST", cloneConnectionDetails, jsonBody, client) | ||||
| 	if err != nil { | ||||
| 		err = abaputils.HandleHTTPError(resp, err, "Could not clone the Repository / Software Component "+repositoryName+" with branch "+branchName, uriConnectionDetails) | ||||
| 		err = abaputils.HandleHTTPError(resp, err, "Could not clone the Repository / Software Component "+repo.Name+", branch "+repo.Branch+commitString, uriConnectionDetails) | ||||
| 		return uriConnectionDetails, err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 	log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", repositoryName).WithField("branchName", branchName).Info("Triggered Clone of Repository / Software Component") | ||||
| 	log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", repo.Name).WithField("branchName", repo.Branch).WithField("commitID", repo.CommitID).Info("Triggered Clone of Repository / Software Component") | ||||
|  | ||||
| 	// Parse Response | ||||
| 	var body abaputils.CloneEntity | ||||
| @@ -141,7 +146,7 @@ func triggerClone(repositoryName string, branchName string, cloneConnectionDetai | ||||
| 	json.Unmarshal(bodyText, &abapResp) | ||||
| 	json.Unmarshal(*abapResp["d"], &body) | ||||
| 	if reflect.DeepEqual(abaputils.CloneEntity{}, body) { | ||||
| 		log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", repositoryName).WithField("branchName", branchName).Error("Could not Clone the Repository / Software Component") | ||||
| 		log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", repo.Name).WithField("branchName", repo.Branch).WithField("commitID", repo.CommitID).Error("Could not Clone the Repository / Software Component") | ||||
| 		err := errors.New("Request to ABAP System not successful") | ||||
| 		return uriConnectionDetails, err | ||||
| 	} | ||||
| @@ -151,13 +156,13 @@ func triggerClone(repositoryName string, branchName string, cloneConnectionDetai | ||||
| 	// The entity "Clones" does not allow for polling. To poll the progress, the related entity "Pull" has to be called | ||||
| 	// While "Clones" has the key fields UUID, SC_NAME and BRANCH_NAME, "Pull" only has the key field UUID | ||||
| 	tempURI := strings.Replace(body.Metadata.URI, "/sap/opu/odata/sap/MANAGE_GIT_REPOSITORY/Clones", "/sap/opu/odata/sap/MANAGE_GIT_REPOSITORY/Pull", 1) | ||||
| 	pollingURI := strings.Replace(tempURI, ",sc_name='"+repositoryName+"',branch_name='"+branchName+"'", "", 1) | ||||
| 	pollingURI := strings.Replace(tempURI, ",sc_name='"+repo.Name+"',branch_name='"+repo.Branch+"'", "", 1) | ||||
|  | ||||
| 	uriConnectionDetails.URL = pollingURI + expandLog | ||||
| 	return uriConnectionDetails, nil | ||||
| } | ||||
|  | ||||
| func convertConfig(config *abapEnvironmentCloneGitRepoOptions) abaputils.AbapEnvironmentOptions { | ||||
| func convertCloneConfig(config *abapEnvironmentCloneGitRepoOptions) abaputils.AbapEnvironmentOptions { | ||||
| 	subOptions := abaputils.AbapEnvironmentOptions{} | ||||
|  | ||||
| 	subOptions.CfAPIEndpoint = config.CfAPIEndpoint | ||||
|   | ||||
| @@ -112,7 +112,7 @@ repositories: | ||||
|  | ||||
| 		err := runAbapEnvironmentCloneGitRepo(&config, nil, &autils, client) | ||||
| 		if assert.Error(t, err, "Expected error") { | ||||
| 			assert.Equal(t, "Clone of '"+config.RepositoryName+"' with branch '"+config.BranchName+"' failed on the ABAP System: Request to ABAP System not successful", err.Error(), "Expected different error message") | ||||
| 			assert.Equal(t, "Clone of '"+config.RepositoryName+"', branch '"+config.BranchName+"' failed on the ABAP System: Request to ABAP System not successful", err.Error(), "Expected different error message") | ||||
| 		} | ||||
|  | ||||
| 	}) | ||||
| @@ -127,6 +127,29 @@ func TestCloneStepErrorMessages(t *testing.T) { | ||||
| 		autils.ReturnedConnectionDetailsHTTP.URL = "https://example.com" | ||||
| 		autils.ReturnedConnectionDetailsHTTP.XCsrfToken = "xcsrftoken" | ||||
|  | ||||
| 		dir, errDir := ioutil.TempDir("", "test read addon descriptor") | ||||
| 		if errDir != nil { | ||||
| 			t.Fatal("Failed to create temporary directory") | ||||
| 		} | ||||
| 		oldCWD, _ := os.Getwd() | ||||
| 		_ = os.Chdir(dir) | ||||
| 		// clean up tmp dir | ||||
| 		defer func() { | ||||
| 			_ = os.Chdir(oldCWD) | ||||
| 			_ = os.RemoveAll(dir) | ||||
| 		}() | ||||
|  | ||||
| 		body := `--- | ||||
| repositories: | ||||
| - name: /DMO/REPO_A | ||||
|   tag: v-1.0.1-build-0001 | ||||
|   branch: branchA | ||||
|   version: 1.0.1 | ||||
|   commitID: ABCD1234 | ||||
| ` | ||||
| 		file, _ := os.Create("filename.yaml") | ||||
| 		file.Write([]byte(body)) | ||||
|  | ||||
| 		config := abapEnvironmentCloneGitRepoOptions{ | ||||
| 			CfAPIEndpoint:     "https://api.endpoint.com", | ||||
| 			CfOrg:             "testOrg", | ||||
| @@ -135,8 +158,7 @@ func TestCloneStepErrorMessages(t *testing.T) { | ||||
| 			CfServiceKeyName:  "testServiceKey", | ||||
| 			Username:          "testUser", | ||||
| 			Password:          "testPassword", | ||||
| 			RepositoryName:    "testRepo1", | ||||
| 			BranchName:        "testBranch1", | ||||
| 			Repositories:      "filename.yaml", | ||||
| 		} | ||||
|  | ||||
| 		client := &abaputils.ClientMock{ | ||||
| @@ -151,7 +173,7 @@ func TestCloneStepErrorMessages(t *testing.T) { | ||||
|  | ||||
| 		err := runAbapEnvironmentCloneGitRepo(&config, nil, &autils, client) | ||||
| 		if assert.Error(t, err, "Expected error") { | ||||
| 			assert.Equal(t, "Clone of '"+config.RepositoryName+"' with branch '"+config.BranchName+"' failed on the ABAP System", err.Error(), "Expected different error message") | ||||
| 			assert.Equal(t, "Clone of '/DMO/REPO_A', branch 'branchA', commit 'ABCD1234' failed on the ABAP System", err.Error(), "Expected different error message") | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| @@ -187,7 +209,7 @@ func TestCloneStepErrorMessages(t *testing.T) { | ||||
|  | ||||
| 		err := runAbapEnvironmentCloneGitRepo(&config, nil, &autils, client) | ||||
| 		if assert.Error(t, err, "Expected error") { | ||||
| 			assert.Equal(t, "Clone of '"+config.RepositoryName+"' with branch '"+config.BranchName+"' failed on the ABAP System: Request to ABAP System not successful", err.Error(), "Expected different error message") | ||||
| 			assert.Equal(t, "Clone of '"+config.RepositoryName+"', branch '"+config.BranchName+"' failed on the ABAP System: Request to ABAP System not successful", err.Error(), "Expected different error message") | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| @@ -222,7 +244,7 @@ func TestCloneStepErrorMessages(t *testing.T) { | ||||
|  | ||||
| 		err := runAbapEnvironmentCloneGitRepo(&config, nil, &autils, client) | ||||
| 		if assert.Error(t, err, "Expected error") { | ||||
| 			assert.Equal(t, "Clone of '"+config.RepositoryName+"' with branch '"+config.BranchName+"' failed on the ABAP System: Request to ABAP System not successful", err.Error(), "Expected different error message") | ||||
| 			assert.Equal(t, "Clone of '"+config.RepositoryName+"', branch '"+config.BranchName+"' failed on the ABAP System: Request to ABAP System not successful", err.Error(), "Expected different error message") | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
|   | ||||
| @@ -30,10 +30,6 @@ func abapEnvironmentPullGitRepo(options abapEnvironmentPullGitRepoOptions, telem | ||||
|  | ||||
| 	client := piperhttp.Client{} | ||||
|  | ||||
| 	// for http calls import  piperhttp "github.com/SAP/jenkins-library/pkg/http" | ||||
| 	// and use a  &piperhttp.Client{} in a custom system | ||||
| 	// Example: step checkmarxExecuteScan.go | ||||
|  | ||||
| 	// error situations should stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end | ||||
| 	err := runAbapEnvironmentPullGitRepo(&options, telemetryData, &autils, &client) | ||||
| 	if err != nil { | ||||
| @@ -42,16 +38,8 @@ func abapEnvironmentPullGitRepo(options abapEnvironmentPullGitRepoOptions, telem | ||||
| } | ||||
|  | ||||
| func runAbapEnvironmentPullGitRepo(options *abapEnvironmentPullGitRepoOptions, telemetryData *telemetry.CustomData, com abaputils.Communication, client piperhttp.Sender) (err error) { | ||||
| 	subOptions := abaputils.AbapEnvironmentOptions{} | ||||
|  | ||||
| 	subOptions.CfAPIEndpoint = options.CfAPIEndpoint | ||||
| 	subOptions.CfServiceInstance = options.CfServiceInstance | ||||
| 	subOptions.CfServiceKeyName = options.CfServiceKeyName | ||||
| 	subOptions.CfOrg = options.CfOrg | ||||
| 	subOptions.CfSpace = options.CfSpace | ||||
| 	subOptions.Host = options.Host | ||||
| 	subOptions.Password = options.Password | ||||
| 	subOptions.Username = options.Username | ||||
| 	subOptions := convertPullConfig(options) | ||||
|  | ||||
| 	// Determine the host, user and password, either via the input parameters or via a cloud foundry service key | ||||
| 	connectionDetails, err := com.GetAbapCommunicationArrangementInfo(subOptions, "/sap/opu/odata/sap/MANAGE_GIT_REPOSITORY/Pull") | ||||
| @@ -77,6 +65,7 @@ func runAbapEnvironmentPullGitRepo(options *abapEnvironmentPullGitRepoOptions, t | ||||
|  | ||||
| 	if err == nil { | ||||
| 		repositories, err = abaputils.GetRepositories(&abaputils.RepositoriesConfig{RepositoryNames: options.RepositoryNames, Repositories: options.Repositories}) | ||||
| 		handleIgnoreCommit(repositories, options.IgnoreCommit) | ||||
| 	} | ||||
|  | ||||
| 	if err == nil { | ||||
| @@ -93,7 +82,7 @@ func runAbapEnvironmentPullGitRepo(options *abapEnvironmentPullGitRepoOptions, t | ||||
| } | ||||
|  | ||||
| func pullRepositories(repositories []abaputils.Repository, pullConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, pollIntervall time.Duration) (err error) { | ||||
| 	log.Entry().Infof("Start cloning %v repositories", len(repositories)) | ||||
| 	log.Entry().Infof("Start pulling %v repositories", len(repositories)) | ||||
| 	for _, repo := range repositories { | ||||
| 		err = handlePull(repo, pullConnectionDetails, client, pollIntervall) | ||||
| 		if err != nil { | ||||
| @@ -104,7 +93,30 @@ func pullRepositories(repositories []abaputils.Repository, pullConnectionDetails | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func triggerPull(repositoryName string, pullConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender) (abaputils.ConnectionDetailsHTTP, error) { | ||||
| func handlePull(repo abaputils.Repository, pullConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, pollIntervall time.Duration) (err error) { | ||||
|  | ||||
| 	startPullLogs(repo) | ||||
|  | ||||
| 	_, commitString := abaputils.GetCommitStrings(repo.CommitID) | ||||
|  | ||||
| 	uriConnectionDetails, err := triggerPull(repo, pullConnectionDetails, client) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrapf(err, "Pull of '%s'%s failed on the ABAP System", repo.Name, commitString) | ||||
| 	} | ||||
|  | ||||
| 	// Polling the status of the repository import on the ABAP Environment system | ||||
| 	status, errorPollEntity := abaputils.PollEntity(repo.Name, uriConnectionDetails, client, pollIntervall) | ||||
| 	if errorPollEntity != nil { | ||||
| 		return errors.Wrapf(errorPollEntity, "Pull of '%s'%s failed on the ABAP System", repo.Name, commitString) | ||||
| 	} | ||||
| 	if status == "E" { | ||||
| 		return errors.New("Pull of '" + repo.Name + "'" + commitString + " failed on the ABAP System") | ||||
| 	} | ||||
| 	log.Entry().Info(repo.Name + " was pulled successfully") | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func triggerPull(repo abaputils.Repository, pullConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender) (abaputils.ConnectionDetailsHTTP, error) { | ||||
|  | ||||
| 	uriConnectionDetails := pullConnectionDetails | ||||
| 	uriConnectionDetails.URL = "" | ||||
| @@ -119,24 +131,25 @@ func triggerPull(repositoryName string, pullConnectionDetails abaputils.Connecti | ||||
| 	defer resp.Body.Close() | ||||
|  | ||||
| 	// workaround until golang version 1.16 is used | ||||
| 	time.Sleep(1 * time.Second) | ||||
| 	time.Sleep(100 * time.Millisecond) | ||||
|  | ||||
| 	log.Entry().WithField("StatusCode", resp.Status).WithField("ABAP Endpoint", pullConnectionDetails.URL).Info("Authentication on the ABAP system successful") | ||||
| 	log.Entry().WithField("StatusCode", resp.Status).WithField("ABAP Endpoint", pullConnectionDetails.URL).Debug("Authentication on the ABAP system successful") | ||||
| 	uriConnectionDetails.XCsrfToken = resp.Header.Get("X-Csrf-Token") | ||||
| 	pullConnectionDetails.XCsrfToken = uriConnectionDetails.XCsrfToken | ||||
|  | ||||
| 	// Trigger the Pull of a Repository | ||||
| 	if repositoryName == "" { | ||||
| 	if repo.Name == "" { | ||||
| 		return uriConnectionDetails, errors.New("An empty string was passed for the parameter 'repositoryName'") | ||||
| 	} | ||||
| 	jsonBody := []byte(`{"sc_name":"` + repositoryName + `"}`) | ||||
| 	commitQuery, commitString := abaputils.GetCommitStrings(repo.CommitID) | ||||
| 	jsonBody := []byte(`{"sc_name":"` + repo.Name + `"` + commitQuery + `}`) | ||||
| 	resp, err = abaputils.GetHTTPResponse("POST", pullConnectionDetails, jsonBody, client) | ||||
| 	if err != nil { | ||||
| 		err = abaputils.HandleHTTPError(resp, err, "Could not pull the Repository / Software Component "+repositoryName, uriConnectionDetails) | ||||
| 		err = abaputils.HandleHTTPError(resp, err, "Could not pull the Repository / Software Component '"+repo.Name+"'"+commitString, uriConnectionDetails) | ||||
| 		return uriConnectionDetails, err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 	log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", repositoryName).Info("Triggered Pull of Repository / Software Component") | ||||
| 	log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", repo.Name).WithField("commitID", repo.CommitID).Debug("Triggered Pull of Repository / Software Component") | ||||
|  | ||||
| 	// Parse Response | ||||
| 	var body abaputils.PullEntity | ||||
| @@ -148,7 +161,7 @@ func triggerPull(repositoryName string, pullConnectionDetails abaputils.Connecti | ||||
| 	json.Unmarshal(bodyText, &abapResp) | ||||
| 	json.Unmarshal(*abapResp["d"], &body) | ||||
| 	if reflect.DeepEqual(abaputils.PullEntity{}, body) { | ||||
| 		log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", repositoryName).Error("Could not pull the Repository / Software Component") | ||||
| 		log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", repo.Name).WithField("commitID", repo.CommitID).Error("Could not pull the Repository / Software Component") | ||||
| 		err := errors.New("Request to ABAP System not successful") | ||||
| 		return uriConnectionDetails, err | ||||
| 	} | ||||
| @@ -168,29 +181,10 @@ func checkPullRepositoryConfiguration(options abapEnvironmentPullGitRepoOptions) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func handlePull(repo abaputils.Repository, pullConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, pollIntervall time.Duration) (err error) { | ||||
| 	startPullLogs(repo.Branch) | ||||
|  | ||||
| 	uriConnectionDetails, err := triggerPull(repo.Name, pullConnectionDetails, client) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrapf(err, "Pull of '%s' failed on the ABAP System", repo.Name) | ||||
| 	} | ||||
|  | ||||
| 	// Polling the status of the repository import on the ABAP Environment system | ||||
| 	status, errorPollEntity := abaputils.PollEntity(repo.Name, uriConnectionDetails, client, pollIntervall) | ||||
| 	if errorPollEntity != nil { | ||||
| 		return errors.Wrapf(errorPollEntity, "Pull of '%s' failed on the ABAP System", repo.Name) | ||||
| 	} | ||||
| 	if status == "E" { | ||||
| 		return errors.New("Pull of " + repo.Name + " failed on the ABAP System") | ||||
| 	} | ||||
| 	log.Entry().Info(repo.Name + " was pulled successfully") | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func startPullLogs(repositoryName string) { | ||||
| func startPullLogs(repo abaputils.Repository) { | ||||
| 	_, commitString := abaputils.GetCommitStrings(repo.CommitID) | ||||
| 	log.Entry().Info("-------------------------") | ||||
| 	log.Entry().Info("Start pulling " + repositoryName) | ||||
| 	log.Entry().Info("Start pulling '" + repo.Name + "'" + commitString) | ||||
| 	log.Entry().Info("-------------------------") | ||||
| } | ||||
|  | ||||
| @@ -198,3 +192,25 @@ func finishPullLogs() { | ||||
| 	log.Entry().Info("-------------------------") | ||||
| 	log.Entry().Info("All repositories were pulled successfully") | ||||
| } | ||||
|  | ||||
| func convertPullConfig(config *abapEnvironmentPullGitRepoOptions) abaputils.AbapEnvironmentOptions { | ||||
| 	subOptions := abaputils.AbapEnvironmentOptions{} | ||||
|  | ||||
| 	subOptions.CfAPIEndpoint = config.CfAPIEndpoint | ||||
| 	subOptions.CfServiceInstance = config.CfServiceInstance | ||||
| 	subOptions.CfServiceKeyName = config.CfServiceKeyName | ||||
| 	subOptions.CfOrg = config.CfOrg | ||||
| 	subOptions.CfSpace = config.CfSpace | ||||
| 	subOptions.Host = config.Host | ||||
| 	subOptions.Password = config.Password | ||||
| 	subOptions.Username = config.Username | ||||
| 	return subOptions | ||||
| } | ||||
|  | ||||
| func handleIgnoreCommit(repositories []abaputils.Repository, ignoreCommit bool) { | ||||
| 	for i := range repositories { | ||||
| 		if ignoreCommit { | ||||
| 			repositories[i].CommitID = "" | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -24,6 +24,7 @@ type abapEnvironmentPullGitRepoOptions struct { | ||||
| 	CfSpace           string   `json:"cfSpace,omitempty"` | ||||
| 	CfServiceInstance string   `json:"cfServiceInstance,omitempty"` | ||||
| 	CfServiceKeyName  string   `json:"cfServiceKeyName,omitempty"` | ||||
| 	IgnoreCommit      bool     `json:"ignoreCommit,omitempty"` | ||||
| } | ||||
|  | ||||
| // AbapEnvironmentPullGitRepoCommand Pulls a git repository to a SAP Cloud Platform ABAP Environment system | ||||
| @@ -100,6 +101,7 @@ func addAbapEnvironmentPullGitRepoFlags(cmd *cobra.Command, stepConfig *abapEnvi | ||||
| 	cmd.Flags().StringVar(&stepConfig.CfSpace, "cfSpace", os.Getenv("PIPER_cfSpace"), "Cloud Foundry target space") | ||||
| 	cmd.Flags().StringVar(&stepConfig.CfServiceInstance, "cfServiceInstance", os.Getenv("PIPER_cfServiceInstance"), "Cloud Foundry Service Instance") | ||||
| 	cmd.Flags().StringVar(&stepConfig.CfServiceKeyName, "cfServiceKeyName", os.Getenv("PIPER_cfServiceKeyName"), "Cloud Foundry Service Key") | ||||
| 	cmd.Flags().BoolVar(&stepConfig.IgnoreCommit, "ignoreCommit", false, "ingores a commit provided via the repositories file") | ||||
|  | ||||
| 	cmd.MarkFlagRequired("username") | ||||
| 	cmd.MarkFlagRequired("password") | ||||
| @@ -207,6 +209,14 @@ func abapEnvironmentPullGitRepoMetadata() config.StepData { | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{{Name: "cloudFoundry/serviceKey"}, {Name: "cloudFoundry/serviceKeyName"}, {Name: "cfServiceKey"}}, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "ignoreCommit", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS"}, | ||||
| 						Type:        "bool", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
|   | ||||
| @@ -46,6 +46,7 @@ func TestPullStep(t *testing.T) { | ||||
| 		err := runAbapEnvironmentPullGitRepo(&config, nil, &autils, client) | ||||
| 		assert.NoError(t, err, "Did not expect error") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Run Step Failure", func(t *testing.T) { | ||||
| 		expectedErrorMessage := "Something failed during the pull of the repositories: Checking configuration failed: You have not specified any repository configuration to be pulled into the ABAP Environment System. Please make sure that you specified the repositories that should be pulled either in a dedicated file or via the parameter 'repositoryNames'. For more information please read the User documentation" | ||||
|  | ||||
| @@ -69,6 +70,7 @@ func TestPullStep(t *testing.T) { | ||||
| 		err := runAbapEnvironmentPullGitRepo(&config, nil, &autils, client) | ||||
| 		assert.Equal(t, expectedErrorMessage, err.Error(), "Different error message expected") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Success case: pull repos from file config", func(t *testing.T) { | ||||
| 		var autils = abaputils.AUtilsMock{} | ||||
| 		defer autils.Cleanup() | ||||
| @@ -101,6 +103,7 @@ func TestPullStep(t *testing.T) { | ||||
| repositories: | ||||
| - name: 'testRepo' | ||||
|   branch: 'testBranch' | ||||
|   commitID: '9caede7f31028cd52333eb496434275687fefb47' | ||||
| - name: 'testRepo2' | ||||
|   branch: 'testBranch2' | ||||
| - name: 'testRepo3' | ||||
| @@ -121,6 +124,124 @@ repositories: | ||||
| 		err = runAbapEnvironmentPullGitRepo(&config, nil, &autils, client) | ||||
| 		assert.NoError(t, err) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Status Error", func(t *testing.T) { | ||||
| 		var autils = abaputils.AUtilsMock{} | ||||
| 		defer autils.Cleanup() | ||||
| 		autils.ReturnedConnectionDetailsHTTP.Password = "password" | ||||
| 		autils.ReturnedConnectionDetailsHTTP.User = "user" | ||||
| 		autils.ReturnedConnectionDetailsHTTP.URL = "https://example.com" | ||||
| 		autils.ReturnedConnectionDetailsHTTP.XCsrfToken = "xcsrftoken" | ||||
|  | ||||
| 		dir, errDir := ioutil.TempDir("", "test read addon descriptor") | ||||
| 		if errDir != nil { | ||||
| 			t.Fatal("Failed to create temporary directory") | ||||
| 		} | ||||
| 		oldCWD, _ := os.Getwd() | ||||
| 		_ = os.Chdir(dir) | ||||
| 		// clean up tmp dir | ||||
| 		defer func() { | ||||
| 			_ = os.Chdir(oldCWD) | ||||
| 			_ = os.RemoveAll(dir) | ||||
| 		}() | ||||
|  | ||||
| 		body := `--- | ||||
| repositories: | ||||
| - name: /DMO/REPO_A | ||||
|   tag: v-1.0.1-build-0001 | ||||
|   branch: branchA | ||||
|   version: 1.0.1 | ||||
|   commitID: ABCD1234 | ||||
| ` | ||||
| 		file, _ := os.Create("filename.yaml") | ||||
| 		file.Write([]byte(body)) | ||||
|  | ||||
| 		config := abapEnvironmentPullGitRepoOptions{ | ||||
| 			CfAPIEndpoint:     "https://api.endpoint.com", | ||||
| 			CfOrg:             "testOrg", | ||||
| 			CfSpace:           "testSpace", | ||||
| 			CfServiceInstance: "testInstance", | ||||
| 			CfServiceKeyName:  "testServiceKey", | ||||
| 			Username:          "testUser", | ||||
| 			Password:          "testPassword", | ||||
| 			Repositories:      "filename.yaml", | ||||
| 		} | ||||
|  | ||||
| 		client := &abaputils.ClientMock{ | ||||
| 			BodyList: []string{ | ||||
| 				`{"d" : { "status" : "E" } }`, | ||||
| 				`{"d" : { "status" : "R" } }`, | ||||
| 				`{"d" : { "status" : "R" } }`, | ||||
| 			}, | ||||
| 			Token:      "myToken", | ||||
| 			StatusCode: 200, | ||||
| 		} | ||||
|  | ||||
| 		err := runAbapEnvironmentPullGitRepo(&config, nil, &autils, client) | ||||
| 		if assert.Error(t, err, "Expected error") { | ||||
| 			assert.Equal(t, "Something failed during the pull of the repositories: Pull of '/DMO/REPO_A', commit 'ABCD1234' failed on the ABAP System", err.Error(), "Expected different error message") | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Status Error, Ignore Commit", func(t *testing.T) { | ||||
| 		var autils = abaputils.AUtilsMock{} | ||||
| 		defer autils.Cleanup() | ||||
| 		autils.ReturnedConnectionDetailsHTTP.Password = "password" | ||||
| 		autils.ReturnedConnectionDetailsHTTP.User = "user" | ||||
| 		autils.ReturnedConnectionDetailsHTTP.URL = "https://example.com" | ||||
| 		autils.ReturnedConnectionDetailsHTTP.XCsrfToken = "xcsrftoken" | ||||
|  | ||||
| 		dir, errDir := ioutil.TempDir("", "test read addon descriptor") | ||||
| 		if errDir != nil { | ||||
| 			t.Fatal("Failed to create temporary directory") | ||||
| 		} | ||||
| 		oldCWD, _ := os.Getwd() | ||||
| 		_ = os.Chdir(dir) | ||||
| 		// clean up tmp dir | ||||
| 		defer func() { | ||||
| 			_ = os.Chdir(oldCWD) | ||||
| 			_ = os.RemoveAll(dir) | ||||
| 		}() | ||||
|  | ||||
| 		body := `--- | ||||
| repositories: | ||||
| - name: /DMO/REPO_A | ||||
|   tag: v-1.0.1-build-0001 | ||||
|   branch: branchA | ||||
|   version: 1.0.1 | ||||
|   commitID: ABCD1234 | ||||
| ` | ||||
| 		file, _ := os.Create("filename.yaml") | ||||
| 		file.Write([]byte(body)) | ||||
|  | ||||
| 		config := abapEnvironmentPullGitRepoOptions{ | ||||
| 			CfAPIEndpoint:     "https://api.endpoint.com", | ||||
| 			CfOrg:             "testOrg", | ||||
| 			CfSpace:           "testSpace", | ||||
| 			CfServiceInstance: "testInstance", | ||||
| 			CfServiceKeyName:  "testServiceKey", | ||||
| 			Username:          "testUser", | ||||
| 			Password:          "testPassword", | ||||
| 			Repositories:      "filename.yaml", | ||||
| 			IgnoreCommit:      true, | ||||
| 		} | ||||
|  | ||||
| 		client := &abaputils.ClientMock{ | ||||
| 			BodyList: []string{ | ||||
| 				`{"d" : { "status" : "E" } }`, | ||||
| 				`{"d" : { "status" : "R" } }`, | ||||
| 				`{"d" : { "status" : "R" } }`, | ||||
| 			}, | ||||
| 			Token:      "myToken", | ||||
| 			StatusCode: 200, | ||||
| 		} | ||||
|  | ||||
| 		err := runAbapEnvironmentPullGitRepo(&config, nil, &autils, client) | ||||
| 		if assert.Error(t, err, "Expected error") { | ||||
| 			assert.Equal(t, "Something failed during the pull of the repositories: Pull of '/DMO/REPO_A' failed on the ABAP System", err.Error(), "Expected different error message") | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Failure case: pull repos from empty file config", func(t *testing.T) { | ||||
| 		expectedErrorMessage := "Something failed during the pull of the repositories: Error in config file repositoriesTest.yml, AddonDescriptor doesn't contain any repositories" | ||||
|  | ||||
| @@ -168,6 +289,7 @@ repositories: | ||||
| 		err = runAbapEnvironmentPullGitRepo(&config, nil, &autils, client) | ||||
| 		assert.EqualError(t, err, expectedErrorMessage) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Failure case: pull repos from wrong file config", func(t *testing.T) { | ||||
| 		expectedErrorMessage := "Something failed during the pull of the repositories: Could not unmarshal repositoriesTest.yml" | ||||
|  | ||||
| @@ -235,23 +357,16 @@ func TestTriggerPull(t *testing.T) { | ||||
| 			Token:      tokenExpected, | ||||
| 			StatusCode: 200, | ||||
| 		} | ||||
| 		config := abapEnvironmentPullGitRepoOptions{ | ||||
| 			CfAPIEndpoint:     "https://api.endpoint.com", | ||||
| 			CfOrg:             "testOrg", | ||||
| 			CfSpace:           "testSpace", | ||||
| 			CfServiceInstance: "testInstance", | ||||
| 			CfServiceKeyName:  "testServiceKey", | ||||
| 			Username:          "testUser", | ||||
| 			Password:          "testPassword", | ||||
| 			RepositoryNames:   []string{"testRepo1", "testRepo2"}, | ||||
| 		} | ||||
|  | ||||
| 		repoName := "testRepo1" | ||||
| 		testCommit := "9caede7f31028cd52333eb496434275687fefb47" | ||||
|  | ||||
| 		con := abaputils.ConnectionDetailsHTTP{ | ||||
| 			User:     "MY_USER", | ||||
| 			Password: "MY_PW", | ||||
| 			URL:      "https://api.endpoint.com/Entity/", | ||||
| 		} | ||||
| 		entityConnection, err := triggerPull(config.RepositoryNames[0], con, client) | ||||
| 		entityConnection, err := triggerPull(abaputils.Repository{Name: repoName, CommitID: testCommit}, con, client) | ||||
| 		assert.Nil(t, err) | ||||
| 		assert.Equal(t, uriExpected, entityConnection.URL) | ||||
| 		assert.Equal(t, tokenExpected, entityConnection.XCsrfToken) | ||||
| @@ -270,23 +385,16 @@ func TestTriggerPull(t *testing.T) { | ||||
| 			StatusCode: 400, | ||||
| 			Error:      errors.New(HTTPErrorMessage), | ||||
| 		} | ||||
| 		config := abapEnvironmentPullGitRepoOptions{ | ||||
| 			CfAPIEndpoint:     "https://api.endpoint.com", | ||||
| 			CfOrg:             "testOrg", | ||||
| 			CfSpace:           "testSpace", | ||||
| 			CfServiceInstance: "testInstance", | ||||
| 			CfServiceKeyName:  "testServiceKey", | ||||
| 			Username:          "testUser", | ||||
| 			Password:          "testPassword", | ||||
| 			RepositoryNames:   []string{"testRepo1", "testRepo2"}, | ||||
| 		} | ||||
|  | ||||
| 		repoName := "testRepo1" | ||||
| 		testCommit := "9caede7f31028cd52333eb496434275687fefb47" | ||||
|  | ||||
| 		con := abaputils.ConnectionDetailsHTTP{ | ||||
| 			User:     "MY_USER", | ||||
| 			Password: "MY_PW", | ||||
| 			URL:      "https://api.endpoint.com/Entity/", | ||||
| 		} | ||||
| 		_, err := triggerPull(config.RepositoryNames[0], con, client) | ||||
| 		_, err := triggerPull(abaputils.Repository{Name: repoName, CommitID: testCommit}, con, client) | ||||
| 		assert.Equal(t, combinedErrorMessage, err.Error(), "Different error message expected") | ||||
| 	}) | ||||
| } | ||||
| @@ -313,3 +421,38 @@ func TestPullConfigChecker(t *testing.T) { | ||||
| 		assert.Equal(t, errorMessage, err.Error(), "Different error message expected") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestHelpFunctions(t *testing.T) { | ||||
| 	t.Run("Ignore Commit", func(t *testing.T) { | ||||
| 		repo1 := abaputils.Repository{ | ||||
| 			Name:     "Repo1", | ||||
| 			CommitID: "ABCD1234", | ||||
| 		} | ||||
| 		repo2 := abaputils.Repository{ | ||||
| 			Name: "Repo2", | ||||
| 		} | ||||
|  | ||||
| 		repoList := []abaputils.Repository{repo1, repo2} | ||||
|  | ||||
| 		handleIgnoreCommit(repoList, true) | ||||
|  | ||||
| 		assert.Equal(t, "", repoList[0].CommitID, "Expected emtpy CommitID") | ||||
| 		assert.Equal(t, "", repoList[1].CommitID, "Expected emtpy CommitID") | ||||
| 	}) | ||||
| 	t.Run("Not Ignore Commit", func(t *testing.T) { | ||||
| 		repo1 := abaputils.Repository{ | ||||
| 			Name:     "Repo1", | ||||
| 			CommitID: "ABCD1234", | ||||
| 		} | ||||
| 		repo2 := abaputils.Repository{ | ||||
| 			Name: "Repo2", | ||||
| 		} | ||||
|  | ||||
| 		repoList := []abaputils.Repository{repo1, repo2} | ||||
|  | ||||
| 		handleIgnoreCommit(repoList, false) | ||||
|  | ||||
| 		assert.Equal(t, "ABCD1234", repoList[0].CommitID, "Expected CommitID") | ||||
| 		assert.Equal(t, "", repoList[1].CommitID, "Expected emtpy CommitID") | ||||
| 	}) | ||||
| } | ||||
|   | ||||
| @@ -28,15 +28,6 @@ func abapEnvironmentRunATCCheck(options abapEnvironmentRunATCCheckOptions, telem | ||||
| 	// Mapping for options | ||||
| 	subOptions := abaputils.AbapEnvironmentOptions{} | ||||
|  | ||||
| 	subOptions.CfAPIEndpoint = options.CfAPIEndpoint | ||||
| 	subOptions.CfServiceInstance = options.CfServiceInstance | ||||
| 	subOptions.CfServiceKeyName = options.CfServiceKeyName | ||||
| 	subOptions.CfOrg = options.CfOrg | ||||
| 	subOptions.CfSpace = options.CfSpace | ||||
| 	subOptions.Host = options.Host | ||||
| 	subOptions.Password = options.Password | ||||
| 	subOptions.Username = options.Username | ||||
|  | ||||
| 	c := &command.Command{} | ||||
| 	c.Stdout(log.Entry().Writer()) | ||||
| 	c.Stderr(log.Entry().Writer()) | ||||
| @@ -131,6 +122,7 @@ func triggerATCrun(config abapEnvironmentRunATCCheckOptions, details abaputils.C | ||||
| 	//Trigger ATC run | ||||
| 	var resp *http.Response | ||||
| 	var bodyString = `<?xml version="1.0" encoding="UTF-8"?><atc:runparameters xmlns:atc="http://www.sap.com/adt/atc" xmlns:obj="http://www.sap.com/adt/objectset"` + checkVariantString + `><obj:objectSet>` + softwareComponentString + packageString + `</obj:objectSet></atc:runparameters>` | ||||
| 	log.Entry().Debugf("Request Body: %s", bodyString) | ||||
| 	var body = []byte(bodyString) | ||||
| 	if err == nil { | ||||
| 		details.URL = abapEndpoint + "/sap/bc/adt/api/atc/runs?clientWait=false" | ||||
| @@ -150,6 +142,7 @@ func buildATCCheckBody(ATCConfig ATCconfig) (checkVariantString string, packageS | ||||
| 	//Build Check Variant and Configuration XML Body | ||||
| 	if len(ATCConfig.CheckVariant) != 0 { | ||||
| 		checkVariantString += ` checkVariant="` + ATCConfig.CheckVariant + `"` | ||||
| 		log.Entry().Infof("ATC Check Variant: %s", ATCConfig.CheckVariant) | ||||
| 		if len(ATCConfig.Configuration) != 0 { | ||||
| 			checkVariantString += ` configuration="` + ATCConfig.Configuration + `"` | ||||
| 		} | ||||
| @@ -179,15 +172,19 @@ func parseATCResult(body []byte, atcResultFileName string) (err error) { | ||||
| 	if len(body) == 0 { | ||||
| 		return fmt.Errorf("Parsing ATC result failed: %w", errors.New("Body is empty, can't parse empty body")) | ||||
| 	} | ||||
|  | ||||
| 	responseBody := string(body) | ||||
| 	log.Entry().Debugf("Response body: %s", responseBody) | ||||
| 	if strings.HasPrefix(responseBody, "<html>") { | ||||
| 		return errors.New("The Software Component could not be checked. Please make sure the respective Software Component has been cloned successfully on the system") | ||||
| 	} | ||||
|  | ||||
| 	parsedXML := new(Result) | ||||
| 	xml.Unmarshal([]byte(body), &parsedXML) | ||||
| 	if len(parsedXML.Files) == 0 { | ||||
| 		log.Entry().Info("There were no results from this run, most likely the checked Software Components are empty or contain no ATC findings") | ||||
| 	} | ||||
| 	s := string(body) | ||||
| 	if strings.HasPrefix(s, "<html>") { | ||||
| 		return errors.New("The Software Component could not be checked. Please make sure the respective Software Component has been cloned successfully on the system") | ||||
| 	} | ||||
|  | ||||
| 	err = ioutil.WriteFile(atcResultFileName, body, 0644) | ||||
| 	if err == nil { | ||||
| 		var reports []piperutils.Path | ||||
| @@ -223,7 +220,7 @@ func runATC(requestType string, details abaputils.ConnectionDetailsHTTP, body [] | ||||
|  | ||||
| func fetchXcsrfToken(requestType string, details abaputils.ConnectionDetailsHTTP, body []byte, client piperhttp.Sender) (string, error) { | ||||
|  | ||||
| 	log.Entry().WithField("ABAP Endpoint: ", details.URL).Info("Fetching Xcrsf-Token") | ||||
| 	log.Entry().WithField("ABAP Endpoint: ", details.URL).Debug("Fetching Xcrsf-Token") | ||||
|  | ||||
| 	details.URL += "/sap/bc/adt/api/atc/runs/00000000000000000000000000000000" | ||||
| 	details.XCsrfToken = "fetch" | ||||
| @@ -303,6 +300,21 @@ func getResultATCRun(requestType string, details abaputils.ConnectionDetailsHTTP | ||||
| 	return req, err | ||||
| } | ||||
|  | ||||
| func convertATCOptions(options *abapEnvironmentRunATCCheckOptions) abaputils.AbapEnvironmentOptions { | ||||
| 	subOptions := abaputils.AbapEnvironmentOptions{} | ||||
|  | ||||
| 	subOptions.CfAPIEndpoint = options.CfAPIEndpoint | ||||
| 	subOptions.CfServiceInstance = options.CfServiceInstance | ||||
| 	subOptions.CfServiceKeyName = options.CfServiceKeyName | ||||
| 	subOptions.CfOrg = options.CfOrg | ||||
| 	subOptions.CfSpace = options.CfSpace | ||||
| 	subOptions.Host = options.Host | ||||
| 	subOptions.Password = options.Password | ||||
| 	subOptions.Username = options.Username | ||||
|  | ||||
| 	return subOptions | ||||
| } | ||||
|  | ||||
| //ATCconfig object for parsing yaml config of software components and packages | ||||
| type ATCconfig struct { | ||||
| 	CheckVariant  string     `json:"checkvariant,omitempty"` | ||||
|   | ||||
| @@ -56,7 +56,7 @@ repositories: | ||||
| ``` | ||||
|  | ||||
| Please note that you need to use the YAML data structure as in the example above when using the `repositories.yml` config file. | ||||
| For this step it is mandatory to fill the branch values. You can also use this file for the abapEnvironmentPullGitRepo step. | ||||
| For this step it is mandatory to fill the branch values. You can also use this file for the abapEnvironmentPullGitRepo step. Using this configuration file is the recommended approach. | ||||
|  | ||||
| If you want to read the host and credentials from the cloud foundry service key of the respective instance, the configuration could look as follows: | ||||
|  | ||||
|   | ||||
| @@ -60,6 +60,11 @@ repositories: | ||||
|     branch: 'feature' | ||||
| ``` | ||||
|  | ||||
| Using such a configuration file is the recommended approach. Please note that you need to use the YAML data structure as in the example above when using the `repositories.yml` config file. | ||||
|  | ||||
| !!! note "Commit IDs" | ||||
|     CommitIDs will also be supported in the future. While the step already includes the handling of commit IDs, the ABAP Environment system will support this not until a later release. | ||||
|  | ||||
| ## Example: Configuration in the Jenkinsfile | ||||
|  | ||||
| It is also possible to call the steps - including all parameters - directly in the Jenkinsfile. | ||||
|   | ||||
| @@ -31,7 +31,7 @@ steps: | ||||
|     host: '1234-abcd-5678-efgh-ijk.abap.eu10.hana.ondemand.com' | ||||
| ``` | ||||
|  | ||||
| Also you can specify a dedicated file, e.g. `repositories.yml` containing the repositories to be pulled: | ||||
| However, we recommend to use a dedicated file, e.g. `repositories.yml` to specify the repositories to be pulled: | ||||
|  | ||||
| ```yaml | ||||
| steps: | ||||
| @@ -51,8 +51,10 @@ repositories: | ||||
|   branch: 'master' | ||||
| ``` | ||||
|  | ||||
| Please note that you need to adapt the file structure according to the structure in this example in order to work. | ||||
| It is possible to leave the branch value out. However if you also want to use this file for the abapEnvironmentCheckoutBranch step it is recommended to follow above structure. | ||||
| It is optional to provide a branch. However, if you also want to use this file for the abapEnvironmentCheckoutBranch step it is recommended to follow the above structure. | ||||
|  | ||||
| !!! note "Commit IDs" | ||||
|     CommitIDs will also be supported in the future. While the step already includes the handling of commit IDs, the ABAP Environment system will support this not until a later release. | ||||
|  | ||||
| If you want to read the host and credentials from the cloud foundry service key of the respective instance, the configuration could look as follows: | ||||
|  | ||||
|   | ||||
| @@ -29,6 +29,7 @@ type Repository struct { | ||||
| 	Name                string `json:"name"` | ||||
| 	Tag                 string `json:"tag"` | ||||
| 	Branch              string `json:"branch"` | ||||
| 	CommitID            string `json:"commitID"` | ||||
| 	VersionYAML         string `json:"version"` | ||||
| 	Version             string `json:"versionAAK"` | ||||
| 	PackageName         string | ||||
|   | ||||
| @@ -44,7 +44,11 @@ func PollEntity(repositoryName string, connectionDetails ConnectionDetailsHTTP, | ||||
| 		status = body.Status | ||||
| 		log.Entry().WithField("StatusCode", resp.Status).Info("Pull Status: " + body.StatusDescription) | ||||
| 		if body.Status != "R" { | ||||
| 			PrintLogs(body) | ||||
| 			if body.Status == "E" { | ||||
| 				PrintLogs(body, true) | ||||
| 			} else { | ||||
| 				PrintLogs(body, false) | ||||
| 			} | ||||
| 			break | ||||
| 		} | ||||
| 		time.Sleep(pollIntervall) | ||||
| @@ -53,7 +57,7 @@ func PollEntity(repositoryName string, connectionDetails ConnectionDetailsHTTP, | ||||
| } | ||||
|  | ||||
| // PrintLogs sorts and formats the received transport and execution log of an import | ||||
| func PrintLogs(entity PullEntity) { | ||||
| func PrintLogs(entity PullEntity, errorOnSystem bool) { | ||||
|  | ||||
| 	// Sort logs | ||||
| 	sort.SliceStable(entity.ToExecutionLog.Results, func(i, j int) bool { | ||||
| @@ -64,21 +68,41 @@ func PrintLogs(entity PullEntity) { | ||||
| 		return entity.ToTransportLog.Results[i].Index < entity.ToTransportLog.Results[j].Index | ||||
| 	}) | ||||
|  | ||||
| 	log.Entry().Info("-------------------------") | ||||
| 	log.Entry().Info("Transport Log") | ||||
| 	log.Entry().Info("-------------------------") | ||||
| 	for _, logEntry := range entity.ToTransportLog.Results { | ||||
| 	// Show transport and execution log if either the action was erroenous on the system or the log level is set to "debug" (verbose = true) | ||||
| 	if errorOnSystem { | ||||
| 		log.Entry().Info("-------------------------") | ||||
| 		log.Entry().Info("Transport Log") | ||||
| 		log.Entry().Info("-------------------------") | ||||
| 		for _, logEntry := range entity.ToTransportLog.Results { | ||||
|  | ||||
| 		log.Entry().WithField("Timestamp", ConvertTime(logEntry.Timestamp)).Info(logEntry.Description) | ||||
| 			log.Entry().WithField("Timestamp", ConvertTime(logEntry.Timestamp)).Info(logEntry.Description) | ||||
| 		} | ||||
|  | ||||
| 		log.Entry().Info("-------------------------") | ||||
| 		log.Entry().Info("Execution Log") | ||||
| 		log.Entry().Info("-------------------------") | ||||
| 		for _, logEntry := range entity.ToExecutionLog.Results { | ||||
| 			log.Entry().WithField("Timestamp", ConvertTime(logEntry.Timestamp)).Info(logEntry.Description) | ||||
| 		} | ||||
| 		log.Entry().Info("-------------------------") | ||||
| 	} else { | ||||
| 		log.Entry().Debug("-------------------------") | ||||
| 		log.Entry().Debug("Transport Log") | ||||
| 		log.Entry().Debug("-------------------------") | ||||
| 		for _, logEntry := range entity.ToTransportLog.Results { | ||||
|  | ||||
| 			log.Entry().WithField("Timestamp", ConvertTime(logEntry.Timestamp)).Debug(logEntry.Description) | ||||
| 		} | ||||
|  | ||||
| 		log.Entry().Debug("-------------------------") | ||||
| 		log.Entry().Debug("Execution Log") | ||||
| 		log.Entry().Debug("-------------------------") | ||||
| 		for _, logEntry := range entity.ToExecutionLog.Results { | ||||
| 			log.Entry().WithField("Timestamp", ConvertTime(logEntry.Timestamp)).Debug(logEntry.Description) | ||||
| 		} | ||||
| 		log.Entry().Debug("-------------------------") | ||||
| 	} | ||||
|  | ||||
| 	log.Entry().Info("-------------------------") | ||||
| 	log.Entry().Info("Execution Log") | ||||
| 	log.Entry().Info("-------------------------") | ||||
| 	for _, logEntry := range entity.ToExecutionLog.Results { | ||||
| 		log.Entry().WithField("Timestamp", ConvertTime(logEntry.Timestamp)).Info(logEntry.Description) | ||||
| 	} | ||||
| 	log.Entry().Info("-------------------------") | ||||
| } | ||||
|  | ||||
| //GetRepositories for parsing  one or multiple branches and repositories from repositories file or branchName and repositoryName configuration | ||||
| @@ -112,6 +136,15 @@ func GetRepositories(config *RepositoriesConfig) ([]Repository, error) { | ||||
| 	return repositories, nil | ||||
| } | ||||
|  | ||||
| //GetCommitStrings for getting the commit_id property for the http request and a string for logging output | ||||
| func GetCommitStrings(commitID string) (commitQuery string, commitString string) { | ||||
| 	if commitID != "" { | ||||
| 		commitQuery = `, "commit_id":"` + commitID + `"` | ||||
| 		commitString = ", commit '" + commitID + "'" | ||||
| 	} | ||||
| 	return commitQuery, commitString | ||||
| } | ||||
|  | ||||
| /**************************************** | ||||
|  *	Structs for the A4C_A2G_GHA service * | ||||
|  ****************************************/ | ||||
|   | ||||
| @@ -215,3 +215,16 @@ repositories: | ||||
| 		assert.EqualError(t, err, expectedErrorMessage) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestGetCommitStrings(t *testing.T) { | ||||
| 	t.Run("CommitID available", func(t *testing.T) { | ||||
| 		commitQuery, commitString := GetCommitStrings("ABCD1234") | ||||
| 		assert.Equal(t, `, "commit_id":"ABCD1234"`, commitQuery, "Expected different query") | ||||
| 		assert.Equal(t, `, commit 'ABCD1234'`, commitString, "Expected different string") | ||||
| 	}) | ||||
| 	t.Run("CommitID available", func(t *testing.T) { | ||||
| 		commitQuery, commitString := GetCommitStrings("") | ||||
| 		assert.Equal(t, ``, commitQuery, "Expected empty query") | ||||
| 		assert.Equal(t, ``, commitString, "Expected empty string") | ||||
| 	}) | ||||
| } | ||||
|   | ||||
| @@ -66,9 +66,6 @@ general: | ||||
|  | ||||
| #Steps Specific Configuration | ||||
| steps: | ||||
|   abapEnvironmentPullGitRepo: | ||||
|     dockerImage: 'ppiper/cf-cli' | ||||
|     dockerWorkspace: '/home/piper' | ||||
|   artifactSetVersion: | ||||
|     timestampTemplate: '%Y%m%d%H%M%S' | ||||
|     tagPrefix: 'build_' | ||||
| @@ -212,9 +209,6 @@ steps: | ||||
|     stashContent: | ||||
|       - 'tests' | ||||
|     testReportFilePath: 'cst-report.json' | ||||
|   cloudFoundryCreateServiceKey: | ||||
|     dockerImage: 'ppiper/cf-cli' | ||||
|     dockerWorkspace: '/home/piper' | ||||
|   debugReportArchive: | ||||
|     shareConfidentialInformation: false | ||||
|   dockerExecute: | ||||
|   | ||||
| @@ -120,6 +120,12 @@ spec: | ||||
|           - name: cloudFoundry/serviceKey | ||||
|           - name: cloudFoundry/serviceKeyName | ||||
|           - name: cfServiceKey | ||||
|       - name: ignoreCommit | ||||
|         type: bool | ||||
|         description: ingores a commit provided via the repositories file | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|         default: false | ||||
|   containers: | ||||
|     - name: cf | ||||
|       image: ppiper/cf-cli | ||||
|   | ||||
		Reference in New Issue
	
	Block a user