Skip to content
37 changes: 36 additions & 1 deletion cmd/pythonBuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
}

Expand All @@ -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{
Expand All @@ -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)
}
}
95 changes: 95 additions & 0 deletions cmd/pythonBuild_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ package cmd

import (
"fmt"
"io"
"os"
"path/filepath"
"testing"

Expand Down Expand Up @@ -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{
Expand Down Expand Up @@ -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)
}
}
})
}
}
Loading