diff --git a/cmd/pythonBuild.go b/cmd/pythonBuild.go index cbfdf5d39..f24cd706e 100644 --- a/cmd/pythonBuild.go +++ b/cmd/pythonBuild.go @@ -3,6 +3,7 @@ package cmd import ( "fmt" + "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/piperutils" @@ -35,16 +36,16 @@ func newPythonBuildUtils() pythonBuildUtils { return &utils } -func pythonBuild(config pythonBuildOptions, telemetryData *telemetry.CustomData) { +func pythonBuild(config pythonBuildOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *pythonBuildCommonPipelineEnvironment) { utils := newPythonBuildUtils() - err := runPythonBuild(&config, telemetryData, utils) + err := runPythonBuild(&config, telemetryData, utils, commonPipelineEnvironment) if err != nil { log.Entry().WithError(err).Fatal("step execution failed") } } -func runPythonBuild(config *pythonBuildOptions, telemetryData *telemetry.CustomData, utils pythonBuildUtils) error { +func runPythonBuild(config *pythonBuildOptions, telemetryData *telemetry.CustomData, utils pythonBuildUtils, commonPipelineEnvironment *pythonBuildCommonPipelineEnvironment) error { installFlags := []string{"-m", "pip", "install", "--upgrade"} @@ -59,6 +60,25 @@ func runPythonBuild(config *pythonBuildOptions, telemetryData *telemetry.CustomD } } + log.Entry().Debugf("creating build settings information...") + stepName := "pythonBuild" + dockerImage, err := GetDockerImageValue(stepName) + if err != nil { + return err + } + + pythonConfig := buildsettings.BuildOptions{ + CreateBOM: config.CreateBOM, + Publish: config.Publish, + BuildSettingsInfo: config.BuildSettingsInfo, + DockerImage: dockerImage, + } + buildSettingsInfo, err := buildsettings.CreateBuildSettingsInfo(&pythonConfig, stepName) + if err != nil { + log.Entry().Warnf("failed to create build settings info: %v", err) + } + commonPipelineEnvironment.custom.buildSettingsInfo = buildSettingsInfo + if config.Publish { if err := publishWithTwine(config, utils, installFlags); err != nil { return fmt.Errorf("failed to publish: %w", err) diff --git a/cmd/pythonBuild_generated.go b/cmd/pythonBuild_generated.go index 90ecbe842..51f4cf01b 100644 --- a/cmd/pythonBuild_generated.go +++ b/cmd/pythonBuild_generated.go @@ -5,10 +5,12 @@ 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" @@ -22,6 +24,35 @@ type pythonBuildOptions struct { TargetRepositoryPassword string `json:"targetRepositoryPassword,omitempty"` TargetRepositoryUser string `json:"targetRepositoryUser,omitempty"` TargetRepositoryURL string `json:"targetRepositoryURL,omitempty"` + BuildSettingsInfo string `json:"buildSettingsInfo,omitempty"` +} + +type pythonBuildCommonPipelineEnvironment struct { + custom struct { + buildSettingsInfo string + } +} + +func (p *pythonBuildCommonPipelineEnvironment) persist(path, resourceName string) { + content := []struct { + category string + name string + value interface{} + }{ + {category: "custom", name: "buildSettingsInfo", value: p.custom.buildSettingsInfo}, + } + + 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") + } } // PythonBuildCommand Step build a python project @@ -31,6 +62,7 @@ func PythonBuildCommand() *cobra.Command { metadata := pythonBuildMetadata() var stepConfig pythonBuildOptions var startTime time.Time + var commonPipelineEnvironment pythonBuildCommonPipelineEnvironment var logCollector *log.CollectorHook var splunkClient *splunk.Splunk telemetryClient := &telemetry.Telemetry{} @@ -84,6 +116,7 @@ func PythonBuildCommand() *cobra.Command { 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() @@ -104,7 +137,7 @@ func PythonBuildCommand() *cobra.Command { GeneralConfig.HookConfig.SplunkConfig.Index, GeneralConfig.HookConfig.SplunkConfig.SendLogs) } - pythonBuild(stepConfig, &stepTelemetryData) + pythonBuild(stepConfig, &stepTelemetryData, &commonPipelineEnvironment) stepTelemetryData.ErrorCode = "0" log.Entry().Info("SUCCESS") }, @@ -121,6 +154,7 @@ func addPythonBuildFlags(cmd *cobra.Command, stepConfig *pythonBuildOptions) { cmd.Flags().StringVar(&stepConfig.TargetRepositoryPassword, "targetRepositoryPassword", os.Getenv("PIPER_targetRepositoryPassword"), "Password for the target repository where the compiled binaries shall be uploaded - typically provided by the CI/CD environment.") cmd.Flags().StringVar(&stepConfig.TargetRepositoryUser, "targetRepositoryUser", os.Getenv("PIPER_targetRepositoryUser"), "Username for the target repository where the compiled binaries shall be uploaded - typically provided by the CI/CD environment.") cmd.Flags().StringVar(&stepConfig.TargetRepositoryURL, "targetRepositoryURL", os.Getenv("PIPER_targetRepositoryURL"), "URL of the target repository where the compiled binaries shall be uploaded - typically provided by the CI/CD environment.") + 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.") } @@ -204,10 +238,35 @@ func pythonBuildMetadata() config.StepData { Aliases: []config.Alias{}, Default: os.Getenv("PIPER_targetRepositoryURL"), }, + { + Name: "buildSettingsInfo", + ResourceRef: []config.ResourceReference{ + { + Name: "commonPipelineEnvironment", + Param: "custom/buildSettingsInfo", + }, + }, + Scope: []string{"STEPS", "STAGES", "PARAMETERS"}, + Type: "string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: os.Getenv("PIPER_buildSettingsInfo"), + }, }, }, Containers: []config.Container{ - {Name: "python", Image: "python:3.9", WorkingDir: "/home/node"}, + {Name: "python", Image: "python:3.9", Options: []config.Option{{Name: "-u", Value: "0"}}}, + }, + Outputs: config.StepOutputs{ + Resources: []config.StepResources{ + { + Name: "commonPipelineEnvironment", + Type: "piperEnvironment", + Parameters: []map[string]interface{}{ + {"name": "custom/buildSettingsInfo"}, + }, + }, + }, }, }, } diff --git a/cmd/pythonBuild_test.go b/cmd/pythonBuild_test.go index 6ecab4956..ad60c177e 100644 --- a/cmd/pythonBuild_test.go +++ b/cmd/pythonBuild_test.go @@ -40,13 +40,13 @@ func (f *pythonBuildMockUtils) GetConfig() *pythonBuildOptions { } func TestRunPythonBuild(t *testing.T) { - + cpe := pythonBuildCommonPipelineEnvironment{} t.Run("success - build", func(t *testing.T) { config := pythonBuildOptions{} utils := newPythonBuildTestsUtils() telemetryData := telemetry.CustomData{} - err := runPythonBuild(&config, &telemetryData, utils) + err := runPythonBuild(&config, &telemetryData, utils, &cpe) assert.NoError(t, err) assert.Equal(t, "python3", utils.ExecMockRunner.Calls[0].Exec) assert.Equal(t, []string{"setup.py", "sdist", "bdist_wheel"}, utils.ExecMockRunner.Calls[0].Params) @@ -58,7 +58,7 @@ func TestRunPythonBuild(t *testing.T) { utils.ShouldFailOnCommand = map[string]error{"python3 setup.py sdist bdist_wheel": fmt.Errorf("build failure")} telemetryData := telemetry.CustomData{} - err := runPythonBuild(&config, &telemetryData, utils) + err := runPythonBuild(&config, &telemetryData, utils, &cpe) assert.EqualError(t, err, "Python build failed with error: build failure") }) @@ -72,7 +72,7 @@ func TestRunPythonBuild(t *testing.T) { utils := newPythonBuildTestsUtils() telemetryData := telemetry.CustomData{} - err := runPythonBuild(&config, &telemetryData, utils) + err := runPythonBuild(&config, &telemetryData, utils, &cpe) assert.NoError(t, err) assert.Equal(t, "python3", utils.ExecMockRunner.Calls[0].Exec) assert.Equal(t, []string{"setup.py", "sdist", "bdist_wheel"}, utils.ExecMockRunner.Calls[0].Params) @@ -91,7 +91,7 @@ func TestRunPythonBuild(t *testing.T) { utils := newPythonBuildTestsUtils() telemetryData := telemetry.CustomData{} - err := runPythonBuild(&config, &telemetryData, utils) + err := runPythonBuild(&config, &telemetryData, utils, &cpe) assert.NoError(t, err) assert.Equal(t, "python3", utils.ExecMockRunner.Calls[0].Exec) assert.Equal(t, []string{"setup.py", "sdist", "bdist_wheel"}, utils.ExecMockRunner.Calls[0].Params) @@ -109,7 +109,7 @@ func TestRunPythonBuild(t *testing.T) { utils.ShouldFailOnCommand = map[string]error{"python3 -m pip install --upgrade cyclonedx-bom": fmt.Errorf("install failure")} telemetryData := telemetry.CustomData{} - err := runPythonBuild(&config, &telemetryData, utils) + err := runPythonBuild(&config, &telemetryData, utils, &cpe) assert.EqualError(t, err, "BOM creation failed: install failure") }) @@ -121,7 +121,7 @@ func TestRunPythonBuild(t *testing.T) { utils.ShouldFailOnCommand = map[string]error{"python3 -m pip install --upgrade twine": fmt.Errorf("install failure")} telemetryData := telemetry.CustomData{} - err := runPythonBuild(&config, &telemetryData, utils) + err := runPythonBuild(&config, &telemetryData, utils, &cpe) assert.EqualError(t, err, "failed to publish: install failure") }) } diff --git a/resources/metadata/pythonBuild.yaml b/resources/metadata/pythonBuild.yaml index 18ef3f662..6b3610ce1 100644 --- a/resources/metadata/pythonBuild.yaml +++ b/resources/metadata/pythonBuild.yaml @@ -60,7 +60,26 @@ spec: resourceRef: - name: commonPipelineEnvironment param: custom/repositoryUrl + - name: buildSettingsInfo + type: string + description: 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. + scope: + - STEPS + - STAGES + - PARAMETERS + resourceRef: + - name: commonPipelineEnvironment + param: custom/buildSettingsInfo + outputs: + resources: + - name: commonPipelineEnvironment + type: piperEnvironment + params: + - name: custom/buildSettingsInfo containers: - name: python image: python:3.9 - workingDir: /home/node + # workingDir: /home/node + options: + - name: -u + value: "0" diff --git a/src/com/sap/piper/BuildTool.groovy b/src/com/sap/piper/BuildTool.groovy index c177a5b76..33d85325e 100644 --- a/src/com/sap/piper/BuildTool.groovy +++ b/src/com/sap/piper/BuildTool.groovy @@ -1,5 +1,5 @@ package com.sap.piper enum BuildTool { - MAVEN, NPM, MTA + MAVEN, NPM, MTA, PIP }