From 4c26b942ee07869a4000e8abe217ea1095dc7682 Mon Sep 17 00:00:00 2001
From: tiloKo <70266685+tiloKo@users.noreply.github.com>
Date: Tue, 26 Mar 2024 10:39:51 +0100
Subject: [PATCH 01/15] new step abapAddonAssemblyKitCheck
---
cmd/abapAddonAssemblyKitCheck.go | 80 +++++
cmd/abapAddonAssemblyKitCheck_generated.go | 296 ++++++++++++++++++
...bapAddonAssemblyKitCheck_generated_test.go | 20 ++
cmd/abapAddonAssemblyKitCheck_test.go | 52 +++
cmd/metadata_generated.go | 1 +
.../metadata/abapAddonAssemblyKitCheck.yaml | 102 ++++++
6 files changed, 551 insertions(+)
create mode 100644 cmd/abapAddonAssemblyKitCheck.go
create mode 100644 cmd/abapAddonAssemblyKitCheck_generated.go
create mode 100644 cmd/abapAddonAssemblyKitCheck_generated_test.go
create mode 100644 cmd/abapAddonAssemblyKitCheck_test.go
create mode 100644 resources/metadata/abapAddonAssemblyKitCheck.yaml
diff --git a/cmd/abapAddonAssemblyKitCheck.go b/cmd/abapAddonAssemblyKitCheck.go
new file mode 100644
index 0000000000..37122b0d7b
--- /dev/null
+++ b/cmd/abapAddonAssemblyKitCheck.go
@@ -0,0 +1,80 @@
+package cmd
+
+import (
+ "github.com/SAP/jenkins-library/pkg/command"
+ piperhttp "github.com/SAP/jenkins-library/pkg/http"
+ "github.com/SAP/jenkins-library/pkg/log"
+ "github.com/SAP/jenkins-library/pkg/telemetry"
+)
+
+type abapAddonAssemblyKitCheckUtils interface {
+ command.ExecRunner
+ piperhttp.Sender
+}
+
+type abapAddonAssemblyKitCheckUtilsBundle struct {
+ *command.Command
+ *piperhttp.Client
+}
+
+func newAbapAddonAssemblyKitCheckUtils() abapAddonAssemblyKitCheckUtils {
+ utils := abapAddonAssemblyKitCheckUtilsBundle{
+ Command: &command.Command{},
+ }
+ // Reroute command output to logging framework
+ utils.Stdout(log.Writer())
+ utils.Stderr(log.Writer())
+ return &utils
+}
+
+func abapAddonAssemblyKitCheck(config abapAddonAssemblyKitCheckOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *abapAddonAssemblyKitCheckCommonPipelineEnvironment) {
+ utils := newAbapAddonAssemblyKitCheckUtils()
+
+ err := runAbapAddonAssemblyKitCheck(&config, telemetryData, utils, commonPipelineEnvironment)
+ if err != nil {
+ log.Entry().WithError(err).Fatal("step execution failed")
+ }
+}
+
+func runAbapAddonAssemblyKitCheck(config *abapAddonAssemblyKitCheckOptions, telemetryData *telemetry.CustomData, utils abapAddonAssemblyKitCheckUtils, commonPipelineEnvironment *abapAddonAssemblyKitCheckCommonPipelineEnvironment) error {
+
+ // log.Entry().WithField("LogField", "Log field content").Info("This is just a demo for a simple step.")
+ // // Example of calling methods from external dependencies directly on utils:
+ // exists, err := utils.FileExists("file.txt")
+ // if err != nil {
+ // // It is good practice to set an error category.
+ // // Most likely you want to do this at the place where enough context is known.
+ // log.SetErrorCategory(log.ErrorConfiguration)
+ // // Always wrap non-descriptive errors to enrich them with context for when they appear in the log:
+ // return fmt.Errorf("failed to check for important file: %w", err)
+ // }
+ // if !exists {
+ // log.SetErrorCategory(log.ErrorConfiguration)
+ // return fmt.Errorf("cannot run without important file")
+ // }
+
+ return nil
+}
+
+type ProductVersionHeader struct {
+ ProductName string
+ SemanticProductVersion string `json:"SemProductVersion"`
+ ProductVersion string
+ Spslevel string
+ PatchLevel string
+ Vendor string
+ VendorType string
+ Content []ProductVersionContent
+}
+
+type ProductVersionContent struct {
+ ProductName string
+ SemanticProductVersion string `json:"SemProductVersion"`
+ SoftwareComponentName string `json:"ScName"`
+ SemanticSoftwareComponentVersion string `json:"SemScVersion"`
+ SoftwareComponentVersion string `json:"ScVersion"`
+ SpLevel string
+ PatchLevel string
+ Vendor string
+ VendorType string
+}
diff --git a/cmd/abapAddonAssemblyKitCheck_generated.go b/cmd/abapAddonAssemblyKitCheck_generated.go
new file mode 100644
index 0000000000..1027325870
--- /dev/null
+++ b/cmd/abapAddonAssemblyKitCheck_generated.go
@@ -0,0 +1,296 @@
+// 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/splunk"
+ "github.com/SAP/jenkins-library/pkg/telemetry"
+ "github.com/SAP/jenkins-library/pkg/validation"
+ "github.com/spf13/cobra"
+)
+
+type abapAddonAssemblyKitCheckOptions struct {
+ AbapAddonAssemblyKitCertificateFile string `json:"abapAddonAssemblyKitCertificateFile,omitempty"`
+ AbapAddonAssemblyKitCertificatePass string `json:"abapAddonAssemblyKitCertificatePass,omitempty"`
+ AbapAddonAssemblyKitEndpoint string `json:"abapAddonAssemblyKitEndpoint,omitempty"`
+ Username string `json:"username,omitempty"`
+ Password string `json:"password,omitempty"`
+ AddonDescriptorFileName string `json:"addonDescriptorFileName,omitempty"`
+ AddonDescriptor string `json:"addonDescriptor,omitempty"`
+}
+
+type abapAddonAssemblyKitCheckCommonPipelineEnvironment struct {
+ abap struct {
+ addonDescriptor string
+ }
+}
+
+func (p *abapAddonAssemblyKitCheckCommonPipelineEnvironment) persist(path, resourceName string) {
+ content := []struct {
+ category string
+ name string
+ value interface{}
+ }{
+ {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().Error("failed to persist Piper environment")
+ }
+}
+
+// AbapAddonAssemblyKitCheckCommand This step calls AAKaaS to check the validity of the Addon Product Modelling.
+func AbapAddonAssemblyKitCheckCommand() *cobra.Command {
+ const STEP_NAME = "abapAddonAssemblyKitCheck"
+
+ metadata := abapAddonAssemblyKitCheckMetadata()
+ var stepConfig abapAddonAssemblyKitCheckOptions
+ var startTime time.Time
+ var commonPipelineEnvironment abapAddonAssemblyKitCheckCommonPipelineEnvironment
+ var logCollector *log.CollectorHook
+ var splunkClient *splunk.Splunk
+ telemetryClient := &telemetry.Telemetry{}
+
+ var createAbapAddonAssemblyKitCheckCmd = &cobra.Command{
+ Use: STEP_NAME,
+ Short: "This step calls AAKaaS to check the validity of the Addon Product Modelling.",
+ Long: `This step does the following:
+
+ - [The Addon Product Modelling](https://www.project-piper.io/scenarios/abapEnvironmentAddons/#add-on-descriptor-file) is read from the addonDescriptorFileName (e.g. addon.yml)
+ - A connection to AAKaaS (Addon Assembly Kit as a Service) is established and the Addon Product Modelling is transfered for detailed [checks](https://www.project-piper.io/scenarios/abapEnvironmentAddons/#versioning-rules)
+ - The semantic versions are resolved and stored into the piper commonPipelineEnviroment for usage of subsequent pipeline steps
+
+
+For logon to AAKaaS you can either provide a credential with basic authorization (username and password) or two secret text credentials containing the technical s-users certificate (see note [2805811](https://me.sap.com/notes/2805811) for download) as base64 encoded string and the password to decrypt the file
+
+For Terminology refer to the [Scenario Description](https://www.project-piper.io/scenarios/abapEnvironmentAddons/).`,
+ PreRunE: func(cmd *cobra.Command, _ []string) error {
+ startTime = time.Now()
+ log.SetStepName(STEP_NAME)
+ log.SetVerbose(GeneralConfig.Verbose)
+
+ GeneralConfig.GitHubAccessTokens = ResolveAccessTokens(GeneralConfig.GitHubTokens)
+
+ 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.AbapAddonAssemblyKitCertificateFile)
+ log.RegisterSecret(stepConfig.AbapAddonAssemblyKitCertificatePass)
+ 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)
+ }
+
+ if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 || len(GeneralConfig.HookConfig.SplunkConfig.ProdCriblEndpoint) > 0 {
+ splunkClient = &splunk.Splunk{}
+ logCollector = &log.CollectorHook{CorrelationID: GeneralConfig.CorrelationID}
+ log.RegisterHook(logCollector)
+ }
+
+ if err = log.RegisterANSHookIfConfigured(GeneralConfig.CorrelationID); err != nil {
+ log.Entry().WithError(err).Warn("failed to set up SAP Alert Notification Service log hook")
+ }
+
+ validation, err := validation.New(validation.WithJSONNamesForStructFields(), validation.WithPredefinedErrorMessages())
+ if err != nil {
+ return err
+ }
+ if err = validation.ValidateStruct(stepConfig); err != nil {
+ log.SetErrorCategory(log.ErrorConfiguration)
+ return err
+ }
+
+ return nil
+ },
+ Run: func(_ *cobra.Command, _ []string) {
+ stepTelemetryData := telemetry.CustomData{}
+ stepTelemetryData.ErrorCode = "1"
+ handler := func() {
+ commonPipelineEnvironment.persist(GeneralConfig.EnvRootPath, "commonPipelineEnvironment")
+ config.RemoveVaultSecretFiles()
+ stepTelemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds())
+ stepTelemetryData.ErrorCategory = log.GetErrorCategory().String()
+ stepTelemetryData.PiperCommitHash = GitCommit
+ telemetryClient.SetData(&stepTelemetryData)
+ telemetryClient.Send()
+ if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 {
+ splunkClient.Initialize(GeneralConfig.CorrelationID,
+ GeneralConfig.HookConfig.SplunkConfig.Dsn,
+ GeneralConfig.HookConfig.SplunkConfig.Token,
+ GeneralConfig.HookConfig.SplunkConfig.Index,
+ GeneralConfig.HookConfig.SplunkConfig.SendLogs)
+ splunkClient.Send(telemetryClient.GetData(), logCollector)
+ }
+ if len(GeneralConfig.HookConfig.SplunkConfig.ProdCriblEndpoint) > 0 {
+ splunkClient.Initialize(GeneralConfig.CorrelationID,
+ GeneralConfig.HookConfig.SplunkConfig.ProdCriblEndpoint,
+ GeneralConfig.HookConfig.SplunkConfig.ProdCriblToken,
+ GeneralConfig.HookConfig.SplunkConfig.ProdCriblIndex,
+ GeneralConfig.HookConfig.SplunkConfig.SendLogs)
+ splunkClient.Send(telemetryClient.GetData(), logCollector)
+ }
+ }
+ log.DeferExitHandler(handler)
+ defer handler()
+ telemetryClient.Initialize(GeneralConfig.NoTelemetry, STEP_NAME, GeneralConfig.HookConfig.PendoConfig.Token)
+ abapAddonAssemblyKitCheck(stepConfig, &stepTelemetryData, &commonPipelineEnvironment)
+ stepTelemetryData.ErrorCode = "0"
+ log.Entry().Info("SUCCESS")
+ },
+ }
+
+ addAbapAddonAssemblyKitCheckFlags(createAbapAddonAssemblyKitCheckCmd, &stepConfig)
+ return createAbapAddonAssemblyKitCheckCmd
+}
+
+func addAbapAddonAssemblyKitCheckFlags(cmd *cobra.Command, stepConfig *abapAddonAssemblyKitCheckOptions) {
+ cmd.Flags().StringVar(&stepConfig.AbapAddonAssemblyKitCertificateFile, "abapAddonAssemblyKitCertificateFile", os.Getenv("PIPER_abapAddonAssemblyKitCertificateFile"), "base64 encoded certificate pfx file (PKCS12 format) see note [2805811](https://me.sap.com/notes/2805811)")
+ cmd.Flags().StringVar(&stepConfig.AbapAddonAssemblyKitCertificatePass, "abapAddonAssemblyKitCertificatePass", os.Getenv("PIPER_abapAddonAssemblyKitCertificatePass"), "password to decrypt the certificate file")
+ cmd.Flags().StringVar(&stepConfig.AbapAddonAssemblyKitEndpoint, "abapAddonAssemblyKitEndpoint", `https://apps.support.sap.com`, "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.AddonDescriptorFileName, "addonDescriptorFileName", `addon.yml`, "File name of the YAML file which describes the Product Version and corresponding Software Component Versions")
+ 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("addonDescriptorFileName")
+}
+
+// retrieve step metadata
+func abapAddonAssemblyKitCheckMetadata() config.StepData {
+ var theMetaData = config.StepData{
+ Metadata: config.StepMetadata{
+ Name: "abapAddonAssemblyKitCheck",
+ Aliases: []config.Alias{},
+ Description: "This step calls AAKaaS to check the validity of the Addon Product Modelling.",
+ },
+ Spec: config.StepSpec{
+ Inputs: config.StepInputs{
+ Secrets: []config.StepSecrets{
+ {Name: "abapAddonAssemblyKitCredentialsId", Description: "CredentialsId stored in Jenkins for the Addon Assembly Kit as a Service (AAKaaS) system", Type: "jenkins"},
+ {Name: "abapAddonAssemblyKitCertificateFileCredentialsId", Description: "Jenkins secret text credential ID containing the base64 encoded certificate pfx file (PKCS12 format) see note [2805811](https://me.sap.com/notes/2805811)", Type: "jenkins"},
+ {Name: "abapAddonAssemblyKitCertificatePassCredentialsId", Description: "Jenkins secret text credential ID containing the password to decrypt the certificate file stored in abapAddonAssemblyKitCertificateFileCredentialsId", Type: "jenkins"},
+ },
+ Parameters: []config.StepParameters{
+ {
+ Name: "abapAddonAssemblyKitCertificateFile",
+ ResourceRef: []config.ResourceReference{
+ {
+ Name: "abapAddonAssemblyKitCertificateFileCredentialsId",
+ Param: "abapAddonAssemblyKitCertificateFile",
+ Type: "secret",
+ },
+ },
+ Scope: []string{"PARAMETERS"},
+ Type: "string",
+ Mandatory: false,
+ Aliases: []config.Alias{},
+ Default: os.Getenv("PIPER_abapAddonAssemblyKitCertificateFile"),
+ },
+ {
+ Name: "abapAddonAssemblyKitCertificatePass",
+ ResourceRef: []config.ResourceReference{
+ {
+ Name: "abapAddonAssemblyKitCertificatePassCredentialsId",
+ Param: "abapAddonAssemblyKitCertificatePass",
+ Type: "secret",
+ },
+ },
+ Scope: []string{"PARAMETERS"},
+ Type: "string",
+ Mandatory: false,
+ Aliases: []config.Alias{},
+ Default: os.Getenv("PIPER_abapAddonAssemblyKitCertificatePass"),
+ },
+ {
+ Name: "abapAddonAssemblyKitEndpoint",
+ ResourceRef: []config.ResourceReference{},
+ Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
+ Type: "string",
+ Mandatory: true,
+ Aliases: []config.Alias{},
+ Default: `https://apps.support.sap.com`,
+ },
+ {
+ Name: "username",
+ ResourceRef: []config.ResourceReference{},
+ Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
+ Type: "string",
+ Mandatory: false,
+ Aliases: []config.Alias{},
+ Default: os.Getenv("PIPER_username"),
+ },
+ {
+ Name: "password",
+ ResourceRef: []config.ResourceReference{},
+ Scope: []string{"PARAMETERS"},
+ Type: "string",
+ Mandatory: false,
+ Aliases: []config.Alias{},
+ Default: os.Getenv("PIPER_password"),
+ },
+ {
+ Name: "addonDescriptorFileName",
+ ResourceRef: []config.ResourceReference{},
+ Scope: []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"},
+ Type: "string",
+ Mandatory: true,
+ Aliases: []config.Alias{},
+ Default: `addon.yml`,
+ },
+ {
+ Name: "addonDescriptor",
+ ResourceRef: []config.ResourceReference{
+ {
+ Name: "commonPipelineEnvironment",
+ Param: "abap/addonDescriptor",
+ },
+ },
+ Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
+ Type: "string",
+ Mandatory: false,
+ Aliases: []config.Alias{},
+ Default: os.Getenv("PIPER_addonDescriptor"),
+ },
+ },
+ },
+ Outputs: config.StepOutputs{
+ Resources: []config.StepResources{
+ {
+ Name: "commonPipelineEnvironment",
+ Type: "piperEnvironment",
+ Parameters: []map[string]interface{}{
+ {"name": "abap/addonDescriptor"},
+ },
+ },
+ },
+ },
+ },
+ }
+ return theMetaData
+}
diff --git a/cmd/abapAddonAssemblyKitCheck_generated_test.go b/cmd/abapAddonAssemblyKitCheck_generated_test.go
new file mode 100644
index 0000000000..0cbf7de791
--- /dev/null
+++ b/cmd/abapAddonAssemblyKitCheck_generated_test.go
@@ -0,0 +1,20 @@
+//go:build unit
+// +build unit
+
+package cmd
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestAbapAddonAssemblyKitCheckCommand(t *testing.T) {
+ t.Parallel()
+
+ testCmd := AbapAddonAssemblyKitCheckCommand()
+
+ // only high level testing performed - details are tested in step generation procedure
+ assert.Equal(t, "abapAddonAssemblyKitCheck", testCmd.Use, "command name incorrect")
+
+}
diff --git a/cmd/abapAddonAssemblyKitCheck_test.go b/cmd/abapAddonAssemblyKitCheck_test.go
new file mode 100644
index 0000000000..90ad05caae
--- /dev/null
+++ b/cmd/abapAddonAssemblyKitCheck_test.go
@@ -0,0 +1,52 @@
+package cmd
+
+import (
+ "testing"
+
+ "github.com/SAP/jenkins-library/pkg/mock"
+ "github.com/stretchr/testify/assert"
+)
+
+type abapAddonAssemblyKitCheckMockUtils struct {
+ *mock.ExecMockRunner
+ *mock.HttpClientMock
+}
+
+func newAbapAddonAssemblyKitCheckTestsUtils() abapAddonAssemblyKitCheckUtils {
+ utils := abapAddonAssemblyKitCheckMockUtils{
+ ExecMockRunner: &mock.ExecMockRunner{},
+ }
+ return utils
+}
+
+func TestRunAbapAddonAssemblyKitCheck(t *testing.T) {
+ t.Parallel()
+
+ t.Run("happy path", func(t *testing.T) {
+ t.Parallel()
+ // init
+ config := abapAddonAssemblyKitCheckOptions{}
+
+ utils := newAbapAddonAssemblyKitCheckTestsUtils()
+
+ // test
+ err := runAbapAddonAssemblyKitCheck(&config, nil, utils, nil)
+
+ // assert
+ assert.NoError(t, err)
+ })
+
+ t.Run("error path", func(t *testing.T) {
+ t.Parallel()
+ // init
+ config := abapAddonAssemblyKitCheckOptions{}
+
+ utils := newAbapAddonAssemblyKitCheckTestsUtils()
+
+ // test
+ err := runAbapAddonAssemblyKitCheck(&config, nil, utils, nil)
+
+ // assert
+ assert.EqualError(t, err, "cannot run without important file")
+ })
+}
diff --git a/cmd/metadata_generated.go b/cmd/metadata_generated.go
index 21360f54dd..d39526eb13 100644
--- a/cmd/metadata_generated.go
+++ b/cmd/metadata_generated.go
@@ -7,6 +7,7 @@ import "github.com/SAP/jenkins-library/pkg/config"
// GetStepMetadata return a map with all the step metadata mapped to their stepName
func GetAllStepMetadata() map[string]config.StepData {
return map[string]config.StepData{
+ "abapAddonAssemblyKitCheck": abapAddonAssemblyKitCheckMetadata(),
"abapAddonAssemblyKitCheckCVs": abapAddonAssemblyKitCheckCVsMetadata(),
"abapAddonAssemblyKitCheckPV": abapAddonAssemblyKitCheckPVMetadata(),
"abapAddonAssemblyKitCreateTargetVector": abapAddonAssemblyKitCreateTargetVectorMetadata(),
diff --git a/resources/metadata/abapAddonAssemblyKitCheck.yaml b/resources/metadata/abapAddonAssemblyKitCheck.yaml
new file mode 100644
index 0000000000..13b087e82b
--- /dev/null
+++ b/resources/metadata/abapAddonAssemblyKitCheck.yaml
@@ -0,0 +1,102 @@
+metadata:
+ name: abapAddonAssemblyKitCheck
+ description: This step calls AAKaaS to check the validity of the Addon Product Modelling.
+ longDescription: |
+ This step does the following:
+
+ - [The Addon Product Modelling](https://www.project-piper.io/scenarios/abapEnvironmentAddons/#add-on-descriptor-file) is read from the addonDescriptorFileName (e.g. addon.yml)
+ - A connection to AAKaaS (Addon Assembly Kit as a Service) is established and the Addon Product Modelling is transfered for detailed [checks](https://www.project-piper.io/scenarios/abapEnvironmentAddons/#versioning-rules)
+ - The semantic versions are resolved and stored into the piper commonPipelineEnviroment for usage of subsequent pipeline steps
+
+
+ For logon to AAKaaS you can either provide a credential with basic authorization (username and password) or two secret text credentials containing the technical s-users certificate (see note [2805811](https://me.sap.com/notes/2805811) for download) as base64 encoded string and the password to decrypt the file
+
+ For Terminology refer to the [Scenario Description](https://www.project-piper.io/scenarios/abapEnvironmentAddons/).
+spec:
+ inputs:
+ secrets:
+ - name: abapAddonAssemblyKitCredentialsId
+ description: CredentialsId stored in Jenkins for the Addon Assembly Kit as a Service (AAKaaS) system
+ type: jenkins
+ - name: abapAddonAssemblyKitCertificateFileCredentialsId
+ description: Jenkins secret text credential ID containing the base64 encoded certificate pfx file (PKCS12 format) see note [2805811](https://me.sap.com/notes/2805811)
+ type: jenkins
+ - name: abapAddonAssemblyKitCertificatePassCredentialsId
+ description: Jenkins secret text credential ID containing the password to decrypt the certificate file stored in abapAddonAssemblyKitCertificateFileCredentialsId
+ type: jenkins
+ params:
+ - name: abapAddonAssemblyKitCertificateFile
+ type: string
+ description: base64 encoded certificate pfx file (PKCS12 format) see note [2805811](https://me.sap.com/notes/2805811)
+ scope:
+ - PARAMETERS
+ mandatory: false
+ secret: true
+ resourceRef:
+ - name: abapAddonAssemblyKitCertificateFileCredentialsId
+ type: secret
+ param: abapAddonAssemblyKitCertificateFile
+ - name: abapAddonAssemblyKitCertificatePass
+ type: string
+ description: password to decrypt the certificate file
+ scope:
+ - PARAMETERS
+ mandatory: false
+ secret: true
+ resourceRef:
+ - name: abapAddonAssemblyKitCertificatePassCredentialsId
+ type: secret
+ param: abapAddonAssemblyKitCertificatePass
+ - name: abapAddonAssemblyKitEndpoint
+ type: string
+ description: Base URL to the Addon Assembly Kit as a Service (AAKaaS) system
+ scope:
+ - PARAMETERS
+ - STAGES
+ - STEPS
+ - GENERAL
+ mandatory: true
+ default: https://apps.support.sap.com
+ - name: username
+ type: string
+ description: User for the Addon Assembly Kit as a Service (AAKaaS) system
+ scope:
+ - PARAMETERS
+ - STAGES
+ - STEPS
+ mandatory: false
+ secret: true
+ - name: password
+ type: string
+ description: Password for the Addon Assembly Kit as a Service (AAKaaS) system
+ scope:
+ - PARAMETERS
+ mandatory: false
+ secret: true
+ - name: addonDescriptorFileName
+ type: string
+ description: File name of the YAML file which describes the Product Version and corresponding Software Component Versions
+ mandatory: true
+ default: addon.yml
+ scope:
+ - PARAMETERS
+ - STAGES
+ - STEPS
+ - GENERAL
+ - name: addonDescriptor
+ type: string
+ description: Structure in the commonPipelineEnvironment containing information about the Product Version and corresponding Software Component Versions
+ mandatory: false
+ scope:
+ - PARAMETERS
+ - STAGES
+ - STEPS
+ resourceRef:
+ - name: commonPipelineEnvironment
+ param: abap/addonDescriptor
+ outputs:
+ resources:
+ - name: commonPipelineEnvironment
+ type: piperEnvironment
+ params:
+ - name: abap/addonDescriptor
From 04db344c409c0641e06463139db2df23d097cb8a Mon Sep 17 00:00:00 2001
From: tiloKo <70266685+tiloKo@users.noreply.github.com>
Date: Tue, 26 Mar 2024 16:10:42 +0100
Subject: [PATCH 02/15] build pv header from addon descriptor
---
cmd/abapAddonAssemblyKitCheck.go | 91 ++++++++++++++++++++-------
cmd/abapAddonAssemblyKitCheck_test.go | 56 ++++++++---------
2 files changed, 94 insertions(+), 53 deletions(-)
diff --git a/cmd/abapAddonAssemblyKitCheck.go b/cmd/abapAddonAssemblyKitCheck.go
index 37122b0d7b..6aafb7423c 100644
--- a/cmd/abapAddonAssemblyKitCheck.go
+++ b/cmd/abapAddonAssemblyKitCheck.go
@@ -1,42 +1,48 @@
package cmd
import (
- "github.com/SAP/jenkins-library/pkg/command"
- piperhttp "github.com/SAP/jenkins-library/pkg/http"
+ "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/log"
"github.com/SAP/jenkins-library/pkg/telemetry"
+ "github.com/pkg/errors"
)
-type abapAddonAssemblyKitCheckUtils interface {
- command.ExecRunner
- piperhttp.Sender
-}
+func abapAddonAssemblyKitCheck(config abapAddonAssemblyKitCheckOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *abapAddonAssemblyKitCheckCommonPipelineEnvironment) {
+ utils := aakaas.NewAakBundle()
-type abapAddonAssemblyKitCheckUtilsBundle struct {
- *command.Command
- *piperhttp.Client
+ err := runAbapAddonAssemblyKitCheck(&config, telemetryData, utils, commonPipelineEnvironment)
+ if err != nil {
+ log.Entry().WithError(err).Fatal("step execution failed")
+ }
}
-func newAbapAddonAssemblyKitCheckUtils() abapAddonAssemblyKitCheckUtils {
- utils := abapAddonAssemblyKitCheckUtilsBundle{
- Command: &command.Command{},
+func runAbapAddonAssemblyKitCheck(config *abapAddonAssemblyKitCheckOptions, telemetryData *telemetry.CustomData, utils aakaas.AakUtils, commonPipelineEnvironment *abapAddonAssemblyKitCheckCommonPipelineEnvironment) error {
+
+ log.Entry().Info("╔═══════════════════════════╗")
+ log.Entry().Info("║ abapAddonAssemblyKitCheck ║")
+ log.Entry().Info("╚═══════════════════════════╝")
+
+ conn := new(abapbuild.Connector)
+ if err := conn.InitAAKaaS(config.AbapAddonAssemblyKitEndpoint, config.Username, config.Password, utils, "", config.AbapAddonAssemblyKitCertificateFile, config.AbapAddonAssemblyKitCertificatePass); err != nil {
+ return err
}
- // Reroute command output to logging framework
- utils.Stdout(log.Writer())
- utils.Stderr(log.Writer())
- return &utils
-}
-func abapAddonAssemblyKitCheck(config abapAddonAssemblyKitCheckOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *abapAddonAssemblyKitCheckCommonPipelineEnvironment) {
- utils := newAbapAddonAssemblyKitCheckUtils()
+ log.Entry().Infof("Reading addonDescriptor (aka addon.yml) file: %s", config.AddonDescriptorFileName)
+ addonDescriptor, err := utils.ReadAddonDescriptor(config.AddonDescriptorFileName)
+ if err != nil {
+ return err
+ }
- err := runAbapAddonAssemblyKitCheck(&config, telemetryData, utils, commonPipelineEnvironment)
+ pvh, err := NewProductVersionHeader(&addonDescriptor, conn)
if err != nil {
- log.Entry().WithError(err).Fatal("step execution failed")
+ return err
}
-}
-func runAbapAddonAssemblyKitCheck(config *abapAddonAssemblyKitCheckOptions, telemetryData *telemetry.CustomData, utils abapAddonAssemblyKitCheckUtils, commonPipelineEnvironment *abapAddonAssemblyKitCheckCommonPipelineEnvironment) error {
+ if err := pvh.check(); err != nil {
+ return err
+ }
// log.Entry().WithField("LogField", "Log field content").Info("This is just a demo for a simple step.")
// // Example of calling methods from external dependencies directly on utils:
@@ -64,7 +70,7 @@ type ProductVersionHeader struct {
PatchLevel string
Vendor string
VendorType string
- Content []ProductVersionContent
+ Content []ProductVersionContent //maybe some struct in between see TargetVector???
}
type ProductVersionContent struct {
@@ -78,3 +84,40 @@ type ProductVersionContent struct {
Vendor string
VendorType string
}
+
+func NewProductVersionHeader(addonDescriptor *abaputils.AddonDescriptor, conn *abapbuild.Connector) (*ProductVersionHeader, error) {
+ productVersion := new(aakaas.ProductVersion)
+ if err := productVersion.ConstructProductversion(*addonDescriptor, *conn); err != nil {
+ return nil, err
+ }
+ pvh := ProductVersionHeader{
+ ProductName: productVersion.Name,
+ SemanticProductVersion: productVersion.Version,
+ Content: []ProductVersionContent{},
+ }
+
+ for _, repo := range addonDescriptor.Repositories {
+ componentVersion := new(aakaas.ComponentVersion)
+ if err := componentVersion.ConstructComponentVersion(repo, *conn); err != nil {
+ return nil, err
+ }
+ pvc := ProductVersionContent{
+ ProductName: pvh.ProductName,
+ SemanticProductVersion: pvh.ProductName,
+ SoftwareComponentName: componentVersion.Name,
+ SemanticSoftwareComponentVersion: componentVersion.Version,
+ }
+ pvh.Content = append(pvh.Content, pvc)
+ }
+
+ if len(pvh.Content) == 0 {
+ return nil, errors.New("addonDescriptor must contain at least one software component repository")
+ }
+
+ return &pvh, nil
+}
+
+func (pv *ProductVersionHeader) check() error {
+
+ return nil
+}
diff --git a/cmd/abapAddonAssemblyKitCheck_test.go b/cmd/abapAddonAssemblyKitCheck_test.go
index 90ad05caae..d196794b26 100644
--- a/cmd/abapAddonAssemblyKitCheck_test.go
+++ b/cmd/abapAddonAssemblyKitCheck_test.go
@@ -2,51 +2,49 @@ package cmd
import (
"testing"
-
- "github.com/SAP/jenkins-library/pkg/mock"
- "github.com/stretchr/testify/assert"
+ // "github.com/stretchr/testify/assert"
)
-type abapAddonAssemblyKitCheckMockUtils struct {
- *mock.ExecMockRunner
- *mock.HttpClientMock
-}
+// type abapAddonAssemblyKitCheckMockUtils struct {
+// *mock.ExecMockRunner
+// *mock.HttpClientMock
+// }
-func newAbapAddonAssemblyKitCheckTestsUtils() abapAddonAssemblyKitCheckUtils {
- utils := abapAddonAssemblyKitCheckMockUtils{
- ExecMockRunner: &mock.ExecMockRunner{},
- }
- return utils
-}
+// func newAbapAddonAssemblyKitCheckTestsUtils() abapAddonAssemblyKitCheckUtils {
+// utils := abapAddonAssemblyKitCheckMockUtils{
+// ExecMockRunner: &mock.ExecMockRunner{},
+// }
+// return utils
+// }
func TestRunAbapAddonAssemblyKitCheck(t *testing.T) {
t.Parallel()
t.Run("happy path", func(t *testing.T) {
- t.Parallel()
- // init
- config := abapAddonAssemblyKitCheckOptions{}
+ // t.Parallel()
+ // // init
+ // config := abapAddonAssemblyKitCheckOptions{}
- utils := newAbapAddonAssemblyKitCheckTestsUtils()
+ // utils := newAbapAddonAssemblyKitCheckTestsUtils()
- // test
- err := runAbapAddonAssemblyKitCheck(&config, nil, utils, nil)
+ // // test
+ // err := runAbapAddonAssemblyKitCheck(&config, nil, utils, nil)
- // assert
- assert.NoError(t, err)
+ // // assert
+ // assert.NoError(t, err)
})
t.Run("error path", func(t *testing.T) {
- t.Parallel()
- // init
- config := abapAddonAssemblyKitCheckOptions{}
+ // t.Parallel()
+ // // init
+ // config := abapAddonAssemblyKitCheckOptions{}
- utils := newAbapAddonAssemblyKitCheckTestsUtils()
+ // utils := newAbapAddonAssemblyKitCheckTestsUtils()
- // test
- err := runAbapAddonAssemblyKitCheck(&config, nil, utils, nil)
+ // // test
+ // err := runAbapAddonAssemblyKitCheck(&config, nil, utils, nil)
- // assert
- assert.EqualError(t, err, "cannot run without important file")
+ // // assert
+ // assert.EqualError(t, err, "cannot run without important file")
})
}
From fb61ee0560ff20fd9c71021669494c90799e92d4 Mon Sep 17 00:00:00 2001
From: tiloKo <70266685+tiloKo@users.noreply.github.com>
Date: Fri, 5 Apr 2024 11:37:57 +0200
Subject: [PATCH 03/15] more functions
---
cmd/abapAddonAssemblyKitCheck.go | 99 ++++++++++++++++++++++++++------
1 file changed, 83 insertions(+), 16 deletions(-)
diff --git a/cmd/abapAddonAssemblyKitCheck.go b/cmd/abapAddonAssemblyKitCheck.go
index 6aafb7423c..a106f13a28 100644
--- a/cmd/abapAddonAssemblyKitCheck.go
+++ b/cmd/abapAddonAssemblyKitCheck.go
@@ -1,10 +1,13 @@
package cmd
import (
+ "encoding/json"
+
"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/log"
+ "github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/pkg/errors"
)
@@ -40,28 +43,28 @@ func runAbapAddonAssemblyKitCheck(config *abapAddonAssemblyKitCheckOptions, tele
return err
}
- if err := pvh.check(); err != nil {
+ if err := pvh.checkAndResolveVersion(conn); err != nil {
return err
}
+ pvh.SyncAddonDescriptorVersionFields(&addonDescriptor)
+
+ commonPipelineEnvironment.abap.addonDescriptor = string(addonDescriptor.AsJSON())
- // log.Entry().WithField("LogField", "Log field content").Info("This is just a demo for a simple step.")
- // // Example of calling methods from external dependencies directly on utils:
- // exists, err := utils.FileExists("file.txt")
- // if err != nil {
- // // It is good practice to set an error category.
- // // Most likely you want to do this at the place where enough context is known.
- // log.SetErrorCategory(log.ErrorConfiguration)
- // // Always wrap non-descriptive errors to enrich them with context for when they appear in the log:
- // return fmt.Errorf("failed to check for important file: %w", err)
- // }
- // if !exists {
- // log.SetErrorCategory(log.ErrorConfiguration)
- // return fmt.Errorf("cannot run without important file")
- // }
+ publishAddonYaml(config, utils)
return nil
}
+func publishAddonYaml(config *abapAddonAssemblyKitCheckOptions, utils aakaas.AakUtils) {
+ var filesToPublish []piperutils.Path
+ log.Entry().Infof("Add %s to be published", config.AddonDescriptorFileName)
+ filesToPublish = append(filesToPublish, piperutils.Path{Target: config.AddonDescriptorFileName, Name: "AddonDescriptor", Mandatory: true})
+ log.Entry().Infof("Publishing %v files", len(filesToPublish))
+ if err := piperutils.PersistReportsAndLinks("abapAddonAssemblyKitCheckPV", "", utils, filesToPublish, nil); err != nil {
+ log.Entry().WithError(err).Error("failed to persist report information")
+ }
+}
+
type ProductVersionHeader struct {
ProductName string
SemanticProductVersion string `json:"SemProductVersion"`
@@ -117,7 +120,71 @@ func NewProductVersionHeader(addonDescriptor *abaputils.AddonDescriptor, conn *a
return &pvh, nil
}
-func (pv *ProductVersionHeader) check() error {
+func (pv *ProductVersionHeader) checkAndResolveVersion(conn *abapbuild.Connector) error {
+ requestJson, err := json.Marshal(pv)
+ if err != nil {
+ return err
+ }
+ appendum := "/odata/aas_ocs_package/ProductVersionHeaderSet"
+ responseBody, err := conn.Post(appendum, string(requestJson))
+ if err != nil {
+ return errors.Wrap(err, "Checking Product Modeling in AAkaaS failed")
+ }
+ var resultPv ProductVersionHeader //wrapper struct needed???
+ if err := json.Unmarshal(responseBody, &resultPv); err != nil {
+ return errors.Wrap(err, "Unexpected AAKaaS response for checking Product Modeling "+string(responseBody))
+ }
+
+ pv.ProductVersion = resultPv.ProductVersion
+ pv.Spslevel = resultPv.Spslevel
+ pv.PatchLevel = resultPv.PatchLevel
+
+ //transfer resolved version fields (and others)
+ for pvc_index, pvc := range pv.Content {
+ foundPvc := ProductVersionContent{}
+ for _, resultPvc := range resultPv.Content {
+ if pvc.SoftwareComponentName == resultPvc.SoftwareComponentName && foundPvc.SoftwareComponentName == "" {
+ foundPvc = resultPvc
+ } else if pvc.SoftwareComponentName == resultPvc.SoftwareComponentName {
+ return errors.New("Software Component Name must be unique in the ProductVersionContent")
+ }
+ }
+ if foundPvc.SoftwareComponentName == "" {
+ return errors.New("Software Component Name not found in the ProductVersionContent")
+ }
+ pv.Content[pvc_index].PatchLevel = foundPvc.PatchLevel
+ pv.Content[pvc_index].SpLevel = foundPvc.SpLevel
+ pv.Content[pvc_index].SoftwareComponentVersion = foundPvc.SoftwareComponentVersion
+ }
+
+ return nil
+}
+
+func (pv *ProductVersionHeader) SyncAddonDescriptorVersionFields(addonDescriptor *abaputils.AddonDescriptor) error {
+ addonDescriptor.AddonVersion = pv.ProductVersion
+ addonDescriptor.AddonSpsLevel = pv.Spslevel
+ addonDescriptor.AddonPatchLevel = pv.PatchLevel
+
+ //in NewPvh function pvh was build up 1:1 based on addonDescriptor
+ //in checkAndResolve pvh was synced from AAKaaS reply assuming it does not contain more content than before(if it does it is ignored)
+ //anyway we are defenisve once more
+ for repo_index, repo := range addonDescriptor.Repositories {
+ foundPvc := ProductVersionContent{}
+ for _, pvc := range pv.Content {
+ if pvc.SoftwareComponentName == repo.Name && foundPvc.SoftwareComponentName == "" {
+ foundPvc = pvc
+ } else if pvc.SoftwareComponentName == repo.Name {
+ return errors.New("Software Component Name must be unique in addon descriptor(aka addon.yml)")
+ }
+ }
+ if foundPvc.SoftwareComponentName == "" {
+ return errors.New("ProductVersionContent & addon descriptor (aka addon.yml) out of sync")
+ }
+
+ addonDescriptor.Repositories[repo_index].PatchLevel = foundPvc.PatchLevel
+ addonDescriptor.Repositories[repo_index].SpLevel = foundPvc.SpLevel
+ addonDescriptor.Repositories[repo_index].Version = foundPvc.SoftwareComponentVersion
+ }
return nil
}
From ad621673fbe6e25d5c98862d0443d85acd5f5818 Mon Sep 17 00:00:00 2001
From: tiloKo <70266685+tiloKo@users.noreply.github.com>
Date: Mon, 15 Apr 2024 15:25:53 +0200
Subject: [PATCH 04/15] happy path unit test
---
cmd/abapAddonAssemblyKitCheck.go | 68 ++++++++++++++++++++++-----
cmd/abapAddonAssemblyKitCheck_test.go | 59 +++++++++++++----------
pkg/abap/aakaas/aakUtils_mock.go | 7 ++-
pkg/abap/aakaas/testData.go | 38 +++++++++++++++
4 files changed, 134 insertions(+), 38 deletions(-)
diff --git a/cmd/abapAddonAssemblyKitCheck.go b/cmd/abapAddonAssemblyKitCheck.go
index a106f13a28..89b189c82d 100644
--- a/cmd/abapAddonAssemblyKitCheck.go
+++ b/cmd/abapAddonAssemblyKitCheck.go
@@ -37,24 +37,55 @@ func runAbapAddonAssemblyKitCheck(config *abapAddonAssemblyKitCheckOptions, tele
if err != nil {
return err
}
-
+ log.Entry().Info("Building Product Modeling (and Resolving potential wildcards)")
pvh, err := NewProductVersionHeader(&addonDescriptor, conn)
if err != nil {
return err
}
+ printProductVersionHeader(*pvh)
+ log.Entry().Info("Tranfering Product Modeling to AAKaaS to be checked...")
if err := pvh.checkAndResolveVersion(conn); err != nil {
return err
}
+ log.Entry().Info("... success!")
pvh.SyncAddonDescriptorVersionFields(&addonDescriptor)
-
+ log.Entry().Info("Resolved Version Fields:")
+ printAddonDescriptorVersionFields(addonDescriptor)
+ log.Entry().Info("Transfering addonDescriptor to commonPipelineEnvironment for usage by following steps of the pipeline")
commonPipelineEnvironment.abap.addonDescriptor = string(addonDescriptor.AsJSON())
publishAddonYaml(config, utils)
-
return nil
}
+func printProductVersionHeader(pvh ProductVersionHeader) {
+ logLine30 := "──────────────────────────────"
+ log.Entry().Infof("┌─%-30v─┬─%-30v─┐", logLine30, logLine30)
+ log.Entry().Infof("│ %-30v │ %-30v │", "Product Name", pvh.ProductName)
+ log.Entry().Infof("│ %-30v │ %-30v │", "Product Version", pvh.SemanticProductVersion)
+ log.Entry().Infof("├─%-30v─┼─%-30v─┤", logLine30, logLine30)
+ log.Entry().Infof("│ %-30v │ %-30v │", "Software Component Name", "Software Component Version")
+ log.Entry().Infof("├─%-30v─┼─%-30v─┤", logLine30, logLine30)
+ for _, pvc := range pvh.Content {
+ log.Entry().Infof("│ %-30v │ %-30v │", pvc.SoftwareComponentName, pvc.SemanticSoftwareComponentVersion)
+ }
+ log.Entry().Infof("└─%-30v─┴─%-30v─┘", logLine30, logLine30)
+}
+
+func printAddonDescriptorVersionFields(addonDescriptor abaputils.AddonDescriptor) {
+ logLine30 := "──────────────────────────────"
+ logLine4 := "────"
+ log.Entry().Infof("┌─%-30v─┬─%-4v─┬─%-4v─┬─%-4v─┐", logLine30, logLine4, logLine4, logLine4)
+ log.Entry().Infof("│ %-30v │ %-4v │ %-4v │ %-4v │", "Name", "Vers", "SP", "Pat.")
+ log.Entry().Infof("├─%-30v─┼─%-4v─┼─%-4v─┼─%-4v─┤", logLine30, logLine4, logLine4, logLine4)
+ log.Entry().Infof("│ %-30v │ %-4v │ %-4v │ %-4v │", addonDescriptor.AddonProduct, addonDescriptor.AddonVersion, addonDescriptor.AddonSpsLevel, addonDescriptor.AddonPatchLevel)
+ for _, repo := range addonDescriptor.Repositories {
+ log.Entry().Infof("│ %-30v │ %-4v │ %-4v │ %-4v │", repo.Name, repo.Version, repo.SpLevel, repo.PatchLevel)
+ }
+ log.Entry().Infof("└─%-30v─┴─%-4v─┴─%-4v─┴─%-4v─┘", logLine30, logLine4, logLine4, logLine4)
+}
+
func publishAddonYaml(config *abapAddonAssemblyKitCheckOptions, utils aakaas.AakUtils) {
var filesToPublish []piperutils.Path
log.Entry().Infof("Add %s to be published", config.AddonDescriptorFileName)
@@ -65,6 +96,10 @@ func publishAddonYaml(config *abapAddonAssemblyKitCheckOptions, utils aakaas.Aak
}
}
+type jsonProductVersionHeader struct {
+ Pvh *ProductVersionHeader `json:"d"`
+}
+
type ProductVersionHeader struct {
ProductName string
SemanticProductVersion string `json:"SemProductVersion"`
@@ -73,7 +108,12 @@ type ProductVersionHeader struct {
PatchLevel string
Vendor string
VendorType string
- Content []ProductVersionContent //maybe some struct in between see TargetVector???
+ Content []ProductVersionContent `json:"-"` //for developer access
+ JsonContent ProductVersionContents `json:"Content"` //for json (Un)Marshaling
+}
+
+type ProductVersionContents struct {
+ Content []ProductVersionContent `json:"results"`
}
type ProductVersionContent struct {
@@ -106,7 +146,7 @@ func NewProductVersionHeader(addonDescriptor *abaputils.AddonDescriptor, conn *a
}
pvc := ProductVersionContent{
ProductName: pvh.ProductName,
- SemanticProductVersion: pvh.ProductName,
+ SemanticProductVersion: pvh.SemanticProductVersion,
SoftwareComponentName: componentVersion.Name,
SemanticSoftwareComponentVersion: componentVersion.Version,
}
@@ -121,28 +161,32 @@ func NewProductVersionHeader(addonDescriptor *abaputils.AddonDescriptor, conn *a
}
func (pv *ProductVersionHeader) checkAndResolveVersion(conn *abapbuild.Connector) error {
+ pv.JsonContent = ProductVersionContents{
+ Content: pv.Content,
+ }
requestJson, err := json.Marshal(pv)
if err != nil {
return err
}
+
appendum := "/odata/aas_ocs_package/ProductVersionHeaderSet"
responseBody, err := conn.Post(appendum, string(requestJson))
if err != nil {
return errors.Wrap(err, "Checking Product Modeling in AAkaaS failed")
}
- var resultPv ProductVersionHeader //wrapper struct needed???
+
+ var resultPv jsonProductVersionHeader
if err := json.Unmarshal(responseBody, &resultPv); err != nil {
return errors.Wrap(err, "Unexpected AAKaaS response for checking Product Modeling "+string(responseBody))
}
- pv.ProductVersion = resultPv.ProductVersion
- pv.Spslevel = resultPv.Spslevel
- pv.PatchLevel = resultPv.PatchLevel
+ pv.ProductVersion = resultPv.Pvh.ProductVersion
+ pv.Spslevel = resultPv.Pvh.Spslevel
+ pv.PatchLevel = resultPv.Pvh.PatchLevel
- //transfer resolved version fields (and others)
for pvc_index, pvc := range pv.Content {
foundPvc := ProductVersionContent{}
- for _, resultPvc := range resultPv.Content {
+ for _, resultPvc := range resultPv.Pvh.JsonContent.Content {
if pvc.SoftwareComponentName == resultPvc.SoftwareComponentName && foundPvc.SoftwareComponentName == "" {
foundPvc = resultPvc
} else if pvc.SoftwareComponentName == resultPvc.SoftwareComponentName {
@@ -157,6 +201,7 @@ func (pv *ProductVersionHeader) checkAndResolveVersion(conn *abapbuild.Connector
pv.Content[pvc_index].SoftwareComponentVersion = foundPvc.SoftwareComponentVersion
}
+ pv.JsonContent = ProductVersionContents{}
return nil
}
@@ -167,7 +212,6 @@ func (pv *ProductVersionHeader) SyncAddonDescriptorVersionFields(addonDescriptor
//in NewPvh function pvh was build up 1:1 based on addonDescriptor
//in checkAndResolve pvh was synced from AAKaaS reply assuming it does not contain more content than before(if it does it is ignored)
- //anyway we are defenisve once more
for repo_index, repo := range addonDescriptor.Repositories {
foundPvc := ProductVersionContent{}
for _, pvc := range pv.Content {
diff --git a/cmd/abapAddonAssemblyKitCheck_test.go b/cmd/abapAddonAssemblyKitCheck_test.go
index d196794b26..15e303c571 100644
--- a/cmd/abapAddonAssemblyKitCheck_test.go
+++ b/cmd/abapAddonAssemblyKitCheck_test.go
@@ -1,37 +1,46 @@
+//go:build unit
+// +build unit
+
package cmd
import (
"testing"
- // "github.com/stretchr/testify/assert"
-)
-// type abapAddonAssemblyKitCheckMockUtils struct {
-// *mock.ExecMockRunner
-// *mock.HttpClientMock
-// }
-
-// func newAbapAddonAssemblyKitCheckTestsUtils() abapAddonAssemblyKitCheckUtils {
-// utils := abapAddonAssemblyKitCheckMockUtils{
-// ExecMockRunner: &mock.ExecMockRunner{},
-// }
-// return utils
-// }
+ "github.com/SAP/jenkins-library/pkg/abap/aakaas"
+ "github.com/SAP/jenkins-library/pkg/abaputils"
+ "github.com/stretchr/testify/assert"
+)
func TestRunAbapAddonAssemblyKitCheck(t *testing.T) {
- t.Parallel()
+ var config abapAddonAssemblyKitCheckOptions
+ var cpe abapAddonAssemblyKitCheckCommonPipelineEnvironment
+ bundle := aakaas.NewAakBundleMock()
+ utils := bundle.GetUtils()
+ config.Username = "dummyUser"
+ config.Password = "dummyPassword"
t.Run("happy path", func(t *testing.T) {
- // t.Parallel()
- // // init
- // config := abapAddonAssemblyKitCheckOptions{}
-
- // utils := newAbapAddonAssemblyKitCheckTestsUtils()
-
- // // test
- // err := runAbapAddonAssemblyKitCheck(&config, nil, utils, nil)
-
- // // assert
- // assert.NoError(t, err)
+ config.AddonDescriptorFileName = "addon.yml.mock"
+ bundle.SetBody(aakaas.ResponseCheck)
+ bundle.MockAddonDescriptor = abaputils.AddonDescriptor{
+ AddonProduct: "/DRNMSPC/PRD01",
+ AddonVersionYAML: "2.0.0",
+ Repositories: []abaputils.Repository{
+ {
+ Name: "/DRNMSPC/COMP01",
+ VersionYAML: "2.0.0",
+ },
+ {
+ Name: "/DRNMSPC/COMP02",
+ VersionYAML: "1.0.0",
+ },
+ },
+ }
+
+ err := runAbapAddonAssemblyKitCheck(&config, nil, utils, &cpe)
+
+ assert.NoError(t, err)
+ assert.EqualError(t, err, "dummy - get logoutput")
})
t.Run("error path", func(t *testing.T) {
diff --git a/pkg/abap/aakaas/aakUtils_mock.go b/pkg/abap/aakaas/aakUtils_mock.go
index 307771ef4a..5e4de0a8f0 100644
--- a/pkg/abap/aakaas/aakUtils_mock.go
+++ b/pkg/abap/aakaas/aakUtils_mock.go
@@ -17,7 +17,8 @@ type AakBundleMock struct {
*mock.ExecMockRunner
*abaputils.ClientMock
*mock.FilesMock
- maxRuntime time.Duration
+ maxRuntime time.Duration
+ MockAddonDescriptor abaputils.AddonDescriptor
}
func NewAakBundleMock() *AakBundleMock {
@@ -99,6 +100,10 @@ func (bundle *AakBundleMock) ReadAddonDescriptor(FileName string) (abaputils.Add
{
err = errors.New("error in ReadAddonDescriptor")
}
+ case "addon.yml.mock":
+ {
+ return bundle.MockAddonDescriptor, nil
+ }
}
return addonDescriptor, err
}
diff --git a/pkg/abap/aakaas/testData.go b/pkg/abap/aakaas/testData.go
index 3a0b10dbe4..adc64a167a 100644
--- a/pkg/abap/aakaas/testData.go
+++ b/pkg/abap/aakaas/testData.go
@@ -34,6 +34,44 @@ var ResponseCheckCVs = `{
}
}`
+var ResponseCheck = `{
+ "d": {
+ "ProductName": "/DRNMSPC/PRD01",
+ "SemProductVersion": "2.0.0",
+ "ProductVersion": "0002",
+ "SpsLevel": "0000",
+ "PatchLevel": "0000",
+ "Vendor": "",
+ "VendorType": "",
+ "Content": {
+ "results": [
+ {
+ "ProductName": "/DRNMSPC/PRD01",
+ "SemProductVersion": "2.0.0",
+ "ScName": "/DRNMSPC/COMP01",
+ "SemScVersion": "2.0.0",
+ "ScVersion": "0002",
+ "SpLevel": "0000",
+ "PatchLevel": "0000",
+ "Vendor": "",
+ "VendorType": ""
+ },
+ {
+ "ProductName": "/DRNMSPC/PRD01",
+ "SemProductVersion": "2.0.0",
+ "ScName": "/DRNMSPC/COMP02",
+ "SemScVersion": "1.0.0",
+ "ScVersion": "0001",
+ "SpLevel": "0000",
+ "PatchLevel": "0000",
+ "Vendor": "",
+ "VendorType": ""
+ }
+ ]
+ }
+ }
+}`
+
var emptyResultBody = `{
"d": {
"results": []
From e00606ba0176cc5878bef054a1569d7eb6cd123b Mon Sep 17 00:00:00 2001
From: tiloKo <70266685+tiloKo@users.noreply.github.com>
Date: Mon, 15 Apr 2024 15:41:15 +0200
Subject: [PATCH 05/15] one unhappy path
---
cmd/abapAddonAssemblyKitCheck_test.go | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/cmd/abapAddonAssemblyKitCheck_test.go b/cmd/abapAddonAssemblyKitCheck_test.go
index 15e303c571..a9b2f41fbe 100644
--- a/cmd/abapAddonAssemblyKitCheck_test.go
+++ b/cmd/abapAddonAssemblyKitCheck_test.go
@@ -40,20 +40,21 @@ func TestRunAbapAddonAssemblyKitCheck(t *testing.T) {
err := runAbapAddonAssemblyKitCheck(&config, nil, utils, &cpe)
assert.NoError(t, err)
- assert.EqualError(t, err, "dummy - get logoutput")
})
t.Run("error path", func(t *testing.T) {
- // t.Parallel()
- // // init
- // config := abapAddonAssemblyKitCheckOptions{}
-
- // utils := newAbapAddonAssemblyKitCheckTestsUtils()
+ config.AddonDescriptorFileName = "addon.yml.mock"
+ bundle.SetBody(aakaas.ResponseCheck)
+ bundle.MockAddonDescriptor = abaputils.AddonDescriptor{
+ AddonProduct: "/DRNMSPC/PRD01",
+ AddonVersionYAML: "2.0.0",
+ Repositories: []abaputils.Repository{
+ //no repos should fail during pvh creation...
+ },
+ }
- // // test
- // err := runAbapAddonAssemblyKitCheck(&config, nil, utils, nil)
+ err := runAbapAddonAssemblyKitCheck(&config, nil, utils, &cpe)
- // // assert
- // assert.EqualError(t, err, "cannot run without important file")
+ assert.EqualError(t, err, "addonDescriptor must contain at least one software component repository")
})
}
From 679a29641718b5f9401477c8264c25da286be0ec Mon Sep 17 00:00:00 2001
From: tiloKo <70266685+tiloKo@users.noreply.github.com>
Date: Mon, 15 Apr 2024 15:56:14 +0200
Subject: [PATCH 06/15] fix trailing space yaml
---
resources/metadata/abapAddonAssemblyKitCheck.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/metadata/abapAddonAssemblyKitCheck.yaml b/resources/metadata/abapAddonAssemblyKitCheck.yaml
index 13b087e82b..dfa6eb90f2 100644
--- a/resources/metadata/abapAddonAssemblyKitCheck.yaml
+++ b/resources/metadata/abapAddonAssemblyKitCheck.yaml
@@ -3,7 +3,7 @@ metadata:
description: This step calls AAKaaS to check the validity of the Addon Product Modelling.
longDescription: |
This step does the following:
-
+
- [The Addon Product Modelling](https://www.project-piper.io/scenarios/abapEnvironmentAddons/#add-on-descriptor-file) is read from the addonDescriptorFileName (e.g. addon.yml)
- A connection to AAKaaS (Addon Assembly Kit as a Service) is established and the Addon Product Modelling is transfered for detailed [checks](https://www.project-piper.io/scenarios/abapEnvironmentAddons/#versioning-rules)
- The semantic versions are resolved and stored into the piper commonPipelineEnviroment for usage of subsequent pipeline steps
From 33c31e5f500f3728620ab21537dd1066c89fef6c Mon Sep 17 00:00:00 2001
From: tiloKo <70266685+tiloKo@users.noreply.github.com>
Date: Mon, 15 Apr 2024 16:06:00 +0200
Subject: [PATCH 07/15] dummy change in yaml
---
cmd/abapAddonAssemblyKitCheck_generated.go | 3 +--
resources/metadata/abapAddonAssemblyKitCheck.yaml | 3 +--
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/cmd/abapAddonAssemblyKitCheck_generated.go b/cmd/abapAddonAssemblyKitCheck_generated.go
index 1027325870..e153d4e165 100644
--- a/cmd/abapAddonAssemblyKitCheck_generated.go
+++ b/cmd/abapAddonAssemblyKitCheck_generated.go
@@ -70,8 +70,7 @@ func AbapAddonAssemblyKitCheckCommand() *cobra.Command {
var createAbapAddonAssemblyKitCheckCmd = &cobra.Command{
Use: STEP_NAME,
Short: "This step calls AAKaaS to check the validity of the Addon Product Modelling.",
- Long: `This step does the following:
-
+ Long: `This step does the following:
- [The Addon Product Modelling](https://www.project-piper.io/scenarios/abapEnvironmentAddons/#add-on-descriptor-file) is read from the addonDescriptorFileName (e.g. addon.yml)
- A connection to AAKaaS (Addon Assembly Kit as a Service) is established and the Addon Product Modelling is transfered for detailed [checks](https://www.project-piper.io/scenarios/abapEnvironmentAddons/#versioning-rules)
- The semantic versions are resolved and stored into the piper commonPipelineEnviroment for usage of subsequent pipeline steps
diff --git a/resources/metadata/abapAddonAssemblyKitCheck.yaml b/resources/metadata/abapAddonAssemblyKitCheck.yaml
index dfa6eb90f2..19842737b1 100644
--- a/resources/metadata/abapAddonAssemblyKitCheck.yaml
+++ b/resources/metadata/abapAddonAssemblyKitCheck.yaml
@@ -2,8 +2,7 @@ metadata:
name: abapAddonAssemblyKitCheck
description: This step calls AAKaaS to check the validity of the Addon Product Modelling.
longDescription: |
- This step does the following:
-
+ This step does the following:
- [The Addon Product Modelling](https://www.project-piper.io/scenarios/abapEnvironmentAddons/#add-on-descriptor-file) is read from the addonDescriptorFileName (e.g. addon.yml)
- A connection to AAKaaS (Addon Assembly Kit as a Service) is established and the Addon Product Modelling is transfered for detailed [checks](https://www.project-piper.io/scenarios/abapEnvironmentAddons/#versioning-rules)
- The semantic versions are resolved and stored into the piper commonPipelineEnviroment for usage of subsequent pipeline steps
From fc0820123c6de2e59c66b6858e426d692cae9863 Mon Sep 17 00:00:00 2001
From: tiloKo <70266685+tiloKo@users.noreply.github.com>
Date: Tue, 16 Apr 2024 10:41:45 +0200
Subject: [PATCH 08/15] boilerplate stuff
---
cmd/piper.go | 1 +
.../docs/steps/abapAddonAssemblyKitCheck.md | 42 +++++++++++++++++++
documentation/mkdocs.yml | 16 +++----
test/groovy/CommonStepsTest.groovy | 1 +
vars/abapAddonAssemblyKitCheck.groovy | 13 ++++++
5 files changed, 66 insertions(+), 7 deletions(-)
create mode 100644 documentation/docs/steps/abapAddonAssemblyKitCheck.md
create mode 100644 vars/abapAddonAssemblyKitCheck.groovy
diff --git a/cmd/piper.go b/cmd/piper.go
index bcd5217a05..8377f61a41 100644
--- a/cmd/piper.go
+++ b/cmd/piper.go
@@ -154,6 +154,7 @@ func Execute() {
rootCmd.AddCommand(AbapEnvironmentAssemblePackagesCommand())
rootCmd.AddCommand(AbapAddonAssemblyKitCheckCVsCommand())
rootCmd.AddCommand(AbapAddonAssemblyKitCheckPVCommand())
+ rootCmd.AddCommand(AbapAddonAssemblyKitCheckCommand())
rootCmd.AddCommand(AbapAddonAssemblyKitCreateTargetVectorCommand())
rootCmd.AddCommand(AbapAddonAssemblyKitPublishTargetVectorCommand())
rootCmd.AddCommand(AbapAddonAssemblyKitRegisterPackagesCommand())
diff --git a/documentation/docs/steps/abapAddonAssemblyKitCheck.md b/documentation/docs/steps/abapAddonAssemblyKitCheck.md
new file mode 100644
index 0000000000..feb11316c8
--- /dev/null
+++ b/documentation/docs/steps/abapAddonAssemblyKitCheck.md
@@ -0,0 +1,42 @@
+# ${docGenStepName}
+
+## ${docGenDescription}
+
+### Artifacts
+
+- addonDescriptorFile (addon.yml)
+ The addonDescriptorFile as specified in parameter addonDescriptorFileName is archived as artifact. This is done as this file is the main configuration and usually changed with every run. Thus it simplifies support if the corresponding configuration file is directly accessible in the pipeline.
+
+## Prerequisites
+
+* The credentials to access the AAKaaS (Technical Communication User) must be stored in the Jenkins Credential Store
+* The step needs an addon.yml containing information about the Product Version and corresponding Software Component Versions/Repositories
+
+A detailed description of all prerequisites of the scenario and how to configure them can be found in the [Scenario Description](https://www.project-piper.io/scenarios/abapEnvironmentAddons/).
+
+## ${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
+abapAddonAssemblyKitCheck script: this
+```
+
+If the step is to be configured individually the config.yml should look like this:
+
+```yaml
+steps:
+ abapAddonAssemblyKitCheck:
+ abapAddonAssemblyKitCredentialsId: 'abapAddonAssemblyKitCredentialsId',
+ addonDescriptorFileName: 'addon.yml'
+```
+
+More convenient ways of configuration (e.g. on stage level) are described in the respective scenario/pipeline documentation.
diff --git a/documentation/mkdocs.yml b/documentation/mkdocs.yml
index b56abdf4ce..c7e3674b75 100644
--- a/documentation/mkdocs.yml
+++ b/documentation/mkdocs.yml
@@ -51,13 +51,15 @@ nav:
- 'Set up a Pipeline-Based ABAP Development and Testing Process Using Git-Enabled Change and Transport System': scenarios/gCTS_Scenario.md
- Extensibility: extensibility.md
- 'Library steps':
- - abapAddonAssemblyKitCheckCVs: steps/abapAddonAssemblyKitCheckCVs.md
- - abapAddonAssemblyKitCheckPV: steps/abapAddonAssemblyKitCheckPV.md
- - abapAddonAssemblyKitCreateTargetVector: steps/abapAddonAssemblyKitCreateTargetVector.md
- - abapAddonAssemblyKitPublishTargetVector: steps/abapAddonAssemblyKitPublishTargetVector.md
- - abapAddonAssemblyKitRegisterPackages: steps/abapAddonAssemblyKitRegisterPackages.md
- - abapAddonAssemblyKitReleasePackages: steps/abapAddonAssemblyKitReleasePackages.md
- - abapAddonAssemblyKitReserveNextPackages: steps/abapAddonAssemblyKitReserveNextPackages.md
+ - 'abapAddonAssemblyKit':
+ - Check: steps/abapAddonAssemblyKitCheck.md
+ - CheckCVs: steps/abapAddonAssemblyKitCheckCVs.md
+ - CheckPV: steps/abapAddonAssemblyKitCheckPV.md
+ - CreateTargetVector: steps/abapAddonAssemblyKitCreateTargetVector.md
+ - PublishTargetVector: steps/abapAddonAssemblyKitPublishTargetVector.md
+ - RegisterPackages: steps/abapAddonAssemblyKitRegisterPackages.md
+ - ReleasePackages: steps/abapAddonAssemblyKitReleasePackages.md
+ - ReserveNextPackages: steps/abapAddonAssemblyKitReserveNextPackages.md
- abapEnvironmentBuild: steps/abapEnvironmentBuild.md
- abapEnvironmentAssemblePackages: steps/abapEnvironmentAssemblePackages.md
- abapEnvironmentAssembleConfirm: steps/abapEnvironmentAssembleConfirm.md
diff --git a/test/groovy/CommonStepsTest.groovy b/test/groovy/CommonStepsTest.groovy
index a5ff1bbedf..30c5715828 100644
--- a/test/groovy/CommonStepsTest.groovy
+++ b/test/groovy/CommonStepsTest.groovy
@@ -106,6 +106,7 @@ public class CommonStepsTest extends BasePiperTest{
}
private static fieldRelatedWhitelist = [
+ 'abapAddonAssemblyKitCheck', //implementing new golang pattern without fields
'abapAddonAssemblyKitCheckCVs', //implementing new golang pattern without fields
'abapAddonAssemblyKitCheckPV', //implementing new golang pattern without fields
'abapAddonAssemblyKitCreateTargetVector', //implementing new golang pattern without fields
diff --git a/vars/abapAddonAssemblyKitCheck.groovy b/vars/abapAddonAssemblyKitCheck.groovy
new file mode 100644
index 0000000000..30c5f1b0e5
--- /dev/null
+++ b/vars/abapAddonAssemblyKitCheck.groovy
@@ -0,0 +1,13 @@
+import groovy.transform.Field
+
+@Field String STEP_NAME = getClass().getName()
+@Field String METADATA_FILE = 'metadata/abapAddonAssemblyKitCheck.yaml'
+
+void call(Map parameters = [:]) {
+ List credentials = [
+ [type: 'usernamePassword', id: 'abapAddonAssemblyKitCredentialsId', env: ['PIPER_username', 'PIPER_password']],
+ [type: 'token', id: 'abapAddonAssemblyKitCertificateFileCredentialsId', env: ['PIPER_abapAddonAssemblyKitCertificateFile']],
+ [type: 'token', id: 'abapAddonAssemblyKitCertificatePassCredentialsId', env: ['PIPER_abapAddonAssemblyKitCertificatePass']]
+ ]
+ piperExecuteBin(parameters, STEP_NAME, METADATA_FILE, credentials, false, false, true)
+}
From f8b40217909716f55ead7932b36c64da20037a40 Mon Sep 17 00:00:00 2001
From: tiloKo <70266685+tiloKo@users.noreply.github.com>
Date: Tue, 16 Apr 2024 13:31:38 +0200
Subject: [PATCH 09/15] csrf token fetch
---
cmd/abapAddonAssemblyKitCheck.go | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/cmd/abapAddonAssemblyKitCheck.go b/cmd/abapAddonAssemblyKitCheck.go
index 89b189c82d..f23cc061e3 100644
--- a/cmd/abapAddonAssemblyKitCheck.go
+++ b/cmd/abapAddonAssemblyKitCheck.go
@@ -44,7 +44,7 @@ func runAbapAddonAssemblyKitCheck(config *abapAddonAssemblyKitCheckOptions, tele
}
printProductVersionHeader(*pvh)
- log.Entry().Info("Tranfering Product Modeling to AAKaaS to be checked...")
+ log.Entry().Info("Calling AAKaaS to be check product Modelling...")
if err := pvh.checkAndResolveVersion(conn); err != nil {
return err
}
@@ -161,6 +161,7 @@ func NewProductVersionHeader(addonDescriptor *abaputils.AddonDescriptor, conn *a
}
func (pv *ProductVersionHeader) checkAndResolveVersion(conn *abapbuild.Connector) error {
+ conn.GetToken("/odata/aas_ocs_package")
pv.JsonContent = ProductVersionContents{
Content: pv.Content,
}
From 14641877397d01e0c1caafbc4d2b210488072aa4 Mon Sep 17 00:00:00 2001
From: tiloKo <70266685+tiloKo@users.noreply.github.com>
Date: Tue, 16 Apr 2024 13:46:20 +0200
Subject: [PATCH 10/15] SpsLevel
---
cmd/abapAddonAssemblyKitCheck.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/cmd/abapAddonAssemblyKitCheck.go b/cmd/abapAddonAssemblyKitCheck.go
index f23cc061e3..77d23290ef 100644
--- a/cmd/abapAddonAssemblyKitCheck.go
+++ b/cmd/abapAddonAssemblyKitCheck.go
@@ -104,7 +104,7 @@ type ProductVersionHeader struct {
ProductName string
SemanticProductVersion string `json:"SemProductVersion"`
ProductVersion string
- Spslevel string
+ SpsLevel string
PatchLevel string
Vendor string
VendorType string
@@ -182,7 +182,7 @@ func (pv *ProductVersionHeader) checkAndResolveVersion(conn *abapbuild.Connector
}
pv.ProductVersion = resultPv.Pvh.ProductVersion
- pv.Spslevel = resultPv.Pvh.Spslevel
+ pv.SpsLevel = resultPv.Pvh.SpsLevel
pv.PatchLevel = resultPv.Pvh.PatchLevel
for pvc_index, pvc := range pv.Content {
@@ -208,7 +208,7 @@ func (pv *ProductVersionHeader) checkAndResolveVersion(conn *abapbuild.Connector
func (pv *ProductVersionHeader) SyncAddonDescriptorVersionFields(addonDescriptor *abaputils.AddonDescriptor) error {
addonDescriptor.AddonVersion = pv.ProductVersion
- addonDescriptor.AddonSpsLevel = pv.Spslevel
+ addonDescriptor.AddonSpsLevel = pv.SpsLevel
addonDescriptor.AddonPatchLevel = pv.PatchLevel
//in NewPvh function pvh was build up 1:1 based on addonDescriptor
From c101541bb56148296ef144235270ffe8da333832 Mon Sep 17 00:00:00 2001
From: tiloKo <70266685+tiloKo@users.noreply.github.com>
Date: Tue, 16 Apr 2024 16:06:25 +0200
Subject: [PATCH 11/15] typos
---
cmd/abapAddonAssemblyKitCheck.go | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/cmd/abapAddonAssemblyKitCheck.go b/cmd/abapAddonAssemblyKitCheck.go
index 77d23290ef..e6c0fb7822 100644
--- a/cmd/abapAddonAssemblyKitCheck.go
+++ b/cmd/abapAddonAssemblyKitCheck.go
@@ -32,27 +32,27 @@ func runAbapAddonAssemblyKitCheck(config *abapAddonAssemblyKitCheckOptions, tele
return err
}
- log.Entry().Infof("Reading addonDescriptor (aka addon.yml) file: %s", config.AddonDescriptorFileName)
+ log.Entry().Infof("reading addonDescriptor (aka addon.yml) file: %s", config.AddonDescriptorFileName)
addonDescriptor, err := utils.ReadAddonDescriptor(config.AddonDescriptorFileName)
if err != nil {
return err
}
- log.Entry().Info("Building Product Modeling (and Resolving potential wildcards)")
+ log.Entry().Info("building product modeling (and resolving potential wildcards)")
pvh, err := NewProductVersionHeader(&addonDescriptor, conn)
if err != nil {
return err
}
printProductVersionHeader(*pvh)
- log.Entry().Info("Calling AAKaaS to be check product Modelling...")
+ log.Entry().Info("calling AAKaaS to check product modelling...")
if err := pvh.checkAndResolveVersion(conn); err != nil {
return err
}
log.Entry().Info("... success!")
pvh.SyncAddonDescriptorVersionFields(&addonDescriptor)
- log.Entry().Info("Resolved Version Fields:")
+ log.Entry().Info("resolved version fields:")
printAddonDescriptorVersionFields(addonDescriptor)
- log.Entry().Info("Transfering addonDescriptor to commonPipelineEnvironment for usage by following steps of the pipeline")
+ log.Entry().Info("transfering addonDescriptor to commonPipelineEnvironment for usage by following steps of the pipeline")
commonPipelineEnvironment.abap.addonDescriptor = string(addonDescriptor.AsJSON())
publishAddonYaml(config, utils)
@@ -88,9 +88,9 @@ func printAddonDescriptorVersionFields(addonDescriptor abaputils.AddonDescriptor
func publishAddonYaml(config *abapAddonAssemblyKitCheckOptions, utils aakaas.AakUtils) {
var filesToPublish []piperutils.Path
- log.Entry().Infof("Add %s to be published", config.AddonDescriptorFileName)
+ log.Entry().Infof("adding %s to be published", config.AddonDescriptorFileName)
filesToPublish = append(filesToPublish, piperutils.Path{Target: config.AddonDescriptorFileName, Name: "AddonDescriptor", Mandatory: true})
- log.Entry().Infof("Publishing %v files", len(filesToPublish))
+ log.Entry().Infof("publishing %v files", len(filesToPublish))
if err := piperutils.PersistReportsAndLinks("abapAddonAssemblyKitCheckPV", "", utils, filesToPublish, nil); err != nil {
log.Entry().WithError(err).Error("failed to persist report information")
}
From 78e72f0b6563179a5204f2d9471d6a2b25d26175 Mon Sep 17 00:00:00 2001
From: tiloKo <70266685+tiloKo@users.noreply.github.com>
Date: Tue, 16 Apr 2024 17:13:39 +0200
Subject: [PATCH 12/15] subsequent
---
cmd/abapAddonAssemblyKitCheck.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cmd/abapAddonAssemblyKitCheck.go b/cmd/abapAddonAssemblyKitCheck.go
index e6c0fb7822..663c969d8d 100644
--- a/cmd/abapAddonAssemblyKitCheck.go
+++ b/cmd/abapAddonAssemblyKitCheck.go
@@ -52,7 +52,7 @@ func runAbapAddonAssemblyKitCheck(config *abapAddonAssemblyKitCheckOptions, tele
pvh.SyncAddonDescriptorVersionFields(&addonDescriptor)
log.Entry().Info("resolved version fields:")
printAddonDescriptorVersionFields(addonDescriptor)
- log.Entry().Info("transfering addonDescriptor to commonPipelineEnvironment for usage by following steps of the pipeline")
+ log.Entry().Info("transfering addonDescriptor to commonPipelineEnvironment for usage by subsequent steps of the pipeline")
commonPipelineEnvironment.abap.addonDescriptor = string(addonDescriptor.AsJSON())
publishAddonYaml(config, utils)
From c1a2f5ab3e45c0ba7bf96b65f22c0e5ad7cffee2 Mon Sep 17 00:00:00 2001
From: tiloKo <70266685+tiloKo@users.noreply.github.com>
Date: Tue, 16 Apr 2024 17:41:58 +0200
Subject: [PATCH 13/15] typos
---
cmd/abapAddonAssemblyKitCheck.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/cmd/abapAddonAssemblyKitCheck.go b/cmd/abapAddonAssemblyKitCheck.go
index 663c969d8d..54084ef0ad 100644
--- a/cmd/abapAddonAssemblyKitCheck.go
+++ b/cmd/abapAddonAssemblyKitCheck.go
@@ -37,7 +37,7 @@ func runAbapAddonAssemblyKitCheck(config *abapAddonAssemblyKitCheckOptions, tele
if err != nil {
return err
}
- log.Entry().Info("building product modeling (and resolving potential wildcards)")
+ log.Entry().Info("building product modelling (and resolving potential wildcards)")
pvh, err := NewProductVersionHeader(&addonDescriptor, conn)
if err != nil {
return err
@@ -52,7 +52,7 @@ func runAbapAddonAssemblyKitCheck(config *abapAddonAssemblyKitCheckOptions, tele
pvh.SyncAddonDescriptorVersionFields(&addonDescriptor)
log.Entry().Info("resolved version fields:")
printAddonDescriptorVersionFields(addonDescriptor)
- log.Entry().Info("transfering addonDescriptor to commonPipelineEnvironment for usage by subsequent steps of the pipeline")
+ log.Entry().Info("transferring addonDescriptor to commonPipelineEnvironment for usage by subsequent steps of the pipeline")
commonPipelineEnvironment.abap.addonDescriptor = string(addonDescriptor.AsJSON())
publishAddonYaml(config, utils)
From ad614f67002eddc43995791efdf2abacc31c89b6 Mon Sep 17 00:00:00 2001
From: tiloKo <70266685+tiloKo@users.noreply.github.com>
Date: Tue, 16 Apr 2024 19:53:08 +0200
Subject: [PATCH 14/15] replace checks
---
vars/abapEnvironmentPipelineStageInitialChecks.groovy | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/vars/abapEnvironmentPipelineStageInitialChecks.groovy b/vars/abapEnvironmentPipelineStageInitialChecks.groovy
index 0d07359909..9ee6aaea9d 100644
--- a/vars/abapEnvironmentPipelineStageInitialChecks.groovy
+++ b/vars/abapEnvironmentPipelineStageInitialChecks.groovy
@@ -6,8 +6,8 @@ import static com.sap.piper.Prerequisites.checkScript
@Field String STEP_NAME = getClass().getName()
@Field Set GENERAL_CONFIG_KEYS = []
@Field STAGE_STEP_KEYS = [
- 'abapAddonAssemblyKitCheckPV',
- 'abapAddonAssemblyKitCheckCVs'
+ 'abapAddonAssemblyKitCheck',
+ 'abapAddonAssemblyKitReserveNextPackages'
]
@Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus(STAGE_STEP_KEYS)
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
@@ -19,8 +19,7 @@ void call(Map parameters = [:]) {
def stageName = parameters.stageName?:env.STAGE_NAME
piperStageWrapper (script: script, stageName: stageName, stashContent: [], stageLocking: false) {
- abapAddonAssemblyKitCheckPV script: parameters.script
- abapAddonAssemblyKitCheckCVs script: parameters.script
+ abapAddonAssemblyKitCheck script: parameters.script
abapAddonAssemblyKitReserveNextPackages script: parameters.script
}
From 681a84472dc528b4ebe4d102133cdac7f036f7f6 Mon Sep 17 00:00:00 2001
From: tiloKo <70266685+tiloKo@users.noreply.github.com>
Date: Wed, 17 Apr 2024 13:11:31 +0200
Subject: [PATCH 15/15] pvh to pkg
---
cmd/abapAddonAssemblyKitCheck.go | 147 +-----------------------
pkg/abap/aakaas/productVersionHeader.go | 147 ++++++++++++++++++++++++
2 files changed, 150 insertions(+), 144 deletions(-)
create mode 100644 pkg/abap/aakaas/productVersionHeader.go
diff --git a/cmd/abapAddonAssemblyKitCheck.go b/cmd/abapAddonAssemblyKitCheck.go
index 54084ef0ad..923c27631c 100644
--- a/cmd/abapAddonAssemblyKitCheck.go
+++ b/cmd/abapAddonAssemblyKitCheck.go
@@ -1,15 +1,12 @@
package cmd
import (
- "encoding/json"
-
"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/log"
"github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/SAP/jenkins-library/pkg/telemetry"
- "github.com/pkg/errors"
)
func abapAddonAssemblyKitCheck(config abapAddonAssemblyKitCheckOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *abapAddonAssemblyKitCheckCommonPipelineEnvironment) {
@@ -38,14 +35,14 @@ func runAbapAddonAssemblyKitCheck(config *abapAddonAssemblyKitCheckOptions, tele
return err
}
log.Entry().Info("building product modelling (and resolving potential wildcards)")
- pvh, err := NewProductVersionHeader(&addonDescriptor, conn)
+ pvh, err := aakaas.NewProductVersionHeader(&addonDescriptor, conn)
if err != nil {
return err
}
printProductVersionHeader(*pvh)
log.Entry().Info("calling AAKaaS to check product modelling...")
- if err := pvh.checkAndResolveVersion(conn); err != nil {
+ if err := pvh.CheckAndResolveVersion(conn); err != nil {
return err
}
log.Entry().Info("... success!")
@@ -59,7 +56,7 @@ func runAbapAddonAssemblyKitCheck(config *abapAddonAssemblyKitCheckOptions, tele
return nil
}
-func printProductVersionHeader(pvh ProductVersionHeader) {
+func printProductVersionHeader(pvh aakaas.ProductVersionHeader) {
logLine30 := "──────────────────────────────"
log.Entry().Infof("┌─%-30v─┬─%-30v─┐", logLine30, logLine30)
log.Entry().Infof("│ %-30v │ %-30v │", "Product Name", pvh.ProductName)
@@ -95,141 +92,3 @@ func publishAddonYaml(config *abapAddonAssemblyKitCheckOptions, utils aakaas.Aak
log.Entry().WithError(err).Error("failed to persist report information")
}
}
-
-type jsonProductVersionHeader struct {
- Pvh *ProductVersionHeader `json:"d"`
-}
-
-type ProductVersionHeader struct {
- ProductName string
- SemanticProductVersion string `json:"SemProductVersion"`
- ProductVersion string
- SpsLevel string
- PatchLevel string
- Vendor string
- VendorType string
- Content []ProductVersionContent `json:"-"` //for developer access
- JsonContent ProductVersionContents `json:"Content"` //for json (Un)Marshaling
-}
-
-type ProductVersionContents struct {
- Content []ProductVersionContent `json:"results"`
-}
-
-type ProductVersionContent struct {
- ProductName string
- SemanticProductVersion string `json:"SemProductVersion"`
- SoftwareComponentName string `json:"ScName"`
- SemanticSoftwareComponentVersion string `json:"SemScVersion"`
- SoftwareComponentVersion string `json:"ScVersion"`
- SpLevel string
- PatchLevel string
- Vendor string
- VendorType string
-}
-
-func NewProductVersionHeader(addonDescriptor *abaputils.AddonDescriptor, conn *abapbuild.Connector) (*ProductVersionHeader, error) {
- productVersion := new(aakaas.ProductVersion)
- if err := productVersion.ConstructProductversion(*addonDescriptor, *conn); err != nil {
- return nil, err
- }
- pvh := ProductVersionHeader{
- ProductName: productVersion.Name,
- SemanticProductVersion: productVersion.Version,
- Content: []ProductVersionContent{},
- }
-
- for _, repo := range addonDescriptor.Repositories {
- componentVersion := new(aakaas.ComponentVersion)
- if err := componentVersion.ConstructComponentVersion(repo, *conn); err != nil {
- return nil, err
- }
- pvc := ProductVersionContent{
- ProductName: pvh.ProductName,
- SemanticProductVersion: pvh.SemanticProductVersion,
- SoftwareComponentName: componentVersion.Name,
- SemanticSoftwareComponentVersion: componentVersion.Version,
- }
- pvh.Content = append(pvh.Content, pvc)
- }
-
- if len(pvh.Content) == 0 {
- return nil, errors.New("addonDescriptor must contain at least one software component repository")
- }
-
- return &pvh, nil
-}
-
-func (pv *ProductVersionHeader) checkAndResolveVersion(conn *abapbuild.Connector) error {
- conn.GetToken("/odata/aas_ocs_package")
- pv.JsonContent = ProductVersionContents{
- Content: pv.Content,
- }
- requestJson, err := json.Marshal(pv)
- if err != nil {
- return err
- }
-
- appendum := "/odata/aas_ocs_package/ProductVersionHeaderSet"
- responseBody, err := conn.Post(appendum, string(requestJson))
- if err != nil {
- return errors.Wrap(err, "Checking Product Modeling in AAkaaS failed")
- }
-
- var resultPv jsonProductVersionHeader
- if err := json.Unmarshal(responseBody, &resultPv); err != nil {
- return errors.Wrap(err, "Unexpected AAKaaS response for checking Product Modeling "+string(responseBody))
- }
-
- pv.ProductVersion = resultPv.Pvh.ProductVersion
- pv.SpsLevel = resultPv.Pvh.SpsLevel
- pv.PatchLevel = resultPv.Pvh.PatchLevel
-
- for pvc_index, pvc := range pv.Content {
- foundPvc := ProductVersionContent{}
- for _, resultPvc := range resultPv.Pvh.JsonContent.Content {
- if pvc.SoftwareComponentName == resultPvc.SoftwareComponentName && foundPvc.SoftwareComponentName == "" {
- foundPvc = resultPvc
- } else if pvc.SoftwareComponentName == resultPvc.SoftwareComponentName {
- return errors.New("Software Component Name must be unique in the ProductVersionContent")
- }
- }
- if foundPvc.SoftwareComponentName == "" {
- return errors.New("Software Component Name not found in the ProductVersionContent")
- }
- pv.Content[pvc_index].PatchLevel = foundPvc.PatchLevel
- pv.Content[pvc_index].SpLevel = foundPvc.SpLevel
- pv.Content[pvc_index].SoftwareComponentVersion = foundPvc.SoftwareComponentVersion
- }
-
- pv.JsonContent = ProductVersionContents{}
- return nil
-}
-
-func (pv *ProductVersionHeader) SyncAddonDescriptorVersionFields(addonDescriptor *abaputils.AddonDescriptor) error {
- addonDescriptor.AddonVersion = pv.ProductVersion
- addonDescriptor.AddonSpsLevel = pv.SpsLevel
- addonDescriptor.AddonPatchLevel = pv.PatchLevel
-
- //in NewPvh function pvh was build up 1:1 based on addonDescriptor
- //in checkAndResolve pvh was synced from AAKaaS reply assuming it does not contain more content than before(if it does it is ignored)
- for repo_index, repo := range addonDescriptor.Repositories {
- foundPvc := ProductVersionContent{}
- for _, pvc := range pv.Content {
- if pvc.SoftwareComponentName == repo.Name && foundPvc.SoftwareComponentName == "" {
- foundPvc = pvc
- } else if pvc.SoftwareComponentName == repo.Name {
- return errors.New("Software Component Name must be unique in addon descriptor(aka addon.yml)")
- }
- }
- if foundPvc.SoftwareComponentName == "" {
- return errors.New("ProductVersionContent & addon descriptor (aka addon.yml) out of sync")
- }
-
- addonDescriptor.Repositories[repo_index].PatchLevel = foundPvc.PatchLevel
- addonDescriptor.Repositories[repo_index].SpLevel = foundPvc.SpLevel
- addonDescriptor.Repositories[repo_index].Version = foundPvc.SoftwareComponentVersion
- }
-
- return nil
-}
diff --git a/pkg/abap/aakaas/productVersionHeader.go b/pkg/abap/aakaas/productVersionHeader.go
new file mode 100644
index 0000000000..b7a83e251a
--- /dev/null
+++ b/pkg/abap/aakaas/productVersionHeader.go
@@ -0,0 +1,147 @@
+package aakaas
+
+import (
+ "encoding/json"
+
+ abapbuild "github.com/SAP/jenkins-library/pkg/abap/build"
+ "github.com/SAP/jenkins-library/pkg/abaputils"
+ "github.com/pkg/errors"
+)
+
+type jsonProductVersionHeader struct {
+ Pvh *ProductVersionHeader `json:"d"`
+}
+
+type ProductVersionHeader struct {
+ ProductName string
+ SemanticProductVersion string `json:"SemProductVersion"`
+ ProductVersion string
+ SpsLevel string
+ PatchLevel string
+ Vendor string
+ VendorType string
+ Content []ProductVersionContent `json:"-"` //for developer access
+ JsonContent ProductVersionContents `json:"Content"` //for json (Un)Marshaling
+}
+
+type ProductVersionContents struct {
+ Content []ProductVersionContent `json:"results"`
+}
+
+type ProductVersionContent struct {
+ ProductName string
+ SemanticProductVersion string `json:"SemProductVersion"`
+ SoftwareComponentName string `json:"ScName"`
+ SemanticSoftwareComponentVersion string `json:"SemScVersion"`
+ SoftwareComponentVersion string `json:"ScVersion"`
+ SpLevel string
+ PatchLevel string
+ Vendor string
+ VendorType string
+}
+
+func NewProductVersionHeader(addonDescriptor *abaputils.AddonDescriptor, conn *abapbuild.Connector) (*ProductVersionHeader, error) {
+ productVersion := new(ProductVersion)
+ if err := productVersion.ConstructProductversion(*addonDescriptor, *conn); err != nil {
+ return nil, err
+ }
+ pvh := ProductVersionHeader{
+ ProductName: productVersion.Name,
+ SemanticProductVersion: productVersion.Version,
+ Content: []ProductVersionContent{},
+ }
+
+ for _, repo := range addonDescriptor.Repositories {
+ componentVersion := new(ComponentVersion)
+ if err := componentVersion.ConstructComponentVersion(repo, *conn); err != nil {
+ return nil, err
+ }
+ pvc := ProductVersionContent{
+ ProductName: pvh.ProductName,
+ SemanticProductVersion: pvh.SemanticProductVersion,
+ SoftwareComponentName: componentVersion.Name,
+ SemanticSoftwareComponentVersion: componentVersion.Version,
+ }
+ pvh.Content = append(pvh.Content, pvc)
+ }
+
+ if len(pvh.Content) == 0 {
+ return nil, errors.New("addonDescriptor must contain at least one software component repository")
+ }
+
+ return &pvh, nil
+}
+
+func (pv *ProductVersionHeader) CheckAndResolveVersion(conn *abapbuild.Connector) error {
+ conn.GetToken("/odata/aas_ocs_package")
+ pv.JsonContent = ProductVersionContents{
+ Content: pv.Content,
+ }
+ requestJson, err := json.Marshal(pv)
+ if err != nil {
+ return err
+ }
+
+ appendum := "/odata/aas_ocs_package/ProductVersionHeaderSet"
+ responseBody, err := conn.Post(appendum, string(requestJson))
+ if err != nil {
+ return errors.Wrap(err, "Checking Product Modeling in AAkaaS failed")
+ }
+
+ var resultPv jsonProductVersionHeader
+ if err := json.Unmarshal(responseBody, &resultPv); err != nil {
+ return errors.Wrap(err, "Unexpected AAKaaS response for checking Product Modeling "+string(responseBody))
+ }
+
+ pv.ProductVersion = resultPv.Pvh.ProductVersion
+ pv.SpsLevel = resultPv.Pvh.SpsLevel
+ pv.PatchLevel = resultPv.Pvh.PatchLevel
+
+ for pvc_index, pvc := range pv.Content {
+ foundPvc := ProductVersionContent{}
+ for _, resultPvc := range resultPv.Pvh.JsonContent.Content {
+ if pvc.SoftwareComponentName == resultPvc.SoftwareComponentName && foundPvc.SoftwareComponentName == "" {
+ foundPvc = resultPvc
+ } else if pvc.SoftwareComponentName == resultPvc.SoftwareComponentName {
+ return errors.New("Software Component Name must be unique in the ProductVersionContent")
+ }
+ }
+ if foundPvc.SoftwareComponentName == "" {
+ return errors.New("Software Component Name not found in the ProductVersionContent")
+ }
+ pv.Content[pvc_index].PatchLevel = foundPvc.PatchLevel
+ pv.Content[pvc_index].SpLevel = foundPvc.SpLevel
+ pv.Content[pvc_index].SoftwareComponentVersion = foundPvc.SoftwareComponentVersion
+ }
+
+ pv.JsonContent = ProductVersionContents{}
+ return nil
+}
+
+func (pv *ProductVersionHeader) SyncAddonDescriptorVersionFields(addonDescriptor *abaputils.AddonDescriptor) error {
+ addonDescriptor.AddonVersion = pv.ProductVersion
+ addonDescriptor.AddonSpsLevel = pv.SpsLevel
+ addonDescriptor.AddonPatchLevel = pv.PatchLevel
+
+ //in NewPvh function pvh was build up 1:1 based on addonDescriptor
+ //in checkAndResolve pvh was synced from AAKaaS reply assuming it does not contain more content than before(if it does it is ignored)
+ for repo_index, repo := range addonDescriptor.Repositories {
+ foundPvc := ProductVersionContent{}
+ for _, pvc := range pv.Content {
+ if pvc.SoftwareComponentName == repo.Name && foundPvc.SoftwareComponentName == "" {
+ foundPvc = pvc
+ } else if pvc.SoftwareComponentName == repo.Name {
+ return errors.New("Software Component Name must be unique in addon descriptor(aka addon.yml)")
+ }
+ }
+ if foundPvc.SoftwareComponentName == "" {
+ return errors.New("ProductVersionContent & addon descriptor (aka addon.yml) out of sync")
+ }
+
+ addonDescriptor.Repositories[repo_index].PatchLevel = foundPvc.PatchLevel
+ addonDescriptor.Repositories[repo_index].SpLevel = foundPvc.SpLevel
+ addonDescriptor.Repositories[repo_index].Version = foundPvc.SoftwareComponentVersion
+ }
+
+ return nil
+}