1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-01-04 04:07:16 +02:00

AAKaaS: 7 reserve next package (#2046)

* adding my steps

* messy step

* Update abapEnvironmentAssembly.go

* clean up

* change yaml

* corrections

* Update cloudFoundryDeploy.go

* update

* delete simulation step

* remove simulate

* Update PiperGoUtils.groovy

* Update PiperGoUtils.groovy

* Update CommonStepsTest.groovy

* add docu

* Update abapEnvironmentAssembly.md

* changes due to PR

* Update .gitignore

* b

* CV list

* Update abapEnvironmentAssembly.go

* testing with simulation

* Update abapEnvironmentAssembly.go

* remove simulation

* renaming

* Update mkdocs.yml

* moving service key to yaml and fixing code climate

* Update abapEnvironmentAssemblePackages.go

* Update abapEnvironmentAssemblePackages.go

* Update abapEnvironmentAssemblePackages.go

* Update abapEnvironmentAssemblePackages.go

* change input

* Update abapEnvironmentAssemblePackages.go

* change json tag

* fixed error handling

* documentation

* Update abapEnvironmentAssemblePackages.md

* Update abapEnvironmentAssemblePackages.md

* fixing code climate issues

* fixing code climate issues

* Update abapEnvironmentAssemblePackages.yaml

* fixing code climate issues

* Update abapEnvironmentAssemblePackages.yaml

* adding unittests

* adding unittests and improved logging

* yaml -> json

* change scope of cfServiceKeyName

* correct indentation

* Update CommonStepsTest.groovy

* maintain correct step order

* AAKaaS register package

* AAKaaS register package #2

* Update documentation/docs/steps/abapAddonAssemblyKitPublishTargetVector.md

Co-authored-by: Daniel Mieg <56156797+DanielMieg@users.noreply.github.com>

* AAKaaS register package #3

* AAKaaS release package

* Update abapAddonAssemblyKitReleasePackages.go

* AAKaas release package #2

* AAKaaS reserve

* AAKaaS reserve #2

Co-authored-by: rosemarieB <45030247+rosemarieB@users.noreply.github.com>
Co-authored-by: Daniel Mieg <56156797+DanielMieg@users.noreply.github.com>
Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com>
This commit is contained in:
tiloKo 2020-09-18 17:27:04 +02:00 committed by GitHub
parent 3c87648c00
commit fa17611a59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 896 additions and 3 deletions

View File

@ -0,0 +1,123 @@
package cmd
import (
"encoding/json"
"fmt"
"time"
"github.com/SAP/jenkins-library/pkg/abap/aakaas"
abapbuild "github.com/SAP/jenkins-library/pkg/abap/build"
"github.com/SAP/jenkins-library/pkg/abaputils"
"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/telemetry"
"github.com/pkg/errors"
)
func abapAddonAssemblyKitReserveNextPackages(config abapAddonAssemblyKitReserveNextPackagesOptions, telemetryData *telemetry.CustomData, cpe *abapAddonAssemblyKitReserveNextPackagesCommonPipelineEnvironment) {
// for command execution use Command
c := command.Command{}
// reroute command output to logging framework
c.Stdout(log.Writer())
c.Stderr(log.Writer())
client := piperhttp.Client{}
maxRuntimeInMinutes := time.Duration(5 * time.Minute)
pollIntervalsInSeconds := time.Duration(30 * time.Second)
// error situations should stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end
err := runAbapAddonAssemblyKitReserveNextPackages(&config, telemetryData, &client, cpe, maxRuntimeInMinutes, pollIntervalsInSeconds)
if err != nil {
log.Entry().WithError(err).Fatal("step execution failed")
}
}
func runAbapAddonAssemblyKitReserveNextPackages(config *abapAddonAssemblyKitReserveNextPackagesOptions, telemetryData *telemetry.CustomData, client piperhttp.Sender,
cpe *abapAddonAssemblyKitReserveNextPackagesCommonPipelineEnvironment, maxRuntimeInMinutes time.Duration, pollIntervalsInSeconds time.Duration) error {
conn := new(abapbuild.Connector)
conn.InitAAKaaS(config.AbapAddonAssemblyKitEndpoint, config.Username, config.Password, client)
var addonDescriptor abaputils.AddonDescriptor
json.Unmarshal([]byte(config.AddonDescriptor), &addonDescriptor)
packagesWithRepos, err := reservePackages(addonDescriptor.Repositories, *conn)
if err != nil {
return err
}
err = pollReserveNextPackages(packagesWithRepos, maxRuntimeInMinutes, pollIntervalsInSeconds)
if err != nil {
return err
}
addonDescriptor.Repositories = copyFieldsToRepositories(packagesWithRepos)
log.Entry().Info("Writing package names, types, status, namespace and predecessorCommitID to CommonPipelineEnvironment")
backToCPE, _ := json.Marshal(addonDescriptor)
cpe.abap.addonDescriptor = string(backToCPE)
return nil
}
func copyFieldsToRepositories(pckgWR []aakaas.PackageWithRepository) []abaputils.Repository {
var repos []abaputils.Repository
for i := range pckgWR {
pckgWR[i].Package.CopyFieldsToRepo(&pckgWR[i].Repo)
repos = append(repos, pckgWR[i].Repo)
}
return repos
}
func pollReserveNextPackages(pckgWR []aakaas.PackageWithRepository, maxRuntimeInMinutes time.Duration, pollIntervalsInSeconds time.Duration) error {
timeout := time.After(maxRuntimeInMinutes)
ticker := time.Tick(pollIntervalsInSeconds)
for {
select {
case <-timeout:
return errors.New("Timed out")
case <-ticker:
var allFinished bool = true
for i := range pckgWR {
err := pckgWR[i].Package.GetPackageAndNamespace()
// if there is an error, reservation is not yet finished
if err != nil {
log.Entry().Infof("Reservation of %s is not yet finished, check again in %s", pckgWR[i].Package.PackageName, pollIntervalsInSeconds)
allFinished = false
} else {
switch pckgWR[i].Package.Status {
case aakaas.PackageStatusLocked:
return fmt.Errorf("Package %s has invalid status 'locked'", pckgWR[i].Package.PackageName)
case aakaas.PackageStatusCreationTriggered:
log.Entry().Infof("Reservation of %s is still running with status 'creation triggered', check again in %s", pckgWR[i].Package.PackageName, pollIntervalsInSeconds)
allFinished = false
case aakaas.PackageStatusPlanned:
log.Entry().Infof("Reservation of %s was succesful with status 'planned'", pckgWR[i].Package.PackageName)
case aakaas.PackageStatusReleased:
log.Entry().Infof("Reservation of %s not needed, package is already in status 'released'", pckgWR[i].Package.PackageName)
default:
return fmt.Errorf("Package %s has unknown status '%s'", pckgWR[i].Package.PackageName, pckgWR[i].Package.Status)
}
}
}
if allFinished {
log.Entry().Infof("Reservation of package(s) was succesful")
return nil
}
}
}
}
func reservePackages(repositories []abaputils.Repository, conn abapbuild.Connector) ([]aakaas.PackageWithRepository, error) {
var packagesWithRepos []aakaas.PackageWithRepository
for i := range repositories {
var p aakaas.Package
p.InitPackage(repositories[i], conn)
err := p.ReserveNext()
if err != nil {
return packagesWithRepos, err
}
pWR := aakaas.PackageWithRepository{
Package: p,
Repo: repositories[i],
}
packagesWithRepos = append(packagesWithRepos, pWR)
}
return packagesWithRepos, nil
}

View File

@ -0,0 +1,180 @@
// Code generated by piper's step-generator. DO NOT EDIT.
package cmd
import (
"fmt"
"os"
"path/filepath"
"time"
"github.com/SAP/jenkins-library/pkg/config"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/piperenv"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/spf13/cobra"
)
type abapAddonAssemblyKitReserveNextPackagesOptions struct {
AbapAddonAssemblyKitEndpoint string `json:"abapAddonAssemblyKitEndpoint,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
AddonDescriptor string `json:"addonDescriptor,omitempty"`
}
type abapAddonAssemblyKitReserveNextPackagesCommonPipelineEnvironment struct {
abap struct {
addonDescriptor string
}
}
func (p *abapAddonAssemblyKitReserveNextPackagesCommonPipelineEnvironment) persist(path, resourceName string) {
content := []struct {
category string
name string
value string
}{
{category: "abap", name: "addonDescriptor", value: p.abap.addonDescriptor},
}
errCount := 0
for _, param := range content {
err := piperenv.SetResourceParameter(path, resourceName, filepath.Join(param.category, param.name), param.value)
if err != nil {
log.Entry().WithError(err).Error("Error persisting piper environment.")
errCount++
}
}
if errCount > 0 {
log.Entry().Fatal("failed to persist Piper environment")
}
}
// AbapAddonAssemblyKitReserveNextPackagesCommand This step determines the ABAP delivery packages (name and type), which are needed to deliver Software Component Versions.
func AbapAddonAssemblyKitReserveNextPackagesCommand() *cobra.Command {
const STEP_NAME = "abapAddonAssemblyKitReserveNextPackages"
metadata := abapAddonAssemblyKitReserveNextPackagesMetadata()
var stepConfig abapAddonAssemblyKitReserveNextPackagesOptions
var startTime time.Time
var commonPipelineEnvironment abapAddonAssemblyKitReserveNextPackagesCommonPipelineEnvironment
var createAbapAddonAssemblyKitReserveNextPackagesCmd = &cobra.Command{
Use: STEP_NAME,
Short: "This step determines the ABAP delivery packages (name and type), which are needed to deliver Software Component Versions.",
Long: `This step takes the list of Software Component Versions from the addonDescriptor in the commonPipelineEnvironment and determines the ABAP delivery packages.
If a package does not exist yet in the package registry, it is created there. The response contains detail information for this package and a package status, which determines the next actions:
"P": Package was created in the registry; production can be started / continued
"R": Package exists and is already released; production is not needed and must be skipped
The steps waits until the status "P" or "R" is achieved.
The name, type and namespace of each package is written back to the addonDescriptor in the commonPipelineEnvironment.`,
PreRunE: func(cmd *cobra.Command, _ []string) error {
startTime = time.Now()
log.SetStepName(STEP_NAME)
log.SetVerbose(GeneralConfig.Verbose)
path, _ := os.Getwd()
fatalHook := &log.FatalHook{CorrelationID: GeneralConfig.CorrelationID, Path: path}
log.RegisterHook(fatalHook)
err := PrepareConfig(cmd, &metadata, STEP_NAME, &stepConfig, config.OpenPiperFile)
if err != nil {
log.SetErrorCategory(log.ErrorConfiguration)
return err
}
log.RegisterSecret(stepConfig.Username)
log.RegisterSecret(stepConfig.Password)
if len(GeneralConfig.HookConfig.SentryConfig.Dsn) > 0 {
sentryHook := log.NewSentryHook(GeneralConfig.HookConfig.SentryConfig.Dsn, GeneralConfig.CorrelationID)
log.RegisterHook(&sentryHook)
}
return nil
},
Run: func(_ *cobra.Command, _ []string) {
telemetryData := telemetry.CustomData{}
telemetryData.ErrorCode = "1"
handler := func() {
commonPipelineEnvironment.persist(GeneralConfig.EnvRootPath, "commonPipelineEnvironment")
telemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds())
telemetry.Send(&telemetryData)
}
log.DeferExitHandler(handler)
defer handler()
telemetry.Initialize(GeneralConfig.NoTelemetry, STEP_NAME)
abapAddonAssemblyKitReserveNextPackages(stepConfig, &telemetryData, &commonPipelineEnvironment)
telemetryData.ErrorCode = "0"
log.Entry().Info("SUCCESS")
},
}
addAbapAddonAssemblyKitReserveNextPackagesFlags(createAbapAddonAssemblyKitReserveNextPackagesCmd, &stepConfig)
return createAbapAddonAssemblyKitReserveNextPackagesCmd
}
func addAbapAddonAssemblyKitReserveNextPackagesFlags(cmd *cobra.Command, stepConfig *abapAddonAssemblyKitReserveNextPackagesOptions) {
cmd.Flags().StringVar(&stepConfig.AbapAddonAssemblyKitEndpoint, "abapAddonAssemblyKitEndpoint", os.Getenv("PIPER_abapAddonAssemblyKitEndpoint"), "Base URL to the Addon Assembly Kit as a Service (AAKaaS) system")
cmd.Flags().StringVar(&stepConfig.Username, "username", os.Getenv("PIPER_username"), "User for the Addon Assembly Kit as a Service (AAKaaS) system")
cmd.Flags().StringVar(&stepConfig.Password, "password", os.Getenv("PIPER_password"), "Password for the Addon Assembly Kit as a Service (AAKaaS) system")
cmd.Flags().StringVar(&stepConfig.AddonDescriptor, "addonDescriptor", os.Getenv("PIPER_addonDescriptor"), "Structure in the commonPipelineEnvironment containing information about the Product Version and corresponding Software Component Versions")
cmd.MarkFlagRequired("abapAddonAssemblyKitEndpoint")
cmd.MarkFlagRequired("username")
cmd.MarkFlagRequired("password")
cmd.MarkFlagRequired("addonDescriptor")
}
// retrieve step metadata
func abapAddonAssemblyKitReserveNextPackagesMetadata() config.StepData {
var theMetaData = config.StepData{
Metadata: config.StepMetadata{
Name: "abapAddonAssemblyKitReserveNextPackages",
Aliases: []config.Alias{},
},
Spec: config.StepSpec{
Inputs: config.StepInputs{
Parameters: []config.StepParameters{
{
Name: "abapAddonAssemblyKitEndpoint",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
Type: "string",
Mandatory: true,
Aliases: []config.Alias{},
},
{
Name: "username",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: true,
Aliases: []config.Alias{},
},
{
Name: "password",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS"},
Type: "string",
Mandatory: true,
Aliases: []config.Alias{},
},
{
Name: "addonDescriptor",
ResourceRef: []config.ResourceReference{
{
Name: "commonPipelineEnvironment",
Param: "abap/addonDescriptor",
},
},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: true,
Aliases: []config.Alias{},
},
},
},
},
}
return theMetaData
}

View File

@ -0,0 +1,16 @@
package cmd
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestAbapAddonAssemblyKitReserveNextPackagesCommand(t *testing.T) {
testCmd := AbapAddonAssemblyKitReserveNextPackagesCommand()
// only high level testing performed - details are tested in step generation procedure
assert.Equal(t, "abapAddonAssemblyKitReserveNextPackages", testCmd.Use, "command name incorrect")
}

View File

@ -0,0 +1,421 @@
package cmd
import (
"encoding/json"
"testing"
"time"
"github.com/SAP/jenkins-library/pkg/abap/aakaas"
abapbuild "github.com/SAP/jenkins-library/pkg/abap/build"
"github.com/SAP/jenkins-library/pkg/abaputils"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
func TestReserveNextPackagesStep(t *testing.T) {
var config abapAddonAssemblyKitReserveNextPackagesOptions
var cpe abapAddonAssemblyKitReserveNextPackagesCommonPipelineEnvironment
timeout := time.Duration(5 * time.Second)
pollInterval := time.Duration(1 * time.Second)
t.Run("step success", func(t *testing.T) {
addonDescriptor := abaputils.AddonDescriptor{
Repositories: []abaputils.Repository{
{
Name: "/DRNMSPC/COMP01",
VersionYAML: "1.0.0.",
},
{
Name: "/DRNMSPC/COMP02",
VersionYAML: "1.0.0.",
},
},
}
adoDesc, _ := json.Marshal(addonDescriptor)
config.AddonDescriptor = string(adoDesc)
client := &abaputils.ClientMock{
BodyList: []string{responseReserveNextPackageReleased, responseReserveNextPackagePlanned, responseReserveNextPackagePostReleased, "myToken", responseReserveNextPackagePostPlanned, "myToken"},
}
err := runAbapAddonAssemblyKitReserveNextPackages(&config, nil, client, &cpe, timeout, pollInterval)
assert.NoError(t, err, "Did not expect error")
var addonDescriptorFinal abaputils.AddonDescriptor
json.Unmarshal([]byte(cpe.abap.addonDescriptor), &addonDescriptorFinal)
assert.Equal(t, "P", addonDescriptorFinal.Repositories[0].Status)
assert.Equal(t, "R", addonDescriptorFinal.Repositories[1].Status)
})
t.Run("step error - invalid input", func(t *testing.T) {
addonDescriptor := abaputils.AddonDescriptor{
Repositories: []abaputils.Repository{
{
Name: "/DRNMSPC/COMP01",
},
},
}
adoDesc, _ := json.Marshal(addonDescriptor)
config.AddonDescriptor = string(adoDesc)
client := &abaputils.ClientMock{}
err := runAbapAddonAssemblyKitReserveNextPackages(&config, nil, client, &cpe, timeout, pollInterval)
assert.Error(t, err, "Did expect error")
})
t.Run("step error - timeout", func(t *testing.T) {
addonDescriptor := abaputils.AddonDescriptor{
Repositories: []abaputils.Repository{
{
Name: "/DRNMSPC/COMP01",
VersionYAML: "1.0.0.",
},
},
}
adoDesc, _ := json.Marshal(addonDescriptor)
config.AddonDescriptor = string(adoDesc)
client := &abaputils.ClientMock{
BodyList: []string{responseReserveNextPackageCreationTriggered, responseReserveNextPackagePostPlanned, "myToken"},
}
timeout := time.Duration(1 * time.Second)
err := runAbapAddonAssemblyKitReserveNextPackages(&config, nil, client, &cpe, timeout, pollInterval)
assert.Error(t, err, "Did expect error")
})
}
// ********************* Test init *******************
func TestInitPackage(t *testing.T) {
t.Run("test init", func(t *testing.T) {
conn := new(abapbuild.Connector)
conn.Client = &abaputils.ClientMock{}
repo := abaputils.Repository{
Name: "/DRNMSPC/COMP01",
VersionYAML: "1.0.0",
}
var p aakaas.Package
p.InitPackage(repo, *conn)
assert.Equal(t, "/DRNMSPC/COMP01", p.ComponentName)
assert.Equal(t, "1.0.0", p.VersionYAML)
})
}
// ********************* Test copyFieldsToRepositories *******************
func TestCopyFieldsToRepositoriesPackage(t *testing.T) {
t.Run("test copyFieldsToRepositories", func(t *testing.T) {
pckgWR := []aakaas.PackageWithRepository{
{
Package: aakaas.Package{
ComponentName: "/DRNMSPC/COMP01",
VersionYAML: "1.0.0",
PackageName: "SAPK-001AAINDRNMSPC",
Type: "AOI",
Status: aakaas.PackageStatusPlanned,
Namespace: "/DRNMSPC/",
},
Repo: abaputils.Repository{
Name: "/DRNMSPC/COMP01",
VersionYAML: "1.0.0",
},
},
}
repos := copyFieldsToRepositories(pckgWR)
assert.Equal(t, "SAPK-001AAINDRNMSPC", repos[0].PackageName)
assert.Equal(t, "AOI", repos[0].PackageType)
assert.Equal(t, string(aakaas.PackageStatusPlanned), repos[0].Status)
assert.Equal(t, "/DRNMSPC/", repos[0].Namespace)
})
}
// ********************* Test reserveNext *******************
func TestReserveNextPackage(t *testing.T) {
t.Run("test reserveNext - success", func(t *testing.T) {
client := abaputils.ClientMock{
Body: responseReserveNextPackagePostPlanned,
}
p := testPackageSetup("/DRNMSPC/COMP01", "1.0.0", client)
err := p.ReserveNext()
assert.NoError(t, err)
assert.Equal(t, "SAPK-001AAINDRNMSPC", p.PackageName)
assert.Equal(t, "AOI", p.Type)
assert.Equal(t, aakaas.PackageStatusPlanned, p.Status)
})
t.Run("test reserveNext - missing versionYAML", func(t *testing.T) {
client := abaputils.ClientMock{}
p := testPackageSetup("/DRNMSPC/COMP01", "", client)
err := p.ReserveNext()
assert.Error(t, err)
assert.Equal(t, "", p.PackageName)
assert.Equal(t, "", p.Type)
assert.Equal(t, aakaas.PackageStatus(""), p.Status)
})
t.Run("test reserveNext - error from call", func(t *testing.T) {
client := abaputils.ClientMock{
Body: "ErrorBody",
Error: errors.New("Failure during reserve next"),
}
p := testPackageSetup("/DRNMSPC/COMP01", "1.0.0", client)
err := p.ReserveNext()
assert.Error(t, err)
assert.Equal(t, "", p.PackageName)
assert.Equal(t, "", p.Type)
assert.Equal(t, aakaas.PackageStatus(""), p.Status)
})
}
// ********************* Test reservePackages *******************
func TestReservePackages(t *testing.T) {
t.Run("test reservePackages - success", func(t *testing.T) {
client := abaputils.ClientMock{
Body: responseReserveNextPackagePostPlanned,
}
repositories, conn := testRepositoriesSetup("/DRNMSPC/COMP01", "1.0.0", client)
repos, err := reservePackages(repositories, conn)
assert.NoError(t, err)
assert.Equal(t, "/DRNMSPC/COMP01", repos[0].Package.ComponentName)
assert.Equal(t, "1.0.0", repos[0].Package.VersionYAML)
assert.Equal(t, aakaas.PackageStatusPlanned, repos[0].Package.Status)
})
t.Run("test reservePackages - error from call", func(t *testing.T) {
client := abaputils.ClientMock{
Body: "ErrorBody",
Error: errors.New("Failure during reserve next"),
}
repositories, conn := testRepositoriesSetup("/DRNMSPC/COMP01", "1.0.0", client)
_, err := reservePackages(repositories, conn)
assert.Error(t, err)
})
}
// ********************* Test pollReserveNextPackages *******************
func TestPollReserveNextPackages(t *testing.T) {
timeout := time.Duration(5 * time.Second)
pollInterval := time.Duration(1 * time.Second)
t.Run("test pollReserveNextPackages - testing loop", func(t *testing.T) {
client := abaputils.ClientMock{
BodyList: []string{responseReserveNextPackagePlanned, responseReserveNextPackageCreationTriggered},
}
pckgWR := testPollPackagesSetup(client)
err := pollReserveNextPackages(pckgWR, timeout, pollInterval)
assert.NoError(t, err)
assert.Equal(t, aakaas.PackageStatusPlanned, pckgWR[0].Package.Status)
assert.Equal(t, "/DRNMSPC/", pckgWR[0].Package.Namespace)
})
t.Run("test pollReserveNextPackages - status locked", func(t *testing.T) {
client := abaputils.ClientMock{
Body: responseReserveNextPackageLocked,
}
pckgWR := testPollPackagesSetup(client)
err := pollReserveNextPackages(pckgWR, timeout, pollInterval)
assert.Error(t, err)
assert.Equal(t, aakaas.PackageStatusLocked, pckgWR[0].Package.Status)
})
t.Run("test pollReserveNextPackages - status released", func(t *testing.T) {
client := abaputils.ClientMock{
Body: responseReserveNextPackageReleased,
}
pckgWR := testPollPackagesSetup(client)
err := pollReserveNextPackages(pckgWR, timeout, pollInterval)
assert.NoError(t, err)
assert.Equal(t, aakaas.PackageStatusReleased, pckgWR[0].Package.Status)
})
t.Run("test pollReserveNextPackages - unknow status", func(t *testing.T) {
client := abaputils.ClientMock{
Body: responseReserveNextPackageUnknownState,
}
pckgWR := testPollPackagesSetup(client)
err := pollReserveNextPackages(pckgWR, timeout, pollInterval)
assert.Error(t, err)
assert.Equal(t, aakaas.PackageStatus("X"), pckgWR[0].Package.Status)
})
t.Run("test pollReserveNextPackages - timeout", func(t *testing.T) {
client := abaputils.ClientMock{
Body: "ErrorBody",
Error: errors.New("Failure during reserve next"),
}
pckgWR := testPollPackagesSetup(client)
timeout := time.Duration(2 * time.Second)
err := pollReserveNextPackages(pckgWR, timeout, pollInterval)
assert.Error(t, err)
})
}
// ********************* Setup functions *******************
func testPollPackagesSetup(client abaputils.ClientMock) []aakaas.PackageWithRepository {
conn := new(abapbuild.Connector)
conn.Client = &client
conn.Header = make(map[string][]string)
pckgWR := []aakaas.PackageWithRepository{
{
Package: aakaas.Package{
Connector: *conn,
ComponentName: "/DRNMSPC/COMP01",
VersionYAML: "1.0.0",
PackageName: "SAPK-001AAINDRNMSPC",
Type: "AOI",
},
Repo: abaputils.Repository{},
},
}
return pckgWR
}
func testRepositoriesSetup(componentName string, versionYAML string, client abaputils.ClientMock) ([]abaputils.Repository, abapbuild.Connector) {
conn := new(abapbuild.Connector)
conn.Client = &client
conn.Header = make(map[string][]string)
repositories := []abaputils.Repository{
{
Name: componentName,
VersionYAML: versionYAML,
},
}
return repositories, *conn
}
func testPackageSetup(componentName string, versionYAML string, client abaputils.ClientMock) aakaas.Package {
conn := new(abapbuild.Connector)
conn.Client = &client
conn.Header = make(map[string][]string)
p := aakaas.Package{
Connector: *conn,
ComponentName: componentName,
VersionYAML: versionYAML,
}
return p
}
// ********************* Testdata *******************
var responseReserveNextPackagePostPlanned = `{
"d": {
"DeterminePackageForScv": {
"__metadata": {
"type": "SSDA.AAS_ODATA_PACKAGE_SRV.PackageExtended"
},
"Name": "SAPK-001AAINDRNMSPC",
"Type": "AOI",
"ScName": "/DRNMSPC/COMP01",
"ScVersion": "0001",
"SpLevel": "0000",
"PatchLevel": "0000",
"Predecessor": "",
"PredecessorCommitId": "",
"Status": "P"
}
}
}`
var responseReserveNextPackagePostReleased = `{
"d": {
"DeterminePackageForScv": {
"__metadata": {
"type": "SSDA.AAS_ODATA_PACKAGE_SRV.PackageExtended"
},
"Name": "SAPK-001AAINDRNMSPC",
"Type": "AOI",
"ScName": "/DRNMSPC/COMP02",
"ScVersion": "0001",
"SpLevel": "0000",
"PatchLevel": "0000",
"Predecessor": "",
"PredecessorCommitId": "",
"Status": "R"
}
}
}`
var responseReserveNextPackageCreationTriggered = `{
"d": {
"__metadata": {
"id": "https://W7Q.DMZWDF.SAP.CORP:443/odata/aas_ocs_package/OcsPackageSet('SAPK-001AAINDRNMSPC')",
"uri": "https://W7Q.DMZWDF.SAP.CORP:443/odata/aas_ocs_package/OcsPackageSet('SAPK-001AAINDRNMSPC')",
"type": "SSDA.AAS_ODATA_PACKAGE_SRV.OcsPackage"
},
"Name": "SAPK-001AAINDRNMSPC",
"Type": "AOI",
"Component": "/DRNMSPC/COMP01",
"Release": "0001",
"Level": "0000",
"Status": "C",
"Operation": "",
"Namespace": "/DRNMSPC/",
"Vendorid": "0000203069"
}
}`
var responseReserveNextPackageLocked = `{
"d": {
"__metadata": {
"id": "https://W7Q.DMZWDF.SAP.CORP:443/odata/aas_ocs_package/OcsPackageSet('SAPK-001AAINDRNMSPC')",
"uri": "https://W7Q.DMZWDF.SAP.CORP:443/odata/aas_ocs_package/OcsPackageSet('SAPK-001AAINDRNMSPC')",
"type": "SSDA.AAS_ODATA_PACKAGE_SRV.OcsPackage"
},
"Name": "SAPK-001AAINDRNMSPC",
"Type": "AOI",
"Component": "/DRNMSPC/COMP01",
"Release": "0001",
"Level": "0000",
"Status": "L",
"Operation": "",
"Namespace": "/DRNMSPC/",
"Vendorid": "0000203069"
}
}`
var responseReserveNextPackagePlanned = `{
"d": {
"__metadata": {
"id": "https://W7Q.DMZWDF.SAP.CORP:443/odata/aas_ocs_package/OcsPackageSet('SAPK-001AAINDRNMSPC')",
"uri": "https://W7Q.DMZWDF.SAP.CORP:443/odata/aas_ocs_package/OcsPackageSet('SAPK-001AAINDRNMSPC')",
"type": "SSDA.AAS_ODATA_PACKAGE_SRV.OcsPackage"
},
"Name": "SAPK-001AAINDRNMSPC",
"Type": "AOI",
"Component": "/DRNMSPC/COMP01",
"Release": "0001",
"Level": "0000",
"Status": "P",
"Operation": "",
"Namespace": "/DRNMSPC/",
"Vendorid": "0000203069"
}
}`
var responseReserveNextPackageReleased = `{
"d": {
"__metadata": {
"id": "https://W7Q.DMZWDF.SAP.CORP:443/odata/aas_ocs_package/OcsPackageSet('SAPK-001AAINDRNMSPC')",
"uri": "https://W7Q.DMZWDF.SAP.CORP:443/odata/aas_ocs_package/OcsPackageSet('SAPK-001AAINDRNMSPC')",
"type": "SSDA.AAS_ODATA_PACKAGE_SRV.OcsPackage"
},
"Name": "SAPK-001AAINDRNMSPC",
"Type": "AOI",
"Component": "/DRNMSPC/COMP01",
"Release": "0001",
"Level": "0000",
"Status": "R",
"Operation": "",
"Namespace": "/DRNMSPC/",
"Vendorid": "0000203069"
}
}`
var responseReserveNextPackageUnknownState = `{
"d": {
"__metadata": {
"id": "https://W7Q.DMZWDF.SAP.CORP:443/odata/aas_ocs_package/OcsPackageSet('SAPK-001AAINDRNMSPC')",
"uri": "https://W7Q.DMZWDF.SAP.CORP:443/odata/aas_ocs_package/OcsPackageSet('SAPK-001AAINDRNMSPC')",
"type": "SSDA.AAS_ODATA_PACKAGE_SRV.OcsPackage"
},
"Name": "SAPK-001AAINDRNMSPC",
"Type": "AOI",
"Component": "/DRNMSPC/COMP01",
"Release": "0001",
"Level": "0000",
"Status": "X",
"Operation": "",
"Namespace": "/DRNMSPC/",
"Vendorid": "0000203069"
}
}`

View File

@ -111,7 +111,7 @@ func Execute() {
rootCmd.AddCommand(AbapAddonAssemblyKitPublishTargetVectorCommand())
rootCmd.AddCommand(AbapAddonAssemblyKitRegisterPackagesCommand())
rootCmd.AddCommand(AbapAddonAssemblyKitReleasePackagesCommand())
// rootCmd.AddCommand(AbapAddonAssemblyKitReserveNextPackagesCommand())
rootCmd.AddCommand(AbapAddonAssemblyKitReserveNextPackagesCommand())
addRootFlags(rootCmd)
if err := rootCmd.Execute(); err != nil {

View File

@ -0,0 +1,83 @@
# ${docGenStepName}
## ${docGenDescription}
## Prerequisites
* The credentials to access the AAKaaS (e.g. S-User) must be stored in the Jenkins Credential Store
* The step needs information about the Software Component Versions for which packages should be reserved.
* This information is provided via the addonDescriptor in the commonPipelineEnvironment where the fields 'name' and 'version' in the repositories list need to be filled.
* The Software Component Versions must be valid.
* The validation is performed and the required information is written to the CommonPipelineEnvironment if you run prior to this step the step [abapAddonAssemblyKitCheckCVs](https://sap.github.io/jenkins-library/steps/abapAddonAssemblyKitCheckCVs)
## ${docGenParameters}
## ${docGenConfiguration}
## ${docJenkinsPluginDependencies}
## Examples
### Configuration in the config.yml
The recommended way to configure your pipeline is via the config.yml file. In this case, calling the step in the Jenkinsfile is reduced to one line:
```groovy
abapAddonAssemblyKitReserveNextPackages script: this
```
The config.yml should look like this:
```yaml
steps:
abapAddonAssemblyKitReserveNextPackages:
abapAddonAssemblyKitCredentialsId: 'abapAddonAssemblyKitCredentialsId',
abapAddonAssemblyKitEndpoint: 'https://myabapAddonAssemblyKitEndpoint.com',
```
### Input via the CommonPipelineEnvironment
Mandatory fields:
```json
{"addonProduct":"",
"addonVersion":"",
"addonVersionAAK":"",
"addonUniqueID":"",
"customerID":"",
"AddonSpsLevel":"",
"AddonPatchLevel":"",
"TargetVectorID":"",
"repositories":[
{
"name":"/DMO/REPO_A",
"tag":"",
"branch":"",
"version":"1.0.1",
"versionAAK":"",
"PackageName":"",
"PackageType":"",
"SpLevel":"",
"PatchLevel":"",
"PredecessorCommitID":"",
"Status":"",
"Namespace":"",
"SarXMLFilePath":""
},
{
"name":"/DMO/REPO_B",
"tag":"",
"branch":"",
"version":"2.1.1",
"versionAAK":"",
"PackageName":"",
"PackageType":"",
"SpLevel":"",
"PatchLevel":"",
"PredecessorCommitID":"",
"Status":"",
"Namespace":"",
"SarXMLFilePath":""
}
]}
```

View File

@ -55,7 +55,7 @@ nav:
- abapAddonAssemblyKitPublishTargetVector: steps/abapAddonAssemblyKitPublishTargetVector.md
- abapAddonAssemblyKitRegisterPackages: steps/abapAddonAssemblyKitRegisterPackages.md
- abapAddonAssemblyKitReleasePackages: steps/abapAddonAssemblyKitReleasePackages.md
# - abapAddonAssemblyKitReserveNextPackages: steps/abapAddonAssemblyKitReserveNextPackages.md
- abapAddonAssemblyKitReserveNextPackages: steps/abapAddonAssemblyKitReserveNextPackages.md
- abapEnvironmentAssemblePackages: steps/abapEnvironmentAssemblePackages.md
- abapEnvironmentCheckoutBranch: steps/abapEnvironmentCheckoutBranch.md
- abapEnvironmentCloneGitRepo: steps/abapEnvironmentCloneGitRepo.md

View File

@ -0,0 +1,59 @@
metadata:
name: abapAddonAssemblyKitReserveNextPackages
description: This step determines the ABAP delivery packages (name and type), which are needed to deliver Software Component Versions.
longDescription: |
This step takes the list of Software Component Versions from the addonDescriptor in the commonPipelineEnvironment and determines the ABAP delivery packages.
If a package does not exist yet in the package registry, it is created there. The response contains detail information for this package and a package status, which determines the next actions:
"P": Package was created in the registry; production can be started / continued
"R": Package exists and is already released; production is not needed and must be skipped
The steps waits until the status "P" or "R" is achieved.
The name, type and namespace of each package is written back to the addonDescriptor in the commonPipelineEnvironment.
spec:
inputs:
secrets:
- name: abapAddonAssemblyKitCredentialsId
description: Credential stored in Jenkins for the Addon Assembly Kit as a Service (AAKaaS) system
type: jenkins
params:
- name: abapAddonAssemblyKitEndpoint
type: string
description: Base URL to the Addon Assembly Kit as a Service (AAKaaS) system
scope:
- PARAMETERS
- STAGES
- STEPS
- GENERAL
mandatory: true
- name: username
type: string
description: User for the Addon Assembly Kit as a Service (AAKaaS) system
scope:
- PARAMETERS
- STAGES
- STEPS
mandatory: true
secret: true
- name: password
type: string
description: Password for the Addon Assembly Kit as a Service (AAKaaS) system
scope:
- PARAMETERS
mandatory: true
secret: true
- name: addonDescriptor
type: string
description: Structure in the commonPipelineEnvironment containing information about the Product Version and corresponding Software Component Versions
mandatory: true
scope:
- PARAMETERS
- STAGES
- STEPS
resourceRef:
- name: commonPipelineEnvironment
param: abap/addonDescriptor
outputs:
resources:
- name: commonPipelineEnvironment
type: piperEnvironment
params:
- name: abap/addonDescriptor

View File

@ -112,7 +112,7 @@ public class CommonStepsTest extends BasePiperTest{
'abapAddonAssemblyKitPublishTargetVector', //implementing new golang pattern without fields
'abapAddonAssemblyKitRegisterPackages', //implementing new golang pattern without fields
'abapAddonAssemblyKitReleasePackages', //implementing new golang pattern without fields
//'abapAddonAssemblyKitReserveNextPackages', //implementing new golang pattern without fields
'abapAddonAssemblyKitReserveNextPackages', //implementing new golang pattern without fields
'abapEnvironmentAssemblePackages', //implementing new golang pattern without fields
'abapEnvironmentCheckoutBranch', //implementing new golang pattern without fields
'abapEnvironmentCloneGitRepo', //implementing new golang pattern without fields

View File

@ -0,0 +1,11 @@
import groovy.transform.Field
@Field String STEP_NAME = getClass().getName()
@Field String METADATA_FILE = 'metadata/abapAddonAssemblyKitReserveNextPackages.yaml'
void call(Map parameters = [:]) {
List credentials = [
[type: 'usernamePassword', id: 'abapAddonAssemblyKitCredentialsId', env: ['PIPER_username', 'PIPER_password']]
]
piperExecuteBin(parameters, STEP_NAME, METADATA_FILE, credentials, false, false, true)
}