mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-12 10:55:20 +02:00
8b36ae70e7
* Adjust npmExecuteLint (output-format, print output to console) Co-authored-by: Srinikitha Kondreddy <srinikitha.kondreddy@sap.com>
422 lines
16 KiB
Go
422 lines
16 KiB
Go
//go:build unit
|
|
// +build unit
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"errors"
|
|
"github.com/SAP/jenkins-library/pkg/command"
|
|
"github.com/SAP/jenkins-library/pkg/mock"
|
|
"github.com/SAP/jenkins-library/pkg/npm"
|
|
"github.com/stretchr/testify/assert"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
type mockLintUtilsBundle struct {
|
|
*mock.FilesMock
|
|
execRunner *mock.ExecMockRunner
|
|
}
|
|
|
|
func (u *mockLintUtilsBundle) getExecRunner() command.ExecRunner {
|
|
return u.execRunner
|
|
}
|
|
|
|
func (u *mockLintUtilsBundle) getGeneralPurposeConfig(configURL string) {
|
|
u.AddFile(filepath.Join(".pipeline", ".eslintrc.json"), []byte(`abc`))
|
|
}
|
|
|
|
func newLintMockUtilsBundle() mockLintUtilsBundle {
|
|
utils := mockLintUtilsBundle{FilesMock: &mock.FilesMock{}, execRunner: &mock.ExecMockRunner{}}
|
|
return utils
|
|
}
|
|
|
|
func TestNpmExecuteLint(t *testing.T) {
|
|
defaultConfig := npmExecuteLintOptions{RunScript: "ci-lint", OutputFormat: "checkstyle", OutputFileName: "defaultlint.xml"}
|
|
|
|
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\": \"\" } }"))
|
|
|
|
npmUtils := npm.NewNpmMockUtilsBundle()
|
|
npmUtils.ExecRunner = lintUtils.execRunner
|
|
npmUtils.FilesMock = lintUtils.FilesMock
|
|
|
|
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)
|
|
|
|
assert.NoError(t, err)
|
|
})
|
|
|
|
t.Run("Call default with ESLint config from user", func(t *testing.T) {
|
|
lintUtils := newLintMockUtilsBundle()
|
|
lintUtils.AddFile("package.json", []byte("{\"name\": \"Test\" }"))
|
|
lintUtils.AddFile(".eslintrc.json", []byte("{\"name\": \"Test\" }"))
|
|
|
|
config := defaultConfig
|
|
config.DefaultNpmRegistry = "foo.bar"
|
|
|
|
npmUtils := newNpmMockUtilsBundle()
|
|
npmUtils.execRunner = lintUtils.execRunner
|
|
npmExecutor := npm.Execute{Utils: &npmUtils, Options: npm.ExecutorOptions{}}
|
|
|
|
err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config)
|
|
|
|
if assert.NoError(t, err) {
|
|
if assert.Equal(t, 2, len(lintUtils.execRunner.Calls)) {
|
|
assert.Equal(t, mock.ExecCall{Exec: "npx", Params: []string{
|
|
"eslint",
|
|
".",
|
|
"-f", "checkstyle",
|
|
"--ignore-pattern", "node_modules/",
|
|
"--ignore-pattern", ".eslintrc.js",
|
|
"-o", "./0_defaultlint.xml"}}, lintUtils.execRunner.Calls[1])
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("Call default with ESLint config from user - no redirect to file, stylish format", func(t *testing.T) {
|
|
lintUtils := newLintMockUtilsBundle()
|
|
lintUtils.AddFile("package.json", []byte("{\"name\": \"Test\" }"))
|
|
lintUtils.AddFile(".eslintrc.json", []byte("{\"name\": \"Test\" }"))
|
|
|
|
config := npmExecuteLintOptions{RunScript: "ci-lint", OutputFormat: "stylish", OutputFileName: ""}
|
|
config.DefaultNpmRegistry = "foo.bar"
|
|
|
|
npmUtils := newNpmMockUtilsBundle()
|
|
npmUtils.execRunner = lintUtils.execRunner
|
|
npmExecutor := npm.Execute{Utils: &npmUtils, Options: npm.ExecutorOptions{}}
|
|
|
|
err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config)
|
|
|
|
if assert.NoError(t, err) {
|
|
if assert.Equal(t, 2, len(lintUtils.execRunner.Calls)) {
|
|
assert.Equal(t, mock.ExecCall{Exec: "npx", Params: []string{
|
|
"eslint",
|
|
".",
|
|
"-f", "stylish",
|
|
"--ignore-pattern",
|
|
"node_modules/",
|
|
"--ignore-pattern", ".eslintrc.js",
|
|
// no -o, --output-file in this case.
|
|
}}, lintUtils.execRunner.Calls[1])
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("Call default with two ESLint configs from user", func(t *testing.T) {
|
|
lintUtils := newLintMockUtilsBundle()
|
|
lintUtils.AddFile("package.json", []byte("{\"name\": \"Test\" }"))
|
|
lintUtils.AddFile(".eslintrc.json", []byte("{\"name\": \"Test\" }"))
|
|
lintUtils.AddFile(filepath.Join("src", ".eslintrc.json"), []byte("{\"name\": \"Test\" }"))
|
|
|
|
config := defaultConfig
|
|
config.DefaultNpmRegistry = "foo.bar"
|
|
|
|
npmUtils := newNpmMockUtilsBundle()
|
|
npmUtils.execRunner = lintUtils.execRunner
|
|
npmExecutor := npm.Execute{Utils: &npmUtils, Options: npm.ExecutorOptions{}}
|
|
|
|
err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config)
|
|
|
|
if assert.NoError(t, err) {
|
|
if assert.Equal(t, 3, len(lintUtils.execRunner.Calls)) {
|
|
assert.Equal(t, mock.ExecCall{Exec: "npx", Params: []string{
|
|
"eslint",
|
|
".",
|
|
"-f", "checkstyle",
|
|
"--ignore-pattern", "node_modules/",
|
|
"--ignore-pattern", ".eslintrc.js",
|
|
"-o", "./0_defaultlint.xml",
|
|
}}, lintUtils.execRunner.Calls[1])
|
|
assert.Equal(t, mock.ExecCall{Exec: "npx", Params: []string{
|
|
"eslint",
|
|
"src/**/*.js",
|
|
"-f", "checkstyle",
|
|
"--ignore-pattern", "node_modules/",
|
|
"--ignore-pattern", ".eslintrc.js",
|
|
"-o", "./1_defaultlint.xml",
|
|
}}, lintUtils.execRunner.Calls[2])
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("Call default with two ESLint configs from user - no redirect to file, stylish format", func(t *testing.T) {
|
|
lintUtils := newLintMockUtilsBundle()
|
|
lintUtils.AddFile("package.json", []byte("{\"name\": \"Test\" }"))
|
|
lintUtils.AddFile(".eslintrc.json", []byte("{\"name\": \"Test\" }"))
|
|
lintUtils.AddFile(filepath.Join("src", ".eslintrc.json"), []byte("{\"name\": \"Test\" }"))
|
|
|
|
config := defaultConfig
|
|
config.DefaultNpmRegistry = "foo.bar"
|
|
config.OutputFormat = "stylish"
|
|
config.OutputFileName = ""
|
|
|
|
npmUtils := newNpmMockUtilsBundle()
|
|
npmUtils.execRunner = lintUtils.execRunner
|
|
npmExecutor := npm.Execute{Utils: &npmUtils, Options: npm.ExecutorOptions{}}
|
|
|
|
err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config)
|
|
|
|
if assert.NoError(t, err) {
|
|
if assert.Equal(t, 3, len(lintUtils.execRunner.Calls)) {
|
|
assert.Equal(t, mock.ExecCall{Exec: "npx", Params: []string{
|
|
"eslint",
|
|
".",
|
|
"-f", "stylish",
|
|
"--ignore-pattern", "node_modules/",
|
|
"--ignore-pattern", ".eslintrc.js",
|
|
// no -o --output-file in this case.
|
|
}}, lintUtils.execRunner.Calls[1])
|
|
assert.Equal(t, mock.ExecCall{Exec: "npx", Params: []string{
|
|
"eslint",
|
|
"src/**/*.js",
|
|
"-f", "stylish",
|
|
"--ignore-pattern", "node_modules/",
|
|
"--ignore-pattern", ".eslintrc.js",
|
|
// no -o --output-file in this case.
|
|
}}, lintUtils.execRunner.Calls[2])
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("Default without ESLint config", func(t *testing.T) {
|
|
lintUtils := newLintMockUtilsBundle()
|
|
lintUtils.AddFile("package.json", []byte("{\"name\": \"Test\" }"))
|
|
|
|
config := defaultConfig
|
|
config.DefaultNpmRegistry = "foo.bar"
|
|
|
|
npmUtils := newNpmMockUtilsBundle()
|
|
npmUtils.execRunner = lintUtils.execRunner
|
|
npmExecutor := npm.Execute{Utils: &npmUtils, Options: npm.ExecutorOptions{}}
|
|
|
|
err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config)
|
|
|
|
if assert.NoError(t, err) {
|
|
if assert.Equal(t, 3, len(lintUtils.execRunner.Calls)) {
|
|
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"install", "eslint@^7.0.0", "typescript@^3.7.4", "@typescript-eslint/parser@^3.0.0", "@typescript-eslint/eslint-plugin@^3.0.0"}}, lintUtils.execRunner.Calls[1])
|
|
assert.Equal(t, mock.ExecCall{Exec: "npx", Params: []string{
|
|
"--no-install",
|
|
"eslint",
|
|
".",
|
|
"--ext",
|
|
".js,.jsx,.ts,.tsx",
|
|
"-c", ".pipeline/.eslintrc.json",
|
|
"-f", "checkstyle",
|
|
"--ignore-pattern", ".eslintrc.js",
|
|
"-o", "./defaultlint.xml",
|
|
}}, lintUtils.execRunner.Calls[2])
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("Default without ESLint config - no redirect to file, stylish format", func(t *testing.T) {
|
|
lintUtils := newLintMockUtilsBundle()
|
|
lintUtils.AddFile("package.json", []byte("{\"name\": \"Test\" }"))
|
|
|
|
config := defaultConfig
|
|
config.DefaultNpmRegistry = "foo.bar"
|
|
config.OutputFormat = "stylish"
|
|
config.OutputFileName = ""
|
|
|
|
npmUtils := newNpmMockUtilsBundle()
|
|
npmUtils.execRunner = lintUtils.execRunner
|
|
npmExecutor := npm.Execute{Utils: &npmUtils, Options: npm.ExecutorOptions{}}
|
|
|
|
err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config)
|
|
|
|
if assert.NoError(t, err) {
|
|
if assert.Equal(t, 3, len(lintUtils.execRunner.Calls)) {
|
|
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"install", "eslint@^7.0.0", "typescript@^3.7.4", "@typescript-eslint/parser@^3.0.0", "@typescript-eslint/eslint-plugin@^3.0.0"}}, lintUtils.execRunner.Calls[1])
|
|
assert.Equal(t, mock.ExecCall{Exec: "npx", Params: []string{
|
|
"--no-install",
|
|
"eslint",
|
|
".",
|
|
"--ext",
|
|
".js,.jsx,.ts,.tsx",
|
|
"-c", ".pipeline/.eslintrc.json",
|
|
"-f", "stylish",
|
|
"--ignore-pattern", ".eslintrc.js",
|
|
// no -o --output-file in this case.
|
|
}}, lintUtils.execRunner.Calls[2])
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("Call with ci-lint script 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.DefaultNpmRegistry = "foo.bar"
|
|
|
|
npmUtils := newNpmMockUtilsBundle()
|
|
npmUtils.execRunner = lintUtils.execRunner
|
|
npmUtils.FilesMock = lintUtils.FilesMock
|
|
npmExecutor := npm.Execute{Utils: &npmUtils, Options: npm.ExecutorOptions{}}
|
|
|
|
err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config)
|
|
|
|
if assert.EqualError(t, err, "ci-lint script execution failed with error: failed to run npm script ci-lint: exit 1. 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. ") {
|
|
if assert.Equal(t, 2, len(lintUtils.execRunner.Calls)) {
|
|
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run", "ci-lint", "--silent"}}, lintUtils.execRunner.Calls[1])
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("Call default with ESLint config from user and failOnError", func(t *testing.T) {
|
|
lintUtils := newLintMockUtilsBundle()
|
|
lintUtils.AddFile("package.json", []byte("{\"name\": \"Test\" }"))
|
|
lintUtils.AddFile(".eslintrc.json", []byte("{\"name\": \"Test\" }"))
|
|
lintUtils.execRunner = &mock.ExecMockRunner{ShouldFailOnCommand: map[string]error{
|
|
"eslint . -f checkstyle --ignore-pattern node_modules/ --ignore-pattern .eslintrc.js -o ./0_defaultlint.xml": errors.New("exit 1")}}
|
|
|
|
config := defaultConfig
|
|
config.FailOnError = true
|
|
config.DefaultNpmRegistry = "foo.bar"
|
|
|
|
npmUtils := newNpmMockUtilsBundle()
|
|
npmUtils.execRunner = lintUtils.execRunner
|
|
npmExecutor := npm.Execute{Utils: &npmUtils, Options: npm.ExecutorOptions{}}
|
|
|
|
err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config)
|
|
|
|
if assert.EqualError(t, err, "Lint execution failed. This might be the result of severe linting findings, problems with the provided ESLint configuration (.eslintrc.json), or another issue. Please examine the linting results in the UI or in 0_defaultlint.xml, if available, or the log above. ") {
|
|
if assert.Equal(t, 2, len(lintUtils.execRunner.Calls)) {
|
|
assert.Equal(t, mock.ExecCall{Exec: "npx", Params: []string{
|
|
"eslint",
|
|
".",
|
|
"-f", "checkstyle",
|
|
"--ignore-pattern", "node_modules/",
|
|
"--ignore-pattern", ".eslintrc.js",
|
|
"-o", "./0_defaultlint.xml",
|
|
}}, lintUtils.execRunner.Calls[1])
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("Call default with ESLint config from user and failOnError - no redirect to file, stylish format", func(t *testing.T) {
|
|
lintUtils := newLintMockUtilsBundle()
|
|
lintUtils.AddFile("package.json", []byte("{\"name\": \"Test\" }"))
|
|
lintUtils.AddFile(".eslintrc.json", []byte("{\"name\": \"Test\" }"))
|
|
lintUtils.execRunner = &mock.ExecMockRunner{ShouldFailOnCommand: map[string]error{
|
|
"eslint . -f stylish --ignore-pattern node_modules/ --ignore-pattern .eslintrc.js": errors.New("exit 1")}}
|
|
|
|
config := defaultConfig
|
|
config.FailOnError = true
|
|
config.OutputFormat = "stylish"
|
|
config.OutputFileName = ""
|
|
config.DefaultNpmRegistry = "foo.bar"
|
|
|
|
npmUtils := newNpmMockUtilsBundle()
|
|
npmUtils.execRunner = lintUtils.execRunner
|
|
npmExecutor := npm.Execute{Utils: &npmUtils, Options: npm.ExecutorOptions{}}
|
|
|
|
err := runNpmExecuteLint(&npmExecutor, &lintUtils, &config)
|
|
|
|
if assert.EqualError(t, err, "Lint execution failed. This might be the result of severe linting findings, problems with the provided ESLint configuration (.eslintrc.json), or another issue. Please examine the linting results in the UI or in 0_defaultlint.xml, if available, or the log above. ") {
|
|
if assert.Equal(t, 2, len(lintUtils.execRunner.Calls)) {
|
|
assert.Equal(t, mock.ExecCall{Exec: "npx", Params: []string{
|
|
"eslint",
|
|
".",
|
|
"-f", "stylish",
|
|
"--ignore-pattern", "node_modules/",
|
|
"--ignore-pattern", ".eslintrc.js",
|
|
// no -o, --output-file in this case.
|
|
}}, lintUtils.execRunner.Calls[1])
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("Find ESLint configs", func(t *testing.T) {
|
|
lintUtils := newLintMockUtilsBundle()
|
|
lintUtils.AddFile("package.json", []byte("{\"name\": \"Test\" }"))
|
|
lintUtils.AddFile(".eslintrc.json", []byte("{\"name\": \"Test\" }"))
|
|
lintUtils.AddFile("src/.eslintrc.json", []byte("{\"name\": \"Test\" }"))
|
|
lintUtils.AddFile("node_modules/.eslintrc.json", []byte("{\"name\": \"Test\" }")) // should be filtered out
|
|
lintUtils.AddFile(".pipeline/.eslintrc.json", []byte("{\"name\": \"Test\" }")) // should be filtered out
|
|
|
|
eslintConfigs := findEslintConfigs(&lintUtils)
|
|
if assert.Equal(t, 2, len(eslintConfigs)) {
|
|
assert.Contains(t, eslintConfigs, ".eslintrc.json")
|
|
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!")
|
|
})
|
|
}
|