2022-03-29 19:01:44 +02:00
|
|
|
package cmd
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2022-04-26 14:15:24 +02:00
|
|
|
"path/filepath"
|
2022-03-29 19:01:44 +02:00
|
|
|
|
2022-04-05 09:16:46 +02:00
|
|
|
"github.com/SAP/jenkins-library/pkg/buildsettings"
|
2022-03-29 19:01:44 +02:00
|
|
|
"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/telemetry"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2022-08-01 13:38:49 +02:00
|
|
|
PyBomFilename = "bom-pip.xml"
|
2022-04-26 14:15:24 +02:00
|
|
|
stepName = "pythonBuild"
|
2022-03-29 19:01:44 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
type pythonBuildUtils interface {
|
|
|
|
command.ExecRunner
|
|
|
|
FileExists(filename string) (bool, error)
|
|
|
|
piperutils.FileUtils
|
|
|
|
}
|
|
|
|
|
|
|
|
type pythonBuildUtilsBundle struct {
|
|
|
|
*command.Command
|
|
|
|
*piperutils.Files
|
|
|
|
}
|
|
|
|
|
|
|
|
func newPythonBuildUtils() pythonBuildUtils {
|
|
|
|
utils := pythonBuildUtilsBundle{
|
2022-08-05 13:08:19 +02:00
|
|
|
Command: &command.Command{
|
|
|
|
StepName: "pythonBuild",
|
|
|
|
},
|
|
|
|
Files: &piperutils.Files{},
|
2022-03-29 19:01:44 +02:00
|
|
|
}
|
|
|
|
// Reroute command output to logging framework
|
|
|
|
utils.Stdout(log.Writer())
|
|
|
|
utils.Stderr(log.Writer())
|
|
|
|
return &utils
|
|
|
|
}
|
|
|
|
|
2022-04-05 09:16:46 +02:00
|
|
|
func pythonBuild(config pythonBuildOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *pythonBuildCommonPipelineEnvironment) {
|
2022-03-29 19:01:44 +02:00
|
|
|
utils := newPythonBuildUtils()
|
|
|
|
|
2022-04-05 09:16:46 +02:00
|
|
|
err := runPythonBuild(&config, telemetryData, utils, commonPipelineEnvironment)
|
2022-03-29 19:01:44 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Entry().WithError(err).Fatal("step execution failed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-05 09:16:46 +02:00
|
|
|
func runPythonBuild(config *pythonBuildOptions, telemetryData *telemetry.CustomData, utils pythonBuildUtils, commonPipelineEnvironment *pythonBuildCommonPipelineEnvironment) error {
|
2022-03-29 19:01:44 +02:00
|
|
|
|
2022-04-26 14:15:24 +02:00
|
|
|
pipInstallFlags := []string{"install", "--upgrade"}
|
|
|
|
virutalEnvironmentPathMap := make(map[string]string)
|
2022-03-29 19:01:44 +02:00
|
|
|
|
2022-04-26 14:15:24 +02:00
|
|
|
err := createVirtualEnvironment(utils, config, virutalEnvironmentPathMap)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = buildExecute(config, utils, pipInstallFlags, virutalEnvironmentPathMap)
|
2022-03-29 19:01:44 +02:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Python build failed with error: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if config.CreateBOM {
|
2022-04-26 14:15:24 +02:00
|
|
|
if err := runBOMCreationForPy(utils, pipInstallFlags, virutalEnvironmentPathMap, config); err != nil {
|
2022-03-29 19:01:44 +02:00
|
|
|
return fmt.Errorf("BOM creation failed: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-05 09:16:46 +02:00
|
|
|
log.Entry().Debugf("creating build settings information...")
|
2022-04-26 14:15:24 +02:00
|
|
|
|
2022-04-05 09:16:46 +02:00
|
|
|
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
|
|
|
|
|
2022-03-29 19:01:44 +02:00
|
|
|
if config.Publish {
|
2022-04-26 14:15:24 +02:00
|
|
|
if err := publishWithTwine(config, utils, pipInstallFlags, virutalEnvironmentPathMap); err != nil {
|
2022-03-29 19:01:44 +02:00
|
|
|
return fmt.Errorf("failed to publish: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-26 14:15:24 +02:00
|
|
|
err = removeVirtualEnvironment(utils, config)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-03-29 19:01:44 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-04-26 14:15:24 +02:00
|
|
|
func buildExecute(config *pythonBuildOptions, utils pythonBuildUtils, pipInstallFlags []string, virutalEnvironmentPathMap map[string]string) error {
|
|
|
|
|
2022-03-29 19:01:44 +02:00
|
|
|
var flags []string
|
|
|
|
flags = append(flags, config.BuildFlags...)
|
|
|
|
flags = append(flags, "setup.py", "sdist", "bdist_wheel")
|
|
|
|
|
|
|
|
log.Entry().Info("starting building python project:")
|
2022-04-26 14:15:24 +02:00
|
|
|
err := utils.RunExecutable(virutalEnvironmentPathMap["python"], flags...)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func createVirtualEnvironment(utils pythonBuildUtils, config *pythonBuildOptions, virutalEnvironmentPathMap map[string]string) error {
|
|
|
|
virtualEnvironmentFlags := []string{"-m", "venv", config.VirutalEnvironmentName}
|
|
|
|
err := utils.RunExecutable("python3", virtualEnvironmentFlags...)
|
2022-03-29 19:01:44 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-04-26 14:15:24 +02:00
|
|
|
err = utils.RunExecutable("bash", "-c", "source "+filepath.Join(config.VirutalEnvironmentName, "bin", "activate"))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
virutalEnvironmentPathMap["pip"] = filepath.Join(config.VirutalEnvironmentName, "bin", "pip")
|
|
|
|
// venv will create symlinks to python3 inside the container
|
|
|
|
virutalEnvironmentPathMap["python"] = "python"
|
|
|
|
virutalEnvironmentPathMap["deactivate"] = filepath.Join(config.VirutalEnvironmentName, "bin", "deactivate")
|
2022-03-29 19:01:44 +02:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-04-26 14:15:24 +02:00
|
|
|
func removeVirtualEnvironment(utils pythonBuildUtils, config *pythonBuildOptions) error {
|
|
|
|
err := utils.RemoveAll(config.VirutalEnvironmentName)
|
|
|
|
if err != nil {
|
2022-03-29 19:01:44 +02:00
|
|
|
return err
|
|
|
|
}
|
2022-04-26 14:15:24 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func runBOMCreationForPy(utils pythonBuildUtils, pipInstallFlags []string, virutalEnvironmentPathMap map[string]string, config *pythonBuildOptions) error {
|
|
|
|
pipInstallFlags = append(pipInstallFlags, "cyclonedx-bom")
|
|
|
|
if err := utils.RunExecutable(virutalEnvironmentPathMap["pip"], pipInstallFlags...); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
virutalEnvironmentPathMap["cyclonedx"] = filepath.Join(config.VirutalEnvironmentName, "bin", "cyclonedx-bom")
|
|
|
|
|
|
|
|
if err := utils.RunExecutable(virutalEnvironmentPathMap["cyclonedx"], "--e", "--output", PyBomFilename); err != nil {
|
2022-03-29 19:01:44 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-04-26 14:15:24 +02:00
|
|
|
func publishWithTwine(config *pythonBuildOptions, utils pythonBuildUtils, pipInstallFlags []string, virutalEnvironmentPathMap map[string]string) error {
|
|
|
|
pipInstallFlags = append(pipInstallFlags, "twine")
|
|
|
|
if err := utils.RunExecutable(virutalEnvironmentPathMap["pip"], pipInstallFlags...); err != nil {
|
2022-03-29 19:01:44 +02:00
|
|
|
return err
|
|
|
|
}
|
2022-04-26 14:15:24 +02:00
|
|
|
virutalEnvironmentPathMap["twine"] = filepath.Join(config.VirutalEnvironmentName, "bin", "twine")
|
|
|
|
if err := utils.RunExecutable(virutalEnvironmentPathMap["twine"], "upload", "--username", config.TargetRepositoryUser,
|
2022-06-28 12:15:25 +02:00
|
|
|
"--password", config.TargetRepositoryPassword, "--repository-url", config.TargetRepositoryURL, "--disable-progress-bar",
|
2022-03-29 19:01:44 +02:00
|
|
|
"dist/*"); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|