1
0
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:
tiloKo
2022-08-23 15:33:42 +02:00
committed by GitHub
parent f089e3d89e
commit 0a2327dda8
6 changed files with 109 additions and 12 deletions

View File

@@ -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
}

View File

@@ -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)
})
}

View File

@@ -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 {

View File

@@ -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)
})
}

View File

@@ -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)
}

View File

@@ -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)