mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-01-16 05:16:08 +02:00
Install maven artifacts before running Detect (#2292)
This commit is contained in:
parent
c6afd7696b
commit
7946265e21
@ -2,6 +2,8 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
@ -17,7 +19,7 @@ import (
|
||||
"github.com/SAP/jenkins-library/pkg/versioning"
|
||||
)
|
||||
|
||||
type detectFileUtils interface {
|
||||
type detectUtils interface {
|
||||
Abs(path string) (string, error)
|
||||
FileExists(filename string) (bool, error)
|
||||
FileRemove(filename string) error
|
||||
@ -27,27 +29,46 @@ type detectFileUtils interface {
|
||||
MkdirAll(path string, perm os.FileMode) error
|
||||
Chmod(path string, mode os.FileMode) error
|
||||
Glob(pattern string) (matches []string, err error)
|
||||
|
||||
Stdout(out io.Writer)
|
||||
Stderr(err io.Writer)
|
||||
SetDir(dir string)
|
||||
SetEnv(env []string)
|
||||
RunExecutable(e string, p ...string) error
|
||||
RunShell(shell, script string) error
|
||||
|
||||
DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error
|
||||
}
|
||||
|
||||
type detectUtilsBundle struct {
|
||||
*command.Command
|
||||
*piperutils.Files
|
||||
*piperhttp.Client
|
||||
}
|
||||
|
||||
func newDetectUtils() detectUtils {
|
||||
utils := detectUtilsBundle{
|
||||
Command: &command.Command{
|
||||
ErrorCategoryMapping: map[string][]string{
|
||||
log.ErrorCompliance.String(): {
|
||||
"FAILURE_POLICY_VIOLATION - Detect found policy violations.",
|
||||
},
|
||||
log.ErrorConfiguration.String(): {
|
||||
"FAILURE_CONFIGURATION - Detect was unable to start due to issues with it's configuration.",
|
||||
},
|
||||
},
|
||||
},
|
||||
Files: &piperutils.Files{},
|
||||
Client: &piperhttp.Client{},
|
||||
}
|
||||
utils.Stdout(log.Writer())
|
||||
utils.Stderr(log.Writer())
|
||||
return &utils
|
||||
}
|
||||
|
||||
func detectExecuteScan(config detectExecuteScanOptions, _ *telemetry.CustomData) {
|
||||
c := command.Command{
|
||||
ErrorCategoryMapping: map[string][]string{
|
||||
log.ErrorCompliance.String(): {
|
||||
"FAILURE_POLICY_VIOLATION - Detect found policy violations.",
|
||||
},
|
||||
log.ErrorConfiguration.String(): {
|
||||
"FAILURE_CONFIGURATION - Detect was unable to start due to issues with it's configuration.",
|
||||
},
|
||||
},
|
||||
}
|
||||
// reroute command output to logging framework
|
||||
c.Stdout(log.Writer())
|
||||
c.Stderr(log.Writer())
|
||||
|
||||
fileUtils := piperutils.Files{}
|
||||
httpClient := piperhttp.Client{}
|
||||
|
||||
err := runDetect(config, &c, &fileUtils, &httpClient)
|
||||
utils := newDetectUtils()
|
||||
err := runDetect(config, utils)
|
||||
|
||||
if err != nil {
|
||||
log.Entry().
|
||||
@ -56,24 +77,36 @@ func detectExecuteScan(config detectExecuteScanOptions, _ *telemetry.CustomData)
|
||||
}
|
||||
}
|
||||
|
||||
func runDetect(config detectExecuteScanOptions, command command.ShellRunner, fileUtils detectFileUtils, httpClient piperhttp.Downloader) error {
|
||||
func runDetect(config detectExecuteScanOptions, utils detectUtils) error {
|
||||
// detect execution details, see https://synopsys.atlassian.net/wiki/spaces/INTDOCS/pages/88440888/Sample+Synopsys+Detect+Scan+Configuration+Scenarios+for+Black+Duck
|
||||
err := httpClient.DownloadFile("https://detect.synopsys.com/detect.sh", "detect.sh", nil, nil)
|
||||
err := utils.DownloadFile("https://detect.synopsys.com/detect.sh", "detect.sh", nil, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to download 'detect.sh' script: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
err := fileUtils.FileRemove("detect.sh")
|
||||
err := utils.FileRemove("detect.sh")
|
||||
if err != nil {
|
||||
log.Entry().Warnf("failed to delete 'detect.sh' script: %v", err)
|
||||
}
|
||||
}()
|
||||
err = fileUtils.Chmod("detect.sh", 0700)
|
||||
err = utils.Chmod("detect.sh", 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if config.InstallArtifacts {
|
||||
err := maven.InstallMavenArtifacts(utils, &maven.EvaluateOptions{
|
||||
M2Path: config.M2Path,
|
||||
ProjectSettingsFile: config.ProjectSettingsFile,
|
||||
GlobalSettingsFile: config.GlobalSettingsFile,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
args := []string{"./detect.sh"}
|
||||
args, err = addDetectArgs(args, config, fileUtils, httpClient)
|
||||
args, err = addDetectArgs(args, config, utils)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -81,13 +114,13 @@ func runDetect(config detectExecuteScanOptions, command command.ShellRunner, fil
|
||||
|
||||
envs := []string{"BLACKDUCK_SKIP_PHONE_HOME=true"}
|
||||
|
||||
command.SetDir(".")
|
||||
command.SetEnv(envs)
|
||||
utils.SetDir(".")
|
||||
utils.SetEnv(envs)
|
||||
|
||||
return command.RunShell("/bin/bash", script)
|
||||
return utils.RunShell("/bin/bash", script)
|
||||
}
|
||||
|
||||
func addDetectArgs(args []string, config detectExecuteScanOptions, fileUtils piperutils.FileUtils, httpClient piperhttp.Downloader) ([]string, error) {
|
||||
func addDetectArgs(args []string, config detectExecuteScanOptions, utils detectUtils) ([]string, error) {
|
||||
|
||||
coordinates := struct {
|
||||
Version string
|
||||
@ -130,13 +163,13 @@ func addDetectArgs(args []string, config detectExecuteScanOptions, fileUtils pip
|
||||
args = append(args, fmt.Sprintf("--detect.source.path=%v", config.ScanPaths[0]))
|
||||
}
|
||||
|
||||
mavenArgs, err := maven.DownloadAndGetMavenParameters(config.GlobalSettingsFile, config.ProjectSettingsFile, fileUtils, httpClient)
|
||||
mavenArgs, err := maven.DownloadAndGetMavenParameters(config.GlobalSettingsFile, config.ProjectSettingsFile, utils, utils)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(config.M2Path) > 0 {
|
||||
absolutePath, err := fileUtils.Abs(config.M2Path)
|
||||
absolutePath, err := utils.Abs(config.M2Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ type detectExecuteScanOptions struct {
|
||||
ProjectSettingsFile string `json:"projectSettingsFile,omitempty"`
|
||||
GlobalSettingsFile string `json:"globalSettingsFile,omitempty"`
|
||||
M2Path string `json:"m2Path,omitempty"`
|
||||
InstallArtifacts bool `json:"installArtifacts,omitempty"`
|
||||
}
|
||||
|
||||
// DetectExecuteScanCommand Executes Synopsys Detect scan
|
||||
@ -104,6 +105,7 @@ func addDetectExecuteScanFlags(cmd *cobra.Command, stepConfig *detectExecuteScan
|
||||
cmd.Flags().StringVar(&stepConfig.ProjectSettingsFile, "projectSettingsFile", os.Getenv("PIPER_projectSettingsFile"), "Path or url to the mvn settings file that should be used as project settings file.")
|
||||
cmd.Flags().StringVar(&stepConfig.GlobalSettingsFile, "globalSettingsFile", os.Getenv("PIPER_globalSettingsFile"), "Path or url to the mvn settings file that should be used as global settings file")
|
||||
cmd.Flags().StringVar(&stepConfig.M2Path, "m2Path", os.Getenv("PIPER_m2Path"), "Path to the location of the local repository that should be used.")
|
||||
cmd.Flags().BoolVar(&stepConfig.InstallArtifacts, "installArtifacts", false, "If enabled, it will install all artifacts to the local maven repository to make them available before running detect. This is required if any maven module has dependencies to other modules in the repository and they were not installed before.")
|
||||
|
||||
cmd.MarkFlagRequired("token")
|
||||
cmd.MarkFlagRequired("projectName")
|
||||
@ -248,6 +250,14 @@ func detectExecuteScanMetadata() config.StepData {
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{{Name: "maven/m2Path"}},
|
||||
},
|
||||
{
|
||||
Name: "installArtifacts",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"GENERAL", "STEPS", "STAGES", "PARAMETERS"},
|
||||
Type: "bool",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -13,16 +13,22 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type httpClientMock struct {
|
||||
type detectTestUtilsBundle struct {
|
||||
expectedError error
|
||||
downloadedFiles map[string]string // src, dest
|
||||
*mock.ShellMockRunner
|
||||
*mock.FilesMock
|
||||
}
|
||||
|
||||
func (c *httpClientMock) SetOptions(options piperhttp.ClientOptions) {
|
||||
func (c *detectTestUtilsBundle) RunExecutable(e string, p ...string) error {
|
||||
panic("not expected to be called in test")
|
||||
}
|
||||
|
||||
func (c *detectTestUtilsBundle) SetOptions(options piperhttp.ClientOptions) {
|
||||
|
||||
}
|
||||
|
||||
func (c *httpClientMock) DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error {
|
||||
func (c *detectTestUtilsBundle) DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error {
|
||||
|
||||
if c.expectedError != nil {
|
||||
return c.expectedError
|
||||
@ -35,60 +41,62 @@ func (c *httpClientMock) DownloadFile(url, filename string, header http.Header,
|
||||
return nil
|
||||
}
|
||||
|
||||
func newDetectTestUtilsBundle() detectTestUtilsBundle {
|
||||
utilsBundle := detectTestUtilsBundle{
|
||||
ShellMockRunner: &mock.ShellMockRunner{},
|
||||
FilesMock: &mock.FilesMock{},
|
||||
}
|
||||
return utilsBundle
|
||||
}
|
||||
|
||||
func TestRunDetect(t *testing.T) {
|
||||
|
||||
t.Run("success case", func(t *testing.T) {
|
||||
s := mock.ShellMockRunner{}
|
||||
fileUtilsMock := mock.FilesMock{}
|
||||
fileUtilsMock.AddFile("detect.sh", []byte(""))
|
||||
httpClient := httpClientMock{}
|
||||
err := runDetect(detectExecuteScanOptions{}, &s, &fileUtilsMock, &httpClient)
|
||||
utilsMock := newDetectTestUtilsBundle()
|
||||
utilsMock.AddFile("detect.sh", []byte(""))
|
||||
err := runDetect(detectExecuteScanOptions{}, &utilsMock)
|
||||
|
||||
assert.Equal(t, httpClient.downloadedFiles["https://detect.synopsys.com/detect.sh"], "detect.sh")
|
||||
assert.True(t, fileUtilsMock.HasRemovedFile("detect.sh"))
|
||||
assert.Equal(t, utilsMock.downloadedFiles["https://detect.synopsys.com/detect.sh"], "detect.sh")
|
||||
assert.True(t, utilsMock.HasRemovedFile("detect.sh"))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, ".", s.Dir, "Wrong execution directory used")
|
||||
assert.Equal(t, "/bin/bash", s.Shell[0], "Bash shell expected")
|
||||
assert.Equal(t, ".", utilsMock.Dir, "Wrong execution directory used")
|
||||
assert.Equal(t, "/bin/bash", utilsMock.Shell[0], "Bash shell expected")
|
||||
expectedScript := "./detect.sh --blackduck.url= --blackduck.api.token= --detect.project.name=\\\"\\\" --detect.project.version.name=\\\"\\\" --detect.code.location.name=\\\"\\\""
|
||||
assert.Equal(t, expectedScript, s.Calls[0])
|
||||
assert.Equal(t, expectedScript, utilsMock.Calls[0])
|
||||
})
|
||||
|
||||
t.Run("failure case", func(t *testing.T) {
|
||||
s := mock.ShellMockRunner{ShouldFailOnCommand: map[string]error{"./detect.sh --blackduck.url= --blackduck.api.token= --detect.project.name=\\\"\\\" --detect.project.version.name=\\\"\\\" --detect.code.location.name=\\\"\\\"": fmt.Errorf("Test Error")}}
|
||||
fileUtilsMock := mock.FilesMock{}
|
||||
fileUtilsMock.AddFile("detect.sh", []byte(""))
|
||||
httpClient := httpClientMock{}
|
||||
err := runDetect(detectExecuteScanOptions{}, &s, &fileUtilsMock, &httpClient)
|
||||
|
||||
utilsMock := newDetectTestUtilsBundle()
|
||||
utilsMock.ShouldFailOnCommand = map[string]error{"./detect.sh --blackduck.url= --blackduck.api.token= --detect.project.name=\\\"\\\" --detect.project.version.name=\\\"\\\" --detect.code.location.name=\\\"\\\"": fmt.Errorf("Test Error")}
|
||||
utilsMock.AddFile("detect.sh", []byte(""))
|
||||
err := runDetect(detectExecuteScanOptions{}, &utilsMock)
|
||||
assert.EqualError(t, err, "Test Error")
|
||||
assert.True(t, fileUtilsMock.HasRemovedFile("detect.sh"))
|
||||
assert.True(t, utilsMock.HasRemovedFile("detect.sh"))
|
||||
})
|
||||
|
||||
t.Run("maven parameters", func(t *testing.T) {
|
||||
s := mock.ShellMockRunner{}
|
||||
fileUtilsMock := mock.FilesMock{
|
||||
CurrentDir: "root_folder",
|
||||
}
|
||||
fileUtilsMock.AddFile("detect.sh", []byte(""))
|
||||
httpClient := httpClientMock{}
|
||||
utilsMock := newDetectTestUtilsBundle()
|
||||
utilsMock.CurrentDir = "root_folder"
|
||||
utilsMock.AddFile("detect.sh", []byte(""))
|
||||
err := runDetect(detectExecuteScanOptions{
|
||||
M2Path: ".pipeline/local_repo",
|
||||
ProjectSettingsFile: "project-settings.xml",
|
||||
GlobalSettingsFile: "global-settings.xml",
|
||||
}, &s, &fileUtilsMock, &httpClient)
|
||||
}, &utilsMock)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, ".", s.Dir, "Wrong execution directory used")
|
||||
assert.Equal(t, "/bin/bash", s.Shell[0], "Bash shell expected")
|
||||
assert.Equal(t, ".", utilsMock.Dir, "Wrong execution directory used")
|
||||
assert.Equal(t, "/bin/bash", utilsMock.Shell[0], "Bash shell expected")
|
||||
absoluteLocalPath := string(os.PathSeparator) + filepath.Join("root_folder", ".pipeline", "local_repo")
|
||||
|
||||
expectedParam := "\"--detect.maven.build.command='--global-settings global-settings.xml --settings project-settings.xml -Dmaven.repo.local=" + absoluteLocalPath + "'\""
|
||||
assert.Contains(t, s.Calls[0], expectedParam)
|
||||
assert.Contains(t, utilsMock.Calls[0], expectedParam)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAddDetectArgs(t *testing.T) {
|
||||
httpClient := piperhttp.Client{}
|
||||
fileUtilsMock := mock.FilesMock{}
|
||||
utilsMock := newDetectTestUtilsBundle()
|
||||
|
||||
testData := []struct {
|
||||
args []string
|
||||
@ -176,7 +184,7 @@ func TestAddDetectArgs(t *testing.T) {
|
||||
|
||||
for k, v := range testData {
|
||||
t.Run(fmt.Sprintf("run %v", k), func(t *testing.T) {
|
||||
got, err := addDetectArgs(v.args, v.options, &fileUtilsMock, &httpClient)
|
||||
got, err := addDetectArgs(v.args, v.options, &utilsMock)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, v.expected, got)
|
||||
})
|
||||
|
@ -207,6 +207,16 @@ spec:
|
||||
- PARAMETERS
|
||||
aliases:
|
||||
- name: maven/m2Path
|
||||
- name: installArtifacts
|
||||
type: bool
|
||||
description:
|
||||
"If enabled, it will install all artifacts to the local maven repository to make them available before running detect.
|
||||
This is required if any maven module has dependencies to other modules in the repository and they were not installed before."
|
||||
scope:
|
||||
- GENERAL
|
||||
- STEPS
|
||||
- STAGES
|
||||
- PARAMETERS
|
||||
containers:
|
||||
- name: openjdk
|
||||
image: openjdk:11
|
||||
|
Loading…
Reference in New Issue
Block a user