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

feat(npmExecuteLint): support to run package installation and usage of custom runScript (#3191)

* feat(npmExecuteLint): support to run package installation and custom runScript

* fix tests

* error handling

* fix test

Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
This commit is contained in:
Christian Volk
2021-10-22 13:01:22 +02:00
committed by GitHub
parent be81da225e
commit 0a30108af3
4 changed files with 142 additions and 15 deletions

View File

@@ -79,15 +79,33 @@ func npmExecuteLint(config npmExecuteLintOptions, telemetryData *telemetry.Custo
}
func runNpmExecuteLint(npmExecutor npm.Executor, utils lintUtils, config *npmExecuteLintOptions) error {
packageJSONFiles := npmExecutor.FindPackageJSONFiles()
packagesWithCiLint, _ := npmExecutor.FindPackageJSONFilesWithScript(packageJSONFiles, "ci-lint")
if len(config.RunScript) == 0 {
return fmt.Errorf("runScript is not allowed to be empty!")
}
if len(packagesWithCiLint) > 0 {
err := runCiLint(npmExecutor, config.FailOnError)
packageJSONFiles := npmExecutor.FindPackageJSONFiles()
packagesWithLintScript, _ := npmExecutor.FindPackageJSONFilesWithScript(packageJSONFiles, config.RunScript)
if len(packagesWithLintScript) > 0 {
if config.Install {
err := npmExecutor.InstallAllDependencies(packagesWithLintScript)
if err != nil {
return err
}
}
err := runLintScript(npmExecutor, config.RunScript, config.FailOnError)
if err != nil {
return err
}
} else {
if config.Install {
err := npmExecutor.InstallAllDependencies(packageJSONFiles)
if err != nil {
return err
}
}
err := runDefaultLint(npmExecutor, utils, config.FailOnError)
if err != nil {
return err
@@ -96,14 +114,14 @@ func runNpmExecuteLint(npmExecutor npm.Executor, utils lintUtils, config *npmExe
return nil
}
func runCiLint(npmExecutor npm.Executor, failOnError bool) error {
runScripts := []string{"ci-lint"}
func runLintScript(npmExecutor npm.Executor, runScript string, failOnError bool) error {
runScripts := []string{runScript}
runOptions := []string{"--silent"}
err := npmExecutor.RunScriptsInAllPackages(runScripts, runOptions, nil, false, nil, nil)
if err != nil {
if failOnError {
return fmt.Errorf("ci-lint script execution failed with error: %w. This might be the result of severe linting findings, or some other issue while executing the script. Please examine the linting results in the UI, the cilint.xml file, if available, or the log above. ", err)
return fmt.Errorf("%s script execution failed with error: %w. This might be the result of severe linting findings, or some other issue while executing the script. Please examine the linting results in the UI, the cilint.xml file, if available, or the log above. ", runScript, err)
}
}
return nil

View File

@@ -16,6 +16,8 @@ import (
)
type npmExecuteLintOptions struct {
Install bool `json:"install,omitempty"`
RunScript string `json:"runScript,omitempty"`
FailOnError bool `json:"failOnError,omitempty"`
DefaultNpmRegistry string `json:"defaultNpmRegistry,omitempty"`
}
@@ -105,6 +107,8 @@ either use ESLint configurations present in the project or use the provided gene
}
func addNpmExecuteLintFlags(cmd *cobra.Command, stepConfig *npmExecuteLintOptions) {
cmd.Flags().BoolVar(&stepConfig.Install, "install", false, "Run npm install or similar commands depending on the project structure.")
cmd.Flags().StringVar(&stepConfig.RunScript, "runScript", `ci-lint`, "List of additional run scripts to execute from package.json.")
cmd.Flags().BoolVar(&stepConfig.FailOnError, "failOnError", false, "Defines the behavior in case linting errors are found.")
cmd.Flags().StringVar(&stepConfig.DefaultNpmRegistry, "defaultNpmRegistry", os.Getenv("PIPER_defaultNpmRegistry"), "URL of the npm registry to use. Defaults to https://registry.npmjs.org/")
@@ -121,6 +125,24 @@ func npmExecuteLintMetadata() config.StepData {
Spec: config.StepSpec{
Inputs: config.StepInputs{
Parameters: []config.StepParameters{
{
Name: "install",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "bool",
Mandatory: false,
Aliases: []config.Alias{},
Default: false,
},
{
Name: "runScript",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{},
Default: `ci-lint`,
},
{
Name: "failOnError",
ResourceRef: []config.ResourceReference{},

View File

@@ -29,6 +29,8 @@ func newLintMockUtilsBundle() mockLintUtilsBundle {
}
func TestNpmExecuteLint(t *testing.T) {
defaultConfig := npmExecuteLintOptions{RunScript: "ci-lint"}
t.Run("Call with ci-lint script and one package.json", func(t *testing.T) {
lintUtils := newLintMockUtilsBundle()
lintUtils.AddFile("package.json", []byte("{\"scripts\": { \"ci-lint\": \"\" } }"))
@@ -37,9 +39,8 @@ func TestNpmExecuteLint(t *testing.T) {
npmUtils.ExecRunner = lintUtils.execRunner
npmUtils.FilesMock = lintUtils.FilesMock
config := npmExecuteLintOptions{
FailOnError: true,
}
config := defaultConfig
config.FailOnError = true
npmExecutor := npm.NpmExecutorMock{Utils: npmUtils, Config: npm.NpmConfig{RunScripts: []string{"ci-lint"}, RunOptions: []string{"--silent"}}}
err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config)
@@ -52,7 +53,7 @@ func TestNpmExecuteLint(t *testing.T) {
lintUtils.AddFile("package.json", []byte("{\"name\": \"Test\" }"))
lintUtils.AddFile(".eslintrc.json", []byte("{\"name\": \"Test\" }"))
config := npmExecuteLintOptions{}
config := defaultConfig
config.DefaultNpmRegistry = "foo.bar"
npmUtils := newNpmMockUtilsBundle()
@@ -74,7 +75,7 @@ func TestNpmExecuteLint(t *testing.T) {
lintUtils.AddFile(".eslintrc.json", []byte("{\"name\": \"Test\" }"))
lintUtils.AddFile(filepath.Join("src", ".eslintrc.json"), []byte("{\"name\": \"Test\" }"))
config := npmExecuteLintOptions{}
config := defaultConfig
config.DefaultNpmRegistry = "foo.bar"
npmUtils := newNpmMockUtilsBundle()
@@ -95,7 +96,7 @@ func TestNpmExecuteLint(t *testing.T) {
lintUtils := newLintMockUtilsBundle()
lintUtils.AddFile("package.json", []byte("{\"name\": \"Test\" }"))
config := npmExecuteLintOptions{}
config := defaultConfig
config.DefaultNpmRegistry = "foo.bar"
npmUtils := newNpmMockUtilsBundle()
@@ -117,7 +118,7 @@ func TestNpmExecuteLint(t *testing.T) {
lintUtils.AddFile("package.json", []byte("{\"scripts\": { \"ci-lint\": \"\" } }"))
lintUtils.execRunner = &mock.ExecMockRunner{ShouldFailOnCommand: map[string]error{"npm run ci-lint --silent": errors.New("exit 1")}}
config := npmExecuteLintOptions{}
config := defaultConfig
config.FailOnError = true
config.DefaultNpmRegistry = "foo.bar"
@@ -141,7 +142,7 @@ func TestNpmExecuteLint(t *testing.T) {
lintUtils.AddFile(".eslintrc.json", []byte("{\"name\": \"Test\" }"))
lintUtils.execRunner = &mock.ExecMockRunner{ShouldFailOnCommand: map[string]error{"eslint . -f checkstyle -o ./0_defaultlint.xml --ignore-pattern node_modules/ --ignore-pattern .eslintrc.js": errors.New("exit 1")}}
config := npmExecuteLintOptions{}
config := defaultConfig
config.FailOnError = true
config.DefaultNpmRegistry = "foo.bar"
@@ -172,4 +173,74 @@ func TestNpmExecuteLint(t *testing.T) {
assert.Contains(t, eslintConfigs, filepath.Join("src", ".eslintrc.json"))
}
})
t.Run("Call with ci-lint script and install", func(t *testing.T) {
lintUtils := newLintMockUtilsBundle()
lintUtils.AddFile("package.json", []byte("{\"name\": \"test\", \"scripts\": { \"ci-lint\": \"\" } }"))
npmUtils := npm.NewNpmMockUtilsBundle()
npmUtils.ExecRunner = lintUtils.execRunner
npmUtils.FilesMock = lintUtils.FilesMock
config := defaultConfig
config.Install = true
npmExecutor := npm.NpmExecutorMock{Utils: npmUtils, Config: npm.NpmConfig{RunScripts: []string{"ci-lint"}, RunOptions: []string{"--silent"}, Install: true}}
err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config)
assert.NoError(t, err)
})
t.Run("Call with default and install", func(t *testing.T) {
lintUtils := newLintMockUtilsBundle()
lintUtils.AddFile("package.json", []byte("{\"name\": \"test\"}"))
npmUtils := npm.NewNpmMockUtilsBundle()
npmUtils.ExecRunner = lintUtils.execRunner
npmUtils.FilesMock = lintUtils.FilesMock
config := defaultConfig
config.Install = true
npmExecutor := npm.NpmExecutorMock{Utils: npmUtils, Config: npm.NpmConfig{RunScripts: []string{"ci-lint"}, RunOptions: []string{"--silent"}, Install: true}}
err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config)
assert.NoError(t, err)
})
t.Run("Call with custom runScript", func(t *testing.T) {
lintUtils := newLintMockUtilsBundle()
lintUtils.AddFile("package.json", []byte("{\"name\": \"test\", \"scripts\": { \"lint:ci\": \"\" } }"))
npmUtils := npm.NewNpmMockUtilsBundle()
npmUtils.ExecRunner = lintUtils.execRunner
npmUtils.FilesMock = lintUtils.FilesMock
config := defaultConfig
config.RunScript = "lint:ci"
npmExecutor := npm.NpmExecutorMock{Utils: npmUtils, Config: npm.NpmConfig{RunScripts: []string{"lint:ci"}, RunOptions: []string{"--silent"}}}
err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config)
assert.NoError(t, err)
})
t.Run("Call with empty runScript and failOnError", func(t *testing.T) {
lintUtils := newLintMockUtilsBundle()
lintUtils.AddFile("package.json", []byte("{\"scripts\": { \"ci-lint\": \"\" } }"))
lintUtils.execRunner = &mock.ExecMockRunner{ShouldFailOnCommand: map[string]error{"npm run ci-lint --silent": errors.New("exit 1")}}
config := defaultConfig
config.FailOnError = true
config.RunScript = ""
npmUtils := newNpmMockUtilsBundle()
npmUtils.execRunner = lintUtils.execRunner
npmUtils.FilesMock = lintUtils.FilesMock
npmExecutor := npm.Execute{Utils: &npmUtils, Options: npm.ExecutorOptions{}}
err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config)
assert.EqualError(t, err, "runScript is not allowed to be empty!")
})
}

View File

@@ -9,6 +9,22 @@ metadata:
spec:
inputs:
params:
- name: install
type: bool
description: Run npm install or similar commands depending on the project structure.
scope:
- PARAMETERS
- STAGES
- STEPS
default: false
- name: runScript
type: string
description: List of additional run scripts to execute from package.json.
scope:
- PARAMETERS
- STAGES
- STEPS
default: "ci-lint"
- name: failOnError
type: bool
description: Defines the behavior in case linting errors are found.