1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-10-30 23:57:50 +02:00

Support maven params in detect scan (#1855)

Co-authored-by: Florian Wilhelm <florian.wilhelm02@sap.com>
Co-authored-by: Stephan Aßmus <stephan.assmus@sap.com>
This commit is contained in:
Daniel Kurzynski
2020-07-30 10:35:46 +02:00
committed by GitHub
parent 9009c831fb
commit 8ee0d358b9
15 changed files with 355 additions and 215 deletions

View File

@@ -2,12 +2,15 @@ package cmd
import (
"fmt"
piperhttp "github.com/SAP/jenkins-library/pkg/http"
"github.com/SAP/jenkins-library/pkg/maven"
"strings"
sliceUtils "github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/SAP/jenkins-library/pkg/command"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/SAP/jenkins-library/pkg/versioning"
)
@@ -17,20 +20,12 @@ func detectExecuteScan(config detectExecuteScanOptions, telemetryData *telemetry
// reroute command output to logging framework
c.Stdout(log.Writer())
c.Stderr(log.Writer())
runDetect(config, &c)
}
func runDetect(config detectExecuteScanOptions, command command.ShellRunner) {
// detect execution details, see https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/88440888/Sample+Synopsys+Detect+Scan+Configuration+Scenarios+for+Black+Duck
fileUtils := piperutils.Files{}
httpClient := piperhttp.Client{}
args := []string{"bash <(curl -s https://detect.synopsys.com/detect.sh)"}
args = addDetectArgs(args, config)
script := strings.Join(args, " ")
err := runDetect(config, &c, &fileUtils, &httpClient)
command.SetDir(".")
command.SetEnv([]string{"BLACKDUCK_SKIP_PHONE_HOME=true"})
err := command.RunShell("/bin/bash", script)
if err != nil {
log.Entry().
WithError(err).
@@ -38,7 +33,29 @@ func runDetect(config detectExecuteScanOptions, command command.ShellRunner) {
}
}
func addDetectArgs(args []string, config detectExecuteScanOptions) []string {
func runDetect(config detectExecuteScanOptions, command command.ShellRunner, fileUtils piperutils.FileUtils, httpClient piperhttp.Downloader) error {
// detect execution details, see https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/88440888/Sample+Synopsys+Detect+Scan+Configuration+Scenarios+for+Black+Duck
httpClient.DownloadFile("https://detect.synopsys.com/detect.sh", "detect.sh", nil, nil)
err := fileUtils.Chmod("detect.sh", 0700)
if err != nil {
return err
}
args := []string{"./detect.sh"}
args, err = addDetectArgs(args, config, fileUtils, httpClient)
if err != nil {
return err
}
script := strings.Join(args, " ")
envs := []string{"BLACKDUCK_SKIP_PHONE_HOME=true"}
command.SetDir(".")
command.SetEnv(envs)
return command.RunShell("/bin/bash", script)
}
func addDetectArgs(args []string, config detectExecuteScanOptions, fileUtils piperutils.FileUtils, httpClient piperhttp.Downloader) ([]string, error) {
coordinates := struct {
Version string
@@ -80,5 +97,23 @@ func addDetectArgs(args []string, config detectExecuteScanOptions) []string {
if sliceUtils.ContainsString(config.Scanners, "source") {
args = append(args, fmt.Sprintf("--detect.source.path=%v", config.ScanPaths[0]))
}
return args
mavenArgs, err := maven.DownloadAndGetMavenParameters(config.GlobalSettingsFile, config.ProjectSettingsFile, fileUtils, httpClient)
if err != nil {
return nil, err
}
if len(config.M2Path) > 0 {
absolutePath, err := fileUtils.Abs(config.M2Path)
if err != nil {
return nil, err
}
mavenArgs = append(mavenArgs, fmt.Sprintf("-Dmaven.repo.local=%v", absolutePath))
}
if len(mavenArgs) > 0 {
args = append(args, fmt.Sprintf("\"--detect.maven.build.command='%v'\"", strings.Join(mavenArgs, " ")))
}
return args, nil
}

View File

@@ -25,6 +25,9 @@ type detectExecuteScanOptions struct {
FailOn []string `json:"failOn,omitempty"`
Version string `json:"version,omitempty"`
VersioningModel string `json:"versioningModel,omitempty"`
ProjectSettingsFile string `json:"projectSettingsFile,omitempty"`
GlobalSettingsFile string `json:"globalSettingsFile,omitempty"`
M2Path string `json:"m2Path,omitempty"`
}
// DetectExecuteScanCommand Executes Synopsys Detect scan
@@ -96,6 +99,9 @@ func addDetectExecuteScanFlags(cmd *cobra.Command, stepConfig *detectExecuteScan
cmd.Flags().StringSliceVar(&stepConfig.FailOn, "failOn", []string{`BLOCKER`}, "Mark the current build as fail based on the policy categories applied.")
cmd.Flags().StringVar(&stepConfig.Version, "version", os.Getenv("PIPER_version"), "Defines the version number of the artifact being build in the pipeline. It is used as source for the Detect version.")
cmd.Flags().StringVar(&stepConfig.VersioningModel, "versioningModel", `major`, "The versioning model used for result reporting (based on the artifact version). Example 1.2.3 using `major` will result in version 1")
cmd.Flags().StringVar(&stepConfig.ProjectSettingsFile, "projectSettingsFile", os.Getenv("PIPER_projectSettingsFile"), "Path or url to the mvn settings file that should be used as project settings file.")
cmd.Flags().StringVar(&stepConfig.GlobalSettingsFile, "globalSettingsFile", os.Getenv("PIPER_globalSettingsFile"), "Path or url to the mvn settings file that should be used as global settings file")
cmd.Flags().StringVar(&stepConfig.M2Path, "m2Path", os.Getenv("PIPER_m2Path"), "Path to the location of the local repository that should be used.")
cmd.MarkFlagRequired("apiToken")
cmd.MarkFlagRequired("projectName")
@@ -200,6 +206,30 @@ func detectExecuteScanMetadata() config.StepData {
Mandatory: false,
Aliases: []config.Alias{},
},
{
Name: "projectSettingsFile",
ResourceRef: []config.ResourceReference{},
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{{Name: "maven/projectSettingsFile"}},
},
{
Name: "globalSettingsFile",
ResourceRef: []config.ResourceReference{},
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{{Name: "maven/globalSettingsFile"}},
},
{
Name: "m2Path",
ResourceRef: []config.ResourceReference{},
Scope: []string{"GENERAL", "STEPS", "STAGES", "PARAMETERS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{{Name: "maven/m2Path"}},
},
},
},
},

View File

@@ -2,37 +2,93 @@ package cmd
import (
"fmt"
piperhttp "github.com/SAP/jenkins-library/pkg/http"
"github.com/SAP/jenkins-library/pkg/mock"
"net/http"
"os"
"path/filepath"
"testing"
"github.com/SAP/jenkins-library/pkg/mock"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/stretchr/testify/assert"
)
type httpClientMock struct {
expectedError error
downloadedFiles map[string]string // src, dest
}
func (c *httpClientMock) SetOptions(options piperhttp.ClientOptions) {
}
func (c *httpClientMock) DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error {
if c.expectedError != nil {
return c.expectedError
}
if c.downloadedFiles == nil {
c.downloadedFiles = make(map[string]string)
}
c.downloadedFiles[url] = filename
return nil
}
func TestRunDetect(t *testing.T) {
t.Run("success case", func(t *testing.T) {
s := mock.ShellMockRunner{}
runDetect(detectExecuteScanOptions{}, &s)
fileUtilsMock := mock.FilesMock{}
fileUtilsMock.AddFile("detect.sh", []byte(""))
httpClient := httpClientMock{}
err := runDetect(detectExecuteScanOptions{}, &s, &fileUtilsMock, &httpClient)
assert.Equal(t, httpClient.downloadedFiles["https://detect.synopsys.com/detect.sh"], "detect.sh")
fileStatus, err := fileUtilsMock.Stat("detect.sh")
assert.NoError(t, err)
assert.Equal(t, fileStatus.Mode(), os.FileMode(0700))
assert.NoError(t, err)
assert.Equal(t, ".", s.Dir, "Wrong execution directory used")
assert.Equal(t, "/bin/bash", s.Shell[0], "Bash shell expected")
expectedScript := "bash <(curl -s https://detect.synopsys.com/detect.sh) --blackduck.url= --blackduck.api.token= --detect.project.name=\\\"\\\" --detect.project.version.name=\\\"\\\" --detect.code.location.name=\\\"\\\""
expectedScript := "./detect.sh --blackduck.url= --blackduck.api.token= --detect.project.name=\\\"\\\" --detect.project.version.name=\\\"\\\" --detect.code.location.name=\\\"\\\""
assert.Equal(t, expectedScript, s.Calls[0])
})
t.Run("failure case", func(t *testing.T) {
var hasFailed bool
log.Entry().Logger.ExitFunc = func(int) { hasFailed = true }
s := mock.ShellMockRunner{ShouldFailOnCommand: map[string]error{"./detect.sh --blackduck.url= --blackduck.api.token= --detect.project.name=\\\"\\\" --detect.project.version.name=\\\"\\\" --detect.code.location.name=\\\"\\\"": fmt.Errorf("Test Error")}}
fileUtilsMock := mock.FilesMock{}
httpClient := httpClientMock{}
err := runDetect(detectExecuteScanOptions{}, &s, &fileUtilsMock, &httpClient)
assert.NotNil(t, err)
})
s := mock.ShellMockRunner{ShouldFailOnCommand: map[string]error{"bash <(curl -s https://detect.synopsys.com/detect.sh) --blackduck.url= --blackduck.api.token= --detect.project.name=\\\"\\\" --detect.project.version.name=\\\"\\\" --detect.code.location.name=\\\"\\\"": fmt.Errorf("Test Error")}}
runDetect(detectExecuteScanOptions{}, &s)
assert.True(t, hasFailed, "expected command to exit with fatal")
t.Run("maven parameters", func(t *testing.T) {
s := mock.ShellMockRunner{}
fileUtilsMock := mock.FilesMock{
CurrentDir: "root_folder",
}
fileUtilsMock.AddFile("detect.sh", []byte(""))
httpClient := httpClientMock{}
err := runDetect(detectExecuteScanOptions{
M2Path: ".pipeline/local_repo",
ProjectSettingsFile: "project-settings.xml",
GlobalSettingsFile: "global-settings.xml",
}, &s, &fileUtilsMock, &httpClient)
assert.NoError(t, err)
assert.Equal(t, ".", s.Dir, "Wrong execution directory used")
assert.Equal(t, "/bin/bash", s.Shell[0], "Bash shell expected")
absoluteLocalPath := string(os.PathSeparator) + filepath.Join("root_folder", ".pipeline", "local_repo")
expectedParam := "\"--detect.maven.build.command='--global-settings global-settings.xml --settings project-settings.xml -Dmaven.repo.local=" + absoluteLocalPath + "'\""
assert.Contains(t, s.Calls[0], expectedParam)
})
}
func TestAddDetectArgs(t *testing.T) {
httpClient := piperhttp.Client{}
fileUtilsMock := mock.FilesMock{}
testData := []struct {
args []string
options detectExecuteScanOptions
@@ -119,7 +175,8 @@ func TestAddDetectArgs(t *testing.T) {
for k, v := range testData {
t.Run(fmt.Sprintf("run %v", k), func(t *testing.T) {
got := addDetectArgs(v.args, v.options)
got, err := addDetectArgs(v.args, v.options, &fileUtilsMock, &httpClient)
assert.NoError(t, err)
assert.Equal(t, v.expected, got)
})
}

View File

@@ -78,6 +78,10 @@ func (f *kanikoFileMock) Abs(path string) (string, error) {
return "", fmt.Errorf("not implemented. func is only present in order to fullfil the interface contract. Needs to be ajusted in case it gets used.")
}
func (f *kanikoFileMock) Glob(pattern string) (matches []string, err error) {
return nil, fmt.Errorf("not implemented. func is only present in order to fullfil the interface contract. Needs to be ajusted in case it gets used.")
}
func TestRunKanikoExecute(t *testing.T) {
t.Run("success case", func(t *testing.T) {

View File

@@ -39,7 +39,7 @@ modules:
build-result: dist`
// for mocking
var getSettingsFile = maven.GetSettingsFile
var downloadAndCopySettingsFiles = maven.DownloadAndCopySettingsFiles
// MTABuildTarget ...
type MTABuildTarget int
@@ -348,28 +348,7 @@ func handleSettingsFiles(config mtaBuildOptions,
p piperutils.FileUtils,
httpClient piperhttp.Downloader) error {
if len(config.ProjectSettingsFile) > 0 {
if err := getSettingsFile(maven.ProjectSettingsFile, config.ProjectSettingsFile, p, httpClient); err != nil {
return err
}
} else {
log.Entry().Debugf("Project settings file not provided via configuration.")
}
if len(config.GlobalSettingsFile) > 0 {
if err := getSettingsFile(maven.GlobalSettingsFile, config.GlobalSettingsFile, p, httpClient); err != nil {
return err
}
} else {
log.Entry().Debugf("Global settings file not provided via configuration.")
}
return nil
return downloadAndCopySettingsFiles(config.GlobalSettingsFile, config.ProjectSettingsFile, p, httpClient)
}
func generateMta(id, applicationName, version string) (string, error) {

View File

@@ -281,20 +281,20 @@ func TestMarBuild(t *testing.T) {
t.Run("Settings file releatd tests", func(t *testing.T) {
var settingsFile string
var settingsFileType maven.SettingsFileType
var projectSettingsFile string
var globalSettingsFile string
defer func() {
getSettingsFile = maven.GetSettingsFile
downloadAndCopySettingsFiles = maven.DownloadAndCopySettingsFiles
}()
getSettingsFile = func(
sfType maven.SettingsFileType,
src string,
fileUtilsMock piperutils.FileUtils,
httpClientMock piperhttp.Downloader) error {
settingsFile = src
settingsFileType = sfType
downloadAndCopySettingsFiles = func(
globalSettings string,
projectSettings string,
fileUtils piperutils.FileUtils,
httpClient maven.SettingsDownloadUtils) error {
projectSettingsFile = projectSettings
globalSettingsFile = globalSettings
return nil
}
@@ -305,8 +305,8 @@ func TestMarBuild(t *testing.T) {
t.Run("Copy global settings file", func(t *testing.T) {
defer func() {
settingsFile = ""
settingsFileType = -1
projectSettingsFile = ""
globalSettingsFile = ""
}()
e := mock.ExecMockRunner{}
@@ -317,15 +317,15 @@ func TestMarBuild(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, settingsFile, "/opt/maven/settings.xml")
assert.Equal(t, settingsFileType, maven.GlobalSettingsFile)
assert.Equal(t, globalSettingsFile, "/opt/maven/settings.xml")
assert.Equal(t, projectSettingsFile, "")
})
t.Run("Copy project settings file", func(t *testing.T) {
defer func() {
settingsFile = ""
settingsFileType = -1
projectSettingsFile = ""
globalSettingsFile = ""
}()
e := mock.ExecMockRunner{}
@@ -336,8 +336,8 @@ func TestMarBuild(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, "/my/project/settings.xml", settingsFile)
assert.Equal(t, maven.ProjectSettingsFile, settingsFileType)
assert.Equal(t, "/my/project/settings.xml", projectSettingsFile)
assert.Equal(t, "", globalSettingsFile)
})
})
}
@@ -391,6 +391,10 @@ func (f *MtaTestFileUtilsMock) Abs(path string) (string, error) {
return "/root_folder/workspace/" + path, nil
}
func (f *MtaTestFileUtilsMock) Glob(pattern string) (matches []string, err error) {
return nil, fmt.Errorf("not implemented. func is only present in order to fullfil the interface contract. Needs to be ajusted in case it gets used.")
}
func (f *MtaTestFileUtilsMock) Chmod(path string, mode os.FileMode) error {
return fmt.Errorf("not implemented. func is only present in order to fullfil the interface contract. Needs to be ajusted in case it gets used.")
}

View File

@@ -46,6 +46,10 @@ func (f *FileUtilsMock) Abs(path string) (string, error) {
return "", fmt.Errorf("not implemented. func is only present in order to fullfil the interface contract. Needs to be ajusted in case it gets used.")
}
func (f *FileUtilsMock) Glob(pattern string) (matches []string, err error) {
return nil, fmt.Errorf("not implemented. func is only present in order to fullfil the interface contract. Needs to be ajusted in case it gets used.")
}
func TestDeploy(t *testing.T) {
myXsDeployOptions := xsDeployOptions{
APIURL: "https://example.org:12345",

View File

@@ -43,11 +43,8 @@ type mavenExecRunner interface {
}
type mavenUtils interface {
FileExists(path string) (bool, error)
piperutils.FileUtils
DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error
Glob(pattern string) (matches []string, err error)
Getwd() (dir string, err error)
Chdir(dir string) error
}
type utilsBundle struct {
@@ -290,21 +287,10 @@ func evaluateStdOut(options *ExecuteOptions) (*bytes.Buffer, io.Writer) {
func getParametersFromOptions(options *ExecuteOptions, utils mavenUtils) ([]string, error) {
var parameters []string
if options.GlobalSettingsFile != "" {
globalSettingsFileName, err := downloadSettingsIfURL(options.GlobalSettingsFile, ".pipeline/mavenGlobalSettings.xml", utils)
parameters, err := DownloadAndGetMavenParameters(options.GlobalSettingsFile, options.ProjectSettingsFile, utils, utils)
if err != nil {
return nil, err
}
parameters = append(parameters, "--global-settings", globalSettingsFileName)
}
if options.ProjectSettingsFile != "" {
projectSettingsFileName, err := downloadSettingsIfURL(options.ProjectSettingsFile, ".pipeline/mavenProjectSettings.xml", utils)
if err != nil {
return nil, err
}
parameters = append(parameters, "--settings", projectSettingsFileName)
}
if options.M2Path != "" {
parameters = append(parameters, "-Dmaven.repo.local="+options.M2Path)
@@ -333,33 +319,6 @@ func getParametersFromOptions(options *ExecuteOptions, utils mavenUtils) ([]stri
return parameters, nil
}
func downloadSettingsIfURL(settingsFileOption, settingsFile string, utils mavenUtils) (string, error) {
result := settingsFileOption
if strings.HasPrefix(settingsFileOption, "http:") || strings.HasPrefix(settingsFileOption, "https:") {
err := downloadSettingsFromURL(settingsFileOption, settingsFile, utils)
if err != nil {
return "", err
}
result = settingsFile
}
return result, nil
}
// ToDo replace with pkg/maven/settings GetSettingsFile
func downloadSettingsFromURL(url, filename string, utils mavenUtils) error {
exists, _ := utils.FileExists(filename)
if exists {
log.Entry().Infof("Not downloading maven settings file, because it already exists at '%s'", filename)
return nil
}
err := utils.DownloadFile(url, filename, nil, nil)
if err != nil {
return fmt.Errorf("failed to download maven settings from URL '%s' to file '%s': %w",
url, filename, err)
}
return nil
}
func GetTestModulesExcludes() []string {
return getTestModulesExcludes(newUtils())
}

View File

@@ -146,19 +146,6 @@ func TestGetParameters(t *testing.T) {
})
}
func TestDownloadSettingsFromURL(t *testing.T) {
t.Run("should pass if download is successful", func(t *testing.T) {
utils := newMockUtils(false)
err := downloadSettingsFromURL("anyURL", "settings.xml", &utils)
assert.NoError(t, err)
})
t.Run("should fail if download fails", func(t *testing.T) {
utils := newMockUtils(true)
err := downloadSettingsFromURL("anyURL", "settings.xml", &utils)
assert.EqualError(t, err, "failed to download maven settings from URL 'anyURL' to file 'settings.xml': something happened")
})
}
func TestGetTestModulesExcludes(t *testing.T) {
t.Run("Should return excludes for unit- and integration-tests", func(t *testing.T) {
utils := newMockUtils(false)

View File

@@ -1,11 +1,10 @@
package maven
import (
"errors"
"fmt"
piperhttp "github.com/SAP/jenkins-library/pkg/http"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/piperutils"
"net/http"
"os"
"path/filepath"
"strings"
@@ -13,44 +12,81 @@ import (
var getenv = os.Getenv
// SettingsFileType ...
type SettingsFileType int
const (
// GlobalSettingsFile ...
GlobalSettingsFile SettingsFileType = iota
// ProjectSettingsFile ...
ProjectSettingsFile
)
// GetSettingsFile ...
func GetSettingsFile(settingsFileType SettingsFileType, src string, fileUtils piperutils.FileUtils, httpClient piperhttp.Downloader) error {
var dest string
var err error
switch settingsFileType {
case GlobalSettingsFile:
dest, err = getGlobalSettingsFileDest()
case ProjectSettingsFile:
dest, err = getProjectSettingsFileDest()
default:
return errors.New("Invalid SettingsFileType")
type SettingsDownloadUtils interface {
DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error
}
func DownloadAndGetMavenParameters(globalSettingsFile string, projectSettingsFile string, fileUtils piperutils.FileUtils, httpClient SettingsDownloadUtils) ([]string, error) {
mavenArgs := []string{}
if len(globalSettingsFile) > 0 {
globalSettingsFileName, err := downloadSettingsIfURL(globalSettingsFile, ".pipeline/mavenGlobalSettings.xml", fileUtils, httpClient, false)
if err != nil {
return nil, err
}
mavenArgs = append(mavenArgs, "--global-settings", globalSettingsFileName)
} else {
log.Entry().Debugf("Global settings file not provided via configuration.")
}
if len(projectSettingsFile) > 0 {
projectSettingsFileName, err := downloadSettingsIfURL(projectSettingsFile, ".pipeline/mavenProjectSettings.xml", fileUtils, httpClient, false)
if err != nil {
return nil, err
}
mavenArgs = append(mavenArgs, "--settings", projectSettingsFileName)
} else {
log.Entry().Debugf("Project settings file not provided via configuration.")
}
return mavenArgs, nil
}
func DownloadAndCopySettingsFiles(globalSettingsFile string, projectSettingsFile string, fileUtils piperutils.FileUtils, httpClient SettingsDownloadUtils) error {
if len(projectSettingsFile) > 0 {
destination, err := getProjectSettingsFileDest()
if err != nil {
return err
}
if err := downloadAndCopySettingsFile(projectSettingsFile, destination, fileUtils, httpClient); err != nil {
return err
}
} else {
log.Entry().Debugf("Project settings file not provided via configuration.")
}
if len(globalSettingsFile) > 0 {
destination, err := getGlobalSettingsFileDest()
if err != nil {
return err
}
if err := downloadAndCopySettingsFile(globalSettingsFile, destination, fileUtils, httpClient); err != nil {
return err
}
} else {
log.Entry().Debugf("Global settings file not provided via configuration.")
}
return nil
}
func downloadAndCopySettingsFile(src string, dest string, fileUtils piperutils.FileUtils, httpClient SettingsDownloadUtils) error {
if len(src) == 0 {
return fmt.Errorf("Settings file source location not provided")
}
if len(dest) == 0 {
return fmt.Errorf("Settings file destination location not provided")
}
log.Entry().Debugf("Copying file \"%s\" to \"%s\"", src, dest)
if strings.HasPrefix(src, "http:") || strings.HasPrefix(src, "https:") {
if err := httpClient.DownloadFile(src, dest, nil, nil); err != nil {
err := downloadSettingsFromURL(src, dest, fileUtils, httpClient, true)
if err != nil {
return err
}
} else {
@@ -79,6 +115,32 @@ func GetSettingsFile(settingsFileType SettingsFileType, src string, fileUtils pi
return nil
}
func downloadSettingsIfURL(settingsFileOption, settingsFile string, fileUtils piperutils.FileUtils, httpClient SettingsDownloadUtils, overwrite bool) (string, error) {
result := settingsFileOption
if strings.HasPrefix(settingsFileOption, "http:") || strings.HasPrefix(settingsFileOption, "https:") {
err := downloadSettingsFromURL(settingsFileOption, settingsFile, fileUtils, httpClient, overwrite)
if err != nil {
return "", err
}
result = settingsFile
}
return result, nil
}
func downloadSettingsFromURL(url, filename string, fileUtils piperutils.FileUtils, httpClient SettingsDownloadUtils, overwrite bool) error {
exists, _ := fileUtils.FileExists(filename)
if exists && !overwrite {
log.Entry().Infof("Not downloading maven settings file, because it already exists at '%s'", filename)
return nil
}
err := httpClient.DownloadFile(url, filename, nil, nil)
if err != nil {
return fmt.Errorf("failed to download maven settings from URL '%s' to file '%s': %w",
url, filename, err)
}
return nil
}
func getGlobalSettingsFileDest() (string, error) {
m2Home, err := getEnvironmentVariable("M2_HOME")

View File

@@ -24,64 +24,50 @@ func TestSettings(t *testing.T) {
return ""
}
t.Run("Invalid settings file type", func(t *testing.T) {
httpClient := httpMock{}
fileUtils := fileUtilsMock{}
err := GetSettingsFile(-1, "/dev/null", &fileUtils, &httpClient)
if assert.Error(t, err) {
assert.Equal(t, "Invalid SettingsFileType", err.Error())
}
})
t.Run("Settings file source location not provided", func(t *testing.T) {
httpClient := httpMock{}
fileUtils := fileUtilsMock{}
err := GetSettingsFile(1, "", &fileUtils, &httpClient)
err := downloadAndCopySettingsFile("", "foo", &fileUtils, &httpClient)
if assert.Error(t, err) {
assert.Equal(t, "Settings file source location not provided", err.Error())
}
assert.EqualError(t, err, "Settings file source location not provided")
})
t.Run("Retrieve global settings file", func(t *testing.T) {
t.Run("Settings file destination location not provided", func(t *testing.T) {
httpClient := httpMock{}
fileUtils := fileUtilsMock{existingFiles: map[string]string{"/opt/sap/maven/global-settings.xml": ""}}
fileUtils := fileUtilsMock{}
err := GetSettingsFile(GlobalSettingsFile, "/opt/sap/maven/global-settings.xml", &fileUtils, &httpClient)
err := downloadAndCopySettingsFile("/opt/sap/maven/global-settings.xml", "", &fileUtils, &httpClient)
assert.EqualError(t, err, "Settings file destination location not provided")
})
t.Run("Retrieve settings files", func(t *testing.T) {
httpClient := httpMock{}
fileUtils := fileUtilsMock{existingFiles: map[string]string{
"/opt/sap/maven/global-settings.xml": "",
"/opt/sap/maven/project-settings.xml": "",
}}
err := DownloadAndCopySettingsFiles("/opt/sap/maven/global-settings.xml", "/opt/sap/maven/project-settings.xml", &fileUtils, &httpClient)
if assert.NoError(t, err) {
assert.Equal(t, "/usr/share/maven/conf/settings.xml", fileUtils.copiedFiles["/opt/sap/maven/global-settings.xml"])
}
assert.Empty(t, httpClient.downloadedFiles)
})
t.Run("Retrieve project settings file", func(t *testing.T) {
httpClient := httpMock{}
fileUtils := fileUtilsMock{existingFiles: map[string]string{"/opt/sap/maven/project-settings.xml": ""}}
err := GetSettingsFile(ProjectSettingsFile, "/opt/sap/maven/project-settings.xml", &fileUtils, &httpClient)
if assert.NoError(t, err) {
assert.Equal(t, "/home/me/.m2/settings.xml", fileUtils.copiedFiles["/opt/sap/maven/project-settings.xml"])
}
assert.Empty(t, httpClient.downloadedFiles)
})
t.Run("Retrieve global settings file via http", func(t *testing.T) {
t.Run("Retrieve settings file via http", func(t *testing.T) {
httpClient := httpMock{}
fileUtils := fileUtilsMock{}
err := GetSettingsFile(GlobalSettingsFile, "https://example.org/maven/global-settings.xml", &fileUtils, &httpClient)
err := downloadAndCopySettingsFile("https://example.org/maven/global-settings.xml", "/usr/share/maven/conf/settings.xml", &fileUtils, &httpClient)
if assert.NoError(t, err) {
assert.Equal(t, "/usr/share/maven/conf/settings.xml", httpClient.downloadedFiles["https://example.org/maven/global-settings.xml"])
@@ -93,22 +79,10 @@ func TestSettings(t *testing.T) {
httpClient := httpMock{expectedError: fmt.Errorf("Download failed")}
fileUtils := fileUtilsMock{}
err := GetSettingsFile(GlobalSettingsFile, "https://example.org/maven/global-settings.xml", &fileUtils, &httpClient)
err := downloadAndCopySettingsFile("https://example.org/maven/global-settings.xml", "/usr/share/maven/conf/settings.xml", &fileUtils, &httpClient)
if assert.Error(t, err) {
assert.Equal(t, "Download failed", err.Error())
}
})
t.Run("Retrieve project settings file via http", func(t *testing.T) {
httpClient := httpMock{}
fileUtils := fileUtilsMock{}
err := GetSettingsFile(ProjectSettingsFile, "https://example.org/maven/project-settings.xml", &fileUtils, &httpClient)
if assert.NoError(t, err) {
assert.Equal(t, "/home/me/.m2/settings.xml", httpClient.downloadedFiles["https://example.org/maven/project-settings.xml"])
assert.Contains(t, err.Error(), "failed to download maven settings from URL")
}
})
@@ -117,7 +91,7 @@ func TestSettings(t *testing.T) {
httpClient := httpMock{}
fileUtils := fileUtilsMock{}
err := GetSettingsFile(ProjectSettingsFile, "/opt/sap/maven/project-settings.xml", &fileUtils, &httpClient)
err := downloadAndCopySettingsFile("/opt/sap/maven/project-settings.xml", "/home/me/.m2/settings.xml", &fileUtils, &httpClient)
if assert.Error(t, err) {
assert.Contains(t, err.Error(), "Source file '/opt/sap/maven/project-settings.xml' does not exist")
@@ -208,3 +182,7 @@ func (f *fileUtilsMock) Chmod(path string, mode os.FileMode) error {
func (f *fileUtilsMock) Abs(path string) (string, error) {
return "", fmt.Errorf("not implemented. func is only present in order to fullfil the interface contract. Needs to be ajusted in case it gets used.")
}
func (f *fileUtilsMock) Glob(pattern string) (matches []string, err error) {
return nil, fmt.Errorf("not implemented. func is only present in order to fullfil the interface contract. Needs to be ajusted in case it gets used.")
}

View File

@@ -49,7 +49,7 @@ type FilesMock struct {
files map[string]*fileProperties
writtenFiles []string
removedFiles []string
currentDir string
CurrentDir string
Separator string
}
@@ -67,10 +67,10 @@ func (f *FilesMock) init() {
// Relative segments such as "../" are currently NOT supported.
func (f *FilesMock) toAbsPath(path string) string {
if path == "." {
return f.Separator + f.currentDir
return f.Separator + f.CurrentDir
}
if !strings.HasPrefix(path, f.Separator) {
path = f.Separator + filepath.Join(f.currentDir, path)
path = f.Separator + filepath.Join(f.CurrentDir, path)
}
return path
}
@@ -246,7 +246,7 @@ func (f *FilesMock) FileRemove(path string) error {
leaf := filepath.Base(absPath)
absPath = strings.TrimSuffix(absPath, f.Separator+leaf)
if absPath != f.Separator {
relPath := strings.TrimPrefix(absPath, f.Separator+f.currentDir+f.Separator)
relPath := strings.TrimPrefix(absPath, f.Separator+f.CurrentDir+f.Separator)
dirExists, _ := f.DirExists(relPath)
if !dirExists {
f.AddDir(relPath)
@@ -304,7 +304,7 @@ func (f *FilesMock) Chdir(path string) error {
return fmt.Errorf("failed to change current directory into '%s': %w", path, os.ErrNotExist)
}
f.currentDir = strings.TrimLeft(path, f.Separator)
f.CurrentDir = strings.TrimLeft(path, f.Separator)
return nil
}
@@ -368,5 +368,6 @@ func (f *FilesMock) Chmod(path string, mode os.FileMode) error {
}
func (f *FilesMock) Abs(path string) (string, error) {
f.init()
return f.toAbsPath(path), nil
}

View File

@@ -21,6 +21,7 @@ type FileUtils interface {
FileWrite(path string, content []byte, perm os.FileMode) error
MkdirAll(path string, perm os.FileMode) error
Chmod(path string, mode os.FileMode) error
Glob(pattern string) (matches []string, err error)
}
// Files ...

View File

@@ -172,6 +172,39 @@ spec:
- major-minor
- semantic
- full
- name: projectSettingsFile
type: string
description: "Path or url to the mvn settings file that should be used as project settings file."
scope:
- GENERAL
- PARAMETERS
- STAGES
- STEPS
mandatory: false
aliases:
- name: maven/projectSettingsFile
- name: globalSettingsFile
type: string
description: "Path or url to the mvn settings file that should be used as global settings file"
scope:
- GENERAL
- PARAMETERS
- STAGES
- STEPS
mandatory: false
aliases:
- name: maven/globalSettingsFile
- name: m2Path
type: string
description: Path to the location of the local repository that should be used.
scope:
- GENERAL
- STEPS
- STAGES
- PARAMETERS
mandatory: false
aliases:
- name: maven/m2Path
containers:
- name: openjdk
image: openjdk:11

View File

@@ -1,9 +1,15 @@
import com.sap.piper.BuildTool
import com.sap.piper.DownloadCacheUtils
import groovy.transform.Field
import static com.sap.piper.Prerequisites.checkScript
@Field String STEP_NAME = getClass().getName()
@Field String METADATA_FILE = 'metadata/detect.yaml'
void call(Map parameters = [:]) {
final script = checkScript(this, parameters) ?: this
parameters = DownloadCacheUtils.injectDownloadCacheInParameters(script, parameters, BuildTool.MAVEN)
List credentials = [
[type: 'token', id: 'detectTokenCredentialsId', env: ['PIPER_apiToken']]
]