1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-12 10:55:20 +02:00
sap-jenkins-library/cmd/hadolintExecute.go
Christopher Fenner 81c8553d6a
refactor(hadolint): implement step in GO (#1169)
* initial commit of yaml file

* initial commit for HaDoLint in GO

* add helper function to load file from url

* load config file

* write report information to disk

* comment the code

* refactor groovy code

* remove download function from FileUtils

* use http.Downloader

* rename step files

* update generated files

* update generated files

* remove duplicate commands

* add credentials for config url

* add generated test file

* reuse piperExecuteBin functions

* correct step name

* update go step

* deactivate test

* fix import

* use differing go step name

* rename step

* correct result publishing

* correct command name

* expose tls insecure flag

* hand through error

* disable tls verification

* fix tls disabling

* use credentials

* mow

* reformat

* add qgate only if set

* correct report name

* remove old defaults

* add qgate to defaults

* handle report name

* restore default

* remove unused step config

* use piperExecuteBin

* remove obsolete type

* add test cases

* remove groovy tests

* move client parameter handling to run function

* use custom interfaces and mockery

* remove commented code

* correct struct names

* rename parameter dockerfile

* add further asserts

* cleanup

* change file permission to read/write

* remove tokenize

* add further comments

* init http client only if necessary

* add todo

* Revert "rename parameter dockerfile"

This reverts commit 2a570685b8.

* add alias for dockerfile parameter

* correct test case

* Apply suggestions from code review

Co-authored-by: Stephan Aßmus <stephan.assmus@sap.com>

* add comment about mock assertions

Co-authored-by: Stephan Aßmus <stephan.assmus@sap.com>
2020-11-16 15:14:54 +01:00

128 lines
4.2 KiB
Go

package cmd
import (
"bytes"
"io"
"net/http"
"os"
"time"
"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/piperutils"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/pkg/errors"
)
const hadolintCommand = "hadolint"
// HadolintPiperFileUtils abstracts piperutils.Files
// mock generated with: mockery --name HadolintPiperFileUtils --dir cmd --output pkg/hadolint/mocks
type HadolintPiperFileUtils interface {
FileExists(filename string) (bool, error)
FileWrite(filename string, data []byte, perm os.FileMode) error
}
// HadolintClient abstracts http.Client
// mock generated with: mockery --name hadolintClient --dir cmd --output pkg/hadolint/mocks
type HadolintClient interface {
SetOptions(options piperhttp.ClientOptions)
DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error
}
// hadolintRunner abstracts command.Command
type hadolintRunner interface {
RunExecutable(executable string, params ...string) error
Stdout(err io.Writer)
Stderr(err io.Writer)
}
type hadolintUtils struct {
HadolintPiperFileUtils
HadolintClient
hadolintRunner
}
func hadolintExecute(config hadolintExecuteOptions, _ *telemetry.CustomData) {
runner := command.Command{
ErrorCategoryMapping: map[string][]string{},
}
// reroute runner output to logging framework
runner.Stdout(log.Writer())
runner.Stderr(log.Writer())
utils := hadolintUtils{
HadolintPiperFileUtils: &piperutils.Files{},
HadolintClient: &piperhttp.Client{},
hadolintRunner: &runner,
}
if err := runHadolint(config, utils); err != nil {
log.Entry().WithError(err).Fatal("Execution failed")
}
}
func runHadolint(config hadolintExecuteOptions, utils hadolintUtils) error {
var outputBuffer bytes.Buffer
var errorBuffer bytes.Buffer
utils.Stdout(&outputBuffer)
utils.Stderr(&errorBuffer)
options := []string{"--format", "checkstyle"}
// load config file from URL
if !hasConfigurationFile(config.ConfigurationFile, utils) && len(config.ConfigurationURL) > 0 {
clientOptions := piperhttp.ClientOptions{
TransportTimeout: 20 * time.Second,
TransportSkipVerification: true,
}
if len(config.ConfigurationUsername) > 0 {
clientOptions.Username = config.ConfigurationUsername
clientOptions.Password = config.ConfigurationPassword
}
utils.SetOptions(clientOptions)
if err := loadConfigurationFile(config.ConfigurationURL, config.ConfigurationFile, utils); err != nil {
return errors.Wrap(err, "failed to load configuration file from URL")
}
}
// use config
if hasConfigurationFile(config.ConfigurationFile, utils) {
options = append(options, "--config", config.ConfigurationFile)
log.Entry().WithField("file", config.ConfigurationFile).Debug("Using configuration file")
} else {
log.Entry().Debug("No configuration file found.")
}
// execute scan command
err := utils.RunExecutable(hadolintCommand, append([]string{config.DockerFile}, options...)...)
//TODO: related to https://github.com/hadolint/hadolint/issues/391
// hadolint exists with 1 if there are processing issues but also if there are findings
// thus check stdout first if a report was created
if output := outputBuffer.String(); len(output) > 0 {
log.Entry().WithField("report", output).Debug("Report created")
utils.FileWrite(config.ReportFile, []byte(output), 0666)
} else if err != nil {
// if stdout is empty a processing issue occured
return errors.Wrap(err, errorBuffer.String())
}
//TODO: mock away in tests
// persist report information
piperutils.PersistReportsAndLinks("hadolintExecute", "./", []piperutils.Path{{Target: config.ReportFile}}, []piperutils.Path{})
return nil
}
// loadConfigurationFile loads a file from the provided url
func loadConfigurationFile(url, file string, utils hadolintUtils) error {
log.Entry().WithField("url", url).Debug("Loading configuration file from URL")
return utils.DownloadFile(url, file, nil, nil)
}
// hasConfigurationFile checks if the given file exists
func hasConfigurationFile(file string, utils hadolintUtils) bool {
exists, err := utils.FileExists(file)
if err != nil {
log.Entry().WithError(err).Error()
}
return exists
}