From 9a18489cc41361f615f9ac39503738d47b3723ce Mon Sep 17 00:00:00 2001 From: Daniel Kurzynski Date: Tue, 10 Nov 2020 17:14:55 +0100 Subject: [PATCH] Refactor maven utils and add tests for install artifacts (#2318) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Stephan Aßmus --- cmd/artifactPrepareVersion.go | 45 +++- cmd/detectExecuteScan.go | 6 +- cmd/fortifyExecuteScan.go | 105 ++++---- cmd/fortifyExecuteScan_test.go | 176 +++++++------- cmd/mavenBuild.go | 15 +- cmd/mavenBuild_test.go | 43 ++-- cmd/mavenExecute.go | 35 ++- cmd/mavenExecuteIntegration.go | 35 +-- cmd/mavenExecuteIntegration_test.go | 10 +- cmd/mavenExecuteStaticCodeChecks.go | 37 +-- cmd/mavenExecuteStaticCodeChecks_test.go | 9 + cmd/mavenExecute_test.go | 84 ++++--- cmd/mtaBuild.go | 135 +++++++---- cmd/mtaBuild_test.go | 296 ++++++++--------------- cmd/nexusUpload.go | 47 ++-- cmd/nexusUpload_test.go | 111 +++++---- pkg/maven/maven.go | 97 ++++---- pkg/maven/maven_test.go | 108 +++++---- pkg/maven/settings.go | 39 ++- pkg/maven/settings_test.go | 129 +++------- pkg/mock/fileUtils.go | 11 + pkg/versioning/docker.go | 4 +- pkg/versioning/maven.go | 27 +-- pkg/versioning/maven_test.go | 4 +- pkg/versioning/versioning.go | 21 +- pkg/whitesource/scanMaven.go | 4 +- pkg/whitesource/utils.go | 10 +- 27 files changed, 791 insertions(+), 852 deletions(-) diff --git a/cmd/artifactPrepareVersion.go b/cmd/artifactPrepareVersion.go index 524687299..bde487357 100644 --- a/cmd/artifactPrepareVersion.go +++ b/cmd/artifactPrepareVersion.go @@ -3,6 +3,10 @@ package cmd import ( "bytes" "fmt" + piperhttp "github.com/SAP/jenkins-library/pkg/http" + "github.com/SAP/jenkins-library/pkg/piperutils" + "io" + netHttp "net/http" "os" "strings" "text/template" @@ -42,11 +46,38 @@ func getGitWorktree(repository gitRepository) (gitWorktree, error) { return repository.Worktree() } +type artifactPrepareVersionUtils interface { + Stdout(out io.Writer) + Stderr(err io.Writer) + RunExecutable(e string, p ...string) error + + DownloadFile(url, filename string, header netHttp.Header, cookies []*netHttp.Cookie) error + + Glob(pattern string) (matches []string, err error) + FileExists(filename string) (bool, error) + Copy(src, dest string) (int64, error) + MkdirAll(path string, perm os.FileMode) error +} + +type artifactPrepareVersionUtilsBundle struct { + *command.Command + *piperutils.Files + *piperhttp.Client +} + +func newArtifactPrepareVersionUtilsBundle() artifactPrepareVersionUtils { + utils := artifactPrepareVersionUtilsBundle{ + Command: &command.Command{}, + Files: &piperutils.Files{}, + Client: &piperhttp.Client{}, + } + utils.Stdout(log.Writer()) + utils.Stderr(log.Writer()) + return &utils +} + func artifactPrepareVersion(config artifactPrepareVersionOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *artifactPrepareVersionCommonPipelineEnvironment) { - c := command.Command{} - // reroute command output to logging framework - c.Stdout(log.Writer()) - c.Stderr(log.Writer()) + utils := newArtifactPrepareVersionUtilsBundle() // open local .git repository repository, err := openGit() @@ -54,7 +85,7 @@ func artifactPrepareVersion(config artifactPrepareVersionOptions, telemetryData log.Entry().WithError(err).Fatal("git repository required - none available") } - err = runArtifactPrepareVersion(&config, telemetryData, commonPipelineEnvironment, nil, &c, repository, getGitWorktree) + err = runArtifactPrepareVersion(&config, telemetryData, commonPipelineEnvironment, nil, utils, repository, getGitWorktree) if err != nil { log.Entry().WithError(err).Fatal("artifactPrepareVersion failed") } @@ -62,7 +93,7 @@ func artifactPrepareVersion(config artifactPrepareVersionOptions, telemetryData var sshAgentAuth = ssh.NewSSHAgentAuth -func runArtifactPrepareVersion(config *artifactPrepareVersionOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *artifactPrepareVersionCommonPipelineEnvironment, artifact versioning.Artifact, runner command.ExecRunner, repository gitRepository, getWorktree func(gitRepository) (gitWorktree, error)) error { +func runArtifactPrepareVersion(config *artifactPrepareVersionOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *artifactPrepareVersionCommonPipelineEnvironment, artifact versioning.Artifact, utils artifactPrepareVersionUtils, repository gitRepository, getWorktree func(gitRepository) (gitWorktree, error)) error { telemetryData.Custom1Label = "buildTool" telemetryData.Custom1 = config.BuildTool @@ -82,7 +113,7 @@ func runArtifactPrepareVersion(config *artifactPrepareVersionOptions, telemetryD var err error if artifact == nil { - artifact, err = versioning.GetArtifact(config.BuildTool, config.FilePath, &artifactOpts, runner) + artifact, err = versioning.GetArtifact(config.BuildTool, config.FilePath, &artifactOpts, utils) if err != nil { log.SetErrorCategory(log.ErrorConfiguration) return errors.Wrap(err, "failed to retrieve artifact") diff --git a/cmd/detectExecuteScan.go b/cmd/detectExecuteScan.go index 01de095e4..38cce4f09 100644 --- a/cmd/detectExecuteScan.go +++ b/cmd/detectExecuteScan.go @@ -95,11 +95,11 @@ func runDetect(config detectExecuteScanOptions, utils detectUtils) error { } if config.InstallArtifacts { - err := maven.InstallMavenArtifacts(utils, &maven.EvaluateOptions{ + err := maven.InstallMavenArtifacts(&maven.EvaluateOptions{ M2Path: config.M2Path, ProjectSettingsFile: config.ProjectSettingsFile, GlobalSettingsFile: config.GlobalSettingsFile, - }) + }, utils) if err != nil { return err } @@ -163,7 +163,7 @@ func addDetectArgs(args []string, config detectExecuteScanOptions, utils detectU args = append(args, fmt.Sprintf("--detect.source.path=%v", config.ScanPaths[0])) } - mavenArgs, err := maven.DownloadAndGetMavenParameters(config.GlobalSettingsFile, config.ProjectSettingsFile, utils, utils) + mavenArgs, err := maven.DownloadAndGetMavenParameters(config.GlobalSettingsFile, config.ProjectSettingsFile, utils) if err != nil { return nil, err } diff --git a/cmd/fortifyExecuteScan.go b/cmd/fortifyExecuteScan.go index 4d152f38f..2857c57fe 100644 --- a/cmd/fortifyExecuteScan.go +++ b/cmd/fortifyExecuteScan.go @@ -5,7 +5,7 @@ import ( "encoding/json" "errors" "fmt" - "io" + piperhttp "github.com/SAP/jenkins-library/pkg/http" "io/ioutil" "math" "os" @@ -37,11 +37,35 @@ type pullRequestService interface { ListPullRequestsWithCommit(ctx context.Context, owner, repo, sha string, opts *github.PullRequestListOptions) ([]*github.PullRequest, *github.Response, error) } -type fortifyExecRunner interface { - Stdout(out io.Writer) - Stderr(err io.Writer) +type fortifyUtils interface { + maven.Utils + SetDir(d string) - RunExecutable(e string, p ...string) error + + GetArtifact(buildTool, buildDescriptorFile string, + options *versioning.Options) (versioning.Artifact, error) +} + +type fortifyUtilsBundle struct { + *command.Command + *piperutils.Files + *piperhttp.Client +} + +func (bundle *fortifyUtilsBundle) GetArtifact(buildTool, buildDescriptorFile string, + options *versioning.Options) (versioning.Artifact, error) { + return versioning.GetArtifact(buildTool, buildDescriptorFile, options, bundle) +} + +func newFortifyUtilsBundleBundle() fortifyUtils { + utils := fortifyUtilsBundle{ + Command: &command.Command{}, + Files: &piperutils.Files{}, + Client: &piperhttp.Client{}, + } + utils.Stdout(log.Writer()) + utils.Stderr(log.Writer()) + return &utils } const checkString = "<---CHECK FORTIFY---" @@ -50,40 +74,37 @@ const classpathFileName = "fortify-execute-scan-cp.txt" func fortifyExecuteScan(config fortifyExecuteScanOptions, telemetryData *telemetry.CustomData, influx *fortifyExecuteScanInflux) { auditStatus := map[string]string{} sys := fortify.NewSystemInstance(config.ServerURL, config.APIEndpoint, config.AuthToken, time.Minute*15) - c := &command.Command{} - // reroute command output to logging framework - c.Stdout(log.Entry().Writer()) - c.Stderr(log.Entry().Writer()) + utils := newFortifyUtilsBundleBundle() - artifact, err := determineArtifact(config, c) - if err != nil { - log.Entry().WithError(err).Fatal() - } - - reports, err := runFortifyScan(config, sys, c, artifact, telemetryData, influx, auditStatus) + reports, err := runFortifyScan(config, sys, utils, telemetryData, influx, auditStatus) piperutils.PersistReportsAndLinks("fortifyExecuteScan", config.ModulePath, reports, nil) if err != nil { log.Entry().WithError(err).Fatal("Fortify scan and check failed") } } -func determineArtifact(config fortifyExecuteScanOptions, c *command.Command) (versioning.Artifact, error) { +func determineArtifact(config fortifyExecuteScanOptions, utils fortifyUtils) (versioning.Artifact, error) { versioningOptions := versioning.Options{ M2Path: config.M2Path, GlobalSettingsFile: config.GlobalSettingsFile, ProjectSettingsFile: config.ProjectSettingsFile, } - artifact, err := versioning.GetArtifact(config.BuildTool, config.BuildDescriptorFile, &versioningOptions, c) + artifact, err := utils.GetArtifact(config.BuildTool, config.BuildDescriptorFile, &versioningOptions) if err != nil { return nil, fmt.Errorf("Unable to get artifact from descriptor %v: %w", config.BuildDescriptorFile, err) } return artifact, nil } -func runFortifyScan(config fortifyExecuteScanOptions, sys fortify.System, command fortifyExecRunner, artifact versioning.Artifact, telemetryData *telemetry.CustomData, influx *fortifyExecuteScanInflux, auditStatus map[string]string) ([]piperutils.Path, error) { +func runFortifyScan(config fortifyExecuteScanOptions, sys fortify.System, utils fortifyUtils, telemetryData *telemetry.CustomData, influx *fortifyExecuteScanInflux, auditStatus map[string]string) ([]piperutils.Path, error) { var reports []piperutils.Path log.Entry().Debugf("Running Fortify scan against SSC at %v", config.ServerURL) + + artifact, err := determineArtifact(config, utils) + if err != nil { + log.Entry().WithError(err).Fatal() + } coordinates, err := artifact.GetCoordinates() if err != nil { return reports, fmt.Errorf("unable to get project coordinates from descriptor %v: %w", config.BuildDescriptorFile, err) @@ -133,21 +154,21 @@ func runFortifyScan(config fortifyExecuteScanOptions, sys fortify.System, comman // Create sourceanalyzer command based on configuration buildID := uuid.New().String() - command.SetDir(config.ModulePath) + utils.SetDir(config.ModulePath) os.MkdirAll(fmt.Sprintf("%v/%v", config.ModulePath, "target"), os.ModePerm) if config.UpdateRulePack { - err := command.RunExecutable("fortifyupdate", "-acceptKey", "-acceptSSLCertificate", "-url", config.ServerURL) + err := utils.RunExecutable("fortifyupdate", "-acceptKey", "-acceptSSLCertificate", "-url", config.ServerURL) if err != nil { log.Entry().WithError(err).WithField("serverUrl", config.ServerURL).Fatal("Failed to update rule pack") } - err = command.RunExecutable("fortifyupdate", "-acceptKey", "-acceptSSLCertificate", "-showInstalledRules") + err = utils.RunExecutable("fortifyupdate", "-acceptKey", "-acceptSSLCertificate", "-showInstalledRules") if err != nil { log.Entry().WithError(err).WithField("serverUrl", config.ServerURL).Fatal("Failed to fetch details of installed rule pack") } } - triggerFortifyScan(config, command, buildID, buildLabel, fortifyProjectName) + triggerFortifyScan(config, utils, buildID, buildLabel, fortifyProjectName) reports = append(reports, piperutils.Path{Target: fmt.Sprintf("%vtarget/fortify-scan.*", config.ModulePath)}) reports = append(reports, piperutils.Path{Target: fmt.Sprintf("%vtarget/*.fpr", config.ModulePath)}) @@ -161,7 +182,7 @@ func runFortifyScan(config fortifyExecuteScanOptions, sys fortify.System, comman } else { log.Entry().Debug("Generating XML report") xmlReportName := "fortify_result.xml" - err = command.RunExecutable("ReportGenerator", "-format", "xml", "-f", xmlReportName, "-source", fmt.Sprintf("%vtarget/result.fpr", config.ModulePath)) + err = utils.RunExecutable("ReportGenerator", "-format", "xml", "-f", xmlReportName, "-source", fmt.Sprintf("%vtarget/result.fpr", config.ModulePath)) message = fmt.Sprintf("Failed to generate XML report %v", xmlReportName) if err != nil { reports = append(reports, piperutils.Path{Target: fmt.Sprintf("%vfortify_result.xml", config.ModulePath)}) @@ -493,7 +514,7 @@ func calculateTimeDifferenceToLastUpload(uploadDate models.Iso8601MilliDateTime, return absoluteSeconds } -func executeTemplatedCommand(command fortifyExecRunner, cmdTemplate []string, context map[string]string) { +func executeTemplatedCommand(utils fortifyUtils, cmdTemplate []string, context map[string]string) { for index, cmdTemplatePart := range cmdTemplate { result, err := piperutils.ExecuteTemplate(cmdTemplatePart, context) if err != nil { @@ -501,29 +522,29 @@ func executeTemplatedCommand(command fortifyExecRunner, cmdTemplate []string, co } cmdTemplate[index] = result } - err := command.RunExecutable(cmdTemplate[0], cmdTemplate[1:]...) + err := utils.RunExecutable(cmdTemplate[0], cmdTemplate[1:]...) if err != nil { log.Entry().WithError(err).WithField("command", cmdTemplate).Fatal("Failed to execute command") } } -func autoresolvePipClasspath(executable string, parameters []string, file string, command fortifyExecRunner) string { +func autoresolvePipClasspath(executable string, parameters []string, file string, utils fortifyUtils) string { // redirect stdout and create cp file from command output outfile, err := os.Create(file) if err != nil { log.Entry().WithError(err).Fatal("Failed to create classpath file") } defer outfile.Close() - command.Stdout(outfile) - err = command.RunExecutable(executable, parameters...) + utils.Stdout(outfile) + err = utils.RunExecutable(executable, parameters...) if err != nil { log.Entry().WithError(err).WithField("command", fmt.Sprintf("%v with parameters %v", executable, parameters)).Fatal("Failed to run classpath autodetection command") } - command.Stdout(log.Entry().Writer()) + utils.Stdout(log.Entry().Writer()) return readClasspathFile(file) } -func autoresolveMavenClasspath(config fortifyExecuteScanOptions, file string, command fortifyExecRunner) string { +func autoresolveMavenClasspath(config fortifyExecuteScanOptions, file string, utils fortifyUtils) string { if filepath.IsAbs(file) { log.Entry().Warnf("Passing an absolute path for -Dmdep.outputFile results in the classpath only for the last module in multi-module maven projects.") } @@ -536,7 +557,7 @@ func autoresolveMavenClasspath(config fortifyExecuteScanOptions, file string, co Defines: []string{fmt.Sprintf("-Dmdep.outputFile=%v", file), "-DincludeScope=compile"}, ReturnStdout: false, } - _, err := maven.Execute(&executeOptions, command) + _, err := maven.Execute(&executeOptions, utils) if err != nil { log.Entry().WithError(err).Warn("failed to determine classpath using Maven") } @@ -598,7 +619,7 @@ func removeDuplicates(contents, separator string) string { return contents } -func triggerFortifyScan(config fortifyExecuteScanOptions, command fortifyExecRunner, buildID, buildLabel, buildProject string) { +func triggerFortifyScan(config fortifyExecuteScanOptions, utils fortifyUtils, buildID, buildLabel, buildProject string) { var err error = nil // Do special Python related prep pipVersion := "pip3" @@ -609,7 +630,7 @@ func triggerFortifyScan(config fortifyExecuteScanOptions, command fortifyExecRun classpath := "" if config.BuildTool == "maven" { if config.AutodetectClasspath { - classpath = autoresolveMavenClasspath(config, classpathFileName, command) + classpath = autoresolveMavenClasspath(config, classpathFileName, utils) } config.Translate, err = populateMavenTranslate(&config, classpath) if err != nil { @@ -620,17 +641,17 @@ func triggerFortifyScan(config fortifyExecuteScanOptions, command fortifyExecRun if config.AutodetectClasspath { separator := getSeparator() script := fmt.Sprintf("import sys;p=sys.path;p.remove('');print('%v'.join(p))", separator) - classpath = autoresolvePipClasspath(config.PythonVersion, []string{"-c", script}, classpathFileName, command) + classpath = autoresolvePipClasspath(config.PythonVersion, []string{"-c", script}, classpathFileName, utils) } // install the dev dependencies if len(config.PythonRequirementsFile) > 0 { context := map[string]string{} cmdTemplate := []string{pipVersion, "install", "--user", "-r", config.PythonRequirementsFile} cmdTemplate = append(cmdTemplate, tokenize(config.PythonRequirementsInstallSuffix)...) - executeTemplatedCommand(command, cmdTemplate, context) + executeTemplatedCommand(utils, cmdTemplate, context) } - executeTemplatedCommand(command, tokenize(config.PythonInstallCommand), map[string]string{"Pip": pipVersion}) + executeTemplatedCommand(utils, tokenize(config.PythonInstallCommand), map[string]string{"Pip": pipVersion}) config.Translate, err = populatePipTranslate(&config, classpath) if err != nil { @@ -639,9 +660,9 @@ func triggerFortifyScan(config fortifyExecuteScanOptions, command fortifyExecRun } - translateProject(&config, command, buildID, classpath) + translateProject(&config, utils, buildID, classpath) - scanProject(&config, command, buildID, buildLabel, buildProject) + scanProject(&config, utils, buildID, buildLabel, buildProject) } func populatePipTranslate(config *fortifyExecuteScanOptions, classpath string) (string, error) { @@ -685,7 +706,7 @@ func populateMavenTranslate(config *fortifyExecuteScanOptions, classpath string) return string(translateJSON), err } -func translateProject(config *fortifyExecuteScanOptions, command fortifyExecRunner, buildID, classpath string) { +func translateProject(config *fortifyExecuteScanOptions, utils fortifyUtils, buildID, classpath string) { var translateList []map[string]string json.Unmarshal([]byte(config.Translate), &translateList) log.Entry().Debugf("Translating with options: %v", translateList) @@ -693,11 +714,11 @@ func translateProject(config *fortifyExecuteScanOptions, command fortifyExecRunn if len(classpath) > 0 { translate["autoClasspath"] = classpath } - handleSingleTranslate(config, command, buildID, translate) + handleSingleTranslate(config, utils, buildID, translate) } } -func handleSingleTranslate(config *fortifyExecuteScanOptions, command fortifyExecRunner, buildID string, t map[string]string) { +func handleSingleTranslate(config *fortifyExecuteScanOptions, command fortifyUtils, buildID string, t map[string]string) { if t != nil { log.Entry().Debugf("Handling translate config %v", t) translateOptions := []string{ @@ -718,7 +739,7 @@ func handleSingleTranslate(config *fortifyExecuteScanOptions, command fortifyExe } } -func scanProject(config *fortifyExecuteScanOptions, command fortifyExecRunner, buildID, buildLabel, buildProject string) { +func scanProject(config *fortifyExecuteScanOptions, command fortifyUtils, buildID, buildLabel, buildProject string) { var scanOptions = []string{ "-verbose", "-64", diff --git a/cmd/fortifyExecuteScan_test.go b/cmd/fortifyExecuteScan_test.go index 07459fcd5..46331475a 100644 --- a/cmd/fortifyExecuteScan_test.go +++ b/cmd/fortifyExecuteScan_test.go @@ -5,15 +5,16 @@ import ( "context" "errors" "fmt" + "github.com/SAP/jenkins-library/pkg/mock" "io" "io/ioutil" + "net/http" "os" "path/filepath" "strings" "testing" "time" - "github.com/SAP/jenkins-library/pkg/command" "github.com/SAP/jenkins-library/pkg/fortify" "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/versioning" @@ -24,6 +25,31 @@ import ( "github.com/piper-validation/fortify-client-go/models" ) +type fortifyTestUtilsBundle struct { + *execRunnerMock + *mock.FilesMock + getArtifactShouldFail bool +} + +func (f fortifyTestUtilsBundle) DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error { + panic("not expected to be called in tests") +} + +func (f fortifyTestUtilsBundle) GetArtifact(buildTool, buildDescriptorFile string, options *versioning.Options) (versioning.Artifact, error) { + if f.getArtifactShouldFail { + return nil, fmt.Errorf("build tool '%v' not supported", buildTool) + } + return artifactMock{Coordinates: newCoordinatesMock()}, nil +} + +func newFortifyTestUtilsBundle() fortifyTestUtilsBundle { + utilsBundle := fortifyTestUtilsBundle{ + execRunnerMock: &execRunnerMock{}, + FilesMock: &mock.FilesMock{}, + } + return utilsBundle +} + type artifactMock struct { Coordinates coordinatesMock } @@ -325,27 +351,14 @@ func (er *execRunnerMock) RunExecutable(e string, p ...string) error { return nil } -func TestParametersAreValidated(t *testing.T) { - type parameterTestData struct { - nameOfRun string - config fortifyExecuteScanOptions - expectedError string - } +func TestDetermineArtifact(t *testing.T) { + t.Run("Cannot get artifact without build tool", func(t *testing.T) { + utilsMock := newFortifyTestUtilsBundle() + utilsMock.getArtifactShouldFail = true - testData := []parameterTestData{ - { - nameOfRun: "all parameters empty", - config: fortifyExecuteScanOptions{}, - expectedError: "Unable to get artifact from descriptor : build tool '' not supported", - }, - } - - for _, data := range testData { - t.Run(data.nameOfRun, func(t *testing.T) { - _, err := determineArtifact(data.config, &command.Command{}) - assert.EqualError(t, err, data.expectedError) - }) - } + _, err := determineArtifact(fortifyExecuteScanOptions{}, utilsMock) + assert.EqualError(t, err, "Unable to get artifact from descriptor : build tool '' not supported") + }) } func TestExecutions(t *testing.T) { @@ -374,11 +387,10 @@ func TestExecutions(t *testing.T) { for _, data := range testData { t.Run(data.nameOfRun, func(t *testing.T) { ff := fortifyMock{} - runner := &execRunnerMock{} - artMock := artifactMock{Coordinates: newCoordinatesMock()} + utils := newFortifyTestUtilsBundle() influx := fortifyExecuteScanInflux{} auditStatus := map[string]string{} - reports, _ := runFortifyScan(data.config, &ff, runner, artMock, nil, &influx, auditStatus) + reports, _ := runFortifyScan(data.config, &ff, utils, nil, &influx, auditStatus) if len(data.expectedReports) != data.expectedReportsLength { assert.Fail(t, fmt.Sprintf("Wrong number of reports detected, expected %v, actual %v", data.expectedReportsLength, len(data.expectedReports))) } @@ -500,25 +512,25 @@ func TestTriggerFortifyScan(t *testing.T) { _ = os.RemoveAll(dir) }() - runner := execRunnerMock{} + utils := newFortifyTestUtilsBundle() config := fortifyExecuteScanOptions{ BuildTool: "maven", AutodetectClasspath: true, BuildDescriptorFile: "./pom.xml", Memory: "-Xmx4G -Xms2G", Src: []string{"**/*.xml", "**/*.html", "**/*.jsp", "**/*.js", "src/main/resources/**/*", "src/main/java/**/*"}} - triggerFortifyScan(config, &runner, "test", "testLabel", "my.group-myartifact") + triggerFortifyScan(config, &utils, "test", "testLabel", "my.group-myartifact") - assert.Equal(t, 3, runner.numExecutions) + assert.Equal(t, 3, utils.numExecutions) - assert.Equal(t, "mvn", runner.executions[0].executable) - assert.Equal(t, []string{"--file", "./pom.xml", "-Dmdep.outputFile=fortify-execute-scan-cp.txt", "-DincludeScope=compile", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "dependency:build-classpath"}, runner.executions[0].parameters) + assert.Equal(t, "mvn", utils.executions[0].executable) + assert.Equal(t, []string{"--file", "./pom.xml", "-Dmdep.outputFile=fortify-execute-scan-cp.txt", "-DincludeScope=compile", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "dependency:build-classpath"}, utils.executions[0].parameters) - assert.Equal(t, "sourceanalyzer", runner.executions[1].executable) - assert.Equal(t, []string{"-verbose", "-64", "-b", "test", "-Xmx4G", "-Xms2G", "-cp", "some.jar;someother.jar", "**/*.xml", "**/*.html", "**/*.jsp", "**/*.js", "src/main/resources/**/*", "src/main/java/**/*"}, runner.executions[1].parameters) + assert.Equal(t, "sourceanalyzer", utils.executions[1].executable) + assert.Equal(t, []string{"-verbose", "-64", "-b", "test", "-Xmx4G", "-Xms2G", "-cp", "some.jar;someother.jar", "**/*.xml", "**/*.html", "**/*.jsp", "**/*.js", "src/main/resources/**/*", "src/main/java/**/*"}, utils.executions[1].parameters) - assert.Equal(t, "sourceanalyzer", runner.executions[2].executable) - assert.Equal(t, []string{"-verbose", "-64", "-b", "test", "-scan", "-Xmx4G", "-Xms2G", "-build-label", "testLabel", "-build-project", "my.group-myartifact", "-logfile", "target/fortify-scan.log", "-f", "target/result.fpr"}, runner.executions[2].parameters) + assert.Equal(t, "sourceanalyzer", utils.executions[2].executable) + assert.Equal(t, []string{"-verbose", "-64", "-b", "test", "-scan", "-Xmx4G", "-Xms2G", "-build-label", "testLabel", "-build-project", "my.group-myartifact", "-logfile", "target/fortify-scan.log", "-f", "target/result.fpr"}, utils.executions[2].parameters) }) t.Run("pip", func(t *testing.T) { @@ -534,28 +546,28 @@ func TestTriggerFortifyScan(t *testing.T) { _ = os.RemoveAll(dir) }() - runner := execRunnerMock{} + utils := newFortifyTestUtilsBundle() config := fortifyExecuteScanOptions{BuildTool: "pip", PythonVersion: "python2", AutodetectClasspath: true, BuildDescriptorFile: "./setup.py", PythonRequirementsFile: "./requirements.txt", PythonInstallCommand: "pip2 install --user", Memory: "-Xmx4G -Xms2G"} - triggerFortifyScan(config, &runner, "test", "testLabel", "") + triggerFortifyScan(config, &utils, "test", "testLabel", "") - assert.Equal(t, 5, runner.numExecutions) + assert.Equal(t, 5, utils.numExecutions) - assert.Equal(t, "python2", runner.executions[0].executable) + assert.Equal(t, "python2", utils.executions[0].executable) separator := getSeparator() template := fmt.Sprintf("import sys;p=sys.path;p.remove('');print('%v'.join(p))", separator) - assert.Equal(t, []string{"-c", template}, runner.executions[0].parameters) + assert.Equal(t, []string{"-c", template}, utils.executions[0].parameters) - assert.Equal(t, "pip2", runner.executions[1].executable) - assert.Equal(t, []string{"install", "--user", "-r", "./requirements.txt", ""}, runner.executions[1].parameters) + assert.Equal(t, "pip2", utils.executions[1].executable) + assert.Equal(t, []string{"install", "--user", "-r", "./requirements.txt", ""}, utils.executions[1].parameters) - assert.Equal(t, "pip2", runner.executions[2].executable) - assert.Equal(t, []string{"install", "--user"}, runner.executions[2].parameters) + assert.Equal(t, "pip2", utils.executions[2].executable) + assert.Equal(t, []string{"install", "--user"}, utils.executions[2].parameters) - assert.Equal(t, "sourceanalyzer", runner.executions[3].executable) - assert.Equal(t, []string{"-verbose", "-64", "-b", "test", "-Xmx4G", "-Xms2G", "-python-path", "/usr/lib/python35.zip;/usr/lib/python3.5;/usr/lib/python3.5/plat-x86_64-linux-gnu;/usr/lib/python3.5/lib-dynload;/home/piper/.local/lib/python3.5/site-packages;/usr/local/lib/python3.5/dist-packages;/usr/lib/python3/dist-packages;./lib", "-exclude", fmt.Sprintf("./**/tests/**/*%s./**/setup.py", separator), "./**/*"}, runner.executions[3].parameters) + assert.Equal(t, "sourceanalyzer", utils.executions[3].executable) + assert.Equal(t, []string{"-verbose", "-64", "-b", "test", "-Xmx4G", "-Xms2G", "-python-path", "/usr/lib/python35.zip;/usr/lib/python3.5;/usr/lib/python3.5/plat-x86_64-linux-gnu;/usr/lib/python3.5/lib-dynload;/home/piper/.local/lib/python3.5/site-packages;/usr/local/lib/python3.5/dist-packages;/usr/lib/python3/dist-packages;./lib", "-exclude", fmt.Sprintf("./**/tests/**/*%s./**/setup.py", separator), "./**/*"}, utils.executions[3].parameters) - assert.Equal(t, "sourceanalyzer", runner.executions[4].executable) - assert.Equal(t, []string{"-verbose", "-64", "-b", "test", "-scan", "-Xmx4G", "-Xms2G", "-build-label", "testLabel", "-logfile", "target/fortify-scan.log", "-f", "target/result.fpr"}, runner.executions[4].parameters) + assert.Equal(t, "sourceanalyzer", utils.executions[4].executable) + assert.Equal(t, []string{"-verbose", "-64", "-b", "test", "-scan", "-Xmx4G", "-Xms2G", "-build-label", "testLabel", "-logfile", "target/fortify-scan.log", "-f", "target/result.fpr"}, utils.executions[4].parameters) }) } @@ -669,13 +681,13 @@ func TestCalculateTimeDifferenceToLastUpload(t *testing.T) { } func TestExecuteTemplatedCommand(t *testing.T) { - runner := execRunnerMock{} + utils := newFortifyTestUtilsBundle() template := []string{"{{.Executable}}", "-c", "{{.Param}}"} context := map[string]string{"Executable": "test.cmd", "Param": "abcd"} - executeTemplatedCommand(&runner, template, context) + executeTemplatedCommand(&utils, template, context) - assert.Equal(t, "test.cmd", runner.executions[0].executable) - assert.Equal(t, []string{"-c", "abcd"}, runner.executions[0].parameters) + assert.Equal(t, "test.cmd", utils.executions[0].executable) + assert.Equal(t, []string{"-c", "abcd"}, utils.executions[0].parameters) } func TestDeterminePullRequestMerge(t *testing.T) { @@ -717,35 +729,35 @@ func TestDeterminePullRequestMergeGithub(t *testing.T) { func TestTranslateProject(t *testing.T) { t.Run("python", func(t *testing.T) { - execRunner := execRunnerMock{} + utils := newFortifyTestUtilsBundle() config := fortifyExecuteScanOptions{BuildTool: "pip", Memory: "-Xmx4G", Translate: `[{"pythonPath":"./some/path","src":"./**/*","exclude":"./tests/**/*"}]`} - translateProject(&config, &execRunner, "/commit/7267658798797", "") - assert.Equal(t, "sourceanalyzer", execRunner.executions[0].executable, "Expected different executable") - assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-Xmx4G", "-python-path", "./some/path", "-exclude", "./tests/**/*", "./**/*"}, execRunner.executions[0].parameters, "Expected different parameters") + translateProject(&config, &utils, "/commit/7267658798797", "") + assert.Equal(t, "sourceanalyzer", utils.executions[0].executable, "Expected different executable") + assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-Xmx4G", "-python-path", "./some/path", "-exclude", "./tests/**/*", "./**/*"}, utils.executions[0].parameters, "Expected different parameters") }) t.Run("asp", func(t *testing.T) { - execRunner := execRunnerMock{} + utils := newFortifyTestUtilsBundle() config := fortifyExecuteScanOptions{BuildTool: "windows", Memory: "-Xmx6G", Translate: `[{"aspnetcore":"true","dotNetCoreVersion":"3.5","exclude":"./tests/**/*","libDirs":"tmp/","src":"./**/*"}]`} - translateProject(&config, &execRunner, "/commit/7267658798797", "") - assert.Equal(t, "sourceanalyzer", execRunner.executions[0].executable, "Expected different executable") - assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-Xmx6G", "-aspnetcore", "-dotnet-core-version", "3.5", "-libdirs", "tmp/", "-exclude", "./tests/**/*", "./**/*"}, execRunner.executions[0].parameters, "Expected different parameters") + translateProject(&config, &utils, "/commit/7267658798797", "") + assert.Equal(t, "sourceanalyzer", utils.executions[0].executable, "Expected different executable") + assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-Xmx6G", "-aspnetcore", "-dotnet-core-version", "3.5", "-libdirs", "tmp/", "-exclude", "./tests/**/*", "./**/*"}, utils.executions[0].parameters, "Expected different parameters") }) t.Run("java", func(t *testing.T) { - execRunner := execRunnerMock{} + utils := newFortifyTestUtilsBundle() config := fortifyExecuteScanOptions{BuildTool: "maven", Memory: "-Xmx2G", Translate: `[{"classpath":"./classes/*.jar","extdirs":"tmp/","jdk":"1.8.0-21","source":"1.8","sourcepath":"src/ext/","src":"./**/*"}]`} - translateProject(&config, &execRunner, "/commit/7267658798797", "") - assert.Equal(t, "sourceanalyzer", execRunner.executions[0].executable, "Expected different executable") - assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-Xmx2G", "-cp", "./classes/*.jar", "-extdirs", "tmp/", "-source", "1.8", "-jdk", "1.8.0-21", "-sourcepath", "src/ext/", "./**/*"}, execRunner.executions[0].parameters, "Expected different parameters") + translateProject(&config, &utils, "/commit/7267658798797", "") + assert.Equal(t, "sourceanalyzer", utils.executions[0].executable, "Expected different executable") + assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-Xmx2G", "-cp", "./classes/*.jar", "-extdirs", "tmp/", "-source", "1.8", "-jdk", "1.8.0-21", "-sourcepath", "src/ext/", "./**/*"}, utils.executions[0].parameters, "Expected different parameters") }) t.Run("auto classpath", func(t *testing.T) { - execRunner := execRunnerMock{} + utils := newFortifyTestUtilsBundle() config := fortifyExecuteScanOptions{BuildTool: "maven", Memory: "-Xmx2G", Translate: `[{"classpath":"./classes/*.jar", "extdirs":"tmp/","jdk":"1.8.0-21","source":"1.8","sourcepath":"src/ext/","src":"./**/*"}]`} - translateProject(&config, &execRunner, "/commit/7267658798797", "./WEB-INF/lib/*.jar") - assert.Equal(t, "sourceanalyzer", execRunner.executions[0].executable, "Expected different executable") - assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-Xmx2G", "-cp", "./WEB-INF/lib/*.jar", "-extdirs", "tmp/", "-source", "1.8", "-jdk", "1.8.0-21", "-sourcepath", "src/ext/", "./**/*"}, execRunner.executions[0].parameters, "Expected different parameters") + translateProject(&config, &utils, "/commit/7267658798797", "./WEB-INF/lib/*.jar") + assert.Equal(t, "sourceanalyzer", utils.executions[0].executable, "Expected different executable") + assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-Xmx2G", "-cp", "./WEB-INF/lib/*.jar", "-extdirs", "tmp/", "-source", "1.8", "-jdk", "1.8.0-21", "-sourcepath", "src/ext/", "./**/*"}, utils.executions[0].parameters, "Expected different parameters") }) } @@ -753,45 +765,45 @@ func TestScanProject(t *testing.T) { config := fortifyExecuteScanOptions{Memory: "-Xmx4G"} t.Run("normal", func(t *testing.T) { - execRunner := execRunnerMock{} - scanProject(&config, &execRunner, "/commit/7267658798797", "label", "my.group-myartifact") - assert.Equal(t, "sourceanalyzer", execRunner.executions[0].executable, "Expected different executable") - assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-scan", "-Xmx4G", "-build-label", "label", "-build-project", "my.group-myartifact", "-logfile", "target/fortify-scan.log", "-f", "target/result.fpr"}, execRunner.executions[0].parameters, "Expected different parameters") + utils := newFortifyTestUtilsBundle() + scanProject(&config, &utils, "/commit/7267658798797", "label", "my.group-myartifact") + assert.Equal(t, "sourceanalyzer", utils.executions[0].executable, "Expected different executable") + assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-scan", "-Xmx4G", "-build-label", "label", "-build-project", "my.group-myartifact", "-logfile", "target/fortify-scan.log", "-f", "target/result.fpr"}, utils.executions[0].parameters, "Expected different parameters") }) t.Run("quick", func(t *testing.T) { - execRunner := execRunnerMock{} + utils := newFortifyTestUtilsBundle() config.QuickScan = true - scanProject(&config, &execRunner, "/commit/7267658798797", "", "") - assert.Equal(t, "sourceanalyzer", execRunner.executions[0].executable, "Expected different executable") - assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-scan", "-Xmx4G", "-quick", "-logfile", "target/fortify-scan.log", "-f", "target/result.fpr"}, execRunner.executions[0].parameters, "Expected different parameters") + scanProject(&config, &utils, "/commit/7267658798797", "", "") + assert.Equal(t, "sourceanalyzer", utils.executions[0].executable, "Expected different executable") + assert.Equal(t, []string{"-verbose", "-64", "-b", "/commit/7267658798797", "-scan", "-Xmx4G", "-quick", "-logfile", "target/fortify-scan.log", "-f", "target/result.fpr"}, utils.executions[0].parameters, "Expected different parameters") }) } func TestAutoresolveClasspath(t *testing.T) { t.Run("success pip", func(t *testing.T) { - execRunner := execRunnerMock{} + utils := newFortifyTestUtilsBundle() dir, err := ioutil.TempDir("", "classpath") assert.NoError(t, err, "Unexpected error detected") defer os.RemoveAll(dir) file := filepath.Join(dir, "cp.txt") - result := autoresolvePipClasspath("python2", []string{"-c", "import sys;p=sys.path;p.remove('');print(';'.join(p))"}, file, &execRunner) - assert.Equal(t, "python2", execRunner.executions[0].executable, "Expected different executable") - assert.Equal(t, []string{"-c", "import sys;p=sys.path;p.remove('');print(';'.join(p))"}, execRunner.executions[0].parameters, "Expected different parameters") + result := autoresolvePipClasspath("python2", []string{"-c", "import sys;p=sys.path;p.remove('');print(';'.join(p))"}, file, &utils) + assert.Equal(t, "python2", utils.executions[0].executable, "Expected different executable") + assert.Equal(t, []string{"-c", "import sys;p=sys.path;p.remove('');print(';'.join(p))"}, utils.executions[0].parameters, "Expected different parameters") assert.Equal(t, "/usr/lib/python35.zip;/usr/lib/python3.5;/usr/lib/python3.5/plat-x86_64-linux-gnu;/usr/lib/python3.5/lib-dynload;/home/piper/.local/lib/python3.5/site-packages;/usr/local/lib/python3.5/dist-packages;/usr/lib/python3/dist-packages;./lib", result, "Expected different result") }) t.Run("success maven", func(t *testing.T) { - execRunner := execRunnerMock{} + utils := newFortifyTestUtilsBundle() dir, err := ioutil.TempDir("", "classpath") assert.NoError(t, err, "Unexpected error detected") defer os.RemoveAll(dir) file := filepath.Join(dir, "cp.txt") - result := autoresolveMavenClasspath(fortifyExecuteScanOptions{BuildDescriptorFile: "pom.xml"}, file, &execRunner) - assert.Equal(t, "mvn", execRunner.executions[0].executable, "Expected different executable") - assert.Equal(t, []string{"--file", "pom.xml", fmt.Sprintf("-Dmdep.outputFile=%v", file), "-DincludeScope=compile", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "dependency:build-classpath"}, execRunner.executions[0].parameters, "Expected different parameters") + result := autoresolveMavenClasspath(fortifyExecuteScanOptions{BuildDescriptorFile: "pom.xml"}, file, &utils) + assert.Equal(t, "mvn", utils.executions[0].executable, "Expected different executable") + assert.Equal(t, []string{"--file", "pom.xml", fmt.Sprintf("-Dmdep.outputFile=%v", file), "-DincludeScope=compile", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "dependency:build-classpath"}, utils.executions[0].parameters, "Expected different parameters") assert.Equal(t, "some.jar;someother.jar", result, "Expected different result") }) } diff --git a/cmd/mavenBuild.go b/cmd/mavenBuild.go index e318d362a..de5023bed 100644 --- a/cmd/mavenBuild.go +++ b/cmd/mavenBuild.go @@ -1,28 +1,21 @@ package cmd import ( - "github.com/SAP/jenkins-library/pkg/command" "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/maven" - "github.com/SAP/jenkins-library/pkg/piperutils" "github.com/SAP/jenkins-library/pkg/telemetry" ) func mavenBuild(config mavenBuildOptions, telemetryData *telemetry.CustomData) { - c := command.Command{} + utils := maven.NewUtilsBundle() - c.Stdout(log.Writer()) - c.Stderr(log.Writer()) - - utils := piperutils.Files{} - - err := runMavenBuild(&config, telemetryData, &c, &utils) + err := runMavenBuild(&config, telemetryData, utils) if err != nil { log.Entry().WithError(err).Fatal("step execution failed") } } -func runMavenBuild(config *mavenBuildOptions, telemetryData *telemetry.CustomData, command command.ExecRunner, utils piperutils.FileUtils) error { +func runMavenBuild(config *mavenBuildOptions, telemetryData *telemetry.CustomData, utils maven.Utils) error { var flags = []string{"-update-snapshots", "--batch-mode"} exists, _ := utils.FileExists("integration-tests/pom.xml") @@ -57,6 +50,6 @@ func runMavenBuild(config *mavenBuildOptions, telemetryData *telemetry.CustomDat LogSuccessfulMavenTransfers: config.LogSuccessfulMavenTransfers, } - _, err := maven.Execute(&mavenOptions, command) + _, err := maven.Execute(&mavenOptions, utils) return err } diff --git a/cmd/mavenBuild_test.go b/cmd/mavenBuild_test.go index 4dad3ff51..816571b2a 100644 --- a/cmd/mavenBuild_test.go +++ b/cmd/mavenBuild_test.go @@ -1,68 +1,59 @@ package cmd import ( - "github.com/SAP/jenkins-library/pkg/mock" "github.com/stretchr/testify/assert" "testing" ) func TestMavenBuild(t *testing.T) { t.Run("mavenBuild should install the artifact", func(t *testing.T) { - execMockRunner := mock.ExecMockRunner{} - - mockedUtils := mock.FilesMock{} + mockedUtils := newMavenMockUtils() config := mavenBuildOptions{} - err := runMavenBuild(&config, nil, &execMockRunner, &mockedUtils) + err := runMavenBuild(&config, nil, &mockedUtils) assert.Nil(t, err) - assert.Equal(t, execMockRunner.Calls[0].Exec, "mvn") - assert.Contains(t, execMockRunner.Calls[0].Params, "install") + assert.Equal(t, mockedUtils.Calls[0].Exec, "mvn") + assert.Contains(t, mockedUtils.Calls[0].Params, "install") }) t.Run("mavenBuild should skip integration tests", func(t *testing.T) { - execMockRunner := mock.ExecMockRunner{} - - mockedUtils := mock.FilesMock{} + mockedUtils := newMavenMockUtils() mockedUtils.AddFile("integration-tests/pom.xml", []byte{}) config := mavenBuildOptions{} - err := runMavenBuild(&config, nil, &execMockRunner, &mockedUtils) + err := runMavenBuild(&config, nil, &mockedUtils) assert.Nil(t, err) - assert.Equal(t, execMockRunner.Calls[0].Exec, "mvn") - assert.Contains(t, execMockRunner.Calls[0].Params, "-pl", "!integration-tests") + assert.Equal(t, mockedUtils.Calls[0].Exec, "mvn") + assert.Contains(t, mockedUtils.Calls[0].Params, "-pl", "!integration-tests") }) t.Run("mavenBuild should flatten", func(t *testing.T) { - execMockRunner := mock.ExecMockRunner{} - - mockedUtils := mock.FilesMock{} + mockedUtils := newMavenMockUtils() config := mavenBuildOptions{Flatten: true} - err := runMavenBuild(&config, nil, &execMockRunner, &mockedUtils) + err := runMavenBuild(&config, nil, &mockedUtils) assert.Nil(t, err) - assert.Contains(t, execMockRunner.Calls[0].Params, "flatten:flatten") - assert.Contains(t, execMockRunner.Calls[0].Params, "-Dflatten.mode=resolveCiFriendliesOnly") - assert.Contains(t, execMockRunner.Calls[0].Params, "-DupdatePomFile=true") + assert.Contains(t, mockedUtils.Calls[0].Params, "flatten:flatten") + assert.Contains(t, mockedUtils.Calls[0].Params, "-Dflatten.mode=resolveCiFriendliesOnly") + assert.Contains(t, mockedUtils.Calls[0].Params, "-DupdatePomFile=true") }) t.Run("mavenBuild should run only verify", func(t *testing.T) { - execMockRunner := mock.ExecMockRunner{} - - mockedUtils := mock.FilesMock{} + mockedUtils := newMavenMockUtils() config := mavenBuildOptions{Verify: true} - err := runMavenBuild(&config, nil, &execMockRunner, &mockedUtils) + err := runMavenBuild(&config, nil, &mockedUtils) assert.Nil(t, err) - assert.Contains(t, execMockRunner.Calls[0].Params, "verify") - assert.NotContains(t, execMockRunner.Calls[0].Params, "install") + assert.Contains(t, mockedUtils.Calls[0].Params, "verify") + assert.NotContains(t, mockedUtils.Calls[0].Params, "install") }) } diff --git a/cmd/mavenExecute.go b/cmd/mavenExecute.go index 09ebad72b..87d5fb109 100644 --- a/cmd/mavenExecute.go +++ b/cmd/mavenExecute.go @@ -2,24 +2,45 @@ package cmd import ( "github.com/SAP/jenkins-library/pkg/command" + piperhttp "github.com/SAP/jenkins-library/pkg/http" "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/maven" - "io/ioutil" + "github.com/SAP/jenkins-library/pkg/piperutils" + "os" "github.com/SAP/jenkins-library/pkg/telemetry" ) -var writeFile = ioutil.WriteFile +type mavenExecuteUtils interface { + maven.Utils + FileWrite(path string, content []byte, perm os.FileMode) error +} + +type mavenExecuteUtilsBundle struct { + *command.Command + *piperutils.Files + *piperhttp.Client +} + +func newMavenExecuteUtilsBundle() mavenExecuteUtils { + utils := mavenExecuteUtilsBundle{ + Command: &command.Command{}, + Files: &piperutils.Files{}, + Client: &piperhttp.Client{}, + } + utils.Stdout(log.Writer()) + utils.Stderr(log.Writer()) + return &utils +} func mavenExecute(config mavenExecuteOptions, _ *telemetry.CustomData) { - runner := command.Command{} - err := runMavenExecute(config, &runner) + err := runMavenExecute(config, newMavenExecuteUtilsBundle()) if err != nil { log.Entry().WithError(err).Fatal("step execution failed") } } -func runMavenExecute(config mavenExecuteOptions, runner command.ExecRunner) error { +func runMavenExecute(config mavenExecuteOptions, utils mavenExecuteUtils) error { options := maven.ExecuteOptions{ PomPath: config.PomPath, ProjectSettingsFile: config.ProjectSettingsFile, @@ -32,9 +53,9 @@ func runMavenExecute(config mavenExecuteOptions, runner command.ExecRunner) erro ReturnStdout: config.ReturnStdout, } - output, err := maven.Execute(&options, runner) + output, err := maven.Execute(&options, utils) if err == nil && config.ReturnStdout { - err = writeFile(".pipeline/maven_output.txt", []byte(output), 0644) + err = utils.FileWrite(".pipeline/maven_output.txt", []byte(output), 0644) } return err } diff --git a/cmd/mavenExecuteIntegration.go b/cmd/mavenExecuteIntegration.go index a827a2952..8530eac06 100644 --- a/cmd/mavenExecuteIntegration.go +++ b/cmd/mavenExecuteIntegration.go @@ -2,50 +2,23 @@ package cmd import ( "fmt" - "github.com/SAP/jenkins-library/pkg/command" "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/maven" - "github.com/SAP/jenkins-library/pkg/piperutils" "github.com/SAP/jenkins-library/pkg/telemetry" - "io" "path/filepath" "strconv" "strings" "unicode" ) -type mavenExecuteIntegrationUtils interface { - Stdout(out io.Writer) - Stderr(err io.Writer) - RunExecutable(e string, p ...string) error - - FileExists(filename string) (bool, error) -} - -type mavenExecuteIntegrationUtilsBundle struct { - *command.Command - *piperutils.Files -} - -func newMavenExecuteIntegrationUtils() mavenExecuteIntegrationUtils { - utils := mavenExecuteIntegrationUtilsBundle{ - Command: &command.Command{}, - Files: &piperutils.Files{}, - } - utils.Stdout(log.Writer()) - utils.Stderr(log.Writer()) - return &utils -} - func mavenExecuteIntegration(config mavenExecuteIntegrationOptions, _ *telemetry.CustomData) { - utils := newMavenExecuteIntegrationUtils() - err := runMavenExecuteIntegration(&config, utils) + err := runMavenExecuteIntegration(&config, maven.NewUtilsBundle()) if err != nil { log.Entry().WithError(err).Fatal("step execution failed") } } -func runMavenExecuteIntegration(config *mavenExecuteIntegrationOptions, utils mavenExecuteIntegrationUtils) error { +func runMavenExecuteIntegration(config *mavenExecuteIntegrationOptions, utils maven.Utils) error { pomPath := filepath.Join("integration-tests", "pom.xml") hasIntegrationTestsModule, _ := utils.FileExists(pomPath) if !hasIntegrationTestsModule { @@ -53,11 +26,11 @@ func runMavenExecuteIntegration(config *mavenExecuteIntegrationOptions, utils ma } if config.InstallArtifacts { - err := maven.InstallMavenArtifacts(utils, &maven.EvaluateOptions{ + err := maven.InstallMavenArtifacts(&maven.EvaluateOptions{ M2Path: config.M2Path, ProjectSettingsFile: config.ProjectSettingsFile, GlobalSettingsFile: config.GlobalSettingsFile, - }) + }, utils) if err != nil { return err } diff --git a/cmd/mavenExecuteIntegration_test.go b/cmd/mavenExecuteIntegration_test.go index 6bae9cdac..db4367fa6 100644 --- a/cmd/mavenExecuteIntegration_test.go +++ b/cmd/mavenExecuteIntegration_test.go @@ -1,8 +1,10 @@ package cmd import ( + "errors" "github.com/SAP/jenkins-library/pkg/mock" "github.com/stretchr/testify/assert" + "net/http" "path/filepath" "testing" ) @@ -12,6 +14,10 @@ type mavenExecuteIntegrationTestUtilsBundle struct { *mock.FilesMock } +func (m mavenExecuteIntegrationTestUtilsBundle) DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error { + return errors.New("Test should not download files.") +} + func TestIntegrationTestModuleDoesNotExist(t *testing.T) { t.Parallel() utils := newMavenIntegrationTestsUtilsBundle() @@ -130,10 +136,10 @@ func TestValidateForkCount(t *testing.T) { } } -func newMavenIntegrationTestsUtilsBundle() mavenExecuteIntegrationTestUtilsBundle { +func newMavenIntegrationTestsUtilsBundle() *mavenExecuteIntegrationTestUtilsBundle { utilsBundle := mavenExecuteIntegrationTestUtilsBundle{ ExecMockRunner: &mock.ExecMockRunner{}, FilesMock: &mock.FilesMock{}, } - return utilsBundle + return &utilsBundle } diff --git a/cmd/mavenExecuteStaticCodeChecks.go b/cmd/mavenExecuteStaticCodeChecks.go index 45016e248..866cf0dcd 100644 --- a/cmd/mavenExecuteStaticCodeChecks.go +++ b/cmd/mavenExecuteStaticCodeChecks.go @@ -1,47 +1,20 @@ package cmd import ( - "github.com/SAP/jenkins-library/pkg/command" "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/maven" - "github.com/SAP/jenkins-library/pkg/piperutils" "github.com/SAP/jenkins-library/pkg/telemetry" - "io" "strconv" ) -type mavenStaticCodeChecksUtils interface { - Stdout(out io.Writer) - Stderr(err io.Writer) - RunExecutable(e string, p ...string) error - - FileExists(filename string) (bool, error) -} - -type mavenStaticCodeChecksUtilsBundle struct { - *command.Command - *piperutils.Files -} - -func newStaticCodeChecksUtils() mavenStaticCodeChecksUtils { - utils := mavenStaticCodeChecksUtilsBundle{ - Command: &command.Command{}, - Files: &piperutils.Files{}, - } - utils.Stdout(log.Writer()) - utils.Stderr(log.Writer()) - return &utils -} - func mavenExecuteStaticCodeChecks(config mavenExecuteStaticCodeChecksOptions, telemetryData *telemetry.CustomData) { - utils := newStaticCodeChecksUtils() - err := runMavenStaticCodeChecks(&config, telemetryData, utils) + err := runMavenStaticCodeChecks(&config, telemetryData, maven.NewUtilsBundle()) if err != nil { log.Entry().WithError(err).Fatal("step execution failed") } } -func runMavenStaticCodeChecks(config *mavenExecuteStaticCodeChecksOptions, telemetryData *telemetry.CustomData, utils mavenStaticCodeChecksUtils) error { +func runMavenStaticCodeChecks(config *mavenExecuteStaticCodeChecksOptions, telemetryData *telemetry.CustomData, utils maven.Utils) error { var defines []string var goals []string @@ -51,17 +24,17 @@ func runMavenStaticCodeChecks(config *mavenExecuteStaticCodeChecksOptions, telem } if config.InstallArtifacts { - err := maven.InstallMavenArtifacts(utils, &maven.EvaluateOptions{ + err := maven.InstallMavenArtifacts(&maven.EvaluateOptions{ M2Path: config.M2Path, ProjectSettingsFile: config.ProjectSettingsFile, GlobalSettingsFile: config.GlobalSettingsFile, - }) + }, utils) if err != nil { return err } } - if testModulesExcludes := maven.GetTestModulesExcludes(); testModulesExcludes != nil { + if testModulesExcludes := maven.GetTestModulesExcludes(utils); testModulesExcludes != nil { defines = append(defines, testModulesExcludes...) } if config.MavenModulesExcludes != nil { diff --git a/cmd/mavenExecuteStaticCodeChecks_test.go b/cmd/mavenExecuteStaticCodeChecks_test.go index 50f6d3502..dce2a94a3 100644 --- a/cmd/mavenExecuteStaticCodeChecks_test.go +++ b/cmd/mavenExecuteStaticCodeChecks_test.go @@ -1,6 +1,8 @@ package cmd import ( + "errors" + "net/http" "os" "testing" @@ -13,6 +15,9 @@ import ( func TestRunMavenStaticCodeChecks(t *testing.T) { t.Run("should run spotBugs and pmd with all configured options", func(t *testing.T) { utils := newMavenStaticCodeChecksTestUtilsBundle() + utils.FilesMock.AddFile("unit-tests/pom.xml", []byte(` `)) + utils.FilesMock.AddFile("integration-tests/pom.xml", []byte(` `)) + config := mavenExecuteStaticCodeChecksOptions{ SpotBugs: true, Pmd: true, @@ -126,6 +131,10 @@ type mavenStaticCodeChecksTestUtilsBundle struct { *mock.FilesMock } +func (m mavenStaticCodeChecksTestUtilsBundle) DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error { + return errors.New("Test should not download files.") +} + func newMavenStaticCodeChecksTestUtilsBundle() mavenStaticCodeChecksTestUtilsBundle { utilsBundle := mavenStaticCodeChecksTestUtilsBundle{ ExecMockRunner: &mock.ExecMockRunner{}, diff --git a/cmd/mavenExecute_test.go b/cmd/mavenExecute_test.go index d9fb08603..d9d9ce23a 100644 --- a/cmd/mavenExecute_test.go +++ b/cmd/mavenExecute_test.go @@ -1,12 +1,34 @@ package cmd import ( + "errors" "github.com/SAP/jenkins-library/pkg/mock" "github.com/stretchr/testify/assert" - "os" + "net/http" "testing" ) +type mavenMockUtils struct { + shouldFail bool + requestedUrls []string + requestedFiles []string + *mock.FilesMock + *mock.ExecMockRunner +} + +func (m *mavenMockUtils) DownloadFile(_, _ string, _ http.Header, _ []*http.Cookie) error { + return errors.New("Test should not download files.") +} + +func newMavenMockUtils() mavenMockUtils { + utils := mavenMockUtils{ + shouldFail: false, + FilesMock: &mock.FilesMock{}, + ExecMockRunner: &mock.ExecMockRunner{}, + } + return utils +} + func TestMavenExecute(t *testing.T) { t.Run("mavenExecute should write output file", func(t *testing.T) { // init @@ -16,23 +38,12 @@ func TestMavenExecute(t *testing.T) { ReturnStdout: true, } - mockRunner := mock.ExecMockRunner{} - mockRunner.StdoutReturn = map[string]string{} - mockRunner.StdoutReturn[""] = "test output" - - var outputFile string - var output []byte - - oldWriteFile := writeFile - writeFile = func(filename string, data []byte, perm os.FileMode) error { - outputFile = filename - output = data - return nil - } - defer func() { writeFile = oldWriteFile }() + mockUtils := newMavenMockUtils() + mockUtils.StdoutReturn = map[string]string{} + mockUtils.StdoutReturn[""] = "test output" // test - err := runMavenExecute(config, &mockRunner) + err := runMavenExecute(config, &mockUtils) // assert expectedParams := []string{ @@ -40,12 +51,17 @@ func TestMavenExecute(t *testing.T) { } assert.NoError(t, err) - if assert.Equal(t, 1, len(mockRunner.Calls)) { - assert.Equal(t, "mvn", mockRunner.Calls[0].Exec) - assert.Equal(t, expectedParams, mockRunner.Calls[0].Params) + if assert.Equal(t, 1, len(mockUtils.Calls)) { + assert.Equal(t, "mvn", mockUtils.Calls[0].Exec) + assert.Equal(t, expectedParams, mockUtils.Calls[0].Params) } + + outputFileExists, _ := mockUtils.FileExists(".pipeline/maven_output.txt") + assert.True(t, outputFileExists) + + output, _ := mockUtils.FileRead(".pipeline/maven_output.txt") + assert.Equal(t, "test output", string(output)) - assert.Equal(t, ".pipeline/maven_output.txt", outputFile) }) t.Run("mavenExecute should NOT write output file", func(t *testing.T) { @@ -55,23 +71,10 @@ func TestMavenExecute(t *testing.T) { LogSuccessfulMavenTransfers: true, } - mockRunner := mock.ExecMockRunner{} - mockRunner.StdoutReturn = map[string]string{} - mockRunner.StdoutReturn[""] = "test output" - - var outputFile string - var output []byte - - oldWriteFile := writeFile - writeFile = func(filename string, data []byte, perm os.FileMode) error { - outputFile = filename - output = data - return nil - } - defer func() { writeFile = oldWriteFile }() + mockUtils := newMavenMockUtils() // test - err := runMavenExecute(config, &mockRunner) + err := runMavenExecute(config, &mockUtils) // assert expectedParams := []string{ @@ -79,11 +82,12 @@ func TestMavenExecute(t *testing.T) { } assert.NoError(t, err) - if assert.Equal(t, 1, len(mockRunner.Calls)) { - assert.Equal(t, "mvn", mockRunner.Calls[0].Exec) - assert.Equal(t, expectedParams, mockRunner.Calls[0].Params) + if assert.Equal(t, 1, len(mockUtils.Calls)) { + assert.Equal(t, "mvn", mockUtils.Calls[0].Exec) + assert.Equal(t, expectedParams, mockUtils.Calls[0].Params) } - assert.Equal(t, "", string(output)) - assert.Equal(t, "", outputFile) + + outputFileExists, _ := mockUtils.FileExists(".pipeline/maven_output.txt") + assert.False(t, outputFileExists) }) } diff --git a/cmd/mtaBuild.go b/cmd/mtaBuild.go index 7a182e799..920f5ec4d 100644 --- a/cmd/mtaBuild.go +++ b/cmd/mtaBuild.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "net/http" "os" "path" "strings" @@ -39,9 +40,6 @@ modules: builder: grunt build-result: dist` -// for mocking -var downloadAndCopySettingsFiles = maven.DownloadAndCopySettingsFiles - // MTABuildTarget ... type MTABuildTarget int @@ -77,18 +75,64 @@ func (m MTABuildTarget) String() string { }[m] } +type mtaBuildUtils interface { + maven.Utils + + SetEnv(env []string) + AppendEnv(env []string) + + Abs(path string) (string, error) + FileRead(path string) ([]byte, error) + FileWrite(path string, content []byte, perm os.FileMode) error + + DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error + + DownloadAndCopySettingsFiles(globalSettingsFile string, projectSettingsFile string) error + + SetNpmRegistries(defaultNpmRegistry string) error + InstallAllDependencies(defaultNpmRegistry string) error +} + +type mtaBuildUtilsBundle struct { + *command.Command + *piperutils.Files + *piperhttp.Client +} + +func (bundle *mtaBuildUtilsBundle) SetNpmRegistries(defaultNpmRegistry string) error { + npmExecutorOptions := npm.ExecutorOptions{DefaultNpmRegistry: defaultNpmRegistry, ExecRunner: bundle} + npmExecutor := npm.NewExecutor(npmExecutorOptions) + return npmExecutor.SetNpmRegistries() +} + +func (bundle *mtaBuildUtilsBundle) InstallAllDependencies(defaultNpmRegistry string) error { + npmExecutorOptions := npm.ExecutorOptions{DefaultNpmRegistry: defaultNpmRegistry, ExecRunner: bundle} + npmExecutor := npm.NewExecutor(npmExecutorOptions) + return npmExecutor.InstallAllDependencies(npmExecutor.FindPackageJSONFiles()) +} + +func (bundle *mtaBuildUtilsBundle) DownloadAndCopySettingsFiles(globalSettingsFile string, projectSettingsFile string) error { + return maven.DownloadAndCopySettingsFiles(globalSettingsFile, projectSettingsFile, bundle) +} + +func newMtaBuildUtilsBundle() mtaBuildUtils { + utils := mtaBuildUtilsBundle{ + Command: &command.Command{}, + Files: &piperutils.Files{}, + Client: &piperhttp.Client{}, + } + utils.Stdout(log.Writer()) + utils.Stderr(log.Writer()) + return &utils +} + func mtaBuild(config mtaBuildOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *mtaBuildCommonPipelineEnvironment) { log.Entry().Debugf("Launching mta build") - files := piperutils.Files{} - httpClient := piperhttp.Client{} - e := command.Command{} + utils := newMtaBuildUtilsBundle() - npmExecutorOptions := npm.ExecutorOptions{DefaultNpmRegistry: config.DefaultNpmRegistry, ExecRunner: &e} - npmExecutor := npm.NewExecutor(npmExecutorOptions) - - err := runMtaBuild(config, commonPipelineEnvironment, &e, &files, &httpClient, npmExecutor) + err := runMtaBuild(config, commonPipelineEnvironment, utils) if err != nil { log.Entry(). WithError(err). @@ -98,25 +142,19 @@ func mtaBuild(config mtaBuildOptions, func runMtaBuild(config mtaBuildOptions, commonPipelineEnvironment *mtaBuildCommonPipelineEnvironment, - e command.ExecRunner, - p piperutils.FileUtils, - httpClient piperhttp.Downloader, - npmExecutor npm.Executor) error { - - e.Stdout(log.Writer()) // not sure if using the logging framework here is a suitable approach. We handover already log formatted - e.Stderr(log.Writer()) // entries to a logging framework again. But this is considered to be some kind of project standard. + utils mtaBuildUtils) error { var err error - err = handleSettingsFiles(config, p, httpClient) + err = handleSettingsFiles(config, utils) if err != nil { return err } - err = npmExecutor.SetNpmRegistries() + err = utils.SetNpmRegistries(config.DefaultNpmRegistry) mtaYamlFile := "mta.yaml" - mtaYamlFileExists, err := p.FileExists(mtaYamlFile) + mtaYamlFileExists, err := utils.FileExists(mtaYamlFile) if err != nil { return err @@ -124,7 +162,7 @@ func runMtaBuild(config mtaBuildOptions, if !mtaYamlFileExists { - if err = createMtaYamlFile(mtaYamlFile, config.ApplicationName, p); err != nil { + if err = createMtaYamlFile(mtaYamlFile, config.ApplicationName, utils); err != nil { return err } @@ -132,11 +170,11 @@ func runMtaBuild(config mtaBuildOptions, log.Entry().Infof("\"%s\" file found in project sources", mtaYamlFile) } - if err = setTimeStamp(mtaYamlFile, p); err != nil { + if err = setTimeStamp(mtaYamlFile, utils); err != nil { return err } - mtarName, err := getMtarName(config, mtaYamlFile, p) + mtarName, err := getMtarName(config, mtaYamlFile, utils) if err != nil { return err @@ -182,21 +220,21 @@ func runMtaBuild(config mtaBuildOptions, return fmt.Errorf("Unknown mta build tool: \"%s\"", config.MtaBuildTool) } - if err = addNpmBinToPath(e); err != nil { + if err = addNpmBinToPath(utils); err != nil { return err } if len(config.M2Path) > 0 { - absolutePath, err := p.Abs(config.M2Path) + absolutePath, err := utils.Abs(config.M2Path) if err != nil { return err } - e.AppendEnv([]string{"MAVEN_OPTS=-Dmaven.repo.local=" + absolutePath}) + utils.AppendEnv([]string{"MAVEN_OPTS=-Dmaven.repo.local=" + absolutePath}) } log.Entry().Infof("Executing mta build call: \"%s\"", strings.Join(call, " ")) - if err := e.RunExecutable(call[0], call[1:]...); err != nil { + if err := utils.RunExecutable(call[0], call[1:]...); err != nil { log.SetErrorCategory(log.ErrorBuild) return err } @@ -205,12 +243,12 @@ func runMtaBuild(config mtaBuildOptions, if config.InstallArtifacts { // install maven artifacts in local maven repo because `mbt build` executes `mvn package -B` - err = installMavenArtifacts(e, config) + err = installMavenArtifacts(utils, config) if err != nil { return err } // mta-builder executes 'npm install --production', therefore we need 'npm ci/install' to install the dev-dependencies - err = npmExecutor.InstallAllDependencies(npmExecutor.FindPackageJSONFiles()) + err = utils.InstallAllDependencies(config.DefaultNpmRegistry) if err != nil { return err } @@ -218,13 +256,13 @@ func runMtaBuild(config mtaBuildOptions, return err } -func installMavenArtifacts(e command.ExecRunner, config mtaBuildOptions) error { - pomXMLExists, err := piperutils.FileExists("pom.xml") +func installMavenArtifacts(utils mtaBuildUtils, config mtaBuildOptions) error { + pomXMLExists, err := utils.FileExists("pom.xml") if err != nil { return err } if pomXMLExists { - err = maven.InstallMavenArtifacts(e, &maven.EvaluateOptions{M2Path: config.M2Path}) + err = maven.InstallMavenArtifacts(&maven.EvaluateOptions{M2Path: config.M2Path}, utils) if err != nil { return err } @@ -243,25 +281,25 @@ func getMarJarName(config mtaBuildOptions) string { return mtaJar } -func addNpmBinToPath(e command.ExecRunner) error { +func addNpmBinToPath(utils mtaBuildUtils) error { dir, _ := os.Getwd() newPath := path.Join(dir, "node_modules", ".bin") oldPath := os.Getenv("PATH") if len(oldPath) > 0 { newPath = newPath + ":" + oldPath } - e.SetEnv([]string{"PATH=" + newPath}) + utils.SetEnv([]string{"PATH=" + newPath}) return nil } -func getMtarName(config mtaBuildOptions, mtaYamlFile string, p piperutils.FileUtils) (string, error) { +func getMtarName(config mtaBuildOptions, mtaYamlFile string, utils mtaBuildUtils) (string, error) { mtarName := config.MtarName if len(mtarName) == 0 { log.Entry().Debugf("mtar name not provided via config. Extracting from file \"%s\"", mtaYamlFile) - mtaID, err := getMtaID(mtaYamlFile, p) + mtaID, err := getMtaID(mtaYamlFile, utils) if err != nil { log.SetErrorCategory(log.ErrorConfiguration) @@ -282,9 +320,9 @@ func getMtarName(config mtaBuildOptions, mtaYamlFile string, p piperutils.FileUt } -func setTimeStamp(mtaYamlFile string, p piperutils.FileUtils) error { +func setTimeStamp(mtaYamlFile string, utils mtaBuildUtils) error { - mtaYaml, err := p.FileRead(mtaYamlFile) + mtaYaml, err := utils.FileRead(mtaYamlFile) if err != nil { return err } @@ -294,7 +332,7 @@ func setTimeStamp(mtaYamlFile string, p piperutils.FileUtils) error { timestampVar := "${timestamp}" if strings.Contains(mtaYamlStr, timestampVar) { - if err := p.FileWrite(mtaYamlFile, []byte(strings.ReplaceAll(mtaYamlStr, timestampVar, getTimestamp())), 0644); err != nil { + if err := utils.FileWrite(mtaYamlFile, []byte(strings.ReplaceAll(mtaYamlStr, timestampVar, getTimestamp())), 0644); err != nil { log.SetErrorCategory(log.ErrorConfiguration) return err } @@ -311,7 +349,7 @@ func getTimestamp() string { return fmt.Sprintf("%d%02d%02d%02d%02d%02d", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second()) } -func createMtaYamlFile(mtaYamlFile, applicationName string, p piperutils.FileUtils) error { +func createMtaYamlFile(mtaYamlFile, applicationName string, utils mtaBuildUtils) error { log.Entry().Debugf("mta yaml file not found in project sources.") @@ -319,13 +357,13 @@ func createMtaYamlFile(mtaYamlFile, applicationName string, p piperutils.FileUti return fmt.Errorf("'%[1]s' not found in project sources and 'applicationName' not provided as parameter - cannot generate '%[1]s' file", mtaYamlFile) } - packageFileExists, err := p.FileExists("package.json") + packageFileExists, err := utils.FileExists("package.json") if !packageFileExists { return fmt.Errorf("package.json file does not exist") } var result map[string]interface{} - pContent, err := p.FileRead("package.json") + pContent, err := utils.FileRead("package.json") if err != nil { return err } @@ -346,17 +384,14 @@ func createMtaYamlFile(mtaYamlFile, applicationName string, p piperutils.FileUti return err } - p.FileWrite(mtaYamlFile, []byte(mtaConfig), 0644) + utils.FileWrite(mtaYamlFile, []byte(mtaConfig), 0644) log.Entry().Infof("\"%s\" created.", mtaYamlFile) return nil } -func handleSettingsFiles(config mtaBuildOptions, - p piperutils.FileUtils, - httpClient piperhttp.Downloader) error { - - return downloadAndCopySettingsFiles(config.GlobalSettingsFile, config.ProjectSettingsFile, p, httpClient) +func handleSettingsFiles(config mtaBuildOptions, utils mtaBuildUtils) error { + return utils.DownloadAndCopySettingsFiles(config.GlobalSettingsFile, config.ProjectSettingsFile) } func generateMta(id, applicationName, version string) (string, error) { @@ -389,10 +424,10 @@ func generateMta(id, applicationName, version string) (string, error) { return script.String(), nil } -func getMtaID(mtaYamlFile string, fileUtils piperutils.FileUtils) (string, error) { +func getMtaID(mtaYamlFile string, utils mtaBuildUtils) (string, error) { var result map[string]interface{} - p, err := fileUtils.FileRead(mtaYamlFile) + p, err := utils.FileRead(mtaYamlFile) if err != nil { return "", err } diff --git a/cmd/mtaBuild_test.go b/cmd/mtaBuild_test.go index 5c0c0e2a7..9e7121f1c 100644 --- a/cmd/mtaBuild_test.go +++ b/cmd/mtaBuild_test.go @@ -1,32 +1,60 @@ package cmd import ( - "github.com/SAP/jenkins-library/pkg/npm" - "os" + "errors" + "net/http" "testing" - "fmt" - piperhttp "github.com/SAP/jenkins-library/pkg/http" - "github.com/SAP/jenkins-library/pkg/maven" "github.com/SAP/jenkins-library/pkg/mock" "github.com/ghodss/yaml" "github.com/stretchr/testify/assert" ) +type mtaBuildTestUtilsBundle struct { + *mock.ExecMockRunner + *mock.FilesMock + projectSettingsFile string + globalSettingsFile string + registryUsedInSetNpmRegistries string +} + +func (m *mtaBuildTestUtilsBundle) SetNpmRegistries(defaultNpmRegistry string) error { + m.registryUsedInSetNpmRegistries = defaultNpmRegistry + return nil +} + +func (m *mtaBuildTestUtilsBundle) InstallAllDependencies(defaultNpmRegistry string) error { + return errors.New("Test should not install dependencies.") //TODO implement test +} + +func (m *mtaBuildTestUtilsBundle) DownloadAndCopySettingsFiles(globalSettingsFile string, projectSettingsFile string) error { + m.projectSettingsFile = projectSettingsFile + m.globalSettingsFile = globalSettingsFile + return nil +} + +func (m *mtaBuildTestUtilsBundle) DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error { + return errors.New("Test should not download files.") +} + +func newMtaBuildTestUtilsBundle() *mtaBuildTestUtilsBundle { + utilsBundle := mtaBuildTestUtilsBundle{ + ExecMockRunner: &mock.ExecMockRunner{}, + FilesMock: &mock.FilesMock{}, + } + return &utilsBundle +} + func TestMarBuild(t *testing.T) { cpe := mtaBuildCommonPipelineEnvironment{} - httpClient := piperhttp.Client{} t.Run("Application name not set", func(t *testing.T) { - e := mock.ExecMockRunner{} - + utilsMock := newMtaBuildTestUtilsBundle() options := mtaBuildOptions{} - fileUtils := MtaTestFileUtilsMock{} - - err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e)) + err := runMtaBuild(options, &cpe, utilsMock) assert.NotNil(t, err) assert.Equal(t, "'mta.yaml' not found in project sources and 'applicationName' not provided as parameter - cannot generate 'mta.yaml' file", err.Error()) @@ -35,37 +63,25 @@ func TestMarBuild(t *testing.T) { t.Run("Provide default npm registry", func(t *testing.T) { - e := mock.ExecMockRunner{} - e.StdoutReturn = map[string]string{"npm config get registry": "undefined"} - + utilsMock := newMtaBuildTestUtilsBundle() options := mtaBuildOptions{ApplicationName: "myApp", MtaBuildTool: "classic", BuildTarget: "CF", DefaultNpmRegistry: "https://example.org/npm", MtarName: "myName"} - existingFiles := make(map[string]string) - existingFiles["package.json"] = "{\"name\": \"myName\", \"version\": \"1.2.3\"}" - fileUtils := MtaTestFileUtilsMock{existingFiles: existingFiles} + utilsMock.AddFile("package.json", []byte("{\"name\": \"myName\", \"version\": \"1.2.3\"}")) - npmExecutor := newNpmExecutor(&e) - npmExecutor.Options = npm.ExecutorOptions{DefaultNpmRegistry: options.DefaultNpmRegistry} - - err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, npmExecutor) + err := runMtaBuild(options, &cpe, utilsMock) assert.Nil(t, err) - if assert.Len(t, e.Calls, 3) { // the second (unchecked) entry is the mta call - assert.Equal(t, "npm", e.Calls[1].Exec) - assert.Equal(t, []string{"config", "set", "registry", "https://example.org/npm"}, e.Calls[1].Params) - } + assert.Equal(t, "https://example.org/npm", utilsMock.registryUsedInSetNpmRegistries) }) t.Run("Package json does not exist", func(t *testing.T) { - e := mock.ExecMockRunner{} + utilsMock := newMtaBuildTestUtilsBundle() options := mtaBuildOptions{ApplicationName: "myApp"} - fileUtils := MtaTestFileUtilsMock{} - - err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e)) + err := runMtaBuild(options, &cpe, utilsMock) assert.NotNil(t, err) @@ -75,16 +91,13 @@ func TestMarBuild(t *testing.T) { t.Run("Write yaml file", func(t *testing.T) { - e := mock.ExecMockRunner{} + utilsMock := newMtaBuildTestUtilsBundle() options := mtaBuildOptions{ApplicationName: "myApp", MtaBuildTool: "classic", BuildTarget: "CF", MtarName: "myName"} - existingFiles := make(map[string]string) - existingFiles["package.json"] = "{\"name\": \"myName\", \"version\": \"1.2.3\"}" + utilsMock.AddFile("package.json", []byte("{\"name\": \"myName\", \"version\": \"1.2.3\"}")) - fileUtils := MtaTestFileUtilsMock{existingFiles: existingFiles} - - err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e)) + err := runMtaBuild(options, &cpe, utilsMock) assert.Nil(t, err) @@ -99,70 +112,65 @@ func TestMarBuild(t *testing.T) { } } - assert.NotEmpty(t, fileUtils.writtenFiles["mta.yaml"]) + assert.True(t, utilsMock.HasWrittenFile("mta.yaml")) var result MtaResult - yaml.Unmarshal([]byte(fileUtils.writtenFiles["mta.yaml"]), &result) + mtaContent, _ := utilsMock.FileRead("mta.yaml") + yaml.Unmarshal(mtaContent, &result) assert.Equal(t, "myName", result.ID) assert.Equal(t, "1.2.3", result.Version) assert.Equal(t, "myApp", result.Modules[0].Name) - assert.Equal(t, result.Modules[0].Parameters["version"], "1.2.3-${timestamp}") + assert.Regexp(t, "^1\\.2\\.3-[\\d]{14}$", result.Modules[0].Parameters["version"]) assert.Equal(t, "myApp", result.Modules[0].Parameters["name"]) }) t.Run("Dont write mta yaml file when already present no timestamp placeholder", func(t *testing.T) { - e := mock.ExecMockRunner{} + utilsMock := newMtaBuildTestUtilsBundle() options := mtaBuildOptions{ApplicationName: "myApp", MtaBuildTool: "classic", BuildTarget: "CF"} - existingFiles := make(map[string]string) - existingFiles["package.json"] = "{\"name\": \"myName\", \"version\": \"1.2.3\"}" - existingFiles["mta.yaml"] = "already there" - fileUtils := MtaTestFileUtilsMock{existingFiles: existingFiles} + utilsMock.AddFile("package.json", []byte("{\"name\": \"myName\", \"version\": \"1.2.3\"}")) + utilsMock.AddFile("mta.yaml", []byte("already there")) - _ = runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e)) + _ = runMtaBuild(options, &cpe, utilsMock) - assert.Empty(t, fileUtils.writtenFiles) + assert.False(t, utilsMock.HasWrittenFile("mta.yaml")) }) t.Run("Write mta yaml file when already present with timestamp placeholder", func(t *testing.T) { - e := mock.ExecMockRunner{} + utilsMock := newMtaBuildTestUtilsBundle() options := mtaBuildOptions{ApplicationName: "myApp", MtaBuildTool: "classic", BuildTarget: "CF"} - existingFiles := make(map[string]string) - existingFiles["package.json"] = "{\"name\": \"myName\", \"version\": \"1.2.3\"}" - existingFiles["mta.yaml"] = "already there with-${timestamp}" - fileUtils := MtaTestFileUtilsMock{existingFiles: existingFiles} + utilsMock.AddFile("package.json", []byte("{\"name\": \"myName\", \"version\": \"1.2.3\"}")) + utilsMock.AddFile("mta.yaml", []byte("already there with-${timestamp}")) - _ = runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e)) + _ = runMtaBuild(options, &cpe, utilsMock) - assert.NotEmpty(t, fileUtils.writtenFiles["mta.yaml"]) + assert.True(t, utilsMock.HasWrittenFile("mta.yaml")) }) t.Run("Test mta build classic toolset", func(t *testing.T) { - e := mock.ExecMockRunner{} + utilsMock := newMtaBuildTestUtilsBundle() options := mtaBuildOptions{ApplicationName: "myApp", MtaBuildTool: "classic", BuildTarget: "CF", MtarName: "myName.mtar"} cpe.mtarFilePath = "" - existingFiles := make(map[string]string) - existingFiles["package.json"] = "{\"name\": \"myName\", \"version\": \"1.2.3\"}" - fileUtils := MtaTestFileUtilsMock{existingFiles: existingFiles} + utilsMock.AddFile("package.json", []byte("{\"name\": \"myName\", \"version\": \"1.2.3\"}")) - err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e)) + err := runMtaBuild(options, &cpe, utilsMock) assert.Nil(t, err) - if assert.Len(t, e.Calls, 2) { - assert.Equal(t, "java", e.Calls[1].Exec) - assert.Equal(t, []string{"-jar", "mta.jar", "--mtar", "myName.mtar", "--build-target=CF", "build"}, e.Calls[1].Params) + if assert.Len(t, utilsMock.Calls, 1) { + assert.Equal(t, "java", utilsMock.Calls[0].Exec) + assert.Equal(t, []string{"-jar", "mta.jar", "--mtar", "myName.mtar", "--build-target=CF", "build"}, utilsMock.Calls[0].Params) } assert.Equal(t, "myName.mtar", cpe.mtarFilePath) @@ -170,66 +178,60 @@ func TestMarBuild(t *testing.T) { t.Run("Test mta build classic toolset, mtarName from already existing mta.yaml", func(t *testing.T) { - e := mock.ExecMockRunner{} + utilsMock := newMtaBuildTestUtilsBundle() options := mtaBuildOptions{ApplicationName: "myApp", MtaBuildTool: "classic", BuildTarget: "CF"} cpe.mtarFilePath = "" - existingFiles := make(map[string]string) - existingFiles["package.json"] = "{\"name\": \"myName\", \"version\": \"1.2.3\"}" - existingFiles["mta.yaml"] = "ID: \"myNameFromMtar\"" - fileUtils := MtaTestFileUtilsMock{existingFiles: existingFiles} + utilsMock.AddFile("package.json", []byte("{\"name\": \"myName\", \"version\": \"1.2.3\"}")) + utilsMock.AddFile("mta.yaml", []byte("ID: \"myNameFromMtar\"")) - err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e)) + err := runMtaBuild(options, &cpe, utilsMock) assert.Nil(t, err) - if assert.Len(t, e.Calls, 2) { - assert.Equal(t, "java", e.Calls[1].Exec) - assert.Equal(t, []string{"-jar", "mta.jar", "--mtar", "myNameFromMtar.mtar", "--build-target=CF", "build"}, e.Calls[1].Params) + if assert.Len(t, utilsMock.Calls, 1) { + assert.Equal(t, "java", utilsMock.Calls[0].Exec) + assert.Equal(t, []string{"-jar", "mta.jar", "--mtar", "myNameFromMtar.mtar", "--build-target=CF", "build"}, utilsMock.Calls[0].Params) } }) t.Run("Test mta build classic toolset with configured mta jar", func(t *testing.T) { - e := mock.ExecMockRunner{} + utilsMock := newMtaBuildTestUtilsBundle() options := mtaBuildOptions{ApplicationName: "myApp", MtaBuildTool: "classic", BuildTarget: "CF", MtaJarLocation: "/opt/sap/mta/lib/mta.jar", MtarName: "myName.mtar"} - existingFiles := make(map[string]string) - existingFiles["package.json"] = "{\"name\": \"myName\", \"version\": \"1.2.3\"}" - fileUtils := MtaTestFileUtilsMock{existingFiles: existingFiles} + utilsMock.AddFile("package.json", []byte("{\"name\": \"myName\", \"version\": \"1.2.3\"}")) - err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e)) + err := runMtaBuild(options, &cpe, utilsMock) assert.Nil(t, err) - if assert.Len(t, e.Calls, 2) { - assert.Equal(t, "java", e.Calls[1].Exec) - assert.Equal(t, []string{"-jar", "/opt/sap/mta/lib/mta.jar", "--mtar", "myName.mtar", "--build-target=CF", "build"}, e.Calls[1].Params) + if assert.Len(t, utilsMock.Calls, 1) { + assert.Equal(t, "java", utilsMock.Calls[0].Exec) + assert.Equal(t, []string{"-jar", "/opt/sap/mta/lib/mta.jar", "--mtar", "myName.mtar", "--build-target=CF", "build"}, utilsMock.Calls[0].Params) } }) t.Run("Mta build mbt toolset", func(t *testing.T) { - e := mock.ExecMockRunner{} + utilsMock := newMtaBuildTestUtilsBundle() cpe.mtarFilePath = "" options := mtaBuildOptions{ApplicationName: "myApp", MtaBuildTool: "cloudMbt", Platform: "CF", MtarName: "myName.mtar"} - existingFiles := make(map[string]string) - existingFiles["package.json"] = "{\"name\": \"myName\", \"version\": \"1.2.3\"}" - fileUtils := MtaTestFileUtilsMock{existingFiles: existingFiles} + utilsMock.AddFile("package.json", []byte("{\"name\": \"myName\", \"version\": \"1.2.3\"}")) - err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e)) + err := runMtaBuild(options, &cpe, utilsMock) assert.Nil(t, err) - if assert.Len(t, e.Calls, 2) { - assert.Equal(t, "mbt", e.Calls[1].Exec) - assert.Equal(t, []string{"build", "--mtar", "myName.mtar", "--platform", "CF", "--target", "./"}, e.Calls[1].Params) + if assert.Len(t, utilsMock.Calls, 1) { + assert.Equal(t, "mbt", utilsMock.Calls[0].Exec) + assert.Equal(t, []string{"build", "--mtar", "myName.mtar", "--platform", "CF", "--target", "./"}, utilsMock.Calls[0].Params) } assert.Equal(t, "myName.mtar", cpe.mtarFilePath) }) @@ -237,145 +239,51 @@ func TestMarBuild(t *testing.T) { t.Run("M2Path related tests", func(t *testing.T) { t.Run("Mta build mbt toolset with m2Path", func(t *testing.T) { - e := mock.ExecMockRunner{} - + utilsMock := newMtaBuildTestUtilsBundle() + utilsMock.CurrentDir = "root_folder/workspace" cpe.mtarFilePath = "" options := mtaBuildOptions{ApplicationName: "myApp", MtaBuildTool: "cloudMbt", Platform: "CF", MtarName: "myName.mtar", M2Path: ".pipeline/local_repo"} - existingFiles := make(map[string]string) - existingFiles["mta.yaml"] = "ID: \"myNameFromMtar\"" - fileUtils := MtaTestFileUtilsMock{existingFiles: existingFiles} + utilsMock.AddFile("mta.yaml", []byte("ID: \"myNameFromMtar\"")) - err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e)) + err := runMtaBuild(options, &cpe, utilsMock) assert.Nil(t, err) - assert.Contains(t, e.Env, "MAVEN_OPTS=-Dmaven.repo.local=/root_folder/workspace/.pipeline/local_repo") + assert.Contains(t, utilsMock.Env, "MAVEN_OPTS=-Dmaven.repo.local=/root_folder/workspace/.pipeline/local_repo") }) }) t.Run("Settings file releatd tests", func(t *testing.T) { - var projectSettingsFile string - var globalSettingsFile string - - defer func() { - downloadAndCopySettingsFiles = maven.DownloadAndCopySettingsFiles - }() - - downloadAndCopySettingsFiles = func( - globalSettings string, - projectSettings string, - fileUtils maven.FileUtils, - httpClient maven.SettingsDownloadUtils) error { - projectSettingsFile = projectSettings - globalSettingsFile = globalSettings - return nil - } - - fileUtils := MtaTestFileUtilsMock{} - fileUtils.existingFiles = make(map[string]string) - fileUtils.existingFiles["package.json"] = "{\"name\": \"myName\", \"version\": \"1.2.3\"}" - t.Run("Copy global settings file", func(t *testing.T) { - defer func() { - projectSettingsFile = "" - globalSettingsFile = "" - }() - - e := mock.ExecMockRunner{} + utilsMock := newMtaBuildTestUtilsBundle() + utilsMock.AddFile("mta.yaml", []byte("ID: \"myNameFromMtar\"")) options := mtaBuildOptions{ApplicationName: "myApp", GlobalSettingsFile: "/opt/maven/settings.xml", MtaBuildTool: "cloudMbt", Platform: "CF", MtarName: "myName"} - err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e)) + err := runMtaBuild(options, &cpe, utilsMock) assert.Nil(t, err) - assert.Equal(t, globalSettingsFile, "/opt/maven/settings.xml") - assert.Equal(t, projectSettingsFile, "") + assert.Equal(t, "/opt/maven/settings.xml", utilsMock.globalSettingsFile) + assert.Equal(t, "", utilsMock.projectSettingsFile) }) t.Run("Copy project settings file", func(t *testing.T) { - defer func() { - projectSettingsFile = "" - globalSettingsFile = "" - }() - - e := mock.ExecMockRunner{} + utilsMock := newMtaBuildTestUtilsBundle() + utilsMock.AddFile("mta.yaml", []byte("ID: \"myNameFromMtar\"")) options := mtaBuildOptions{ApplicationName: "myApp", ProjectSettingsFile: "/my/project/settings.xml", MtaBuildTool: "cloudMbt", Platform: "CF", MtarName: "myName"} - err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e)) + err := runMtaBuild(options, &cpe, utilsMock) assert.Nil(t, err) - assert.Equal(t, "/my/project/settings.xml", projectSettingsFile) - assert.Equal(t, "", globalSettingsFile) + assert.Equal(t, "/my/project/settings.xml", utilsMock.projectSettingsFile) + assert.Equal(t, "", utilsMock.globalSettingsFile) }) }) } - -type MtaTestFileUtilsMock struct { - existingFiles map[string]string - writtenFiles map[string]string - copiedFiles map[string]string -} - -func (f *MtaTestFileUtilsMock) FileExists(path string) (bool, error) { - - if _, ok := f.existingFiles[path]; ok { - return true, nil - } - return false, nil -} - -func (f *MtaTestFileUtilsMock) Copy(src, dest string) (int64, error) { - - if f.copiedFiles == nil { - f.copiedFiles = make(map[string]string) - } - f.copiedFiles[src] = dest - - return 0, nil -} - -func (f *MtaTestFileUtilsMock) FileRead(path string) ([]byte, error) { - return []byte(f.existingFiles[path]), nil -} - -func (f *MtaTestFileUtilsMock) FileWrite(path string, content []byte, perm os.FileMode) error { - - if f.writtenFiles == nil { - f.writtenFiles = make(map[string]string) - } - - if _, ok := f.writtenFiles[path]; ok { - delete(f.writtenFiles, path) - } - f.writtenFiles[path] = string(content) - return nil -} - -func (f *MtaTestFileUtilsMock) MkdirAll(path string, perm os.FileMode) error { - return nil -} - -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.") -} - -func newNpmExecutor(execRunner *mock.ExecMockRunner) *npm.Execute { - utils := newNpmMockUtilsBundle() - utils.execRunner = execRunner - return &npm.Execute{Utils: &utils} -} diff --git a/cmd/nexusUpload.go b/cmd/nexusUpload.go index 3cf20ffcb..ca7019cc5 100644 --- a/cmd/nexusUpload.go +++ b/cmd/nexusUpload.go @@ -2,7 +2,10 @@ package cmd import ( "fmt" + piperhttp "github.com/SAP/jenkins-library/pkg/http" "github.com/pkg/errors" + "io" + "net/http" "os" "path/filepath" "strings" @@ -22,33 +25,47 @@ import ( // nexusUploadUtils defines an interface for utility functionality used from external packages, // so it can be easily mocked for testing. type nexusUploadUtils interface { + Stdout(out io.Writer) + Stderr(err io.Writer) + SetEnv(env []string) + RunExecutable(e string, p ...string) error + FileExists(path string) (bool, error) FileRead(path string) ([]byte, error) FileWrite(path string, content []byte, perm os.FileMode) error FileRemove(path string) error DirExists(path string) (bool, error) Glob(pattern string) (matches []string, err error) + Copy(src, dest string) (int64, error) + MkdirAll(path string, perm os.FileMode) error + + DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error UsesMta() bool UsesMaven() bool UsesNpm() bool getEnvParameter(path, name string) string - getExecRunner() command.ExecRunner evaluate(options *maven.EvaluateOptions, expression string) (string, error) } type utilsBundle struct { *piperutils.ProjectStructure *piperutils.Files - execRunner *command.Command + *command.Command + *piperhttp.Client } func newUtilsBundle() *utilsBundle { - return &utilsBundle{ + utils := utilsBundle{ ProjectStructure: &piperutils.ProjectStructure{}, Files: &piperutils.Files{}, + Command: &command.Command{}, + Client: &piperhttp.Client{}, } + utils.Stdout(log.Writer()) + utils.Stderr(log.Writer()) + return &utils } func (u *utilsBundle) FileWrite(filePath string, content []byte, perm os.FileMode) error { @@ -66,17 +83,8 @@ func (u *utilsBundle) getEnvParameter(path, name string) string { return piperenv.GetParameter(path, name) } -func (u *utilsBundle) getExecRunner() command.ExecRunner { - if u.execRunner == nil { - u.execRunner = &command.Command{} - u.execRunner.Stdout(log.Writer()) - u.execRunner.Stderr(log.Writer()) - } - return u.execRunner -} - func (u *utilsBundle) evaluate(options *maven.EvaluateOptions, expression string) (string, error) { - return maven.Evaluate(options, expression, u.getExecRunner()) + return maven.Evaluate(options, expression, u) } func nexusUpload(options nexusUploadOptions, _ *telemetry.CustomData) { @@ -123,7 +131,6 @@ func runNexusUpload(utils nexusUploadUtils, uploader nexus.Uploader, options *ne } func uploadNpmArtifacts(utils nexusUploadUtils, uploader nexus.Uploader, options *nexusUploadOptions) error { - execRunner := utils.getExecRunner() environment := []string{"npm_config_registry=http://" + uploader.GetNpmRepoURL(), "npm_config_email=project-piper@no-reply.com"} if options.Username != "" && options.Password != "" { auth := b64.StdEncoding.EncodeToString([]byte(options.Username + ":" + options.Password)) @@ -131,8 +138,8 @@ func uploadNpmArtifacts(utils nexusUploadUtils, uploader nexus.Uploader, options } else { log.Entry().Info("No credentials provided for npm upload, trying to upload anonymously.") } - execRunner.SetEnv(environment) - err := execRunner.RunExecutable("npm", "publish") + utils.SetEnv(environment) + err := utils.RunExecutable("npm", "publish") return err } @@ -236,7 +243,7 @@ func setupNexusCredentialsSettingsFile(utils nexusUploadUtils, options *nexusUpl } log.Entry().Debugf("Writing nexus credentials to environment") - utils.getExecRunner().SetEnv([]string{"NEXUS_username=" + options.Username, "NEXUS_password=" + options.Password}) + utils.SetEnv([]string{"NEXUS_username=" + options.Username, "NEXUS_password=" + options.Password}) mavenOptions.ProjectSettingsFile = settingsPath mavenOptions.Defines = append(mavenOptions.Defines, "-DrepositoryId="+settingsServerID) @@ -299,7 +306,7 @@ func uploadArtifacts(utils nexusUploadUtils, uploader nexus.Uploader, options *n } } - err = uploadArtifactsBundle(d, generatePOM, mavenOptions, utils.getExecRunner()) + err = uploadArtifactsBundle(d, generatePOM, mavenOptions, utils) if err != nil { return fmt.Errorf("uploading artifacts for ID '%s' failed: %w", uploader.GetArtifactsID(), err) } @@ -317,7 +324,7 @@ func appendItemToString(list, item string, first bool) string { } func uploadArtifactsBundle(d artifactDefines, generatePOM bool, mavenOptions maven.ExecuteOptions, - execRunner command.ExecRunner) error { + utils nexusUploadUtils) error { if d.file == "" { return fmt.Errorf("no file specified") } @@ -337,7 +344,7 @@ func uploadArtifactsBundle(d artifactDefines, generatePOM bool, mavenOptions mav } mavenOptions.Defines = append(mavenOptions.Defines, defines...) - _, err := maven.Execute(&mavenOptions, execRunner) + _, err := maven.Execute(&mavenOptions, utils) return err } diff --git a/cmd/nexusUpload_test.go b/cmd/nexusUpload_test.go index f2fec3525..7f60e129c 100644 --- a/cmd/nexusUpload_test.go +++ b/cmd/nexusUpload_test.go @@ -1,12 +1,13 @@ package cmd import ( + "errors" "fmt" - "github.com/SAP/jenkins-library/pkg/command" "github.com/SAP/jenkins-library/pkg/maven" "github.com/SAP/jenkins-library/pkg/mock" "github.com/SAP/jenkins-library/pkg/nexus" "github.com/stretchr/testify/assert" + "net/http" "os" "path/filepath" "strings" @@ -15,19 +16,29 @@ import ( type mockUtilsBundle struct { *mock.FilesMock + *mock.ExecMockRunner mta bool maven bool npm bool properties map[string]map[string]string cpe map[string]string - execRunner mock.ExecMockRunner } -func newMockUtilsBundle(usesMta, usesMaven, usesNpm bool) mockUtilsBundle { - utils := mockUtilsBundle{FilesMock: &mock.FilesMock{}, mta: usesMta, maven: usesMaven, npm: usesNpm} +func (m *mockUtilsBundle) DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error { + return errors.New("Test should not download files.") +} + +func newMockUtilsBundle(usesMta, usesMaven, usesNpm bool) *mockUtilsBundle { + utils := mockUtilsBundle{ + FilesMock: &mock.FilesMock{}, + ExecMockRunner: &mock.ExecMockRunner{}, + mta: usesMta, + maven: usesMaven, + npm: usesNpm, + } utils.properties = map[string]map[string]string{} utils.cpe = map[string]string{} - return utils + return &utils } func (m *mockUtilsBundle) UsesMta() bool { @@ -47,10 +58,6 @@ func (m *mockUtilsBundle) getEnvParameter(path, name string) string { return m.cpe[path] } -func (m *mockUtilsBundle) getExecRunner() command.ExecRunner { - return &m.execRunner -} - func (m *mockUtilsBundle) setProperty(pomFile, expression, value string) { pomFile = strings.ReplaceAll(pomFile, "/", string(os.PathSeparator)) pomFile = strings.ReplaceAll(pomFile, "\\", string(os.PathSeparator)) @@ -148,7 +155,7 @@ func TestUploadMTAProjects(t *testing.T) { options := createOptions() options.GroupID = "" - err := runNexusUpload(&utils, &uploader, &options) + err := runNexusUpload(utils, &uploader, &options) assert.EqualError(t, err, "the 'groupId' parameter needs to be provided for MTA projects") assert.Equal(t, 0, len(uploader.GetArtifacts())) assert.Equal(t, 0, len(uploader.uploadedArtifacts)) @@ -162,7 +169,7 @@ func TestUploadMTAProjects(t *testing.T) { options := createOptions() options.ArtifactID = "" - err := runNexusUpload(&utils, &uploader, &options) + err := runNexusUpload(utils, &uploader, &options) if assert.NoError(t, err) { assert.Equal(t, 2, len(uploader.uploadedArtifacts)) assert.Equal(t, "test", uploader.GetArtifactsID()) @@ -174,7 +181,7 @@ func TestUploadMTAProjects(t *testing.T) { uploader := mockUploader{} options := createOptions() - err := runNexusUpload(&utils, &uploader, &options) + err := runNexusUpload(utils, &uploader, &options) assert.EqualError(t, err, "could not read from required project descriptor file 'mta.yml'") assert.Equal(t, 0, len(uploader.GetArtifacts())) assert.Equal(t, 0, len(uploader.uploadedArtifacts)) @@ -186,7 +193,7 @@ func TestUploadMTAProjects(t *testing.T) { uploader := mockUploader{} options := createOptions() - err := runNexusUpload(&utils, &uploader, &options) + err := runNexusUpload(utils, &uploader, &options) assert.EqualError(t, err, "failed to parse contents of the project descriptor file 'mta.yaml'") assert.Equal(t, 0, len(uploader.GetArtifacts())) @@ -199,7 +206,7 @@ func TestUploadMTAProjects(t *testing.T) { uploader := mockUploader{} options := createOptions() - err := runNexusUpload(&utils, &uploader, &options) + err := runNexusUpload(utils, &uploader, &options) assert.EqualError(t, err, "the project descriptor file 'mta.yaml' has an invalid version: version must not be empty") assert.Equal(t, 0, len(uploader.GetArtifacts())) @@ -212,7 +219,7 @@ func TestUploadMTAProjects(t *testing.T) { uploader := mockUploader{} options := createOptions() - err := runNexusUpload(&utils, &uploader, &options) + err := runNexusUpload(utils, &uploader, &options) assert.EqualError(t, err, "artifact file not found 'test.mtar'") assert.Equal(t, "0.3.0", uploader.GetArtifactsVersion()) @@ -234,7 +241,7 @@ func TestUploadMTAProjects(t *testing.T) { uploader := mockUploader{} options := createOptions() - err := runNexusUpload(&utils, &uploader, &options) + err := runNexusUpload(utils, &uploader, &options) assert.NoError(t, err, "expected mta.yaml project upload to work") assert.Equal(t, "0.3.0", uploader.GetArtifactsVersion()) @@ -257,7 +264,7 @@ func TestUploadMTAProjects(t *testing.T) { uploader := mockUploader{} options := createOptions() - err := runNexusUpload(&utils, &uploader, &options) + err := runNexusUpload(utils, &uploader, &options) assert.NoError(t, err, "expected mta.yml project upload to work") assert.Equal(t, "0.3.0", uploader.GetArtifactsVersion()) @@ -281,7 +288,7 @@ func TestUploadArtifacts(t *testing.T) { uploader := mockUploader{} options := createOptions() - err := uploadArtifacts(&utils, &uploader, &options, false) + err := uploadArtifacts(utils, &uploader, &options, false) assert.EqualError(t, err, "no group ID was provided, or could be established from project files") }) t.Run("Uploading MTA project fails without any artifacts", func(t *testing.T) { @@ -291,15 +298,15 @@ func TestUploadArtifacts(t *testing.T) { _ = uploader.SetInfo(options.GroupID, "some.id", "3.0") - err := uploadArtifacts(&utils, &uploader, &options, false) + err := uploadArtifacts(utils, &uploader, &options, false) assert.EqualError(t, err, "no artifacts to upload") }) t.Run("Uploading MTA project fails for unknown reasons", func(t *testing.T) { utils := newMockUtilsBundle(false, true, false) // Configure mocked execRunner to fail - utils.execRunner.ShouldFailOnCommand = map[string]error{} - utils.execRunner.ShouldFailOnCommand["mvn"] = fmt.Errorf("failed") + utils.ShouldFailOnCommand = map[string]error{} + utils.ShouldFailOnCommand["mvn"] = fmt.Errorf("failed") uploader := mockUploader{} options := createOptions() @@ -313,7 +320,7 @@ func TestUploadArtifacts(t *testing.T) { Type: "yaml", }) - err := uploadArtifacts(&utils, &uploader, &options, false) + err := uploadArtifacts(utils, &uploader, &options, false) assert.EqualError(t, err, "uploading artifacts for ID 'some.id' failed: failed to run executable, command: '[mvn -Durl=http:// -DgroupId=my.group.id -Dversion=3.0 -DartifactId=some.id -Dfile=mta.yaml -Dpackaging=yaml -DgeneratePom=false -Dfiles=artifact.mtar -Dclassifiers= -Dtypes=yaml -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn --batch-mode "+deployGoal+"]', error: failed") }) t.Run("Uploading bundle generates correct maven parameters", func(t *testing.T) { @@ -332,9 +339,9 @@ func TestUploadArtifacts(t *testing.T) { Type: "pom", }) - err := uploadArtifacts(&utils, &uploader, &options, false) + err := uploadArtifacts(utils, &uploader, &options, false) assert.NoError(t, err, "expected upload as two bundles to work") - assert.Equal(t, 1, len(utils.execRunner.Calls)) + assert.Equal(t, 1, len(utils.Calls)) expectedParameters1 := []string{ "-Durl=http://localhost:8081/repository/maven-releases/", @@ -350,8 +357,8 @@ func TestUploadArtifacts(t *testing.T) { "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", deployGoal} - assert.Equal(t, len(expectedParameters1), len(utils.execRunner.Calls[0].Params)) - assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: expectedParameters1}, utils.execRunner.Calls[0]) + assert.Equal(t, len(expectedParameters1), len(utils.Calls[0].Params)) + assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: expectedParameters1}, utils.Calls[0]) }) } @@ -364,13 +371,13 @@ func TestUploadNpmProjects(t *testing.T) { options.Username = "admin" options.Password = "admin123" - err := runNexusUpload(&utils, &uploader, &options) + err := runNexusUpload(utils, &uploader, &options) assert.NoError(t, err, "expected npm upload to work") assert.Equal(t, "localhost:8081/repository/npm-repo/", uploader.GetNpmRepoURL()) - assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"publish"}}, utils.execRunner.Calls[0]) - assert.Equal(t, []string{"npm_config_registry=http://localhost:8081/repository/npm-repo/", "npm_config_email=project-piper@no-reply.com", "npm_config__auth=YWRtaW46YWRtaW4xMjM="}, utils.execRunner.Env) + assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"publish"}}, utils.Calls[0]) + assert.Equal(t, []string{"npm_config_registry=http://localhost:8081/repository/npm-repo/", "npm_config_email=project-piper@no-reply.com", "npm_config__auth=YWRtaW46YWRtaW4xMjM="}, utils.Env) }) } @@ -381,7 +388,7 @@ func TestUploadMavenProjects(t *testing.T) { uploader := mockUploader{} options := createOptions() - err := runNexusUpload(&utils, &uploader, &options) + err := runNexusUpload(utils, &uploader, &options) assert.EqualError(t, err, "pom.xml not found") assert.Equal(t, 0, len(uploader.uploadedArtifacts)) }) @@ -396,7 +403,7 @@ func TestUploadMavenProjects(t *testing.T) { uploader := mockUploader{} options := createOptions() - err := runNexusUpload(&utils, &uploader, &options) + err := runNexusUpload(utils, &uploader, &options) assert.NoError(t, err, "expected Maven upload to work") assert.Equal(t, "1.0", uploader.GetArtifactsVersion()) assert.Equal(t, "my-app", uploader.GetArtifactsID()) @@ -419,7 +426,7 @@ func TestUploadMavenProjects(t *testing.T) { uploader := mockUploader{} options := createOptions() - err := runNexusUpload(&utils, &uploader, &options) + err := runNexusUpload(utils, &uploader, &options) assert.EqualError(t, err, "target artifact not found for packaging 'jar'") assert.Equal(t, 0, len(uploader.uploadedArtifacts)) }) @@ -435,7 +442,7 @@ func TestUploadMavenProjects(t *testing.T) { uploader := mockUploader{} options := createOptions() - err := runNexusUpload(&utils, &uploader, &options) + err := runNexusUpload(utils, &uploader, &options) assert.NoError(t, err, "expected Maven upload to work") assert.Equal(t, "1.0", uploader.GetArtifactsVersion()) @@ -462,7 +469,7 @@ func TestUploadMavenProjects(t *testing.T) { uploader := mockUploader{} options := createOptions() - err := runNexusUpload(&utils, &uploader, &options) + err := runNexusUpload(utils, &uploader, &options) assert.NoError(t, err, "expected Maven upload to work") assert.Equal(t, "1.0", uploader.GetArtifactsVersion()) assert.Equal(t, "my-app", uploader.GetArtifactsID()) @@ -487,7 +494,7 @@ func TestUploadMavenProjects(t *testing.T) { options := createOptions() options.GroupID = "awesome.group" - err := runNexusUpload(&utils, &uploader, &options) + err := runNexusUpload(utils, &uploader, &options) assert.NoError(t, err, "expected Maven upload to work") assert.Equal(t, "localhost:8081/repository/maven-releases/", @@ -512,7 +519,7 @@ func TestUploadMavenProjects(t *testing.T) { uploader := mockUploader{} options := createOptions() - err := runNexusUpload(&utils, &uploader, &options) + err := runNexusUpload(utils, &uploader, &options) assert.NoError(t, err, "expected Maven upload to work") assert.Equal(t, "localhost:8081/repository/maven-releases/", @@ -566,7 +573,7 @@ func TestUploadMavenProjects(t *testing.T) { uploader := mockUploader{} options := createOptions() - err := runNexusUpload(&utils, &uploader, &options) + err := runNexusUpload(utils, &uploader, &options) assert.NoError(t, err, "expected upload of maven project with application module to succeed") assert.Equal(t, "1.0", uploader.GetArtifactsVersion()) assert.Equal(t, "my-app", uploader.GetArtifactsID()) @@ -586,7 +593,7 @@ func TestUploadMavenProjects(t *testing.T) { assert.Equal(t, "pom", artifacts[3].Type) } - if assert.Equal(t, 2, len(utils.execRunner.Calls)) { + if assert.Equal(t, 2, len(utils.Calls)) { expectedParameters1 := []string{ "-Durl=http://localhost:8081/repository/maven-releases/", "-DgroupId=com.mycompany.app", @@ -600,8 +607,8 @@ func TestUploadMavenProjects(t *testing.T) { "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", deployGoal} - assert.Equal(t, len(expectedParameters1), len(utils.execRunner.Calls[0].Params)) - assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: expectedParameters1}, utils.execRunner.Calls[0]) + assert.Equal(t, len(expectedParameters1), len(utils.Calls[0].Params)) + assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: expectedParameters1}, utils.Calls[0]) expectedParameters2 := []string{ "-Durl=http://localhost:8081/repository/maven-releases/", @@ -613,8 +620,8 @@ func TestUploadMavenProjects(t *testing.T) { "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", deployGoal} - assert.Equal(t, len(expectedParameters2), len(utils.execRunner.Calls[1].Params)) - assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: expectedParameters2}, utils.execRunner.Calls[1]) + assert.Equal(t, len(expectedParameters2), len(utils.Calls[1].Params)) + assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: expectedParameters2}, utils.Calls[1]) } }) t.Run("Write credentials settings", func(t *testing.T) { @@ -630,10 +637,10 @@ func TestUploadMavenProjects(t *testing.T) { options.Username = "admin" options.Password = "admin123" - err := runNexusUpload(&utils, &uploader, &options) + err := runNexusUpload(utils, &uploader, &options) assert.NoError(t, err, "expected Maven upload to work") - assert.Equal(t, 1, len(utils.execRunner.Calls)) + assert.Equal(t, 1, len(utils.Calls)) expectedParameters1 := []string{ "--settings", settingsPath, @@ -647,12 +654,12 @@ func TestUploadMavenProjects(t *testing.T) { "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", deployGoal} - assert.Equal(t, len(expectedParameters1), len(utils.execRunner.Calls[0].Params)) - assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: expectedParameters1}, utils.execRunner.Calls[0]) + assert.Equal(t, len(expectedParameters1), len(utils.Calls[0].Params)) + assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: expectedParameters1}, utils.Calls[0]) expectedEnv := []string{"NEXUS_username=admin", "NEXUS_password=admin123"} - assert.Equal(t, 2, len(utils.execRunner.Env)) - assert.Equal(t, expectedEnv, utils.execRunner.Env) + assert.Equal(t, 2, len(utils.Env)) + assert.Equal(t, expectedEnv, utils.Env) assert.False(t, utils.HasFile(settingsPath)) assert.True(t, utils.HasRemovedFile(settingsPath)) @@ -663,13 +670,13 @@ func TestSetupNexusCredentialsSettingsFile(t *testing.T) { utils := newMockUtilsBundle(false, true, false) options := nexusUploadOptions{Username: "admin", Password: "admin123"} mavenOptions := maven.ExecuteOptions{} - settingsPath, err := setupNexusCredentialsSettingsFile(&utils, &options, &mavenOptions) + settingsPath, err := setupNexusCredentialsSettingsFile(utils, &options, &mavenOptions) assert.NoError(t, err, "expected setting up credentials settings.xml to work") - assert.Equal(t, 0, len(utils.execRunner.Calls)) + assert.Equal(t, 0, len(utils.Calls)) expectedEnv := []string{"NEXUS_username=admin", "NEXUS_password=admin123"} - assert.Equal(t, 2, len(utils.execRunner.Env)) - assert.Equal(t, expectedEnv, utils.execRunner.Env) + assert.Equal(t, 2, len(utils.Env)) + assert.Equal(t, expectedEnv, utils.Env) assert.True(t, settingsPath != "") assert.True(t, utils.HasFile(settingsPath)) diff --git a/pkg/maven/maven.go b/pkg/maven/maven.go index a8386c838..10b9e7ccd 100644 --- a/pkg/maven/maven.go +++ b/pkg/maven/maven.go @@ -3,14 +3,16 @@ package maven import ( "bytes" "fmt" + "github.com/SAP/jenkins-library/pkg/command" + piperhttp "github.com/SAP/jenkins-library/pkg/http" + "github.com/SAP/jenkins-library/pkg/piperutils" "io" "net/http" + "os" "path/filepath" "strings" - piperhttp "github.com/SAP/jenkins-library/pkg/http" "github.com/SAP/jenkins-library/pkg/log" - "github.com/SAP/jenkins-library/pkg/piperutils" ) // ExecuteOptions are used by Execute() to construct the Maven command line. @@ -36,44 +38,50 @@ type EvaluateOptions struct { Defines []string `json:"defines,omitempty"` } -type mavenExecRunner interface { +type Utils interface { Stdout(out io.Writer) Stderr(err io.Writer) RunExecutable(e string, p ...string) error -} -type mavenUtils interface { - FileUtils DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error + Glob(pattern string) (matches []string, err error) + FileExists(filename string) (bool, error) + Copy(src, dest string) (int64, error) + MkdirAll(path string, perm os.FileMode) error } type utilsBundle struct { - *piperhttp.Client + *command.Command *piperutils.Files + *piperhttp.Client } -func newUtils() *utilsBundle { - return &utilsBundle{ - Client: &piperhttp.Client{}, - Files: &piperutils.Files{}, +func NewUtilsBundle() Utils { + utils := utilsBundle{ + Command: &command.Command{}, + Files: &piperutils.Files{}, + Client: &piperhttp.Client{}, } + utils.Stdout(log.Writer()) + utils.Stderr(log.Writer()) + return &utils } const mavenExecutable = "mvn" // Execute constructs a mvn command line from the given options, and uses the provided // mavenExecRunner to execute it. -func Execute(options *ExecuteOptions, command mavenExecRunner) (string, error) { +func Execute(options *ExecuteOptions, utils Utils) (string, error) { stdOutBuf, stdOut := evaluateStdOut(options) - command.Stdout(stdOut) - command.Stderr(log.Writer()) + utils.Stdout(stdOut) + utils.Stderr(log.Writer()) - parameters, err := getParametersFromOptions(options, newUtils()) + parameters, err := getParametersFromOptions(options, utils) if err != nil { return "", fmt.Errorf("failed to construct parameters from options: %w", err) } - err = command.RunExecutable(mavenExecutable, parameters...) + err = utils.RunExecutable(mavenExecutable, parameters...) if err != nil { log.SetErrorCategory(log.ErrorBuild) commandLine := append([]string{mavenExecutable}, parameters...) @@ -89,7 +97,7 @@ func Execute(options *ExecuteOptions, command mavenExecRunner) (string, error) { // Evaluate constructs ExecuteOptions for using the maven-help-plugin's 'evaluate' goal to // evaluate a given expression from a pom file. This allows to retrieve the value of - for // example - 'project.version' from a pom file exactly as Maven itself evaluates it. -func Evaluate(options *EvaluateOptions, expression string, command mavenExecRunner) (string, error) { +func Evaluate(options *EvaluateOptions, expression string, utils Utils) (string, error) { defines := []string{"-Dexpression=" + expression, "-DforceStdout", "-q"} defines = append(defines, options.Defines...) executeOptions := ExecuteOptions{ @@ -101,7 +109,7 @@ func Evaluate(options *EvaluateOptions, expression string, command mavenExecRunn Defines: defines, ReturnStdout: true, } - value, err := Execute(&executeOptions, command) + value, err := Execute(&executeOptions, utils) if err != nil { return "", err } @@ -113,7 +121,7 @@ func Evaluate(options *EvaluateOptions, expression string, command mavenExecRunn // InstallFile installs a maven artifact and its pom into the local maven repository. // If "file" is empty, only the pom is installed. "pomFile" must not be empty. -func InstallFile(file, pomFile string, options *EvaluateOptions, command mavenExecRunner) error { +func InstallFile(file, pomFile string, options *EvaluateOptions, utils Utils) error { if len(pomFile) == 0 { return fmt.Errorf("pomFile can't be empty") } @@ -139,7 +147,7 @@ func InstallFile(file, pomFile string, options *EvaluateOptions, command mavenEx ProjectSettingsFile: options.ProjectSettingsFile, GlobalSettingsFile: options.GlobalSettingsFile, } - _, err := Execute(&mavenOptionsInstall, command) + _, err := Execute(&mavenOptionsInstall, utils) if err != nil { return fmt.Errorf("failed to install maven artifacts: %w", err) } @@ -147,12 +155,12 @@ func InstallFile(file, pomFile string, options *EvaluateOptions, command mavenEx } // InstallMavenArtifacts finds maven modules (identified by pom.xml files) and installs the artifacts into the local maven repository. -func InstallMavenArtifacts(command mavenExecRunner, options *EvaluateOptions) error { - return doInstallMavenArtifacts(command, options, newUtils()) +func InstallMavenArtifacts(options *EvaluateOptions, utils Utils) error { + return doInstallMavenArtifacts(options, utils) } -func doInstallMavenArtifacts(command mavenExecRunner, options *EvaluateOptions, utils mavenUtils) error { - err := flattenPom(command, options) +func doInstallMavenArtifacts(options *EvaluateOptions, utils Utils) error { + err := flattenPom(options, utils) if err != nil { return err } @@ -178,7 +186,7 @@ func doInstallMavenArtifacts(command mavenExecRunner, options *EvaluateOptions, // otherwise we would evaluate the root pom in all iterations. evaluateProjectPackagingOptions := *options evaluateProjectPackagingOptions.PomPath = pomFile - packaging, err := Evaluate(&evaluateProjectPackagingOptions, "project.packaging", command) + packaging, err := Evaluate(&evaluateProjectPackagingOptions, "project.packaging", utils) if err != nil { return err } @@ -193,13 +201,13 @@ func doInstallMavenArtifacts(command mavenExecRunner, options *EvaluateOptions, } if packaging == "pom" { - err = InstallFile("", pathToPomFile, options, command) + err = InstallFile("", pathToPomFile, options, utils) if err != nil { return err } } else { - err = installJarWarArtifacts(pathToPomFile, currentModuleDir, command, utils, options) + err = installJarWarArtifacts(pathToPomFile, currentModuleDir, options, utils) if err != nil { return err } @@ -208,15 +216,15 @@ func doInstallMavenArtifacts(command mavenExecRunner, options *EvaluateOptions, return err } -func installJarWarArtifacts(pomFile, dir string, command mavenExecRunner, utils mavenUtils, options *EvaluateOptions) error { +func installJarWarArtifacts(pomFile, dir string, options *EvaluateOptions, utils Utils) error { options.PomPath = filepath.Join(dir, "pom.xml") - finalName, err := Evaluate(options, "project.build.finalName", command) + finalName, err := Evaluate(options, "project.build.finalName", utils) if err != nil { return err } if finalName == "" { log.Entry().Warn("project.build.finalName is empty, skipping install of artifact. Installing only the pom file.") - err = InstallFile("", pomFile, options, command) + err = InstallFile("", pomFile, options, utils) if err != nil { return err } @@ -235,26 +243,26 @@ func installJarWarArtifacts(pomFile, dir string, command mavenExecRunner, utils // Due to spring's jar repackaging we need to check for an "original" jar file because the repackaged one is no suitable source for dependent maven modules if originalJarExists { - err = InstallFile(originalJarFile(dir, finalName), pomFile, options, command) + err = InstallFile(originalJarFile(dir, finalName), pomFile, options, utils) if err != nil { return err } } else if jarExists { - err = InstallFile(jarFile(dir, finalName), pomFile, options, command) + err = InstallFile(jarFile(dir, finalName), pomFile, options, utils) if err != nil { return err } } if warExists { - err = InstallFile(warFile(dir, finalName), pomFile, options, command) + err = InstallFile(warFile(dir, finalName), pomFile, options, utils) if err != nil { return err } } if classesJarExists { - err = InstallFile(classesJarFile(dir, finalName), pomFile, options, command) + err = InstallFile(classesJarFile(dir, finalName), pomFile, options, utils) if err != nil { return err } @@ -278,16 +286,16 @@ func warFile(dir, finalName string) string { return filepath.Join(dir, "target", finalName+".war") } -func flattenPom(command mavenExecRunner, o *EvaluateOptions) error { +func flattenPom(options *EvaluateOptions, utils Utils) error { mavenOptionsFlatten := ExecuteOptions{ Goals: []string{"flatten:flatten"}, Defines: []string{"-Dflatten.mode=resolveCiFriendliesOnly"}, PomPath: "pom.xml", - M2Path: o.M2Path, - ProjectSettingsFile: o.ProjectSettingsFile, - GlobalSettingsFile: o.GlobalSettingsFile, + M2Path: options.M2Path, + ProjectSettingsFile: options.ProjectSettingsFile, + GlobalSettingsFile: options.GlobalSettingsFile, } - _, err := Execute(&mavenOptionsFlatten, command) + _, err := Execute(&mavenOptionsFlatten, utils) return err } @@ -301,10 +309,10 @@ func evaluateStdOut(options *ExecuteOptions) (*bytes.Buffer, io.Writer) { return stdOutBuf, stdOut } -func getParametersFromOptions(options *ExecuteOptions, utils mavenUtils) ([]string, error) { +func getParametersFromOptions(options *ExecuteOptions, utils Utils) ([]string, error) { var parameters []string - parameters, err := DownloadAndGetMavenParameters(options.GlobalSettingsFile, options.ProjectSettingsFile, utils, utils) + parameters, err := DownloadAndGetMavenParameters(options.GlobalSettingsFile, options.ProjectSettingsFile, utils) if err != nil { return nil, err } @@ -336,11 +344,8 @@ func getParametersFromOptions(options *ExecuteOptions, utils mavenUtils) ([]stri return parameters, nil } -func GetTestModulesExcludes() []string { - return getTestModulesExcludes(newUtils()) -} - -func getTestModulesExcludes(utils mavenUtils) []string { +// GetTestModulesExcludes return testing modules that you be excluded from reactor +func GetTestModulesExcludes(utils Utils) []string { var excludes []string exists, _ := utils.FileExists("unit-tests/pom.xml") if exists { diff --git a/pkg/maven/maven_test.go b/pkg/maven/maven_test.go index 3df1fb34e..bf7456b5a 100644 --- a/pkg/maven/maven_test.go +++ b/pkg/maven/maven_test.go @@ -11,14 +11,15 @@ import ( "github.com/stretchr/testify/assert" ) -type mockUtils struct { +type MockUtils struct { shouldFail bool requestedUrls []string requestedFiles []string *mock.FilesMock + *mock.ExecMockRunner } -func (m *mockUtils) DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error { +func (m *MockUtils) DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error { m.requestedUrls = append(m.requestedUrls, url) m.requestedFiles = append(m.requestedFiles, filename) if m.shouldFail { @@ -27,43 +28,48 @@ func (m *mockUtils) DownloadFile(url, filename string, header http.Header, cooki return nil } -func newMockUtils(downloadShouldFail bool) mockUtils { - utils := mockUtils{shouldFail: downloadShouldFail, FilesMock: &mock.FilesMock{}} +func NewMockUtils(downloadShouldFail bool) MockUtils { + utils := MockUtils{ + shouldFail: downloadShouldFail, + FilesMock: &mock.FilesMock{}, + ExecMockRunner: &mock.ExecMockRunner{}, + } return utils } func TestExecute(t *testing.T) { t.Run("should return stdOut", func(t *testing.T) { expectedOutput := "mocked output" - execMockRunner := mock.ExecMockRunner{} - execMockRunner.StdoutReturn = map[string]string{"mvn --file pom.xml -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn --batch-mode": "mocked output"} + utils := NewMockUtils(false) + utils.StdoutReturn = map[string]string{"mvn --file pom.xml -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn --batch-mode": "mocked output"} opts := ExecuteOptions{PomPath: "pom.xml", ReturnStdout: true} - mavenOutput, _ := Execute(&opts, &execMockRunner) + mavenOutput, _ := Execute(&opts, &utils) assert.Equal(t, expectedOutput, mavenOutput) }) t.Run("should not return stdOut", func(t *testing.T) { expectedOutput := "" - execMockRunner := mock.ExecMockRunner{} - execMockRunner.StdoutReturn = map[string]string{"mvn --file pom.xml -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn --batch-mode": "mocked output"} + utils := NewMockUtils(false) + utils.StdoutReturn = map[string]string{"mvn --file pom.xml -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn --batch-mode": "mocked output"} opts := ExecuteOptions{PomPath: "pom.xml", ReturnStdout: false} - mavenOutput, _ := Execute(&opts, &execMockRunner) + mavenOutput, _ := Execute(&opts, &utils) assert.Equal(t, expectedOutput, mavenOutput) }) t.Run("should log that command failed if executing maven failed", func(t *testing.T) { - execMockRunner := mock.ExecMockRunner{ShouldFailOnCommand: map[string]error{"mvn --file pom.xml -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn --batch-mode": errors.New("error case")}} + utils := NewMockUtils(false) + utils.ShouldFailOnCommand = map[string]error{"mvn --file pom.xml -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn --batch-mode": errors.New("error case")} opts := ExecuteOptions{PomPath: "pom.xml", ReturnStdout: false} - output, err := Execute(&opts, &execMockRunner) + output, err := Execute(&opts, &utils) assert.EqualError(t, err, "failed to run executable, command: '[mvn --file pom.xml -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn --batch-mode]', error: error case") assert.Equal(t, "", output) }) t.Run("should have all configured parameters in the exec call", func(t *testing.T) { - execMockRunner := mock.ExecMockRunner{} + utils := NewMockUtils(false) opts := ExecuteOptions{PomPath: "pom.xml", ProjectSettingsFile: "settings.xml", GlobalSettingsFile: "anotherSettings.xml", M2Path: ".m2/", Goals: []string{"flatten", "install"}, Defines: []string{"-Da=b"}, @@ -73,29 +79,29 @@ func TestExecute(t *testing.T) { "-Dmaven.repo.local=.m2/", "--file", "pom.xml", "-q", "-Da=b", "--batch-mode", "flatten", "install"} - mavenOutput, _ := Execute(&opts, &execMockRunner) + mavenOutput, _ := Execute(&opts, &utils) - assert.Equal(t, len(expectedParameters), len(execMockRunner.Calls[0].Params)) - assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: expectedParameters}, execMockRunner.Calls[0]) + assert.Equal(t, len(expectedParameters), len(utils.Calls[0].Params)) + assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: expectedParameters}, utils.Calls[0]) assert.Equal(t, "", mavenOutput) }) } func TestEvaluate(t *testing.T) { t.Run("should evaluate expression", func(t *testing.T) { - execMockRunner := mock.ExecMockRunner{} - execMockRunner.StdoutReturn = map[string]string{"mvn --file pom.xml -Dexpression=project.groupId -DforceStdout -q -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn --batch-mode org.apache.maven.plugins:maven-help-plugin:3.1.0:evaluate": "com.awesome"} + utils := NewMockUtils(false) + utils.StdoutReturn = map[string]string{"mvn --file pom.xml -Dexpression=project.groupId -DforceStdout -q -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn --batch-mode org.apache.maven.plugins:maven-help-plugin:3.1.0:evaluate": "com.awesome"} - result, err := Evaluate(&EvaluateOptions{PomPath: "pom.xml"}, "project.groupId", &execMockRunner) + result, err := Evaluate(&EvaluateOptions{PomPath: "pom.xml"}, "project.groupId", &utils) if assert.NoError(t, err) { assert.Equal(t, "com.awesome", result) } }) t.Run("should not evaluate expression", func(t *testing.T) { - execMockRunner := mock.ExecMockRunner{} - execMockRunner.StdoutReturn = map[string]string{"mvn --file pom.xml -Dexpression=project.groupId -DforceStdout -q -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn --batch-mode org.apache.maven.plugins:maven-help-plugin:3.1.0:evaluate": "null object or invalid expression"} + utils := NewMockUtils(false) + utils.StdoutReturn = map[string]string{"mvn --file pom.xml -Dexpression=project.groupId -DforceStdout -q -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn --batch-mode org.apache.maven.plugins:maven-help-plugin:3.1.0:evaluate": "null object or invalid expression"} - result, err := Evaluate(&EvaluateOptions{PomPath: "pom.xml"}, "project.groupId", &execMockRunner) + result, err := Evaluate(&EvaluateOptions{PomPath: "pom.xml"}, "project.groupId", &utils) if assert.EqualError(t, err, "expression 'project.groupId' in file 'pom.xml' could not be resolved") { assert.Equal(t, "", result) } @@ -104,7 +110,7 @@ func TestEvaluate(t *testing.T) { func TestGetParameters(t *testing.T) { t.Run("should resolve configured parameters and download the settings files", func(t *testing.T) { - utils := newMockUtils(false) + utils := NewMockUtils(false) opts := ExecuteOptions{PomPath: "pom.xml", GlobalSettingsFile: "https://mysettings.com", ProjectSettingsFile: "http://myprojectsettings.com", ReturnStdout: false} expectedParameters := []string{ "--global-settings", ".pipeline/mavenGlobalSettings.xml", @@ -126,7 +132,7 @@ func TestGetParameters(t *testing.T) { } }) t.Run("should resolve configured parameters and not download existing settings files", func(t *testing.T) { - utils := newMockUtils(false) + utils := NewMockUtils(false) utils.AddFile(".pipeline/mavenGlobalSettings.xml", []byte("dummyContent")) utils.AddFile(".pipeline/mavenProjectSettings.xml", []byte("dummyContent")) opts := ExecuteOptions{PomPath: "pom.xml", GlobalSettingsFile: "https://mysettings.com", ProjectSettingsFile: "http://myprojectsettings.com", ReturnStdout: false} @@ -148,20 +154,20 @@ func TestGetParameters(t *testing.T) { func TestGetTestModulesExcludes(t *testing.T) { t.Run("Should return excludes for unit- and integration-tests", func(t *testing.T) { - utils := newMockUtils(false) + utils := NewMockUtils(false) utils.AddFile("unit-tests/pom.xml", []byte("dummyContent")) utils.AddFile("integration-tests/pom.xml", []byte("dummyContent")) expected := []string{"-pl", "!unit-tests", "-pl", "!integration-tests"} - modulesExcludes := getTestModulesExcludes(&utils) + modulesExcludes := GetTestModulesExcludes(&utils) assert.Equal(t, expected, modulesExcludes) }) t.Run("Should not return excludes for unit- and integration-tests", func(t *testing.T) { - utils := newMockUtils(false) + utils := NewMockUtils(false) var expected []string - modulesExcludes := getTestModulesExcludes(&utils) + modulesExcludes := GetTestModulesExcludes(&utils) assert.Equal(t, expected, modulesExcludes) }) } @@ -179,58 +185,54 @@ func TestMavenInstall(t *testing.T) { }) t.Run("Install a file", func(t *testing.T) { - execMockRunner := mock.ExecMockRunner{} + utils := NewMockUtils(false) expectedParameters := []string{"-Dfile=app.jar", "-Dpackaging=jar", "-DpomFile=pom.xml", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "install:install-file"} - err := InstallFile("app.jar", "pom.xml", &EvaluateOptions{}, &execMockRunner) + err := InstallFile("app.jar", "pom.xml", &EvaluateOptions{}, &utils) assert.NoError(t, err) - if assert.Equal(t, len(expectedParameters), len(execMockRunner.Calls[0].Params)) { - assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: expectedParameters}, execMockRunner.Calls[0]) + if assert.Equal(t, len(expectedParameters), len(utils.Calls[0].Params)) { + assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: expectedParameters}, utils.Calls[0]) } }) t.Run("Install files in a project", func(t *testing.T) { - utils := newMockUtils(false) + utils := NewMockUtils(false) utils.AddFile("target/foo.jar", []byte("dummyContent")) utils.AddFile("target/foo.war", []byte("dummyContent")) utils.AddFile("pom.xml", []byte("")) options := EvaluateOptions{} - options.ProjectSettingsFile = "settings.xml" - - execMockRunner := mock.ExecMockRunner{} - execMockRunner.StdoutReturn = map[string]string{"mvn --settings settings.xml --file pom.xml -Dexpression=project.build.finalName -DforceStdout -q -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn --batch-mode org.apache.maven.plugins:maven-help-plugin:3.1.0:evaluate": "foo"} - err := doInstallMavenArtifacts(&execMockRunner, &options, &utils) + utils.StdoutReturn = map[string]string{"mvn --settings settings.xml --file pom.xml -Dexpression=project.build.finalName -DforceStdout -q -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn --batch-mode org.apache.maven.plugins:maven-help-plugin:3.1.0:evaluate": "foo"} + err := doInstallMavenArtifacts(&options, &utils) assert.NoError(t, err) - if assert.Equal(t, 5, len(execMockRunner.Calls)) { - assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: []string{"--settings", "settings.xml", "--file", "pom.xml", "-Dflatten.mode=resolveCiFriendliesOnly", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "flatten:flatten"}}, execMockRunner.Calls[0]) - assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: []string{"--settings", "settings.xml", "--file", "pom.xml", "-Dexpression=project.packaging", "-DforceStdout", "-q", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "org.apache.maven.plugins:maven-help-plugin:3.1.0:evaluate"}}, execMockRunner.Calls[1]) - assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: []string{"--settings", "settings.xml", "--file", "pom.xml", "-Dexpression=project.build.finalName", "-DforceStdout", "-q", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "org.apache.maven.plugins:maven-help-plugin:3.1.0:evaluate"}}, execMockRunner.Calls[2]) - assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: []string{"--settings", "settings.xml", "-Dfile=" + filepath.Join(".", "target", "foo.jar"), "-Dpackaging=jar", "-DpomFile=pom.xml", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "install:install-file"}}, execMockRunner.Calls[3]) - assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: []string{"--settings", "settings.xml", "-Dfile=" + filepath.Join(".", "target", "foo.war"), "-DpomFile=pom.xml", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "install:install-file"}}, execMockRunner.Calls[4]) + if assert.Equal(t, 5, len(utils.Calls)) { + assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: []string{"--settings", "settings.xml", "--file", "pom.xml", "-Dflatten.mode=resolveCiFriendliesOnly", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "flatten:flatten"}}, utils.Calls[0]) + assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: []string{"--settings", "settings.xml", "--file", "pom.xml", "-Dexpression=project.packaging", "-DforceStdout", "-q", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "org.apache.maven.plugins:maven-help-plugin:3.1.0:evaluate"}}, utils.Calls[1]) + assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: []string{"--settings", "settings.xml", "--file", "pom.xml", "-Dexpression=project.build.finalName", "-DforceStdout", "-q", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "org.apache.maven.plugins:maven-help-plugin:3.1.0:evaluate"}}, utils.Calls[2]) + assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: []string{"--settings", "settings.xml", "-Dfile=" + filepath.Join(".", "target", "foo.jar"), "-Dpackaging=jar", "-DpomFile=pom.xml", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "install:install-file"}}, utils.Calls[3]) + assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: []string{"--settings", "settings.xml", "-Dfile=" + filepath.Join(".", "target", "foo.war"), "-DpomFile=pom.xml", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "install:install-file"}}, utils.Calls[4]) } }) t.Run("Install files in a spring-boot project", func(t *testing.T) { - utils := newMockUtils(false) + utils := NewMockUtils(false) utils.AddFile("target/foo.jar", []byte("dummyContent")) utils.AddFile("target/foo.jar.original", []byte("dummyContent")) utils.AddFile("pom.xml", []byte("")) options := EvaluateOptions{} - execMockRunner := mock.ExecMockRunner{} - execMockRunner.StdoutReturn = map[string]string{"mvn --file pom.xml -Dexpression=project.build.finalName -DforceStdout -q -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn --batch-mode org.apache.maven.plugins:maven-help-plugin:3.1.0:evaluate": "foo"} - err := doInstallMavenArtifacts(&execMockRunner, &options, &utils) + utils.StdoutReturn = map[string]string{"mvn --file pom.xml -Dexpression=project.build.finalName -DforceStdout -q -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn --batch-mode org.apache.maven.plugins:maven-help-plugin:3.1.0:evaluate": "foo"} + err := doInstallMavenArtifacts(&options, &utils) assert.NoError(t, err) - if assert.Equal(t, 4, len(execMockRunner.Calls)) { - assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: []string{"--file", "pom.xml", "-Dflatten.mode=resolveCiFriendliesOnly", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "flatten:flatten"}}, execMockRunner.Calls[0]) - assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: []string{"--file", "pom.xml", "-Dexpression=project.packaging", "-DforceStdout", "-q", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "org.apache.maven.plugins:maven-help-plugin:3.1.0:evaluate"}}, execMockRunner.Calls[1]) - assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: []string{"--file", "pom.xml", "-Dexpression=project.build.finalName", "-DforceStdout", "-q", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "org.apache.maven.plugins:maven-help-plugin:3.1.0:evaluate"}}, execMockRunner.Calls[2]) - assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: []string{"-Dfile=" + filepath.Join(".", "target", "foo.jar.original"), "-Dpackaging=jar", "-DpomFile=pom.xml", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "install:install-file"}}, execMockRunner.Calls[3]) + if assert.Equal(t, 4, len(utils.Calls)) { + assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: []string{"--file", "pom.xml", "-Dflatten.mode=resolveCiFriendliesOnly", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "flatten:flatten"}}, utils.Calls[0]) + assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: []string{"--file", "pom.xml", "-Dexpression=project.packaging", "-DforceStdout", "-q", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "org.apache.maven.plugins:maven-help-plugin:3.1.0:evaluate"}}, utils.Calls[1]) + assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: []string{"--file", "pom.xml", "-Dexpression=project.build.finalName", "-DforceStdout", "-q", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "org.apache.maven.plugins:maven-help-plugin:3.1.0:evaluate"}}, utils.Calls[2]) + assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: []string{"-Dfile=" + filepath.Join(".", "target", "foo.jar.original"), "-Dpackaging=jar", "-DpomFile=pom.xml", "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn", "--batch-mode", "install:install-file"}}, utils.Calls[3]) } }) } diff --git a/pkg/maven/settings.go b/pkg/maven/settings.go index 53d62ce2b..0ec73879b 100644 --- a/pkg/maven/settings.go +++ b/pkg/maven/settings.go @@ -11,25 +11,20 @@ import ( var getenv = os.Getenv -// SettingsDownloadUtils defines an interface for downloading files. +// SettingsDownloadUtils defines an interface for downloading and storing maven settings files. type SettingsDownloadUtils interface { DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error -} - -// FileUtils defines the external file-related functionality needed by this package. -type FileUtils interface { FileExists(filename string) (bool, error) Copy(src, dest string) (int64, error) MkdirAll(path string, perm os.FileMode) error - Glob(pattern string) (matches []string, err error) } // DownloadAndGetMavenParameters downloads the global or project settings file if the strings contain URLs. // It then constructs the arguments that need to be passed to maven in order to point to use these settings files. -func DownloadAndGetMavenParameters(globalSettingsFile string, projectSettingsFile string, fileUtils FileUtils, httpClient SettingsDownloadUtils) ([]string, error) { +func DownloadAndGetMavenParameters(globalSettingsFile string, projectSettingsFile string, utils SettingsDownloadUtils) ([]string, error) { mavenArgs := []string{} if len(globalSettingsFile) > 0 { - globalSettingsFileName, err := downloadSettingsIfURL(globalSettingsFile, ".pipeline/mavenGlobalSettings.xml", fileUtils, httpClient, false) + globalSettingsFileName, err := downloadSettingsIfURL(globalSettingsFile, ".pipeline/mavenGlobalSettings.xml", utils, false) if err != nil { return nil, err } @@ -40,7 +35,7 @@ func DownloadAndGetMavenParameters(globalSettingsFile string, projectSettingsFil } if len(projectSettingsFile) > 0 { - projectSettingsFileName, err := downloadSettingsIfURL(projectSettingsFile, ".pipeline/mavenProjectSettings.xml", fileUtils, httpClient, false) + projectSettingsFileName, err := downloadSettingsIfURL(projectSettingsFile, ".pipeline/mavenProjectSettings.xml", utils, false) if err != nil { return nil, err } @@ -55,14 +50,14 @@ func DownloadAndGetMavenParameters(globalSettingsFile string, projectSettingsFil // DownloadAndCopySettingsFiles downloads the global or project settings file if the strings contain URLs. // It copies the given files to either the locations specified in the environment variables M2_HOME and HOME // or the default locations where maven expects them. -func DownloadAndCopySettingsFiles(globalSettingsFile string, projectSettingsFile string, fileUtils FileUtils, httpClient SettingsDownloadUtils) error { +func DownloadAndCopySettingsFiles(globalSettingsFile string, projectSettingsFile string, utils SettingsDownloadUtils) error { if len(projectSettingsFile) > 0 { destination, err := getProjectSettingsFileDest() if err != nil { return err } - if err := downloadAndCopySettingsFile(projectSettingsFile, destination, fileUtils, httpClient); err != nil { + if err := downloadAndCopySettingsFile(projectSettingsFile, destination, utils); err != nil { return err } } else { @@ -75,7 +70,7 @@ func DownloadAndCopySettingsFiles(globalSettingsFile string, projectSettingsFile if err != nil { return err } - if err := downloadAndCopySettingsFile(globalSettingsFile, destination, fileUtils, httpClient); err != nil { + if err := downloadAndCopySettingsFile(globalSettingsFile, destination, utils); err != nil { return err } } else { @@ -86,7 +81,7 @@ func DownloadAndCopySettingsFiles(globalSettingsFile string, projectSettingsFile return nil } -func downloadAndCopySettingsFile(src string, dest string, fileUtils FileUtils, httpClient SettingsDownloadUtils) error { +func downloadAndCopySettingsFile(src string, dest string, utils SettingsDownloadUtils) error { if len(src) == 0 { return fmt.Errorf("Settings file source location not provided") } @@ -98,7 +93,7 @@ func downloadAndCopySettingsFile(src string, dest string, fileUtils FileUtils, h log.Entry().Debugf("Copying file \"%s\" to \"%s\"", src, dest) if strings.HasPrefix(src, "http:") || strings.HasPrefix(src, "https:") { - err := downloadSettingsFromURL(src, dest, fileUtils, httpClient, true) + err := downloadSettingsFromURL(src, dest, utils, true) if err != nil { return err } @@ -108,19 +103,19 @@ func downloadAndCopySettingsFile(src string, dest string, fileUtils FileUtils, h parent := filepath.Dir(dest) - parentFolderExists, err := fileUtils.FileExists(parent) + parentFolderExists, err := utils.FileExists(parent) if err != nil { return err } if !parentFolderExists { - if err = fileUtils.MkdirAll(parent, 0775); err != nil { + if err = utils.MkdirAll(parent, 0775); err != nil { return err } } - if _, err := fileUtils.Copy(src, dest); err != nil { + if _, err := utils.Copy(src, dest); err != nil { return err } } @@ -128,10 +123,10 @@ func downloadAndCopySettingsFile(src string, dest string, fileUtils FileUtils, h return nil } -func downloadSettingsIfURL(settingsFileOption, settingsFile string, fileUtils FileUtils, httpClient SettingsDownloadUtils, overwrite bool) (string, error) { +func downloadSettingsIfURL(settingsFileOption, settingsFile string, utils SettingsDownloadUtils, overwrite bool) (string, error) { result := settingsFileOption if strings.HasPrefix(settingsFileOption, "http:") || strings.HasPrefix(settingsFileOption, "https:") { - err := downloadSettingsFromURL(settingsFileOption, settingsFile, fileUtils, httpClient, overwrite) + err := downloadSettingsFromURL(settingsFileOption, settingsFile, utils, overwrite) if err != nil { return "", err } @@ -140,13 +135,13 @@ func downloadSettingsIfURL(settingsFileOption, settingsFile string, fileUtils Fi return result, nil } -func downloadSettingsFromURL(url, filename string, fileUtils FileUtils, httpClient SettingsDownloadUtils, overwrite bool) error { - exists, _ := fileUtils.FileExists(filename) +func downloadSettingsFromURL(url, filename string, utils SettingsDownloadUtils, overwrite bool) error { + exists, _ := utils.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) + 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) diff --git a/pkg/maven/settings_test.go b/pkg/maven/settings_test.go index 32f8153ca..fc1e79721 100644 --- a/pkg/maven/settings_test.go +++ b/pkg/maven/settings_test.go @@ -3,6 +3,7 @@ package maven import ( "fmt" piperhttp "github.com/SAP/jenkins-library/pkg/http" + "github.com/SAP/jenkins-library/pkg/mock" "github.com/stretchr/testify/assert" "net/http" "os" @@ -26,60 +27,56 @@ func TestSettings(t *testing.T) { t.Run("Settings file source location not provided", func(t *testing.T) { - httpClient := httpMock{} - fileUtils := fileUtilsMock{} + utilsMock := newSettingsDownloadTestUtilsBundle() - err := downloadAndCopySettingsFile("", "foo", &fileUtils, &httpClient) + err := downloadAndCopySettingsFile("", "foo", utilsMock) assert.EqualError(t, err, "Settings file source location not provided") }) t.Run("Settings file destination location not provided", func(t *testing.T) { - httpClient := httpMock{} - fileUtils := fileUtilsMock{} + utilsMock := newSettingsDownloadTestUtilsBundle() - err := downloadAndCopySettingsFile("/opt/sap/maven/global-settings.xml", "", &fileUtils, &httpClient) + err := downloadAndCopySettingsFile("/opt/sap/maven/global-settings.xml", "", utilsMock) 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": "", - }} + utilsMock := newSettingsDownloadTestUtilsBundle() - err := DownloadAndCopySettingsFiles("/opt/sap/maven/global-settings.xml", "/opt/sap/maven/project-settings.xml", &fileUtils, &httpClient) + utilsMock.AddFile("/opt/sap/maven/global-settings.xml", []byte("")) + utilsMock.AddFile("/opt/sap/maven/project-settings.xml", []byte("")) + + err := DownloadAndCopySettingsFiles("/opt/sap/maven/global-settings.xml", "/opt/sap/maven/project-settings.xml", utilsMock) if assert.NoError(t, err) { - assert.Equal(t, "/usr/share/maven/conf/settings.xml", fileUtils.copiedFiles["/opt/sap/maven/global-settings.xml"]) - assert.Equal(t, "/home/me/.m2/settings.xml", fileUtils.copiedFiles["/opt/sap/maven/project-settings.xml"]) + assert.True(t, utilsMock.HasCopiedFile("/opt/sap/maven/global-settings.xml", "/usr/share/maven/conf/settings.xml")) + assert.True(t, utilsMock.HasCopiedFile("/opt/sap/maven/project-settings.xml", "/home/me/.m2/settings.xml")) } - assert.Empty(t, httpClient.downloadedFiles) + assert.Empty(t, utilsMock.downloadedFiles) }) t.Run("Retrieve settings file via http", func(t *testing.T) { - httpClient := httpMock{} - fileUtils := fileUtilsMock{} + utilsMock := newSettingsDownloadTestUtilsBundle() - err := downloadAndCopySettingsFile("https://example.org/maven/global-settings.xml", "/usr/share/maven/conf/settings.xml", &fileUtils, &httpClient) + err := downloadAndCopySettingsFile("https://example.org/maven/global-settings.xml", "/usr/share/maven/conf/settings.xml", utilsMock) if assert.NoError(t, err) { - assert.Equal(t, "/usr/share/maven/conf/settings.xml", httpClient.downloadedFiles["https://example.org/maven/global-settings.xml"]) + assert.Equal(t, "/usr/share/maven/conf/settings.xml", utilsMock.downloadedFiles["https://example.org/maven/global-settings.xml"]) } }) t.Run("Retrieve settings file via http - received error from downloader", func(t *testing.T) { - httpClient := httpMock{expectedError: fmt.Errorf("Download failed")} - fileUtils := fileUtilsMock{} + utilsMock := newSettingsDownloadTestUtilsBundle() + utilsMock.expectedError = fmt.Errorf("Download failed") - err := downloadAndCopySettingsFile("https://example.org/maven/global-settings.xml", "/usr/share/maven/conf/settings.xml", &fileUtils, &httpClient) + err := downloadAndCopySettingsFile("https://example.org/maven/global-settings.xml", "/usr/share/maven/conf/settings.xml", utilsMock) if assert.Error(t, err) { assert.Contains(t, err.Error(), "failed to download maven settings from URL") @@ -88,26 +85,33 @@ func TestSettings(t *testing.T) { t.Run("Retrieve project settings file - file not found", func(t *testing.T) { - httpClient := httpMock{} - fileUtils := fileUtilsMock{} + utilsMock := newSettingsDownloadTestUtilsBundle() - err := downloadAndCopySettingsFile("/opt/sap/maven/project-settings.xml", "/home/me/.m2/settings.xml", &fileUtils, &httpClient) + err := downloadAndCopySettingsFile("/opt/sap/maven/project-settings.xml", "/home/me/.m2/settings.xml", utilsMock) if assert.Error(t, err) { - assert.Contains(t, err.Error(), "Source file '/opt/sap/maven/project-settings.xml' does not exist") + assert.Contains(t, err.Error(), "cannot copy '/opt/sap/maven/project-settings.xml': file does not exist") } }) } -type httpMock struct { +func newSettingsDownloadTestUtilsBundle() *settingsDownloadTestUtils { + utilsBundle := settingsDownloadTestUtils{ + FilesMock: &mock.FilesMock{}, + } + return &utilsBundle +} + +type settingsDownloadTestUtils struct { + *mock.FilesMock expectedError error downloadedFiles map[string]string // src, dest } -func (c *httpMock) SetOptions(options piperhttp.ClientOptions) { +func (c *settingsDownloadTestUtils) SetOptions(options piperhttp.ClientOptions) { } -func (c *httpMock) DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error { +func (c *settingsDownloadTestUtils) DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error { if c.expectedError != nil { return c.expectedError @@ -119,70 +123,3 @@ func (c *httpMock) DownloadFile(url, filename string, header http.Header, cookie c.downloadedFiles[url] = filename return nil } - -type fileUtilsMock struct { - existingFiles map[string]string - writtenFiles map[string]string - copiedFiles map[string]string -} - -func (f *fileUtilsMock) FileExists(path string) (bool, error) { - - if _, ok := f.existingFiles[path]; ok { - return true, nil - } - return false, nil -} - -func (f *fileUtilsMock) Copy(src, dest string) (int64, error) { - - exists, err := f.FileExists(src) - - if err != nil { - return 0, err - } - - if !exists { - return 0, fmt.Errorf("Source file '"+src+"' does not exist", src) - } - - if f.copiedFiles == nil { - f.copiedFiles = make(map[string]string) - } - f.copiedFiles[src] = dest - - return 0, nil -} - -func (f *fileUtilsMock) FileRead(path string) ([]byte, error) { - return []byte(f.existingFiles[path]), nil -} - -func (f *fileUtilsMock) FileWrite(path string, content []byte, perm os.FileMode) error { - - if f.writtenFiles == nil { - f.writtenFiles = make(map[string]string) - } - - if _, ok := f.writtenFiles[path]; ok { - delete(f.writtenFiles, path) - } - f.writtenFiles[path] = string(content) - return nil -} - -func (f *fileUtilsMock) MkdirAll(path string, perm os.FileMode) error { - return nil -} - -func (f *fileUtilsMock) 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.") -} - -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.") -} diff --git a/pkg/mock/fileUtils.go b/pkg/mock/fileUtils.go index 4df27e3af..8a8583d38 100644 --- a/pkg/mock/fileUtils.go +++ b/pkg/mock/fileUtils.go @@ -49,6 +49,7 @@ func (p *fileProperties) isDir() bool { type FilesMock struct { files map[string]*fileProperties writtenFiles []string + copiedFiles map[string]string removedFiles []string CurrentDir string Separator string @@ -61,6 +62,9 @@ func (f *FilesMock) init() { if f.Separator == "" { f.Separator = string(os.PathSeparator) } + if f.copiedFiles == nil { + f.copiedFiles = map[string]string{} + } } // toAbsPath checks if the given path is relative, and if so converts it to an absolute path considering the @@ -134,6 +138,12 @@ func (f *FilesMock) HasWrittenFile(path string) bool { return piperutils.ContainsString(f.writtenFiles, f.toAbsPath(path)) } +// HasCopiedFile returns true if the virtual file system at one point contained an entry for the given source and destination, +// and it was written via CopyFile(). +func (f *FilesMock) HasCopiedFile(src string, dest string) bool { + return f.copiedFiles[f.toAbsPath(src)] == f.toAbsPath(dest) +} + // FileExists returns true if file content has been associated with the given path, false otherwise. // Only relative paths are supported. func (f *FilesMock) FileExists(path string) (bool, error) { @@ -187,6 +197,7 @@ func (f *FilesMock) Copy(src, dst string) (int64, error) { return 0, fmt.Errorf("cannot copy '%s': %w", src, os.ErrNotExist) } f.AddFileWithMode(dst, *props.content, props.mode) + f.copiedFiles[f.toAbsPath(src)] = f.toAbsPath(dst) return int64(len(*props.content)), nil } diff --git a/pkg/versioning/docker.go b/pkg/versioning/docker.go index 43341e4b2..ca368b824 100644 --- a/pkg/versioning/docker.go +++ b/pkg/versioning/docker.go @@ -14,7 +14,7 @@ import ( type Docker struct { artifact Artifact content []byte - execRunner mavenExecRunner + utils Utils options *Options path string versionSource string @@ -75,7 +75,7 @@ func (d *Docker) GetVersion() (string, error) { if d.options == nil { d.options = &Options{} } - d.artifact, err = GetArtifact(d.versionSource, d.path, d.options, d.execRunner) + d.artifact, err = GetArtifact(d.versionSource, d.path, d.options, d.utils) if err != nil { return "", err } diff --git a/pkg/versioning/maven.go b/pkg/versioning/maven.go index 8c1d6f726..db220dcfd 100644 --- a/pkg/versioning/maven.go +++ b/pkg/versioning/maven.go @@ -4,7 +4,6 @@ import ( "fmt" "io" - "github.com/SAP/jenkins-library/pkg/command" "github.com/SAP/jenkins-library/pkg/maven" "github.com/pkg/errors" @@ -17,8 +16,8 @@ type mavenExecRunner interface { } type mavenRunner interface { - Execute(*maven.ExecuteOptions, mavenExecRunner) (string, error) - Evaluate(*maven.EvaluateOptions, string, mavenExecRunner) (string, error) + Execute(*maven.ExecuteOptions, maven.Utils) (string, error) + Evaluate(*maven.EvaluateOptions, string, maven.Utils) (string, error) } // MavenDescriptor holds the unique identifier combination for Maven built Java artifacts @@ -31,9 +30,9 @@ type MavenDescriptor struct { // Maven defines a maven artifact used for versioning type Maven struct { - options maven.EvaluateOptions - runner mavenRunner - execRunner mavenExecRunner + options maven.EvaluateOptions + runner mavenRunner + utils maven.Utils } func (m *Maven) init() { @@ -41,8 +40,8 @@ func (m *Maven) init() { m.options.PomPath = "pom.xml" } - if m.execRunner == nil { - m.execRunner = &command.Command{} + if m.utils == nil { + m.utils = maven.NewUtilsBundle() } } @@ -78,7 +77,7 @@ func (m *Maven) GetCoordinates() (Coordinates, error) { func (m *Maven) GetPackaging() (string, error) { m.init() - packaging, err := m.runner.Evaluate(&m.options, "project.packaging", m.execRunner) + packaging, err := m.runner.Evaluate(&m.options, "project.packaging", m.utils) if err != nil { return "", errors.Wrap(err, "Maven - getting packaging failed") } @@ -89,7 +88,7 @@ func (m *Maven) GetPackaging() (string, error) { func (m *Maven) GetGroupID() (string, error) { m.init() - groupID, err := m.runner.Evaluate(&m.options, "project.groupId", m.execRunner) + groupID, err := m.runner.Evaluate(&m.options, "project.groupId", m.utils) if err != nil { return "", errors.Wrap(err, "Maven - getting groupId failed") } @@ -100,7 +99,7 @@ func (m *Maven) GetGroupID() (string, error) { func (m *Maven) GetArtifactID() (string, error) { m.init() - artifactID, err := m.runner.Evaluate(&m.options, "project.artifactId", m.execRunner) + artifactID, err := m.runner.Evaluate(&m.options, "project.artifactId", m.utils) if err != nil { return "", errors.Wrap(err, "Maven - getting artifactId failed") } @@ -111,7 +110,7 @@ func (m *Maven) GetArtifactID() (string, error) { func (m *Maven) GetVersion() (string, error) { m.init() - version, err := m.runner.Evaluate(&m.options, "project.version", m.execRunner) + version, err := m.runner.Evaluate(&m.options, "project.version", m.utils) if err != nil { return "", errors.Wrap(err, "Maven - getting version failed") } @@ -123,7 +122,7 @@ func (m *Maven) GetVersion() (string, error) { func (m *Maven) SetVersion(version string) error { m.init() - groupID, err := m.runner.Evaluate(&m.options, "project.groupId", m.execRunner) + groupID, err := m.runner.Evaluate(&m.options, "project.groupId", m.utils) if err != nil { return errors.Wrap(err, "Maven - getting groupId failed") } @@ -141,7 +140,7 @@ func (m *Maven) SetVersion(version string) error { "-DgenerateBackupPoms=false", }, } - _, err = m.runner.Execute(&opts, m.execRunner) + _, err = m.runner.Execute(&opts, m.utils) if err != nil { return errors.Wrapf(err, "Maven - setting version %v failed", version) } diff --git a/pkg/versioning/maven_test.go b/pkg/versioning/maven_test.go index 8eba91630..b8fcc0377 100644 --- a/pkg/versioning/maven_test.go +++ b/pkg/versioning/maven_test.go @@ -17,7 +17,7 @@ type mavenMockRunner struct { expression string } -func (m *mavenMockRunner) Evaluate(opts *maven.EvaluateOptions, expression string, runner mavenExecRunner) (string, error) { +func (m *mavenMockRunner) Evaluate(opts *maven.EvaluateOptions, expression string, utils maven.Utils) (string, error) { m.opts = opts m.expression = expression if len(m.evaluateErrorString) > 0 { @@ -26,7 +26,7 @@ func (m *mavenMockRunner) Evaluate(opts *maven.EvaluateOptions, expression strin return m.stdout, nil } -func (m *mavenMockRunner) Execute(opts *maven.ExecuteOptions, runner mavenExecRunner) (string, error) { +func (m *mavenMockRunner) Execute(opts *maven.ExecuteOptions, utils maven.Utils) (string, error) { m.execOpts = opts if len(m.executeErrorString) > 0 { return "", fmt.Errorf(m.executeErrorString) diff --git a/pkg/versioning/versioning.go b/pkg/versioning/versioning.go index 86946fca9..94febcba8 100644 --- a/pkg/versioning/versioning.go +++ b/pkg/versioning/versioning.go @@ -31,19 +31,24 @@ type Options struct { VersioningScheme string } +// Utils defines the versioning operations for various build tools +type Utils interface { + maven.Utils +} + type mvnRunner struct{} -func (m *mvnRunner) Execute(options *maven.ExecuteOptions, execRunner mavenExecRunner) (string, error) { - return maven.Execute(options, execRunner) +func (m *mvnRunner) Execute(options *maven.ExecuteOptions, utils maven.Utils) (string, error) { + return maven.Execute(options, utils) } -func (m *mvnRunner) Evaluate(options *maven.EvaluateOptions, expression string, execRunner mavenExecRunner) (string, error) { - return maven.Evaluate(options, expression, execRunner) +func (m *mvnRunner) Evaluate(options *maven.EvaluateOptions, expression string, utils maven.Utils) (string, error) { + return maven.Evaluate(options, expression, utils) } var fileExists func(string) (bool, error) // GetArtifact returns the build tool specific implementation for retrieving version, etc. of an artifact -func GetArtifact(buildTool, buildDescriptorFilePath string, opts *Options, execRunner mavenExecRunner) (Artifact, error) { +func GetArtifact(buildTool, buildDescriptorFilePath string, opts *Options, utils Utils) (Artifact, error) { var artifact Artifact if fileExists == nil { fileExists = piperutils.FileExists @@ -57,7 +62,7 @@ func GetArtifact(buildTool, buildDescriptorFilePath string, opts *Options, execR } case "docker": artifact = &Docker{ - execRunner: execRunner, + utils: utils, options: opts, path: buildDescriptorFilePath, versionSource: opts.VersionSource, @@ -100,8 +105,8 @@ func GetArtifact(buildTool, buildDescriptorFilePath string, opts *Options, execR buildDescriptorFilePath = "pom.xml" } artifact = &Maven{ - runner: &mvnRunner{}, - execRunner: execRunner, + runner: &mvnRunner{}, + utils: utils, options: maven.EvaluateOptions{ PomPath: buildDescriptorFilePath, ProjectSettingsFile: opts.ProjectSettingsFile, diff --git a/pkg/whitesource/scanMaven.go b/pkg/whitesource/scanMaven.go index 1f370dc1e..89ec4eb93 100644 --- a/pkg/whitesource/scanMaven.go +++ b/pkg/whitesource/scanMaven.go @@ -29,12 +29,12 @@ func (s *Scan) ExecuteMavenScanForPomFile(config *ScanOptions, utils Utils, pomP } if config.InstallArtifacts { - err := maven.InstallMavenArtifacts(utils, &maven.EvaluateOptions{ + err := maven.InstallMavenArtifacts(&maven.EvaluateOptions{ M2Path: config.M2Path, ProjectSettingsFile: config.ProjectSettingsFile, GlobalSettingsFile: config.GlobalSettingsFile, PomPath: pomPath, - }) + }, utils) if err != nil { return err } diff --git a/pkg/whitesource/utils.go b/pkg/whitesource/utils.go index 139296dc2..f54babaf1 100644 --- a/pkg/whitesource/utils.go +++ b/pkg/whitesource/utils.go @@ -1,8 +1,8 @@ package whitesource import ( + "github.com/SAP/jenkins-library/pkg/maven" "io" - "net/http" "os" ) @@ -15,16 +15,10 @@ type File interface { // Utils captures all external functionality that needs to be exchangeable in tests. type Utils interface { - Stdout(out io.Writer) - Stderr(err io.Writer) - RunExecutable(executable string, params ...string) error - - DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error + maven.Utils Chdir(path string) error Getwd() (string, error) - MkdirAll(path string, perm os.FileMode) error - FileExists(path string) (bool, error) FileRead(path string) ([]byte, error) FileWrite(path string, content []byte, perm os.FileMode) error FileRemove(path string) error