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

Refactor maven utils and add tests for install artifacts (#2318)

Co-authored-by: Stephan Aßmus <stephan.assmus@sap.com>
This commit is contained in:
Daniel Kurzynski
2020-11-10 17:14:55 +01:00
committed by GitHub
parent 2c432124fc
commit 9a18489cc4
27 changed files with 791 additions and 852 deletions

View File

@@ -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")

View File

@@ -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
}

View File

@@ -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",

View File

@@ -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")
})
}

View File

@@ -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
}

View File

@@ -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")
})
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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(`<project> </project>`))
utils.FilesMock.AddFile("integration-tests/pom.xml", []byte(`<project> </project>`))
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{},

View File

@@ -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)
})
}

View File

@@ -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
}

View File

@@ -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}
}

View File

@@ -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
}

View File

@@ -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))

View File

@@ -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 {

View File

@@ -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("<project></project>"))
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("<project></project>"))
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])
}
})
}

View File

@@ -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)

View File

@@ -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.")
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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)

View File

@@ -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,

View File

@@ -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
}

View File

@@ -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