1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-01-18 05:18:24 +02:00

fix(golangBuild): BOM creation failed with private Go modules (#4460)

* quickly try to only specify base private repo URLs with git config

* fix the test

* refactoring of private modules

* test

* fix test

* fix url

* typo

* Adding gitConfiguration

* typo

* unit test

* unit test

---------

Co-authored-by: I557621 <jordi.van.liempt@sap.com>
Co-authored-by: aibaend1 <106729492+aibaend1@users.noreply.github.com>
Co-authored-by: asadu <aibyn_sadu@epam.com>
This commit is contained in:
Jordi van Liempt 2023-08-14 10:03:43 +02:00 committed by GitHub
parent 9189ab37b5
commit d01c161822
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 75 additions and 133 deletions

View File

@ -7,7 +7,6 @@ import (
"os"
"path"
"path/filepath"
"regexp"
"strings"
"github.com/SAP/jenkins-library/pkg/buildsettings"
@ -24,7 +23,6 @@ import (
"github.com/SAP/jenkins-library/pkg/versioning"
"golang.org/x/mod/modfile"
"golang.org/x/mod/module"
)
const (
@ -341,26 +339,11 @@ func prepareGolangEnvironment(config *golangBuildOptions, goModFile *modfile.Fil
// pass private repos to go process
os.Setenv("GOPRIVATE", config.PrivateModules)
repoURLs, err := lookupGolangPrivateModulesRepositories(goModFile, config.PrivateModules, utils)
err = gitConfigurationForPrivateModules(config.PrivateModules, config.PrivateModulesGitToken, utils)
if err != nil {
return err
}
// configure credentials git shall use for pulling repos
for _, repoURL := range repoURLs {
if match, _ := regexp.MatchString("(?i)^https?://", repoURL); !match {
continue
}
authenticatedRepoURL := strings.Replace(repoURL, "://", fmt.Sprintf("://%s@", config.PrivateModulesGitToken), 1)
err = utils.RunExecutable("git", "config", "--global", fmt.Sprintf("url.%s.insteadOf", authenticatedRepoURL), repoURL)
if err != nil {
return err
}
}
return nil
}
@ -539,36 +522,6 @@ func runGolangBuildPerArchitecture(config *golangBuildOptions, goModFile *modfil
return binaryNames, nil
}
// lookupPrivateModulesRepositories returns a slice of all modules that match the given glob pattern
func lookupGolangPrivateModulesRepositories(goModFile *modfile.File, globPattern string, utils golangBuildUtils) ([]string, error) {
if globPattern == "" {
return []string{}, nil
}
if goModFile == nil {
return nil, fmt.Errorf("couldn't find go.mod file")
} else if goModFile.Require == nil {
return []string{}, nil // no modules referenced, nothing to do
}
privateModules := []string{}
for _, goModule := range goModFile.Require {
if !module.MatchPrefixPatterns(globPattern, goModule.Mod.Path) {
continue
}
repo, err := utils.GetRepositoryURL(goModule.Mod.Path)
if err != nil {
return nil, err
}
privateModules = append(privateModules, repo)
}
return privateModules, nil
}
func runBOMCreation(utils golangBuildUtils, outputFilename string) error {
if err := utils.RunExecutable("cyclonedx-gomod", "mod", "-licenses", fmt.Sprintf("-verbose=%t", GeneralConfig.Verbose), "-test", "-output", outputFilename, "-output-version", "1.4"); err != nil {
@ -631,3 +584,20 @@ func isMainPackage(utils golangBuildUtils, pkg string) (bool, error) {
return true, nil
}
func gitConfigurationForPrivateModules(privateMod string, token string, utils golangBuildUtils) error {
privateMod = strings.ReplaceAll(privateMod, "/*", "")
privateMod = strings.ReplaceAll(privateMod, "*.", "")
modules := strings.Split(privateMod, ",")
for _, v := range modules {
authenticatedRepoURL := fmt.Sprintf("https://%s@%s", token, v)
repoBaseURL := fmt.Sprintf("https://%s", v)
err := utils.RunExecutable("git", "config", "--global", fmt.Sprintf("url.%s.insteadOf", authenticatedRepoURL), repoBaseURL)
if err != nil {
return err
}
}
return nil
}

View File

@ -911,8 +911,7 @@ go 1.17`
expect: expectations{
envVars: []string{"GOPRIVATE=*.example.com"},
commandsExecuted: [][]string{
{"git", "config", "--global", "url.https://secret@private1.example.com/private/repo.git.insteadOf", "https://private1.example.com/private/repo.git"},
{"git", "config", "--global", "url.https://secret@private2.example.com/another/repo.git.insteadOf", "https://private2.example.com/another/repo.git"},
{"git", "config", "--global", "url.https://secret@example.com.insteadOf", "https://example.com"},
},
},
},
@ -943,89 +942,6 @@ go 1.17`
}
}
func TestLookupGolangPrivateModulesRepositories(t *testing.T) {
t.Parallel()
modTestFile := `
module private.example.com/m
require (
example.com/public/module v1.0.0
private1.example.com/private/repo v0.1.0
private2.example.com/another/repo v0.2.0
)
go 1.17`
type expectations struct {
repos []string
errorMessage string
}
tests := []struct {
name string
modFileContent string
globPattern string
expect expectations
}{
{
name: "Does nothing if glob pattern is empty",
modFileContent: modTestFile,
expect: expectations{
repos: []string{},
},
},
{
name: "Does nothing if there is no go.mod file",
globPattern: "private.example.com",
modFileContent: "",
expect: expectations{
repos: []string{},
},
},
{
name: "Detects all private repos using a glob pattern",
modFileContent: modTestFile,
globPattern: "*.example.com",
expect: expectations{
repos: []string{"https://private1.example.com/private/repo.git", "https://private2.example.com/another/repo.git"},
},
},
{
name: "Detects all private repos",
modFileContent: modTestFile,
globPattern: "private1.example.com,private2.example.com",
expect: expectations{
repos: []string{"https://private1.example.com/private/repo.git", "https://private2.example.com/another/repo.git"},
},
},
{
name: "Detects a dedicated repo",
modFileContent: modTestFile,
globPattern: "private2.example.com",
expect: expectations{
repos: []string{"https://private2.example.com/another/repo.git"},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
utils := newGolangBuildTestsUtils()
goModFile, _ := modfile.Parse("", []byte(tt.modFileContent), nil)
repos, err := lookupGolangPrivateModulesRepositories(goModFile, tt.globPattern, utils)
if tt.expect.errorMessage == "" {
assert.NoError(t, err)
assert.Equal(t, tt.expect.repos, repos)
} else {
assert.EqualError(t, err, tt.expect.errorMessage)
}
})
}
}
func TestRunGolangciLint(t *testing.T) {
t.Parallel()
@ -1153,3 +1069,59 @@ func TestRetrieveGolangciLint(t *testing.T) {
})
}
}
func Test_gitConfigurationForPrivateModules(t *testing.T) {
type args struct {
privateMod string
token string
}
type expectations struct {
commandsExecuted [][]string
}
tests := []struct {
name string
args args
expected expectations
}{
{
name: "with one private module",
args: args{
privateMod: "example.com/*",
token: "mytoken",
},
expected: expectations{
commandsExecuted: [][]string{
{"git", "config", "--global", "url.https://mytoken@example.com.insteadOf", "https://example.com"},
},
},
},
{
name: "with multiple private modules",
args: args{
privateMod: "example.com/*,test.com/*",
token: "mytoken",
},
expected: expectations{
commandsExecuted: [][]string{
{"git", "config", "--global", "url.https://mytoken@example.com.insteadOf", "https://example.com"},
{"git", "config", "--global", "url.https://mytoken@test.com.insteadOf", "https://test.com"},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
utils := newGolangBuildTestsUtils()
err := gitConfigurationForPrivateModules(tt.args.privateMod, tt.args.token, utils)
if assert.NoError(t, err) {
for i, expectedCommand := range tt.expected.commandsExecuted {
assert.Equal(t, expectedCommand[0], utils.Calls[i].Exec)
assert.Equal(t, expectedCommand[1:], utils.Calls[i].Params)
}
}
})
}
}