diff --git a/cmd/pythonBuild.go b/cmd/pythonBuild.go index 871f15b2dc..c52bd0d8db 100644 --- a/cmd/pythonBuild.go +++ b/cmd/pythonBuild.go @@ -2,6 +2,9 @@ package cmd import ( "fmt" + "os" + "path/filepath" + "strings" "github.com/SAP/jenkins-library/pkg/buildsettings" "github.com/SAP/jenkins-library/pkg/command" @@ -85,6 +88,12 @@ func runPythonBuild(config *pythonBuildOptions, telemetryData *telemetry.CustomD return fmt.Errorf("failed to publish: %w", err) } } + + // After build, rename all dist/* files with underscores to dashes in the base name + // This was introduced to fix setuptools renaming from "-" to "_" + const distDir = "dist" + renameArtifactsInDist(distDir) + return nil } @@ -93,7 +102,8 @@ func createBuildSettingsInfo(config *pythonBuildOptions) (string, error) { log.Entry().Debugf("creating build settings information...") dockerImage, err := GetDockerImageValue(stepName) if err != nil { - return "", err + log.Entry().Warnf("failed to get docker image value: %v", err) + dockerImage = "" } pythonConfig := buildsettings.BuildOptions{ @@ -108,3 +118,28 @@ func createBuildSettingsInfo(config *pythonBuildOptions) (string, error) { } return buildSettingsInfo, nil } + +func renameArtifactsInDist(distDir string) { + // After build, rename all dist/* files with underscores to dashes in the base name + // This was introduced to fix setuptools renaming from "-" to "_" + files, err := os.ReadDir(distDir) + if err != nil { + log.Entry().Warnf("Could not read dist directory for artifact renaming: %v", err) + return + } + + for _, f := range files { + oldName := f.Name() + // Only rename if the base name contains an underscore and is a typical Python artifact + if !strings.Contains(oldName, "_") || !strings.HasSuffix(oldName, ".tar.gz") { + continue + } + newName := strings.ReplaceAll(oldName, "_", "-") + oldPath := filepath.Join(distDir, oldName) + newPath := filepath.Join(distDir, newName) + if err := os.Rename(oldPath, newPath); err != nil { + log.Entry().Warnf("Failed to rename artifact %s to %s: %v", oldName, newName, err) + } + log.Entry().Infof("Renamed artifact %s to %s", oldName, newName) + } +} diff --git a/cmd/pythonBuild_test.go b/cmd/pythonBuild_test.go index 39496bf584..6d7d4d9ef2 100644 --- a/cmd/pythonBuild_test.go +++ b/cmd/pythonBuild_test.go @@ -5,6 +5,8 @@ package cmd import ( "fmt" + "io" + "os" "path/filepath" "testing" @@ -33,6 +35,14 @@ func (f *pythonBuildMockUtils) GetConfig() *pythonBuildOptions { } func TestRunPythonBuild(t *testing.T) { + // Initialize GeneralConfig and configOptions to avoid nil pointer panic + GeneralConfig = GeneralConfigOptions{} + configOptions = ConfigCommandOptions{ + OpenFile: func(s string, t map[string]string) (io.ReadCloser, error) { + return nil, fmt.Errorf("not implemented for test") + }, + } + cpe := pythonBuildCommonPipelineEnvironment{} t.Run("success - build", func(t *testing.T) { config := pythonBuildOptions{ @@ -109,3 +119,88 @@ func TestRunPythonBuild(t *testing.T) { assert.Equal(t, []string{"env", "--output-file", "bom-pip.xml", "--output-format", "XML", "--spec-version", "1.4"}, utils.ExecMockRunner.Calls[5].Params) }) } + +func Test_renameArtifactsInDist(t *testing.T) { + // Define test cases + tests := []struct { + testName string + inputFilename string + expectedFilename string + shouldRename bool // Whether renaming is expected + }{ + { + testName: "Rename file with underscore in the name", + inputFilename: "test_artifact_1.0.0.tar.gz", + expectedFilename: "test-artifact-1.0.0.tar.gz", + shouldRename: true, + }, + { + testName: "Rename file with multiple underscores", + inputFilename: "another_test_artifact_1_0_0.tar.gz", + expectedFilename: "another-test-artifact-1-0-0.tar.gz", + shouldRename: true, + }, + { + testName: "Do not rename file without underscore", + inputFilename: "test-artifact-1.0.0.tar.gz", + expectedFilename: "test-artifact-1.0.0.tar.gz", + shouldRename: false, + }, + { + testName: "Ignore non-Python artifact file (ZIP)", + inputFilename: "random_file_1.0.0.zip", + expectedFilename: "random_file_1.0.0.zip", + shouldRename: false, + }, + } + + // Create a temporary directory for testing + distTempDir := t.TempDir() + + // Create test files in the temporary directory + for _, tt := range tests { + filePath := filepath.Join(distTempDir, tt.inputFilename) + if err := os.WriteFile(filePath, []byte("sample"), 0644); err != nil { + t.Fatalf("Failed to create test file %s: %v", tt.inputFilename, err) + } + } + + // Run the function under test + renameArtifactsInDist(distTempDir) + + // Validate the results + for _, tt := range tests { + t.Run(tt.testName, func(t *testing.T) { + oldPath := filepath.Join(distTempDir, tt.inputFilename) + newPath := filepath.Join(distTempDir, tt.expectedFilename) + + if tt.inputFilename == tt.expectedFilename { + // Special case: No renaming expected + if _, err := os.Stat(oldPath); os.IsNotExist(err) { + t.Errorf("Expected file %s to remain, but it does not exist", oldPath) + } + return + } + + // General case: Renaming logic + _, oldExistsErr := os.Stat(oldPath) + _, newExistsErr := os.Stat(newPath) + + if tt.shouldRename { + if oldExistsErr == nil { + t.Errorf("Expected old file %s to be renamed, but it still exists", oldPath) + } + if os.IsNotExist(newExistsErr) { + t.Errorf("Expected new file %s to exist, but it does not", newPath) + } + } else { + if os.IsNotExist(oldExistsErr) { + t.Errorf("Expected file %s to remain, but it does not exist", oldPath) + } + if newExistsErr == nil { + t.Errorf("Expected file %s not to be renamed, but it was renamed to %s", tt.inputFilename, tt.expectedFilename) + } + } + }) + } +}