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 
			
		
		
		
	Abap relese confirm fault tollerant (#3916)
* no error if package release fails
This commit is contained in:
		| @@ -39,7 +39,17 @@ func runAbapAddonAssemblyKitReleasePackages(config *abapAddonAssemblyKitReleaseP | ||||
| 	packagesWithReposLocked, packagesWithReposNotLocked := sortByStatus(addonDescriptor.Repositories, *conn) | ||||
| 	packagesWithReposLocked, err = releaseAndPoll(packagesWithReposLocked, utils) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 		var numberOfReleasedPackages int | ||||
| 		for i := range packagesWithReposLocked { | ||||
| 			if packagesWithReposLocked[i].Package.Status == aakaas.PackageStatusReleased { | ||||
| 				numberOfReleasedPackages += 1 | ||||
| 			} | ||||
| 		} | ||||
| 		if numberOfReleasedPackages == 0 { | ||||
| 			return errors.Wrap(err, "Release of all packages failed/timed out - Aborting as abapEnvironmentAssembleConfirm step is not needed") | ||||
| 		} else { | ||||
| 			log.Entry().WithError(err).Warn("Release of at least one package failed/timed out - Continuing anyway to enable abapEnvironmentAssembleConfirm to run") | ||||
| 		} | ||||
| 	} | ||||
| 	addonDescriptor.Repositories = sortingBack(packagesWithReposLocked, packagesWithReposNotLocked) | ||||
| 	log.Entry().Info("Writing package status to CommonPipelineEnvironment") | ||||
| @@ -78,7 +88,7 @@ func sortByStatus(repos []abaputils.Repository, conn abapbuild.Connector) ([]aak | ||||
| 			Package: pack, | ||||
| 			Repo:    repos[i], | ||||
| 		} | ||||
| 		if pack.Status == "L" { | ||||
| 		if pack.Status == aakaas.PackageStatusLocked { | ||||
| 			packagesWithReposLocked = append(packagesWithReposLocked, pWR) | ||||
| 		} else { | ||||
| 			log.Entry().Infof("Package %s has status %s, cannot release this package", pack.PackageName, pack.Status) | ||||
| @@ -103,6 +113,7 @@ func releaseAndPoll(pckgWR []aakaas.PackageWithRepository, utils *aakaas.AakUtil | ||||
| 					err := pckgWR[i].Package.Release() | ||||
| 					// if there is an error, release is not yet finished | ||||
| 					if err != nil { | ||||
| 						log.Entry().Error(err) | ||||
| 						log.Entry().Infof("Release of %s is not yet finished, check again in %s", pckgWR[i].Package.PackageName, (*utils).GetPollingInterval()) | ||||
| 						allFinished = false | ||||
| 					} | ||||
|   | ||||
| @@ -63,7 +63,7 @@ func TestReleasePackagesStep(t *testing.T) { | ||||
| 		assert.Equal(t, err.Error(), "Parameter missing. Please provide the name of the package which should be released") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("step error - timeout", func(t *testing.T) { | ||||
| 	t.Run("step error - timeout single", func(t *testing.T) { | ||||
| 		//arrange | ||||
| 		bundle.SetError("Release not finished") | ||||
| 		bundle.SetMaxRuntime(1 * time.Microsecond) | ||||
| @@ -81,7 +81,46 @@ func TestReleasePackagesStep(t *testing.T) { | ||||
| 		err := runAbapAddonAssemblyKitReleasePackages(&config, nil, &utils, &cpe) | ||||
| 		//assert | ||||
| 		assert.Error(t, err, "Did expect error") | ||||
| 		assert.Equal(t, err.Error(), "Timed out") | ||||
| 		assert.Equal(t, err.Error(), "Release of all packages failed/timed out - Aborting as abapEnvironmentAssembleConfirm step is not needed: Timed out") | ||||
| 	}) | ||||
| } | ||||
| func TestReleasePackagesStepMix(t *testing.T) { | ||||
| 	var config abapAddonAssemblyKitReleasePackagesOptions | ||||
| 	var cpe abapAddonAssemblyKitReleasePackagesCommonPipelineEnvironment | ||||
| 	bundle := aakaas.NewAakBundleMock() | ||||
| 	bundle.SetBody(responseRelease) | ||||
| 	utils := bundle.GetUtils() | ||||
|  | ||||
| 	config.Username = "dummyUser" | ||||
| 	config.Password = "dummyPassword" | ||||
| 	t.Run("step error - timeout mix", func(t *testing.T) { | ||||
| 		//arrange | ||||
| 		bundle.SetBodyList([]string{responseRelease, responseRelease}) //Head + Post | ||||
| 		bundle.SetMaxRuntime(500 * time.Microsecond) | ||||
| 		bundle.SetErrorInsteadOfDumpToTrue() | ||||
| 		addonDescriptor := abaputils.AddonDescriptor{ | ||||
| 			Repositories: []abaputils.Repository{ | ||||
| 				{ | ||||
| 					PackageName: "SAPK-002AAINDRNMSPC", | ||||
| 					Status:      "L", | ||||
| 				}, | ||||
| 				{ | ||||
| 					PackageName: "SAPK-001AAINDRNMSPC", | ||||
| 					Status:      "L", | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 		adoDesc, _ := json.Marshal(addonDescriptor) | ||||
| 		config.AddonDescriptor = string(adoDesc) | ||||
| 		//act | ||||
| 		err := runAbapAddonAssemblyKitReleasePackages(&config, nil, &utils, &cpe) | ||||
| 		//assert | ||||
| 		assert.NoError(t, err, "Did not expect error") | ||||
| 		var addonDescriptorFinal abaputils.AddonDescriptor | ||||
| 		err = json.Unmarshal([]byte(cpe.abap.addonDescriptor), &addonDescriptorFinal) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "R", addonDescriptorFinal.Repositories[0].Status) | ||||
| 		assert.Equal(t, "L", addonDescriptorFinal.Repositories[1].Status) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -75,6 +75,7 @@ func runAbapEnvironmentAssembleConfirm(config *abapEnvironmentAssembleConfirmOpt | ||||
|  | ||||
| func startingConfirm(repos []abaputils.Repository, conn abapbuild.Connector, delayBetweenPosts time.Duration) ([]buildWithRepository, error) { | ||||
| 	var confirmedBuilds []buildWithRepository | ||||
| 	var releasePackagesFailed error = nil | ||||
| 	for _, repo := range repos { | ||||
| 		assemblyBuild := abapbuild.Build{ | ||||
| 			Connector: conn, | ||||
| @@ -83,12 +84,19 @@ func startingConfirm(repos []abaputils.Repository, conn abapbuild.Connector, del | ||||
| 			build: assemblyBuild, | ||||
| 			repo:  repo, | ||||
| 		} | ||||
| 		if repo.InBuildScope { | ||||
| 		if repo.InBuildScope && repo.Status == "R" { | ||||
| 			err := buildRepo.startConfirm() | ||||
| 			if err != nil { | ||||
| 				return confirmedBuilds, err | ||||
| 			} | ||||
| 			confirmedBuilds = append(confirmedBuilds, buildRepo) | ||||
| 		} else if repo.InBuildScope && repo.Status != "R" { | ||||
| 			errormessage := "Release of package '" + repo.PackageName + "' must have failed as still in status: '" + repo.Status + "'" | ||||
| 			if releasePackagesFailed == nil { | ||||
| 				releasePackagesFailed = errors.New(errormessage) | ||||
| 			} else { | ||||
| 				releasePackagesFailed = errors.Wrapf(releasePackagesFailed, errormessage) | ||||
| 			} | ||||
| 		} else { | ||||
| 			log.Entry().Infof("Packages %s was not assembled in this pipeline run, thus no need to confirm", repo.PackageName) | ||||
| 		} | ||||
| @@ -96,7 +104,7 @@ func startingConfirm(repos []abaputils.Repository, conn abapbuild.Connector, del | ||||
| 		//as batch events in the ABAP Backend need a little time | ||||
| 		time.Sleep(delayBetweenPosts) | ||||
| 	} | ||||
| 	return confirmedBuilds, nil | ||||
| 	return confirmedBuilds, releasePackagesFailed | ||||
| } | ||||
|  | ||||
| func polling(builds []buildWithRepository, maxRuntimeInMinutes time.Duration, pollInterval time.Duration) error { | ||||
|   | ||||
| @@ -75,3 +75,34 @@ func TestStartingConfirmInvalidInput(t *testing.T) { | ||||
| 		assert.Error(t, err) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestStartingConfirmReleaseFailed(t *testing.T) { | ||||
| 	t.Run("Run starting release failed", func(t *testing.T) { | ||||
| 		client := &abapbuild.ClMock{ | ||||
| 			Token: "MyToken", | ||||
| 		} | ||||
| 		conn := new(abapbuild.Connector) | ||||
| 		conn.Client = client | ||||
| 		conn.Header = make(map[string][]string) | ||||
| 		var repos []abaputils.Repository | ||||
| 		repo := abaputils.Repository{ | ||||
| 			Name:         "RepoA", | ||||
| 			Version:      "0001", | ||||
| 			PackageName:  "Package", | ||||
| 			PackageType:  "AOI", | ||||
| 			SpLevel:      "0000", | ||||
| 			PatchLevel:   "0000", | ||||
| 			Status:       "L", | ||||
| 			Namespace:    "/DEMO/", | ||||
| 			InBuildScope: true, | ||||
| 		} | ||||
| 		repos = append(repos, repo) | ||||
| 		repo.Status = "R" | ||||
| 		repos = append(repos, repo) | ||||
|  | ||||
| 		builds, err := startingConfirm(repos, *conn, time.Duration(0*time.Second)) | ||||
| 		assert.Error(t, err) | ||||
| 		assert.Equal(t, 1, len(builds)) | ||||
| 		assert.Equal(t, abapbuild.Accepted, builds[0].build.RunState) | ||||
| 	}) | ||||
| } | ||||
|   | ||||
| @@ -56,6 +56,10 @@ func (bundle *AakBundleMock) SetBody(body string) { | ||||
| 	bundle.ClientMock.BodyList = []string{} | ||||
| } | ||||
|  | ||||
| func (bundle *AakBundleMock) SetErrorInsteadOfDumpToTrue() { | ||||
| 	bundle.ClientMock.ErrorInsteadOfDump = true | ||||
| } | ||||
|  | ||||
| func (bundle *AakBundleMock) SetError(errorText string) { | ||||
| 	bundle.ClientMock.Error = errors.New(errorText) | ||||
| } | ||||
|   | ||||
| @@ -322,12 +322,13 @@ type AbapBinding struct { | ||||
|  | ||||
| // ClientMock contains information about the client mock | ||||
| type ClientMock struct { | ||||
| 	Token       string | ||||
| 	Body        string | ||||
| 	BodyList    []string | ||||
| 	StatusCode  int | ||||
| 	Error       error | ||||
| 	NilResponse bool | ||||
| 	Token              string | ||||
| 	Body               string | ||||
| 	BodyList           []string | ||||
| 	StatusCode         int | ||||
| 	Error              error | ||||
| 	NilResponse        bool | ||||
| 	ErrorInsteadOfDump bool | ||||
| } | ||||
|  | ||||
| // SetOptions sets clientOptions for a client mock | ||||
| @@ -344,6 +345,9 @@ func (c *ClientMock) SendRequest(method, url string, bdy io.Reader, hdr http.Hea | ||||
| 	if c.Body != "" { | ||||
| 		body = []byte(c.Body) | ||||
| 	} else { | ||||
| 		if c.ErrorInsteadOfDump && len(c.BodyList) == 0 { | ||||
| 			return nil, errors.New("No more bodies in the list") | ||||
| 		} | ||||
| 		bodyString := c.BodyList[len(c.BodyList)-1] | ||||
| 		c.BodyList = c.BodyList[:len(c.BodyList)-1] | ||||
| 		body = []byte(bodyString) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user