From 238339c87ef08d14f8ac036589ca8fcff8521088 Mon Sep 17 00:00:00 2001 From: Anil Keshav Date: Tue, 27 Aug 2024 08:24:38 +0200 Subject: [PATCH] Exposing build artifact metadata from maven and npm (#5008) --- cmd/mavenBuild.go | 43 +++++++++++++++++++++- cmd/mavenBuild_generated.go | 16 ++++++++- cmd/mavenBuild_test.go | 21 +++++++++++ cmd/npmExecuteScripts.go | 22 ++++++++++-- cmd/npmExecuteScripts_generated.go | 44 +++++++++++++++-------- cmd/npmExecuteScripts_test.go | 1 + pkg/build/artifact.go | 7 ++++ pkg/npm/mock.go | 3 +- pkg/npm/npm.go | 3 +- pkg/npm/publish.go | 26 ++++++++++++-- pkg/npm/publish_test.go | 4 ++- pkg/versioning/versioning.go | 2 ++ resources/metadata/mavenBuild.yaml | 9 +++++ resources/metadata/npmExecuteScripts.yaml | 9 +++++ vars/commonPipelineEnvironment.groovy | 1 + 15 files changed, 186 insertions(+), 25 deletions(-) create mode 100644 pkg/build/artifact.go diff --git a/cmd/mavenBuild.go b/cmd/mavenBuild.go index c1e61c0a55..af6461a8af 100644 --- a/cmd/mavenBuild.go +++ b/cmd/mavenBuild.go @@ -1,18 +1,21 @@ package cmd import ( + "encoding/json" "os" "path" "path/filepath" "reflect" "strings" + "github.com/SAP/jenkins-library/pkg/build" "github.com/SAP/jenkins-library/pkg/buildsettings" "github.com/SAP/jenkins-library/pkg/command" "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/maven" "github.com/SAP/jenkins-library/pkg/piperutils" "github.com/SAP/jenkins-library/pkg/telemetry" + "github.com/SAP/jenkins-library/pkg/versioning" "github.com/pkg/errors" piperhttp "github.com/SAP/jenkins-library/pkg/http" @@ -159,7 +162,45 @@ func runMavenBuild(config *mavenBuildOptions, telemetryData *telemetry.CustomDat mavenOptions.Goals = []string{"deploy"} mavenOptions.Defines = []string{} _, err := maven.Execute(&mavenOptions, utils) - return err + if err != nil { + return err + } + if config.CreateBuildArtifactsMetadata { + buildCoordinates := []versioning.Coordinates{} + options := versioning.Options{} + var utils versioning.Utils + + matches, _ := fileUtils.Glob("**/pom.xml") + for _, match := range matches { + + artifact, err := versioning.GetArtifact("maven", match, &options, utils) + if err != nil { + log.Entry().Warnf("unable to get artifact metdata : %v", err) + } else { + coordinate, err := artifact.GetCoordinates() + if err != nil { + log.Entry().Warnf("unable to get artifact coordinates : %v", err) + } else { + coordinate.BuildPath = filepath.Dir(match) + coordinate.URL = config.AltDeploymentRepositoryURL + buildCoordinates = append(buildCoordinates, coordinate) + } + } + } + + if len(buildCoordinates) == 0 { + log.Entry().Warnf("unable to identify artifact coordinates for the maven packages published") + return nil + } + + var buildArtifacts build.BuildArtifacts + + buildArtifacts.Coordinates = buildCoordinates + jsonResult, _ := json.Marshal(buildArtifacts) + commonPipelineEnvironment.custom.mavenBuildArtifacts = string(jsonResult) + } + + return nil } else { log.Entry().Infof("publish not detected, ignoring maven deploy") } diff --git a/cmd/mavenBuild_generated.go b/cmd/mavenBuild_generated.go index 278af421bd..57af28804e 100644 --- a/cmd/mavenBuild_generated.go +++ b/cmd/mavenBuild_generated.go @@ -40,11 +40,13 @@ type mavenBuildOptions struct { JavaCaCertFilePath string `json:"javaCaCertFilePath,omitempty"` BuildSettingsInfo string `json:"buildSettingsInfo,omitempty"` DeployFlags []string `json:"deployFlags,omitempty"` + CreateBuildArtifactsMetadata bool `json:"createBuildArtifactsMetadata,omitempty"` } type mavenBuildCommonPipelineEnvironment struct { custom struct { - buildSettingsInfo string + buildSettingsInfo string + mavenBuildArtifacts string } } @@ -55,6 +57,7 @@ func (p *mavenBuildCommonPipelineEnvironment) persist(path, resourceName string) value interface{} }{ {category: "custom", name: "buildSettingsInfo", value: p.custom.buildSettingsInfo}, + {category: "custom", name: "mavenBuildArtifacts", value: p.custom.mavenBuildArtifacts}, } errCount := 0 @@ -269,6 +272,7 @@ func addMavenBuildFlags(cmd *cobra.Command, stepConfig *mavenBuildOptions) { cmd.Flags().StringVar(&stepConfig.JavaCaCertFilePath, "javaCaCertFilePath", os.Getenv("PIPER_javaCaCertFilePath"), "path to the cacerts file used by Java. When maven publish is set to True and customTlsCertificateLinks (to deploy the artifact to a repository with a self signed cert) are provided to trust the self signed certs, Piper will extend the existing Java cacerts to include the new self signed certs. if not provided Piper will search for the cacerts in $JAVA_HOME/jre/lib/security/cacerts") cmd.Flags().StringVar(&stepConfig.BuildSettingsInfo, "buildSettingsInfo", os.Getenv("PIPER_buildSettingsInfo"), "build settings info is typically filled by the step automatically to create information about the build settings that were used during the maven build . This information is typically used for compliance related processes.") cmd.Flags().StringSliceVar(&stepConfig.DeployFlags, "deployFlags", []string{`-Dmaven.main.skip=true`, `-Dmaven.test.skip=true`, `-Dmaven.install.skip=true`}, "maven deploy flags that will be used when publish is detected.") + cmd.Flags().BoolVar(&stepConfig.CreateBuildArtifactsMetadata, "createBuildArtifactsMetadata", false, "metadata about the artifacts that are build and published , this metadata is generally used by steps downstream in the pipeline") } @@ -507,6 +511,15 @@ func mavenBuildMetadata() config.StepData { Aliases: []config.Alias{}, Default: []string{`-Dmaven.main.skip=true`, `-Dmaven.test.skip=true`, `-Dmaven.install.skip=true`}, }, + { + Name: "createBuildArtifactsMetadata", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"STEPS", "STAGES", "PARAMETERS"}, + Type: "bool", + Mandatory: false, + Aliases: []config.Alias{}, + Default: false, + }, }, }, Containers: []config.Container{ @@ -519,6 +532,7 @@ func mavenBuildMetadata() config.StepData { Type: "piperEnvironment", Parameters: []map[string]interface{}{ {"name": "custom/buildSettingsInfo"}, + {"name": "custom/mavenBuildArtifacts"}, }, }, { diff --git a/cmd/mavenBuild_test.go b/cmd/mavenBuild_test.go index bb0cd11674..c7f6bb3d59 100644 --- a/cmd/mavenBuild_test.go +++ b/cmd/mavenBuild_test.go @@ -135,4 +135,25 @@ func TestMavenBuild(t *testing.T) { assert.Contains(t, mockedUtils.Calls[0].Params, "profile1,profile2") }) + t.Run("mavenBuild should not create build artifacts metadata when CreateBuildArtifactsMetadata is false and Publish is true", func(t *testing.T) { + mockedUtils := newMavenMockUtils() + mockedUtils.AddFile("pom.xml", []byte{}) + config := mavenBuildOptions{CreateBuildArtifactsMetadata: false, Publish: true} + err := runMavenBuild(&config, nil, &mockedUtils, &cpe) + assert.Nil(t, err) + assert.Equal(t, mockedUtils.Calls[0].Exec, "mvn") + assert.Contains(t, mockedUtils.Calls[0].Params, "install") + assert.Empty(t, cpe.custom.mavenBuildArtifacts) + }) + + t.Run("mavenBuild should not create build artifacts metadata when CreateBuildArtifactsMetadata is true and Publish is false", func(t *testing.T) { + mockedUtils := newMavenMockUtils() + mockedUtils.AddFile("pom.xml", []byte{}) + config := mavenBuildOptions{CreateBuildArtifactsMetadata: true, Publish: false} + err := runMavenBuild(&config, nil, &mockedUtils, &cpe) + assert.Nil(t, err) + assert.Equal(t, mockedUtils.Calls[0].Exec, "mvn") + assert.Empty(t, cpe.custom.mavenBuildArtifacts) + }) + } diff --git a/cmd/npmExecuteScripts.go b/cmd/npmExecuteScripts.go index b3de55b92b..0b6cd4b18a 100644 --- a/cmd/npmExecuteScripts.go +++ b/cmd/npmExecuteScripts.go @@ -1,12 +1,15 @@ package cmd import ( + "encoding/json" "os" + "github.com/SAP/jenkins-library/pkg/build" "github.com/SAP/jenkins-library/pkg/buildsettings" "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/npm" "github.com/SAP/jenkins-library/pkg/telemetry" + "github.com/SAP/jenkins-library/pkg/versioning" ) func npmExecuteScripts(config npmExecuteScriptsOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *npmExecuteScriptsCommonPipelineEnvironment) { @@ -85,9 +88,11 @@ func runNpmExecuteScripts(npmExecutor npm.Executor, config *npmExecuteScriptsOpt } commonPipelineEnvironment.custom.buildSettingsInfo = buildSettingsInfo + buildCoordinates := []versioning.Coordinates{} + if config.Publish { if len(config.BuildDescriptorList) > 0 { - err = npmExecutor.PublishAllPackages(config.BuildDescriptorList, config.RepositoryURL, config.RepositoryUsername, config.RepositoryPassword, config.PackBeforePublish) + err = npmExecutor.PublishAllPackages(config.BuildDescriptorList, config.RepositoryURL, config.RepositoryUsername, config.RepositoryPassword, config.PackBeforePublish, &buildCoordinates) if err != nil { return err } @@ -97,12 +102,25 @@ func runNpmExecuteScripts(npmExecutor npm.Executor, config *npmExecuteScriptsOpt return err } - err = npmExecutor.PublishAllPackages(packageJSONFiles, config.RepositoryURL, config.RepositoryUsername, config.RepositoryPassword, config.PackBeforePublish) + err = npmExecutor.PublishAllPackages(packageJSONFiles, config.RepositoryURL, config.RepositoryUsername, config.RepositoryPassword, config.PackBeforePublish, &buildCoordinates) if err != nil { return err } } } + if config.CreateBuildArtifactsMetadata { + if len(buildCoordinates) == 0 { + log.Entry().Warnf("unable to identify artifact coordinates for the npm packages published") + return nil + } + + var buildArtifacts build.BuildArtifacts + + buildArtifacts.Coordinates = buildCoordinates + jsonResult, _ := json.Marshal(buildArtifacts) + commonPipelineEnvironment.custom.npmBuildArtifacts = string(jsonResult) + } + return nil } diff --git a/cmd/npmExecuteScripts_generated.go b/cmd/npmExecuteScripts_generated.go index 47d2cb1eff..7359c8827f 100644 --- a/cmd/npmExecuteScripts_generated.go +++ b/cmd/npmExecuteScripts_generated.go @@ -22,26 +22,28 @@ import ( ) type npmExecuteScriptsOptions struct { - Install bool `json:"install,omitempty"` - RunScripts []string `json:"runScripts,omitempty"` - DefaultNpmRegistry string `json:"defaultNpmRegistry,omitempty"` - VirtualFrameBuffer bool `json:"virtualFrameBuffer,omitempty"` - ScriptOptions []string `json:"scriptOptions,omitempty"` - BuildDescriptorExcludeList []string `json:"buildDescriptorExcludeList,omitempty"` - BuildDescriptorList []string `json:"buildDescriptorList,omitempty"` - CreateBOM bool `json:"createBOM,omitempty"` - Publish bool `json:"publish,omitempty"` - RepositoryURL string `json:"repositoryUrl,omitempty"` - RepositoryPassword string `json:"repositoryPassword,omitempty"` - RepositoryUsername string `json:"repositoryUsername,omitempty"` - BuildSettingsInfo string `json:"buildSettingsInfo,omitempty"` - PackBeforePublish bool `json:"packBeforePublish,omitempty"` - Production bool `json:"production,omitempty"` + Install bool `json:"install,omitempty"` + RunScripts []string `json:"runScripts,omitempty"` + DefaultNpmRegistry string `json:"defaultNpmRegistry,omitempty"` + VirtualFrameBuffer bool `json:"virtualFrameBuffer,omitempty"` + ScriptOptions []string `json:"scriptOptions,omitempty"` + BuildDescriptorExcludeList []string `json:"buildDescriptorExcludeList,omitempty"` + BuildDescriptorList []string `json:"buildDescriptorList,omitempty"` + CreateBOM bool `json:"createBOM,omitempty"` + Publish bool `json:"publish,omitempty"` + RepositoryURL string `json:"repositoryUrl,omitempty"` + RepositoryPassword string `json:"repositoryPassword,omitempty"` + RepositoryUsername string `json:"repositoryUsername,omitempty"` + BuildSettingsInfo string `json:"buildSettingsInfo,omitempty"` + PackBeforePublish bool `json:"packBeforePublish,omitempty"` + Production bool `json:"production,omitempty"` + CreateBuildArtifactsMetadata bool `json:"createBuildArtifactsMetadata,omitempty"` } type npmExecuteScriptsCommonPipelineEnvironment struct { custom struct { buildSettingsInfo string + npmBuildArtifacts string } } @@ -52,6 +54,7 @@ func (p *npmExecuteScriptsCommonPipelineEnvironment) persist(path, resourceName value interface{} }{ {category: "custom", name: "buildSettingsInfo", value: p.custom.buildSettingsInfo}, + {category: "custom", name: "npmBuildArtifacts", value: p.custom.npmBuildArtifacts}, } errCount := 0 @@ -241,6 +244,7 @@ func addNpmExecuteScriptsFlags(cmd *cobra.Command, stepConfig *npmExecuteScripts cmd.Flags().StringVar(&stepConfig.BuildSettingsInfo, "buildSettingsInfo", os.Getenv("PIPER_buildSettingsInfo"), "build settings info is typically filled by the step automatically to create information about the build settings that were used during the npm build . This information is typically used for compliance related processes.") cmd.Flags().BoolVar(&stepConfig.PackBeforePublish, "packBeforePublish", false, "used for executing npm pack first, followed by npm publish. This two step maybe required in two cases. case 1) When building multiple npm packages (multiple package.json) please keep this parameter true and also see `buildDescriptorList` or `buildDescriptorExcludeList` to choose which package(s) to publish. case 2)when you are building a single npm (single `package.json` in your repo) / multiple npm (multiple package.json) scoped package(s) and have npm dependencies from the same scope.") cmd.Flags().BoolVar(&stepConfig.Production, "production", false, "used for omitting installation of dev. dependencies if true") + cmd.Flags().BoolVar(&stepConfig.CreateBuildArtifactsMetadata, "createBuildArtifactsMetadata", false, "metadata about the artifacts that are build and published , this metadata is generally used by steps downstream in the pipeline") } @@ -428,6 +432,15 @@ func npmExecuteScriptsMetadata() config.StepData { Aliases: []config.Alias{}, Default: false, }, + { + Name: "createBuildArtifactsMetadata", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"STEPS", "STAGES", "PARAMETERS"}, + Type: "bool", + Mandatory: false, + Aliases: []config.Alias{}, + Default: false, + }, }, }, Containers: []config.Container{ @@ -440,6 +453,7 @@ func npmExecuteScriptsMetadata() config.StepData { Type: "piperEnvironment", Parameters: []map[string]interface{}{ {"name": "custom/buildSettingsInfo"}, + {"name": "custom/npmBuildArtifacts"}, }, }, { diff --git a/cmd/npmExecuteScripts_test.go b/cmd/npmExecuteScripts_test.go index c98bf70960..878dc8f245 100644 --- a/cmd/npmExecuteScripts_test.go +++ b/cmd/npmExecuteScripts_test.go @@ -194,4 +194,5 @@ func TestNpmExecuteScripts(t *testing.T) { v := os.Getenv("NODE_ENV") assert.Equal(t, "production", v) }) + } diff --git a/pkg/build/artifact.go b/pkg/build/artifact.go new file mode 100644 index 0000000000..392402ff47 --- /dev/null +++ b/pkg/build/artifact.go @@ -0,0 +1,7 @@ +package build + +import "github.com/SAP/jenkins-library/pkg/versioning" + +type BuildArtifacts struct { + Coordinates []versioning.Coordinates +} diff --git a/pkg/npm/mock.go b/pkg/npm/mock.go index 036d3f2e61..d162181335 100644 --- a/pkg/npm/mock.go +++ b/pkg/npm/mock.go @@ -5,6 +5,7 @@ package npm import ( "fmt" + "github.com/SAP/jenkins-library/pkg/versioning" "github.com/SAP/jenkins-library/pkg/mock" ) @@ -123,6 +124,6 @@ func (n *NpmExecutorMock) CreateBOM(packageJSONFiles []string) error { } // CreateBOM mock implementation -func (n *NpmExecutorMock) PublishAllPackages(packageJSONFiles []string, registry, username, password string, packBeforePublish bool) error { +func (n *NpmExecutorMock) PublishAllPackages(packageJSONFiles []string, registry, username, password string, packBeforePublish bool, buildCoordinates *[]versioning.Coordinates) error { return nil } diff --git a/pkg/npm/npm.go b/pkg/npm/npm.go index 4768a0247a..45433e5891 100644 --- a/pkg/npm/npm.go +++ b/pkg/npm/npm.go @@ -11,6 +11,7 @@ import ( "github.com/SAP/jenkins-library/pkg/command" "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/piperutils" + "github.com/SAP/jenkins-library/pkg/versioning" ) const ( @@ -34,7 +35,7 @@ type Executor interface { FindPackageJSONFilesWithScript(packageJSONFiles []string, script string) ([]string, error) RunScriptsInAllPackages(runScripts []string, runOptions []string, scriptOptions []string, virtualFrameBuffer bool, excludeList []string, packagesList []string) error InstallAllDependencies(packageJSONFiles []string) error - PublishAllPackages(packageJSONFiles []string, registry, username, password string, packBeforePublish bool) error + PublishAllPackages(packageJSONFiles []string, registry, username, password string, packBeforePublish bool, buildCoordinates *[]versioning.Coordinates) error SetNpmRegistries() error CreateBOM(packageJSONFiles []string) error } diff --git a/pkg/npm/publish.go b/pkg/npm/publish.go index 628729894f..660e1ae114 100644 --- a/pkg/npm/publish.go +++ b/pkg/npm/publish.go @@ -11,6 +11,7 @@ import ( "github.com/SAP/jenkins-library/pkg/log" CredentialUtils "github.com/SAP/jenkins-library/pkg/piperutils" + "github.com/SAP/jenkins-library/pkg/versioning" ) type npmMinimalPackageDescriptor struct { @@ -31,7 +32,7 @@ func (pd *npmMinimalPackageDescriptor) Scope() string { } // PublishAllPackages executes npm publish for all package.json files defined in packageJSONFiles list -func (exec *Execute) PublishAllPackages(packageJSONFiles []string, registry, username, password string, packBeforePublish bool) error { +func (exec *Execute) PublishAllPackages(packageJSONFiles []string, registry, username, password string, packBeforePublish bool, buildCoordinates *[]versioning.Coordinates) error { for _, packageJSON := range packageJSONFiles { log.Entry().Infof("triggering publish for %s", packageJSON) @@ -43,7 +44,7 @@ func (exec *Execute) PublishAllPackages(packageJSONFiles []string, registry, use return fmt.Errorf("package.json file '%s' not found: %w", packageJSON, err) } - err = exec.publish(packageJSON, registry, username, password, packBeforePublish) + err = exec.publish(packageJSON, registry, username, password, packBeforePublish, buildCoordinates) if err != nil { return err } @@ -52,7 +53,7 @@ func (exec *Execute) PublishAllPackages(packageJSONFiles []string, registry, use } // publish executes npm publish for package.json -func (exec *Execute) publish(packageJSON, registry, username, password string, packBeforePublish bool) error { +func (exec *Execute) publish(packageJSON, registry, username, password string, packBeforePublish bool, buildCoordinates *[]versioning.Coordinates) error { execRunner := exec.Utils.GetExecRunner() oldWorkingDirectory, err := exec.Utils.Getwd() @@ -202,6 +203,25 @@ func (exec *Execute) publish(packageJSON, registry, username, password string, p } } + options := versioning.Options{} + var utils versioning.Utils + + artifact, err := versioning.GetArtifact("npm", packageJSON, &options, utils) + if err != nil { + log.Entry().Warnf("unable to get artifact metdata : %v", err) + } else { + coordinate, err := artifact.GetCoordinates() + if err != nil { + log.Entry().Warnf("unable to get artifact coordinates : %v", err) + } else { + coordinate.BuildPath = filepath.Dir(packageJSON) + coordinate.URL = registry + coordinate.Packaging = "tgz" + + *buildCoordinates = append(*buildCoordinates, coordinate) + } + } + return nil } diff --git a/pkg/npm/publish_test.go b/pkg/npm/publish_test.go index 6ca7fdaaaf..782e1b7c5c 100644 --- a/pkg/npm/publish_test.go +++ b/pkg/npm/publish_test.go @@ -10,6 +10,7 @@ import ( "testing" "github.com/SAP/jenkins-library/pkg/piperutils" + "github.com/SAP/jenkins-library/pkg/versioning" "github.com/stretchr/testify/assert" ) @@ -534,7 +535,8 @@ func TestNpmPublish(t *testing.T) { return nil } - err := exec.PublishAllPackages(test.packageDescriptors, test.registryURL, test.registryUser, test.registryPassword, test.packBeforePublish) + coordinates := []versioning.Coordinates{} + err := exec.PublishAllPackages(test.packageDescriptors, test.registryURL, test.registryUser, test.registryPassword, test.packBeforePublish, &coordinates) if len(test.wants.err) == 0 && assert.NoError(t, err) { if assert.NotEmpty(t, utils.execRunner.Calls) { diff --git a/pkg/versioning/versioning.go b/pkg/versioning/versioning.go index 471bd55846..1ea42b48f8 100644 --- a/pkg/versioning/versioning.go +++ b/pkg/versioning/versioning.go @@ -17,6 +17,8 @@ type Coordinates struct { ArtifactID string Version string Packaging string + BuildPath string + URL string } // Artifact defines the versioning operations for various build tools diff --git a/resources/metadata/mavenBuild.yaml b/resources/metadata/mavenBuild.yaml index e2ccfd7c7b..dc56fb3233 100644 --- a/resources/metadata/mavenBuild.yaml +++ b/resources/metadata/mavenBuild.yaml @@ -242,6 +242,14 @@ spec: - -Dmaven.main.skip=true - -Dmaven.test.skip=true - -Dmaven.install.skip=true + - name: createBuildArtifactsMetadata + type: bool + default: false + description: metadata about the artifacts that are build and published , this metadata is generally used by steps downstream in the pipeline + scope: + - STEPS + - STAGES + - PARAMETERS resources: - type: stash outputs: @@ -250,6 +258,7 @@ spec: type: piperEnvironment params: - name: custom/buildSettingsInfo + - name: custom/mavenBuildArtifacts - name: reports type: reports params: diff --git a/resources/metadata/npmExecuteScripts.yaml b/resources/metadata/npmExecuteScripts.yaml index 2dd39b941a..529c6d32ca 100644 --- a/resources/metadata/npmExecuteScripts.yaml +++ b/resources/metadata/npmExecuteScripts.yaml @@ -163,12 +163,21 @@ spec: - STEPS - STAGES - PARAMETERS + - name: createBuildArtifactsMetadata + type: bool + default: false + description: metadata about the artifacts that are build and published , this metadata is generally used by steps downstream in the pipeline + scope: + - STEPS + - STAGES + - PARAMETERS outputs: resources: - name: commonPipelineEnvironment type: piperEnvironment params: - name: custom/buildSettingsInfo + - name: custom/npmBuildArtifacts - name: reports type: reports params: diff --git a/vars/commonPipelineEnvironment.groovy b/vars/commonPipelineEnvironment.groovy index b0997292b8..b44842d9ca 100644 --- a/vars/commonPipelineEnvironment.groovy +++ b/vars/commonPipelineEnvironment.groovy @@ -60,6 +60,7 @@ class commonPipelineEnvironment implements Serializable { String abapAddonDescriptor + private Map valueMap = [:] void setValue(String property, value) {