You've already forked sap-jenkins-library
mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-09-16 09:26:22 +02:00
add support for toml file
This commit is contained in:
@@ -3,17 +3,21 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/SAP/jenkins-library/pkg/buildsettings"
|
"github.com/SAP/jenkins-library/pkg/buildsettings"
|
||||||
"github.com/SAP/jenkins-library/pkg/command"
|
"github.com/SAP/jenkins-library/pkg/command"
|
||||||
|
"github.com/SAP/jenkins-library/pkg/feature"
|
||||||
"github.com/SAP/jenkins-library/pkg/log"
|
"github.com/SAP/jenkins-library/pkg/log"
|
||||||
"github.com/SAP/jenkins-library/pkg/piperutils"
|
"github.com/SAP/jenkins-library/pkg/piperutils"
|
||||||
|
"github.com/SAP/jenkins-library/pkg/python"
|
||||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PyBomFilename = "bom-pip.xml"
|
PyBomFilename = "bom-pip.xml"
|
||||||
stepName = "pythonBuild"
|
stepName = "pythonBuild"
|
||||||
|
cycloneDxVersion = "6.1.1"
|
||||||
cycloneDxPackageVersion = "cyclonedx-bom==6.1.1"
|
cycloneDxPackageVersion = "cyclonedx-bom==6.1.1"
|
||||||
cycloneDxSchemaVersion = "1.4"
|
cycloneDxSchemaVersion = "1.4"
|
||||||
)
|
)
|
||||||
@@ -52,32 +56,49 @@ func pythonBuild(config pythonBuildOptions, telemetryData *telemetry.CustomData,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runPythonBuild(config *pythonBuildOptions, telemetryData *telemetry.CustomData, utils pythonBuildUtils, commonPipelineEnvironment *pythonBuildCommonPipelineEnvironment) error {
|
func runPythonBuild(config *pythonBuildOptions, telemetryData *telemetry.CustomData, utils pythonBuildUtils, commonPipelineEnvironment *pythonBuildCommonPipelineEnvironment) error {
|
||||||
pipInstallFlags := []string{"install", "--upgrade"}
|
|
||||||
virutalEnvironmentPathMap := make(map[string]string)
|
virutalEnvironmentPathMap := make(map[string]string)
|
||||||
|
|
||||||
err := createVirtualEnvironment(utils, config, virutalEnvironmentPathMap)
|
// create virtualEnv
|
||||||
if err != nil {
|
if err := createVirtualEnvironment(utils, config, virutalEnvironmentPathMap); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
//TODO: use a defer func to cleanup the virtual environment
|
||||||
|
|
||||||
err = buildExecute(config, utils, pipInstallFlags, virutalEnvironmentPathMap)
|
// FEATURE FLAG (com_sap_piper_featureFlag_pythonToml) to switch to new implementation of python build step
|
||||||
if err != nil {
|
if feature.IsFeatureEnabled("pythonToml") {
|
||||||
return fmt.Errorf("Python build failed with error: %w", err)
|
// check project descriptor
|
||||||
|
buildDescriptorFilePath, err := searchDescriptor([]string{"pyproject.toml", "setup.py"}, utils.FileExists)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// build package
|
||||||
|
if strings.HasSuffix(buildDescriptorFilePath, "pyproject.toml") {
|
||||||
|
if err := python.InstallProjectDependencies(utils.RunExecutable, python.Binary); err != nil {
|
||||||
|
return fmt.Errorf("Failed to install project dependencies: %w", err)
|
||||||
|
}
|
||||||
|
if err := python.Build(utils.RunExecutable, python.Binary, config.BuildFlags, config.SetupFlags); err != nil {
|
||||||
|
return fmt.Errorf("Failed to build python project: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := buildExecute(config, utils, virutalEnvironmentPathMap); err != nil {
|
||||||
|
return fmt.Errorf("Python build failed with error: %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generate BOM
|
||||||
if config.CreateBOM {
|
if config.CreateBOM {
|
||||||
if err := runBOMCreationForPy(utils, pipInstallFlags, virutalEnvironmentPathMap, config); err != nil {
|
if err := runBOMCreationForPy(utils, virutalEnvironmentPathMap, config); err != nil {
|
||||||
return fmt.Errorf("BOM creation failed: %w", err)
|
return fmt.Errorf("BOM creation failed: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generate build settings information
|
||||||
log.Entry().Debugf("creating build settings information...")
|
log.Entry().Debugf("creating build settings information...")
|
||||||
|
|
||||||
dockerImage, err := GetDockerImageValue(stepName)
|
dockerImage, err := GetDockerImageValue(stepName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
pythonConfig := buildsettings.BuildOptions{
|
pythonConfig := buildsettings.BuildOptions{
|
||||||
CreateBOM: config.CreateBOM,
|
CreateBOM: config.CreateBOM,
|
||||||
Publish: config.Publish,
|
Publish: config.Publish,
|
||||||
@@ -90,21 +111,18 @@ func runPythonBuild(config *pythonBuildOptions, telemetryData *telemetry.CustomD
|
|||||||
}
|
}
|
||||||
commonPipelineEnvironment.custom.buildSettingsInfo = buildSettingsInfo
|
commonPipelineEnvironment.custom.buildSettingsInfo = buildSettingsInfo
|
||||||
|
|
||||||
|
// publish package
|
||||||
if config.Publish {
|
if config.Publish {
|
||||||
if err := publishWithTwine(config, utils, pipInstallFlags, virutalEnvironmentPathMap); err != nil {
|
if err := publishWithTwine(config, utils, virutalEnvironmentPathMap); err != nil {
|
||||||
return fmt.Errorf("failed to publish: %w", err)
|
return fmt.Errorf("failed to publish: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = removeVirtualEnvironment(utils, config)
|
// remove virtualEnv
|
||||||
if err != nil {
|
return removeVirtualEnvironment(utils, config)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildExecute(config *pythonBuildOptions, utils pythonBuildUtils, pipInstallFlags []string, virutalEnvironmentPathMap map[string]string) error {
|
func buildExecute(config *pythonBuildOptions, utils pythonBuildUtils, virutalEnvironmentPathMap map[string]string) error {
|
||||||
var flags []string
|
var flags []string
|
||||||
flags = append(flags, config.BuildFlags...)
|
flags = append(flags, config.BuildFlags...)
|
||||||
flags = append(flags, "setup.py")
|
flags = append(flags, "setup.py")
|
||||||
@@ -138,18 +156,17 @@ func createVirtualEnvironment(utils pythonBuildUtils, config *pythonBuildOptions
|
|||||||
}
|
}
|
||||||
|
|
||||||
func removeVirtualEnvironment(utils pythonBuildUtils, config *pythonBuildOptions) error {
|
func removeVirtualEnvironment(utils pythonBuildUtils, config *pythonBuildOptions) error {
|
||||||
err := utils.RemoveAll(config.VirutalEnvironmentName)
|
if err := utils.RemoveAll(config.VirutalEnvironmentName); err != nil {
|
||||||
if err != nil {
|
return fmt.Errorf("failed to remove virtual environment: %w", err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runBOMCreationForPy(utils pythonBuildUtils, pipInstallFlags []string, virutalEnvironmentPathMap map[string]string, config *pythonBuildOptions) error {
|
func runBOMCreationForPy(utils pythonBuildUtils, virutalEnvironmentPathMap map[string]string, config *pythonBuildOptions) error {
|
||||||
pipInstallOriginalFlags := pipInstallFlags
|
// install dependencies from requirements.txt
|
||||||
exists, _ := utils.FileExists(config.RequirementsFilePath)
|
exists, _ := utils.FileExists(config.RequirementsFilePath)
|
||||||
if exists {
|
if exists {
|
||||||
pipInstallRequirementsFlags := append(pipInstallOriginalFlags, "--requirement", config.RequirementsFilePath)
|
pipInstallRequirementsFlags := append(python.PipInstallFlags, "--requirement", config.RequirementsFilePath)
|
||||||
if err := utils.RunExecutable(virutalEnvironmentPathMap["pip"], pipInstallRequirementsFlags...); err != nil {
|
if err := utils.RunExecutable(virutalEnvironmentPathMap["pip"], pipInstallRequirementsFlags...); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -157,29 +174,58 @@ func runBOMCreationForPy(utils pythonBuildUtils, pipInstallFlags []string, virut
|
|||||||
log.Entry().Warnf("unable to find requirements.txt file at %s , continuing SBOM generation without requirements.txt", config.RequirementsFilePath)
|
log.Entry().Warnf("unable to find requirements.txt file at %s , continuing SBOM generation without requirements.txt", config.RequirementsFilePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
pipInstallCycloneDxFlags := append(pipInstallOriginalFlags, cycloneDxPackageVersion)
|
// install cyclonedx
|
||||||
|
pipInstallCycloneDxFlags := append(python.PipInstallFlags, cycloneDxPackageVersion)
|
||||||
if err := utils.RunExecutable(virutalEnvironmentPathMap["pip"], pipInstallCycloneDxFlags...); err != nil {
|
if err := utils.RunExecutable(virutalEnvironmentPathMap["pip"], pipInstallCycloneDxFlags...); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
virutalEnvironmentPathMap["cyclonedx"] = filepath.Join(config.VirutalEnvironmentName, "bin", "cyclonedx-py")
|
virutalEnvironmentPathMap["cyclonedx"] = filepath.Join(config.VirutalEnvironmentName, "bin", "cyclonedx-py")
|
||||||
|
|
||||||
if err := utils.RunExecutable(virutalEnvironmentPathMap["cyclonedx"], "env", "--output-file", PyBomFilename, "--output-format", "XML", "--spec-version", cycloneDxSchemaVersion); err != nil {
|
// run cyclonedx
|
||||||
|
// TODO: use modules, python -m cyclonedx_py ... to avoid virutalEnvironmentPathMap
|
||||||
|
if err := utils.RunExecutable(
|
||||||
|
virutalEnvironmentPathMap["cyclonedx"],
|
||||||
|
"env",
|
||||||
|
"--output-file", PyBomFilename,
|
||||||
|
"--output-format", "XML",
|
||||||
|
"--spec-version", cycloneDxSchemaVersion,
|
||||||
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func publishWithTwine(config *pythonBuildOptions, utils pythonBuildUtils, pipInstallFlags []string, virutalEnvironmentPathMap map[string]string) error {
|
func publishWithTwine(config *pythonBuildOptions, utils pythonBuildUtils, virutalEnvironmentPathMap map[string]string) error {
|
||||||
pipInstallFlags = append(pipInstallFlags, "twine")
|
if err := python.Install(utils.RunExecutable, "twine", "", config.VirutalEnvironmentName, virutalEnvironmentPathMap); err != nil {
|
||||||
if err := utils.RunExecutable(virutalEnvironmentPathMap["pip"], pipInstallFlags...); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
virutalEnvironmentPathMap["twine"] = filepath.Join(config.VirutalEnvironmentName, "bin", "twine")
|
|
||||||
if err := utils.RunExecutable(virutalEnvironmentPathMap["twine"], "upload", "--username", config.TargetRepositoryUser,
|
// TODO: use modules, python -m twine ... to avoid virutalEnvironmentPathMap
|
||||||
"--password", config.TargetRepositoryPassword, "--repository-url", config.TargetRepositoryURL, "--disable-progress-bar",
|
if err := utils.RunExecutable(
|
||||||
"dist/*"); err != nil {
|
virutalEnvironmentPathMap["twine"],
|
||||||
|
"upload",
|
||||||
|
"--username", config.TargetRepositoryUser,
|
||||||
|
"--password", config.TargetRepositoryPassword,
|
||||||
|
"--repository-url", config.TargetRepositoryURL,
|
||||||
|
"--disable-progress-bar",
|
||||||
|
"dist/*",
|
||||||
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func searchDescriptor(supported []string, existsFunc func(string) (bool, error)) (string, error) {
|
||||||
|
var descriptor string
|
||||||
|
for _, f := range supported {
|
||||||
|
exists, _ := existsFunc(f)
|
||||||
|
if exists {
|
||||||
|
descriptor = f
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(descriptor) == 0 {
|
||||||
|
return "", fmt.Errorf("no build descriptor available, supported: %v", supported)
|
||||||
|
}
|
||||||
|
return descriptor, nil
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user