1
0
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:
Daniel Kurzynski 2020-11-03 11:08:23 +01:00 committed by GitHub
parent c6afd7696b
commit 7946265e21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 123 additions and 62 deletions

View File

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

View File

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

View File

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

View File

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