mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-01-18 05:18:24 +02:00
fix(golangBuild) properly handle multi main package builds
Co-authored-by: Pavel Busko <pavel.busko@sap.com>
This commit is contained in:
parent
2ed1ed76fc
commit
74b6b09609
@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"text/template"
|
||||
@ -18,7 +19,6 @@ import (
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/piperenv"
|
||||
"github.com/SAP/jenkins-library/pkg/piperutils"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/multiarch"
|
||||
@ -182,8 +182,7 @@ func runGolangBuild(config *golangBuildOptions, telemetryData *telemetry.CustomD
|
||||
log.Entry().Infof("ldflags from template: '%v'", ldflags)
|
||||
}
|
||||
|
||||
binaries := []string{}
|
||||
|
||||
var binaries []string
|
||||
platforms, err := multiarch.ParsePlatformStrings(config.TargetArchitectures)
|
||||
|
||||
if err != nil {
|
||||
@ -191,14 +190,14 @@ func runGolangBuild(config *golangBuildOptions, telemetryData *telemetry.CustomD
|
||||
}
|
||||
|
||||
for _, platform := range platforms {
|
||||
binary, err := runGolangBuildPerArchitecture(config, utils, ldflags, platform)
|
||||
binaryNames, err := runGolangBuildPerArchitecture(config, utils, ldflags, platform)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(binary) > 0 {
|
||||
binaries = append(binaries, binary)
|
||||
if len(binaryNames) > 0 {
|
||||
binaries = append(binaries, binaryNames...)
|
||||
}
|
||||
}
|
||||
|
||||
@ -425,8 +424,8 @@ func prepareLdflags(config *golangBuildOptions, utils golangBuildUtils, envRootP
|
||||
return generatedLdflags.String(), nil
|
||||
}
|
||||
|
||||
func runGolangBuildPerArchitecture(config *golangBuildOptions, utils golangBuildUtils, ldflags string, architecture multiarch.Platform) (string, error) {
|
||||
var binaryName string
|
||||
func runGolangBuildPerArchitecture(config *golangBuildOptions, utils golangBuildUtils, ldflags string, architecture multiarch.Platform) ([]string, error) {
|
||||
var binaryNames []string
|
||||
|
||||
envVars := os.Environ()
|
||||
envVars = append(envVars, fmt.Sprintf("GOOS=%v", architecture.OS), fmt.Sprintf("GOARCH=%v", architecture.Arch))
|
||||
@ -437,13 +436,25 @@ func runGolangBuildPerArchitecture(config *golangBuildOptions, utils golangBuild
|
||||
utils.SetEnv(envVars)
|
||||
|
||||
buildOptions := []string{"build", "-trimpath"}
|
||||
|
||||
if len(config.Output) > 0 {
|
||||
fileExtension := ""
|
||||
if architecture.OS == "windows" {
|
||||
fileExtension = ".exe"
|
||||
if len(config.Packages) > 1 {
|
||||
binaries, outputDir, err := getOutputBinaries(config.Output, config.Packages, utils, architecture)
|
||||
if err != nil {
|
||||
log.SetErrorCategory(log.ErrorBuild)
|
||||
return nil, fmt.Errorf("failed to calculate output binaries or directory, error: %s", err.Error())
|
||||
}
|
||||
buildOptions = append(buildOptions, "-o", outputDir)
|
||||
binaryNames = append(binaryNames, binaries...)
|
||||
} else {
|
||||
fileExtension := ""
|
||||
if architecture.OS == "windows" {
|
||||
fileExtension = ".exe"
|
||||
}
|
||||
binaryName := fmt.Sprintf("%s-%s.%s%s", strings.TrimRight(config.Output, string(os.PathSeparator)), architecture.OS, architecture.Arch, fileExtension)
|
||||
buildOptions = append(buildOptions, "-o", binaryName)
|
||||
binaryNames = append(binaryNames, binaryName)
|
||||
}
|
||||
binaryName = fmt.Sprintf("%v-%v.%v%v", config.Output, architecture.OS, architecture.Arch, fileExtension)
|
||||
buildOptions = append(buildOptions, "-o", binaryName)
|
||||
}
|
||||
buildOptions = append(buildOptions, config.BuildFlags...)
|
||||
if len(ldflags) > 0 {
|
||||
@ -454,9 +465,10 @@ func runGolangBuildPerArchitecture(config *golangBuildOptions, utils golangBuild
|
||||
if err := utils.RunExecutable("go", buildOptions...); err != nil {
|
||||
log.Entry().Debugf("buildOptions: %v", buildOptions)
|
||||
log.SetErrorCategory(log.ErrorBuild)
|
||||
return "", fmt.Errorf("failed to run build for %v.%v: %w", architecture.OS, architecture.Arch, err)
|
||||
return nil, fmt.Errorf("failed to run build for %v.%v: %w", architecture.OS, architecture.Arch, err)
|
||||
}
|
||||
return binaryName, nil
|
||||
|
||||
return binaryNames, nil
|
||||
}
|
||||
|
||||
// lookupPrivateModulesRepositories returns a slice of all modules that match the given glob pattern
|
||||
@ -512,3 +524,41 @@ func readGoModFile(utils golangBuildUtils) (*modfile.File, error) {
|
||||
|
||||
return modfile.Parse(modFilePath, modFileContent, nil)
|
||||
}
|
||||
|
||||
func getOutputBinaries(out string, packages []string, utils golangBuildUtils, architecture multiarch.Platform) ([]string, string, error) {
|
||||
var binaries []string
|
||||
outDir := fmt.Sprintf("%s-%s-%s%c", strings.TrimRight(out, string(os.PathSeparator)), architecture.OS, architecture.Arch, os.PathSeparator)
|
||||
|
||||
for _, pkg := range packages {
|
||||
ok, err := isMainPackage(utils, pkg)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
if ok {
|
||||
fileExt := ""
|
||||
if architecture.OS == "windows" {
|
||||
fileExt = ".exe"
|
||||
}
|
||||
binaries = append(binaries, filepath.Join(outDir, filepath.Base(pkg)+fileExt))
|
||||
}
|
||||
}
|
||||
|
||||
return binaries, outDir, nil
|
||||
}
|
||||
|
||||
func isMainPackage(utils golangBuildUtils, pkg string) (bool, error) {
|
||||
outBuffer := bytes.NewBufferString("")
|
||||
utils.Stdout(outBuffer)
|
||||
utils.Stderr(outBuffer)
|
||||
err := utils.RunExecutable("go", "list", "-f", "{{ .Name }}", pkg)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if outBuffer.String() != "main" {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ func newGolangBuildTestsUtils() *golangBuildMockUtils {
|
||||
utils := golangBuildMockUtils{
|
||||
ExecMockRunner: &mock.ExecMockRunner{},
|
||||
FilesMock: &mock.FilesMock{},
|
||||
//clientOptions: []piperhttp.ClientOptions{},
|
||||
// clientOptions: []piperhttp.ClientOptions{},
|
||||
fileUploads: map[string]string{},
|
||||
}
|
||||
return &utils
|
||||
@ -632,14 +632,15 @@ func TestRunGolangBuildPerArchitecture(t *testing.T) {
|
||||
ldflags := "-X test=test"
|
||||
architecture, _ := multiarch.ParsePlatformString("linux,amd64")
|
||||
|
||||
binaryName, err := runGolangBuildPerArchitecture(&config, utils, ldflags, architecture)
|
||||
binaryNames, err := runGolangBuildPerArchitecture(&config, utils, ldflags, architecture)
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, utils.Calls[0].Params, "-o")
|
||||
assert.Contains(t, utils.Calls[0].Params, "testBin-linux.amd64")
|
||||
assert.Contains(t, utils.Calls[0].Params, "./test/..")
|
||||
assert.Contains(t, utils.Calls[0].Params, "-ldflags")
|
||||
assert.Contains(t, utils.Calls[0].Params, "-X test=test")
|
||||
assert.Equal(t, "testBin-linux.amd64", binaryName)
|
||||
assert.Len(t, binaryNames, 1)
|
||||
assert.Contains(t, binaryNames, "testBin-linux.amd64")
|
||||
})
|
||||
|
||||
t.Run("success - windows", func(t *testing.T) {
|
||||
@ -649,11 +650,80 @@ func TestRunGolangBuildPerArchitecture(t *testing.T) {
|
||||
ldflags := ""
|
||||
architecture, _ := multiarch.ParsePlatformString("windows,amd64")
|
||||
|
||||
binaryName, err := runGolangBuildPerArchitecture(&config, utils, ldflags, architecture)
|
||||
binaryNames, err := runGolangBuildPerArchitecture(&config, utils, ldflags, architecture)
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, utils.Calls[0].Params, "-o")
|
||||
assert.Contains(t, utils.Calls[0].Params, "testBin-windows.amd64.exe")
|
||||
assert.Equal(t, "testBin-windows.amd64.exe", binaryName)
|
||||
assert.Len(t, binaryNames, 1)
|
||||
assert.Contains(t, binaryNames, "testBin-windows.amd64.exe")
|
||||
})
|
||||
|
||||
t.Run("success - multiple main packages (linux)", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
config := golangBuildOptions{Output: "test/", Packages: []string{"package/foo", "package/bar"}}
|
||||
utils := newGolangBuildTestsUtils()
|
||||
utils.StdoutReturn = map[string]string{
|
||||
"go list -f {{ .Name }} package/foo": "main",
|
||||
"go list -f {{ .Name }} package/bar": "main",
|
||||
}
|
||||
ldflags := ""
|
||||
architecture, _ := multiarch.ParsePlatformString("linux,amd64")
|
||||
|
||||
binaryNames, err := runGolangBuildPerArchitecture(&config, utils, ldflags, architecture)
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, utils.Calls[0].Params, "list")
|
||||
assert.Contains(t, utils.Calls[0].Params, "package/foo")
|
||||
assert.Contains(t, utils.Calls[1].Params, "list")
|
||||
assert.Contains(t, utils.Calls[1].Params, "package/bar")
|
||||
|
||||
assert.Len(t, binaryNames, 2)
|
||||
assert.Contains(t, binaryNames, "test-linux-amd64/foo")
|
||||
assert.Contains(t, binaryNames, "test-linux-amd64/bar")
|
||||
})
|
||||
|
||||
t.Run("success - multiple main packages (windows)", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
config := golangBuildOptions{Output: "test/", Packages: []string{"package/foo", "package/bar"}}
|
||||
utils := newGolangBuildTestsUtils()
|
||||
utils.StdoutReturn = map[string]string{
|
||||
"go list -f {{ .Name }} package/foo": "main",
|
||||
"go list -f {{ .Name }} package/bar": "main",
|
||||
}
|
||||
ldflags := ""
|
||||
architecture, _ := multiarch.ParsePlatformString("windows,amd64")
|
||||
|
||||
binaryNames, err := runGolangBuildPerArchitecture(&config, utils, ldflags, architecture)
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, utils.Calls[0].Params, "list")
|
||||
assert.Contains(t, utils.Calls[0].Params, "package/foo")
|
||||
assert.Contains(t, utils.Calls[1].Params, "list")
|
||||
assert.Contains(t, utils.Calls[1].Params, "package/bar")
|
||||
|
||||
assert.Len(t, binaryNames, 2)
|
||||
assert.Contains(t, binaryNames, "test-windows-amd64/foo.exe")
|
||||
assert.Contains(t, binaryNames, "test-windows-amd64/bar.exe")
|
||||
})
|
||||
|
||||
t.Run("success - multiple mixed packages", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
config := golangBuildOptions{Output: "test/", Packages: []string{"package/foo", "package/bar"}}
|
||||
utils := newGolangBuildTestsUtils()
|
||||
utils.StdoutReturn = map[string]string{
|
||||
"go list -f {{ .Name }} package/foo": "main",
|
||||
"go list -f {{ .Name }} package/bar": "bar",
|
||||
}
|
||||
ldflags := ""
|
||||
architecture, _ := multiarch.ParsePlatformString("linux,amd64")
|
||||
|
||||
binaryNames, err := runGolangBuildPerArchitecture(&config, utils, ldflags, architecture)
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, utils.Calls[0].Params, "list")
|
||||
assert.Contains(t, utils.Calls[0].Params, "package/foo")
|
||||
assert.Contains(t, utils.Calls[1].Params, "list")
|
||||
assert.Contains(t, utils.Calls[1].Params, "package/bar")
|
||||
|
||||
assert.Len(t, binaryNames, 1)
|
||||
assert.Contains(t, binaryNames, "test-linux-amd64/foo")
|
||||
})
|
||||
|
||||
t.Run("execution error", func(t *testing.T) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user