1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-07-01 00:54:55 +02:00

Refactor pkg/npm and npmExecuteScripts (#1684)

This change refactors the npm pkg and npmExecuteScripts implementations
to be reusable for future steps, e.g., npmExecuteLint.

In addition, it fixes few small bugs related to unit test execution on
Windows and the fileUtils mocking implementation.

Co-authored-by: Daniel Kurzynski <daniel.kurzynski@sap.com>
Co-authored-by: Stephan Aßmus <stephan.assmus@sap.com>
This commit is contained in:
Kevin Hudemann
2020-06-18 17:30:17 +02:00
committed by GitHub
parent be01dd3869
commit ceb3dd0a04
12 changed files with 779 additions and 343 deletions

View File

@ -1,161 +1,140 @@
package cmd
import (
"fmt"
"github.com/SAP/jenkins-library/pkg/mock"
"github.com/bmatcuk/doublestar"
"github.com/SAP/jenkins-library/pkg/npm"
"github.com/stretchr/testify/assert"
"sort"
"testing"
)
type npmExecuteScriptsMockUtilsBundle struct {
execRunner mock.ExecMockRunner
files map[string][]byte
type npmMockUtilsBundle struct {
*mock.FilesMock
execRunner *mock.ExecMockRunner
}
func (u *npmExecuteScriptsMockUtilsBundle) fileExists(path string) (bool, error) {
_, exists := u.files[path]
return exists, nil
func (u *npmMockUtilsBundle) GetExecRunner() npm.ExecRunner {
return u.execRunner
}
// duplicated from nexusUpload_test.go for now, refactor later?
func (u *npmExecuteScriptsMockUtilsBundle) glob(pattern string) ([]string, error) {
var matches []string
for path := range u.files {
matched, _ := doublestar.Match(pattern, path)
if matched {
matches = append(matches, path)
func newNpmMockUtilsBundle() npmMockUtilsBundle {
utils := npmMockUtilsBundle{FilesMock: &mock.FilesMock{}, execRunner: &mock.ExecMockRunner{}}
return utils
}
type npmExecutorMock struct {
utils npmMockUtilsBundle
config npmExecuteScriptsOptions
}
func (n *npmExecutorMock) FindPackageJSONFiles() []string {
packages, _ := n.utils.Glob("**/package.json")
return packages
}
func (n *npmExecutorMock) FindPackageJSONFilesWithScript(packageJSONFiles []string, script string) ([]string, error) {
return packageJSONFiles, nil
}
func (n *npmExecutorMock) RunScriptsInAllPackages(runScripts []string, runOptions []string, virtualFrameBuffer bool) error {
if len(runScripts) != len(n.config.RunScripts) {
return fmt.Errorf("RunScriptsInAllPackages was called with a different list of runScripts than config.RunScripts")
}
for i, script := range runScripts {
if script != n.config.RunScripts[i] {
return fmt.Errorf("RunScriptsInAllPackages was called with a different list of runScripts than config.RunScripts")
}
}
// The order in m.files is not deterministic, this would result in flaky tests.
sort.Strings(matches)
return matches, nil
}
func (u *npmExecuteScriptsMockUtilsBundle) getwd() (dir string, err error) {
return "/project", nil
}
if len(runOptions) != 0 {
return fmt.Errorf("RunScriptsInAllPackages was unexpectedly called with a list of runOptions")
}
if virtualFrameBuffer != n.config.VirtualFrameBuffer {
return fmt.Errorf("RunScriptsInAllPackages was called with a different value of virtualFrameBuffer than config.virtualFrameBuffer")
}
func (u *npmExecuteScriptsMockUtilsBundle) chdir(dir string) error {
return nil
}
func (u *npmExecuteScriptsMockUtilsBundle) getExecRunner() execRunner {
return &u.execRunner
func (n *npmExecutorMock) InstallAllDependencies(packageJSONFiles []string) error {
allPackages := n.FindPackageJSONFiles()
if len(packageJSONFiles) != len(allPackages) {
return fmt.Errorf("packageJSONFiles != n.FindPackageJSONFiles()")
}
for i, packageJSON := range packageJSONFiles {
if packageJSON != allPackages[i] {
return fmt.Errorf("InstallAllDependencies was called with a different list of package.json files than result of n.FindPackageJSONFiles()")
}
}
if !n.config.Install {
return fmt.Errorf("InstallAllDependencies was called but config.Install was false")
}
return nil
}
func (n *npmExecutorMock) SetNpmRegistries() error {
return nil
}
func TestNpmExecuteScripts(t *testing.T) {
t.Run("Call without install and run-scripts", func(t *testing.T) {
utils := newNpmExecuteScriptsMockUtilsBundle()
utils.files["package.json"] = []byte(`abc`)
utils.files["package-lock.json"] = []byte(`abc`)
options := npmExecuteScriptsOptions{}
t.Run("Call with install", func(t *testing.T) {
config := npmExecuteScriptsOptions{Install: true, RunScripts: []string{"ci-build", "ci-test"}}
utils := newNpmMockUtilsBundle()
utils.AddFile("package.json", []byte("{\"name\": \"Test\" }"))
utils.AddFile("src/package.json", []byte("{\"name\": \"Test\" }"))
err := runNpmExecuteScripts(&utils, &options)
npmExecutor := npmExecutorMock{utils: utils, config: config}
err := runNpmExecuteScripts(&npmExecutor, &config)
assert.NoError(t, err)
assert.Equal(t, 2, len(utils.execRunner.Calls))
})
t.Run("Project with package lock", func(t *testing.T) {
utils := newNpmExecuteScriptsMockUtilsBundle()
utils.files["package.json"] = []byte(`abc`)
utils.files["foo/bar/node_modules/package.json"] = []byte(`abc`) // is filtered out
utils.files["gen/bar/package.json"] = []byte(`abc`) // is filtered out
utils.files["foo/gen/package.json"] = []byte(`abc`) // is filtered out
utils.files["package-lock.json"] = []byte(`abc`)
options := npmExecuteScriptsOptions{}
options.Install = true
options.RunScripts = []string{"foo", "bar"}
options.DefaultNpmRegistry = "foo.bar"
t.Run("Call without install", func(t *testing.T) {
config := npmExecuteScriptsOptions{Install: true, RunScripts: []string{"ci-build", "ci-test"}}
utils := newNpmMockUtilsBundle()
utils.AddFile("package.json", []byte("{\"name\": \"Test\" }"))
utils.AddFile("src/package.json", []byte("{\"name\": \"Test\" }"))
err := runNpmExecuteScripts(&utils, &options)
npmExecutor := npmExecutorMock{utils: utils, config: config}
err := runNpmExecuteScripts(&npmExecutor, &config)
assert.NoError(t, err)
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"ci"}}, utils.execRunner.Calls[2])
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run-script", "foo", "--if-present"}}, utils.execRunner.Calls[3])
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run-script", "bar", "--if-present"}}, utils.execRunner.Calls[4])
assert.Equal(t, 5, len(utils.execRunner.Calls))
})
t.Run("Project with two package json files", func(t *testing.T) {
utils := newNpmExecuteScriptsMockUtilsBundle()
utils.files["package.json"] = []byte(`abc`)
utils.files["foo/bar/package.json"] = []byte(`abc`)
utils.files["package-lock.json"] = []byte(`abc`)
options := npmExecuteScriptsOptions{}
options.Install = true
options.RunScripts = []string{"foo", "bar"}
t.Run("Call with virtualFrameBuffer", func(t *testing.T) {
config := npmExecuteScriptsOptions{Install: true, RunScripts: []string{"ci-build", "ci-test"}, VirtualFrameBuffer: true}
utils := newNpmMockUtilsBundle()
utils.AddFile("package.json", []byte("{\"name\": \"Test\" }"))
utils.AddFile("src/package.json", []byte("{\"name\": \"Test\" }"))
err := runNpmExecuteScripts(&utils, &options)
npmExecutor := npmExecutorMock{utils: utils, config: config}
err := runNpmExecuteScripts(&npmExecutor, &config)
assert.NoError(t, err)
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"ci"}}, utils.execRunner.Calls[2])
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run-script", "foo", "--if-present"}}, utils.execRunner.Calls[3])
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run-script", "bar", "--if-present"}}, utils.execRunner.Calls[4])
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"ci"}}, utils.execRunner.Calls[7])
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run-script", "foo", "--if-present"}}, utils.execRunner.Calls[8])
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run-script", "bar", "--if-present"}}, utils.execRunner.Calls[9])
assert.Equal(t, 10, len(utils.execRunner.Calls))
})
t.Run("Project with yarn lock", func(t *testing.T) {
utils := newNpmExecuteScriptsMockUtilsBundle()
utils.files["package.json"] = []byte(`abc`)
utils.files["yarn.lock"] = []byte(`abc`)
options := npmExecuteScriptsOptions{}
options.Install = true
options.RunScripts = []string{"foo", "bar"}
t.Run("Test integration with npm pkg", func(t *testing.T) {
config := npmExecuteScriptsOptions{Install: true, RunScripts: []string{"ci-build"}}
err := runNpmExecuteScripts(&utils, &options)
options := npm.ExecutorOptions{SapNpmRegistry: config.SapNpmRegistry, DefaultNpmRegistry: config.DefaultNpmRegistry}
assert.NoError(t, err)
assert.Equal(t, mock.ExecCall{Exec: "yarn", Params: []string{"install", "--frozen-lockfile"}}, utils.execRunner.Calls[2])
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run-script", "foo", "--if-present"}}, utils.execRunner.Calls[3])
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run-script", "bar", "--if-present"}}, utils.execRunner.Calls[4])
})
utils := newNpmMockUtilsBundle()
utils.AddFile("package.json", []byte("{\"scripts\": { \"ci-build\": \"\" } }"))
utils.AddFile("package-lock.json", []byte(""))
t.Run("Project without lock file", func(t *testing.T) {
utils := newNpmExecuteScriptsMockUtilsBundle()
utils.files["package.json"] = []byte(`abc`)
options := npmExecuteScriptsOptions{}
options.Install = true
options.RunScripts = []string{"foo", "bar"}
npmExecutor := npm.Execute{Utils: &utils, Options: options}
err := runNpmExecuteScripts(&utils, &options)
err := runNpmExecuteScripts(&npmExecutor, &config)
assert.NoError(t, err)
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"install"}}, utils.execRunner.Calls[2])
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run-script", "foo", "--if-present"}}, utils.execRunner.Calls[3])
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run-script", "bar", "--if-present"}}, utils.execRunner.Calls[4])
})
t.Run("Call run-scripts with virtual frame buffer", func(t *testing.T) {
utils := newNpmExecuteScriptsMockUtilsBundle()
utils.files["package.json"] = []byte("{\"scripts\": { \"foo\": \"\" } }")
options := npmExecuteScriptsOptions{}
options.Install = false
options.RunScripts = []string{"foo"}
options.VirtualFrameBuffer = true
err := runNpmExecuteScripts(&utils, &options)
assert.Contains(t, utils.execRunner.Env, "DISPLAY=:99")
assert.NoError(t, err)
if assert.Len(t, utils.execRunner.Calls, 4) {
xvfbCall := utils.execRunner.Calls[0]
assert.Equal(t, "Xvfb", xvfbCall.Exec)
assert.Equal(t, []string{"-ac", ":99", "-screen", "0", "1280x1024x16"}, xvfbCall.Params)
assert.True(t, xvfbCall.Async)
assert.True(t, xvfbCall.Execution.Killed)
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run-script", "foo", "--if-present"}}, utils.execRunner.Calls[3])
if assert.NoError(t, err) {
if assert.Equal(t, 6, len(utils.execRunner.Calls)) {
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"config", "get", "registry"}}, utils.execRunner.Calls[0])
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"config", "get", "@sap:registry"}}, utils.execRunner.Calls[1])
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"ci"}}, utils.execRunner.Calls[2])
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run", "ci-build"}}, utils.execRunner.Calls[5])
}
}
})
}
func newNpmExecuteScriptsMockUtilsBundle() npmExecuteScriptsMockUtilsBundle {
utils := npmExecuteScriptsMockUtilsBundle{}
utils.files = map[string][]byte{}
return utils
}