github.com/jaylevin/jenkins-library@v1.230.4/cmd/pythonBuild.go (about) 1 package cmd 2 3 import ( 4 "fmt" 5 "path/filepath" 6 7 "github.com/SAP/jenkins-library/pkg/buildsettings" 8 "github.com/SAP/jenkins-library/pkg/command" 9 "github.com/SAP/jenkins-library/pkg/log" 10 "github.com/SAP/jenkins-library/pkg/piperutils" 11 "github.com/SAP/jenkins-library/pkg/telemetry" 12 ) 13 14 const ( 15 PyBomFilename = "bom.xml" 16 stepName = "pythonBuild" 17 ) 18 19 type pythonBuildUtils interface { 20 command.ExecRunner 21 FileExists(filename string) (bool, error) 22 piperutils.FileUtils 23 } 24 25 type pythonBuildUtilsBundle struct { 26 *command.Command 27 *piperutils.Files 28 } 29 30 func newPythonBuildUtils() pythonBuildUtils { 31 utils := pythonBuildUtilsBundle{ 32 Command: &command.Command{}, 33 Files: &piperutils.Files{}, 34 } 35 // Reroute command output to logging framework 36 utils.Stdout(log.Writer()) 37 utils.Stderr(log.Writer()) 38 return &utils 39 } 40 41 func pythonBuild(config pythonBuildOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *pythonBuildCommonPipelineEnvironment) { 42 utils := newPythonBuildUtils() 43 44 err := runPythonBuild(&config, telemetryData, utils, commonPipelineEnvironment) 45 if err != nil { 46 log.Entry().WithError(err).Fatal("step execution failed") 47 } 48 } 49 50 func runPythonBuild(config *pythonBuildOptions, telemetryData *telemetry.CustomData, utils pythonBuildUtils, commonPipelineEnvironment *pythonBuildCommonPipelineEnvironment) error { 51 52 pipInstallFlags := []string{"install", "--upgrade"} 53 virutalEnvironmentPathMap := make(map[string]string) 54 55 err := createVirtualEnvironment(utils, config, virutalEnvironmentPathMap) 56 if err != nil { 57 return err 58 } 59 60 err = buildExecute(config, utils, pipInstallFlags, virutalEnvironmentPathMap) 61 if err != nil { 62 return fmt.Errorf("Python build failed with error: %w", err) 63 } 64 65 if config.CreateBOM { 66 if err := runBOMCreationForPy(utils, pipInstallFlags, virutalEnvironmentPathMap, config); err != nil { 67 return fmt.Errorf("BOM creation failed: %w", err) 68 } 69 } 70 71 log.Entry().Debugf("creating build settings information...") 72 73 dockerImage, err := GetDockerImageValue(stepName) 74 if err != nil { 75 return err 76 } 77 78 pythonConfig := buildsettings.BuildOptions{ 79 CreateBOM: config.CreateBOM, 80 Publish: config.Publish, 81 BuildSettingsInfo: config.BuildSettingsInfo, 82 DockerImage: dockerImage, 83 } 84 buildSettingsInfo, err := buildsettings.CreateBuildSettingsInfo(&pythonConfig, stepName) 85 if err != nil { 86 log.Entry().Warnf("failed to create build settings info: %v", err) 87 } 88 commonPipelineEnvironment.custom.buildSettingsInfo = buildSettingsInfo 89 90 if config.Publish { 91 if err := publishWithTwine(config, utils, pipInstallFlags, virutalEnvironmentPathMap); err != nil { 92 return fmt.Errorf("failed to publish: %w", err) 93 } 94 } 95 96 err = removeVirtualEnvironment(utils, config) 97 if err != nil { 98 return err 99 } 100 101 return nil 102 } 103 104 func buildExecute(config *pythonBuildOptions, utils pythonBuildUtils, pipInstallFlags []string, virutalEnvironmentPathMap map[string]string) error { 105 106 var flags []string 107 flags = append(flags, config.BuildFlags...) 108 flags = append(flags, "setup.py", "sdist", "bdist_wheel") 109 110 log.Entry().Info("starting building python project:") 111 err := utils.RunExecutable(virutalEnvironmentPathMap["python"], flags...) 112 if err != nil { 113 return err 114 } 115 return nil 116 } 117 118 func createVirtualEnvironment(utils pythonBuildUtils, config *pythonBuildOptions, virutalEnvironmentPathMap map[string]string) error { 119 virtualEnvironmentFlags := []string{"-m", "venv", config.VirutalEnvironmentName} 120 err := utils.RunExecutable("python3", virtualEnvironmentFlags...) 121 if err != nil { 122 return err 123 } 124 err = utils.RunExecutable("bash", "-c", "source "+filepath.Join(config.VirutalEnvironmentName, "bin", "activate")) 125 if err != nil { 126 return err 127 } 128 virutalEnvironmentPathMap["pip"] = filepath.Join(config.VirutalEnvironmentName, "bin", "pip") 129 // venv will create symlinks to python3 inside the container 130 virutalEnvironmentPathMap["python"] = "python" 131 virutalEnvironmentPathMap["deactivate"] = filepath.Join(config.VirutalEnvironmentName, "bin", "deactivate") 132 133 return nil 134 } 135 136 func removeVirtualEnvironment(utils pythonBuildUtils, config *pythonBuildOptions) error { 137 err := utils.RemoveAll(config.VirutalEnvironmentName) 138 if err != nil { 139 return err 140 } 141 return nil 142 } 143 144 func runBOMCreationForPy(utils pythonBuildUtils, pipInstallFlags []string, virutalEnvironmentPathMap map[string]string, config *pythonBuildOptions) error { 145 pipInstallFlags = append(pipInstallFlags, "cyclonedx-bom") 146 if err := utils.RunExecutable(virutalEnvironmentPathMap["pip"], pipInstallFlags...); err != nil { 147 return err 148 } 149 virutalEnvironmentPathMap["cyclonedx"] = filepath.Join(config.VirutalEnvironmentName, "bin", "cyclonedx-bom") 150 151 if err := utils.RunExecutable(virutalEnvironmentPathMap["cyclonedx"], "--e", "--output", PyBomFilename); err != nil { 152 return err 153 } 154 return nil 155 } 156 157 func publishWithTwine(config *pythonBuildOptions, utils pythonBuildUtils, pipInstallFlags []string, virutalEnvironmentPathMap map[string]string) error { 158 pipInstallFlags = append(pipInstallFlags, "twine") 159 if err := utils.RunExecutable(virutalEnvironmentPathMap["pip"], pipInstallFlags...); err != nil { 160 return err 161 } 162 virutalEnvironmentPathMap["twine"] = filepath.Join(config.VirutalEnvironmentName, "bin", "twine") 163 if err := utils.RunExecutable(virutalEnvironmentPathMap["twine"], "upload", "--username", config.TargetRepositoryUser, 164 "--password", config.TargetRepositoryPassword, "--repository-url", config.TargetRepositoryURL, 165 "dist/*"); err != nil { 166 return err 167 } 168 return nil 169 }