mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-01-28 05:47:08 +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:
parent
be01dd3869
commit
ceb3dd0a04
@ -421,7 +421,7 @@ func TestTriggerFortifyScan(t *testing.T) {
|
||||
assert.Equal(t, []string{"install", "--user"}, runner.executions[2].parameters)
|
||||
|
||||
assert.Equal(t, "sourceanalyzer", runner.executions[3].executable)
|
||||
assert.Equal(t, []string{"-verbose", "-64", "-b", "test", "-Xmx4G", "-Xms2G", "-python-path", "/usr/lib/python35.zip;/usr/lib/python3.5;/usr/lib/python3.5/plat-x86_64-linux-gnu;/usr/lib/python3.5/lib-dynload;/home/piper/.local/lib/python3.5/site-packages;/usr/local/lib/python3.5/dist-packages;/usr/lib/python3/dist-packages;./lib", "-exclude", "./**/tests/**/*:./**/setup.py", "./**/*"}, runner.executions[3].parameters)
|
||||
assert.Equal(t, []string{"-verbose", "-64", "-b", "test", "-Xmx4G", "-Xms2G", "-python-path", "/usr/lib/python35.zip;/usr/lib/python3.5;/usr/lib/python3.5/plat-x86_64-linux-gnu;/usr/lib/python3.5/lib-dynload;/home/piper/.local/lib/python3.5/site-packages;/usr/local/lib/python3.5/dist-packages;/usr/lib/python3/dist-packages;./lib", "-exclude", fmt.Sprintf("./**/tests/**/*%s./**/setup.py", separator), "./**/*"}, runner.executions[3].parameters)
|
||||
|
||||
assert.Equal(t, "sourceanalyzer", runner.executions[4].executable)
|
||||
assert.Equal(t, []string{"-verbose", "-64", "-b", "test", "-scan", "-Xmx4G", "-Xms2G", "-build-label", "testLabel", "-logfile", "target/fortify-scan.log", "-f", "target/result.fpr"}, runner.executions[4].parameters)
|
||||
|
@ -82,7 +82,12 @@ func mtaBuild(config mtaBuildOptions,
|
||||
log.Entry().Debugf("Launching mta build")
|
||||
files := piperutils.Files{}
|
||||
httpClient := piperhttp.Client{}
|
||||
err := runMtaBuild(config, commonPipelineEnvironment, &command.Command{}, &files, &httpClient)
|
||||
e := command.Command{}
|
||||
|
||||
npmExecutorOptions := npm.ExecutorOptions{DefaultNpmRegistry: config.DefaultNpmRegistry, SapNpmRegistry: config.SapNpmRegistry, ExecRunner: &e}
|
||||
npmExecutor := npm.NewExecutor(npmExecutorOptions)
|
||||
|
||||
err := runMtaBuild(config, commonPipelineEnvironment, &e, &files, &httpClient, npmExecutor)
|
||||
if err != nil {
|
||||
log.Entry().
|
||||
WithError(err).
|
||||
@ -94,7 +99,8 @@ func runMtaBuild(config mtaBuildOptions,
|
||||
commonPipelineEnvironment *mtaBuildCommonPipelineEnvironment,
|
||||
e execRunner,
|
||||
p piperutils.FileUtils,
|
||||
httpClient piperhttp.Downloader) error {
|
||||
httpClient piperhttp.Downloader,
|
||||
npmExecutor npm.Executor) error {
|
||||
|
||||
e.Stdout(log.Writer()) // not sure if using the logging framework here is a suitable approach. We handover already log formatted
|
||||
e.Stderr(log.Writer()) // entries to a logging framework again. But this is considered to be some kind of project standard.
|
||||
@ -106,11 +112,7 @@ func runMtaBuild(config mtaBuildOptions,
|
||||
return err
|
||||
}
|
||||
|
||||
err = npm.SetNpmRegistries(
|
||||
&npm.RegistryOptions{
|
||||
DefaultNpmRegistry: config.DefaultNpmRegistry,
|
||||
SapNpmRegistry: config.SapNpmRegistry,
|
||||
}, e)
|
||||
err = npmExecutor.SetNpmRegistries()
|
||||
|
||||
mtaYamlFile := "mta.yaml"
|
||||
mtaYamlFileExists, err := p.FileExists(mtaYamlFile)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/SAP/jenkins-library/pkg/npm"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
@ -25,7 +26,7 @@ func TestMarBuild(t *testing.T) {
|
||||
|
||||
fileUtils := MtaTestFileUtilsMock{}
|
||||
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient)
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e))
|
||||
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, "'mta.yaml' not found in project sources and 'applicationName' not provided as parameter - cannot generate 'mta.yaml' file", err.Error())
|
||||
@ -43,7 +44,10 @@ func TestMarBuild(t *testing.T) {
|
||||
existingFiles["package.json"] = "{\"name\": \"myName\", \"version\": \"1.2.3\"}"
|
||||
fileUtils := MtaTestFileUtilsMock{existingFiles: existingFiles}
|
||||
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient)
|
||||
npmExecutor := newNpmExecutor(&e)
|
||||
npmExecutor.Options = npm.ExecutorOptions{DefaultNpmRegistry: options.DefaultNpmRegistry}
|
||||
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, npmExecutor)
|
||||
|
||||
assert.Nil(t, err)
|
||||
|
||||
@ -64,7 +68,10 @@ func TestMarBuild(t *testing.T) {
|
||||
existingFiles["package.json"] = "{\"name\": \"myName\", \"version\": \"1.2.3\"}"
|
||||
fileUtils := MtaTestFileUtilsMock{existingFiles: existingFiles}
|
||||
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient)
|
||||
npmExecutor := newNpmExecutor(&e)
|
||||
npmExecutor.Options = npm.ExecutorOptions{SapNpmRegistry: options.SapNpmRegistry}
|
||||
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, npmExecutor)
|
||||
|
||||
assert.Nil(t, err)
|
||||
|
||||
@ -82,7 +89,7 @@ func TestMarBuild(t *testing.T) {
|
||||
|
||||
fileUtils := MtaTestFileUtilsMock{}
|
||||
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient)
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e))
|
||||
|
||||
assert.NotNil(t, err)
|
||||
|
||||
@ -101,7 +108,7 @@ func TestMarBuild(t *testing.T) {
|
||||
|
||||
fileUtils := MtaTestFileUtilsMock{existingFiles: existingFiles}
|
||||
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient)
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e))
|
||||
|
||||
assert.Nil(t, err)
|
||||
|
||||
@ -140,7 +147,7 @@ func TestMarBuild(t *testing.T) {
|
||||
existingFiles["mta.yaml"] = "already there"
|
||||
fileUtils := MtaTestFileUtilsMock{existingFiles: existingFiles}
|
||||
|
||||
runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient)
|
||||
_ = runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e))
|
||||
|
||||
assert.Empty(t, fileUtils.writtenFiles)
|
||||
})
|
||||
@ -156,7 +163,7 @@ func TestMarBuild(t *testing.T) {
|
||||
existingFiles["mta.yaml"] = "already there with-${timestamp}"
|
||||
fileUtils := MtaTestFileUtilsMock{existingFiles: existingFiles}
|
||||
|
||||
runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient)
|
||||
_ = runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e))
|
||||
|
||||
assert.NotEmpty(t, fileUtils.writtenFiles["mta.yaml"])
|
||||
})
|
||||
@ -173,7 +180,7 @@ func TestMarBuild(t *testing.T) {
|
||||
existingFiles["package.json"] = "{\"name\": \"myName\", \"version\": \"1.2.3\"}"
|
||||
fileUtils := MtaTestFileUtilsMock{existingFiles: existingFiles}
|
||||
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient)
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e))
|
||||
|
||||
assert.Nil(t, err)
|
||||
|
||||
@ -198,7 +205,7 @@ func TestMarBuild(t *testing.T) {
|
||||
existingFiles["mta.yaml"] = "ID: \"myNameFromMtar\""
|
||||
fileUtils := MtaTestFileUtilsMock{existingFiles: existingFiles}
|
||||
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient)
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e))
|
||||
|
||||
assert.Nil(t, err)
|
||||
|
||||
@ -218,7 +225,7 @@ func TestMarBuild(t *testing.T) {
|
||||
existingFiles["package.json"] = "{\"name\": \"myName\", \"version\": \"1.2.3\"}"
|
||||
fileUtils := MtaTestFileUtilsMock{existingFiles: existingFiles}
|
||||
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient)
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e))
|
||||
|
||||
assert.Nil(t, err)
|
||||
|
||||
@ -240,7 +247,7 @@ func TestMarBuild(t *testing.T) {
|
||||
existingFiles["package.json"] = "{\"name\": \"myName\", \"version\": \"1.2.3\"}"
|
||||
fileUtils := MtaTestFileUtilsMock{existingFiles: existingFiles}
|
||||
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient)
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e))
|
||||
|
||||
assert.Nil(t, err)
|
||||
|
||||
@ -285,7 +292,7 @@ func TestMarBuild(t *testing.T) {
|
||||
|
||||
options := mtaBuildOptions{ApplicationName: "myApp", GlobalSettingsFile: "/opt/maven/settings.xml", MtaBuildTool: "cloudMbt", Platform: "CF", MtarName: "myName"}
|
||||
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient)
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e))
|
||||
|
||||
assert.Nil(t, err)
|
||||
|
||||
@ -304,7 +311,7 @@ func TestMarBuild(t *testing.T) {
|
||||
|
||||
options := mtaBuildOptions{ApplicationName: "myApp", ProjectSettingsFile: "/my/project/settings.xml", MtaBuildTool: "cloudMbt", Platform: "CF", MtarName: "myName"}
|
||||
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient)
|
||||
err := runMtaBuild(options, &cpe, &e, &fileUtils, &httpClient, newNpmExecutor(&e))
|
||||
|
||||
assert.Nil(t, err)
|
||||
|
||||
@ -358,3 +365,9 @@ func (f *MtaTestFileUtilsMock) FileWrite(path string, content []byte, perm os.Fi
|
||||
func (f *MtaTestFileUtilsMock) MkdirAll(path string, perm os.FileMode) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func newNpmExecutor(execRunner *mock.ExecMockRunner) *npm.Execute {
|
||||
utils := newNpmMockUtilsBundle()
|
||||
utils.execRunner = execRunner
|
||||
return &npm.Execute{Utils: &utils}
|
||||
}
|
||||
|
@ -6,6 +6,9 @@ import (
|
||||
"github.com/SAP/jenkins-library/pkg/mock"
|
||||
"github.com/SAP/jenkins-library/pkg/nexus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -48,6 +51,9 @@ func (m *mockUtilsBundle) getExecRunner() execRunner {
|
||||
}
|
||||
|
||||
func (m *mockUtilsBundle) setProperty(pomFile, expression, value string) {
|
||||
pomFile = strings.ReplaceAll(pomFile, "/", string(os.PathSeparator))
|
||||
pomFile = strings.ReplaceAll(pomFile, "\\", string(os.PathSeparator))
|
||||
|
||||
pom := m.properties[pomFile]
|
||||
if pom == nil {
|
||||
pom = map[string]string{}
|
||||
@ -424,7 +430,7 @@ func TestUploadMavenProjects(t *testing.T) {
|
||||
utils.setProperty("pom.xml", "project.packaging", "jar")
|
||||
utils.setProperty("pom.xml", "project.build.finalName", "my-app-1.0")
|
||||
utils.AddFile("pom.xml", testPomXml)
|
||||
utils.AddFile("target/my-app-1.0.jar", []byte("contentsOfJar"))
|
||||
utils.AddFile(filepath.Join("target", "my-app-1.0.jar"), []byte("contentsOfJar"))
|
||||
uploader := mockUploader{}
|
||||
options := createOptions()
|
||||
|
||||
@ -439,7 +445,7 @@ func TestUploadMavenProjects(t *testing.T) {
|
||||
assert.Equal(t, "pom.xml", artifacts[0].File)
|
||||
assert.Equal(t, "pom", artifacts[0].Type)
|
||||
|
||||
assert.Equal(t, "target/my-app-1.0.jar", artifacts[1].File)
|
||||
assert.Equal(t, filepath.Join("target", "my-app-1.0.jar"), artifacts[1].File)
|
||||
assert.Equal(t, "jar", artifacts[1].Type)
|
||||
}
|
||||
})
|
||||
@ -451,7 +457,7 @@ func TestUploadMavenProjects(t *testing.T) {
|
||||
utils.setProperty("pom.xml", "project.packaging", "<empty>")
|
||||
utils.setProperty("pom.xml", "project.build.finalName", "my-app-1.0")
|
||||
utils.AddFile("pom.xml", testPomXml)
|
||||
utils.AddFile("target/my-app-1.0.jar", []byte("contentsOfJar"))
|
||||
utils.AddFile(filepath.Join("target", "my-app-1.0.jar"), []byte("contentsOfJar"))
|
||||
uploader := mockUploader{}
|
||||
options := createOptions()
|
||||
|
||||
@ -465,7 +471,7 @@ func TestUploadMavenProjects(t *testing.T) {
|
||||
assert.Equal(t, "pom.xml", artifacts[0].File)
|
||||
assert.Equal(t, "pom", artifacts[0].Type)
|
||||
|
||||
assert.Equal(t, "target/my-app-1.0.jar", artifacts[1].File)
|
||||
assert.Equal(t, filepath.Join("target", "my-app-1.0.jar"), artifacts[1].File)
|
||||
assert.Equal(t, "jar", artifacts[1].Type)
|
||||
}
|
||||
})
|
||||
@ -501,7 +507,7 @@ func TestUploadMavenProjects(t *testing.T) {
|
||||
utils.setProperty("pom.xml", "project.artifactId", "my-app")
|
||||
utils.setProperty("pom.xml", "project.packaging", "jar")
|
||||
utils.AddFile("pom.xml", testPomXml)
|
||||
utils.AddFile("target/my-app-1.0.jar", []byte("contentsOfJar"))
|
||||
utils.AddFile(filepath.Join("target", "my-app-1.0.jar"), []byte("contentsOfJar"))
|
||||
uploader := mockUploader{}
|
||||
options := createOptions()
|
||||
|
||||
@ -517,7 +523,7 @@ func TestUploadMavenProjects(t *testing.T) {
|
||||
if assert.Equal(t, 2, len(artifacts)) {
|
||||
assert.Equal(t, "pom.xml", artifacts[0].File)
|
||||
assert.Equal(t, "pom", artifacts[0].Type)
|
||||
assert.Equal(t, "target/my-app-1.0.jar", artifacts[1].File)
|
||||
assert.Equal(t, filepath.Join("target", "my-app-1.0.jar"), artifacts[1].File)
|
||||
assert.Equal(t, "jar", artifacts[1].Type)
|
||||
}
|
||||
})
|
||||
@ -548,7 +554,7 @@ func TestUploadMavenProjects(t *testing.T) {
|
||||
utils.setProperty("performance-tests/pom.xml", "project.artifactId", "my-app-app")
|
||||
utils.setProperty("performance-tests/pom.xml", "project.packaging", "")
|
||||
utils.AddFile("pom.xml", testPomXml)
|
||||
utils.AddFile("application/pom.xml", testPomXml)
|
||||
utils.AddFile(filepath.Join("application", "pom.xml"), testPomXml)
|
||||
utils.AddFile("application/target/final-artifact.war", []byte("contentsOfJar"))
|
||||
utils.AddFile("application/target/final-artifact-classes.jar", []byte("contentsOfClassesJar"))
|
||||
utils.AddFile("integration-tests/pom.xml", testPomXml)
|
||||
@ -566,13 +572,13 @@ func TestUploadMavenProjects(t *testing.T) {
|
||||
|
||||
artifacts := uploader.uploadedArtifacts
|
||||
if assert.Equal(t, 4, len(artifacts)) {
|
||||
assert.Equal(t, "application/pom.xml", artifacts[0].File)
|
||||
assert.Equal(t, filepath.Join("application", "pom.xml"), artifacts[0].File)
|
||||
assert.Equal(t, "pom", artifacts[0].Type)
|
||||
|
||||
assert.Equal(t, "application/target/final-artifact.war", artifacts[1].File)
|
||||
assert.Equal(t, filepath.Join("application", "target", "final-artifact.war"), artifacts[1].File)
|
||||
assert.Equal(t, "war", artifacts[1].Type)
|
||||
|
||||
assert.Equal(t, "application/target/final-artifact-classes.jar", artifacts[2].File)
|
||||
assert.Equal(t, filepath.Join("application", "target", "final-artifact-classes.jar"), artifacts[2].File)
|
||||
assert.Equal(t, "jar", artifacts[2].Type)
|
||||
|
||||
assert.Equal(t, "pom.xml", artifacts[3].File)
|
||||
@ -585,9 +591,9 @@ func TestUploadMavenProjects(t *testing.T) {
|
||||
"-DgroupId=com.mycompany.app",
|
||||
"-Dversion=1.0",
|
||||
"-DartifactId=my-app-app",
|
||||
"-Dfile=application/pom.xml",
|
||||
"-Dfile=" + filepath.Join("application", "pom.xml"),
|
||||
"-Dpackaging=pom",
|
||||
"-Dfiles=application/target/final-artifact.war,application/target/final-artifact-classes.jar",
|
||||
"-Dfiles=" + filepath.Join("application", "target", "final-artifact.war") + "," + filepath.Join("application", "target", "final-artifact-classes.jar"),
|
||||
"-Dclassifiers=,classes",
|
||||
"-Dtypes=war,jar",
|
||||
"-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn",
|
||||
|
@ -1,185 +1,30 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/SAP/jenkins-library/pkg/command"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/npm"
|
||||
FileUtils "github.com/SAP/jenkins-library/pkg/piperutils"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
"github.com/bmatcuk/doublestar"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type npmExecuteScriptsUtilsInterface interface {
|
||||
fileExists(path string) (bool, error)
|
||||
glob(pattern string) (matches []string, err error)
|
||||
getwd() (dir string, err error)
|
||||
chdir(dir string) error
|
||||
getExecRunner() execRunner
|
||||
}
|
||||
|
||||
type npmExecuteScriptsUtilsBundle struct {
|
||||
projectStructure FileUtils.ProjectStructure
|
||||
fileUtils FileUtils.Files
|
||||
execRunner *command.Command
|
||||
}
|
||||
|
||||
func (u *npmExecuteScriptsUtilsBundle) fileExists(path string) (bool, error) {
|
||||
return u.fileUtils.FileExists(path)
|
||||
}
|
||||
|
||||
func (u *npmExecuteScriptsUtilsBundle) glob(pattern string) (matches []string, err error) {
|
||||
return doublestar.Glob(pattern)
|
||||
}
|
||||
|
||||
func (u *npmExecuteScriptsUtilsBundle) getwd() (dir string, err error) {
|
||||
return os.Getwd()
|
||||
}
|
||||
|
||||
func (u *npmExecuteScriptsUtilsBundle) chdir(dir string) error {
|
||||
return os.Chdir(dir)
|
||||
}
|
||||
|
||||
func (u *npmExecuteScriptsUtilsBundle) getExecRunner() execRunner {
|
||||
if u.execRunner == nil {
|
||||
u.execRunner = &command.Command{}
|
||||
u.execRunner.Stdout(log.Writer())
|
||||
u.execRunner.Stderr(log.Writer())
|
||||
}
|
||||
return u.execRunner
|
||||
}
|
||||
|
||||
func npmExecuteScripts(config npmExecuteScriptsOptions, telemetryData *telemetry.CustomData) {
|
||||
utils := npmExecuteScriptsUtilsBundle{}
|
||||
npmExecutorOptions := npm.ExecutorOptions{DefaultNpmRegistry: config.DefaultNpmRegistry, SapNpmRegistry: config.SapNpmRegistry}
|
||||
npmExecutor := npm.NewExecutor(npmExecutorOptions)
|
||||
|
||||
err := runNpmExecuteScripts(&utils, &config)
|
||||
err := runNpmExecuteScripts(npmExecutor, &config)
|
||||
if err != nil {
|
||||
log.Entry().WithError(err).Fatal("step execution failed")
|
||||
}
|
||||
}
|
||||
func runNpmExecuteScripts(utils npmExecuteScriptsUtilsInterface, options *npmExecuteScriptsOptions) error {
|
||||
execRunner := utils.getExecRunner()
|
||||
packageJSONFiles, err := findPackageJSONFiles(utils)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
oldWorkingDirectory, err := utils.getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
func runNpmExecuteScripts(npmExecutor npm.Executor, config *npmExecuteScriptsOptions) error {
|
||||
packageJSONFiles := npmExecutor.FindPackageJSONFiles()
|
||||
|
||||
if options.VirtualFrameBuffer {
|
||||
cmd, err := execRunner.RunExecutableInBackground("Xvfb", "-ac", ":99", "-screen", "0", "1280x1024x16")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to start virtual frame buffer%w", err)
|
||||
}
|
||||
defer cmd.Kill()
|
||||
execRunner.SetEnv([]string{"DISPLAY=:99"})
|
||||
}
|
||||
|
||||
for _, file := range packageJSONFiles {
|
||||
dir := path.Dir(file)
|
||||
err = utils.chdir(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set in each directory to respect existing config in rc files
|
||||
err = npm.SetNpmRegistries(
|
||||
&npm.RegistryOptions{
|
||||
DefaultNpmRegistry: options.DefaultNpmRegistry,
|
||||
SapNpmRegistry: options.SapNpmRegistry,
|
||||
}, execRunner)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
packageLockExists, yarnLockExists, err := checkIfLockFilesExist(utils)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if options.Install {
|
||||
err = installDependencies(dir, packageLockExists, yarnLockExists, execRunner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range options.RunScripts {
|
||||
log.Entry().WithField("WorkingDirectory", dir).Info("run-script " + v)
|
||||
err = execRunner.RunExecutable("npm", "run-script", v, "--if-present")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = utils.chdir(oldWorkingDirectory)
|
||||
if config.Install {
|
||||
err := npmExecutor.InstallAllDependencies(packageJSONFiles)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func findPackageJSONFiles(utils npmExecuteScriptsUtilsInterface) ([]string, error) {
|
||||
unfilteredListOfPackageJSONFiles, err := utils.glob("**/package.json")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var packageJSONFiles []string
|
||||
|
||||
for _, file := range unfilteredListOfPackageJSONFiles {
|
||||
if strings.Contains(file, "node_modules") {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(file, "gen/") || strings.Contains(file, "/gen/") {
|
||||
continue
|
||||
}
|
||||
packageJSONFiles = append(packageJSONFiles, file)
|
||||
log.Entry().Info("Discovered package.json file " + file)
|
||||
}
|
||||
return packageJSONFiles, nil
|
||||
}
|
||||
func checkIfLockFilesExist(utils npmExecuteScriptsUtilsInterface) (bool, bool, error) {
|
||||
packageLockExists, err := utils.fileExists("package-lock.json")
|
||||
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
yarnLockExists, err := utils.fileExists("yarn.lock")
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
return packageLockExists, yarnLockExists, nil
|
||||
}
|
||||
|
||||
func installDependencies(dir string, packageLockExists bool, yarnLockExists bool, execRunner execRunner) (err error) {
|
||||
log.Entry().WithField("WorkingDirectory", dir).Info("Running install")
|
||||
if packageLockExists {
|
||||
err = execRunner.RunExecutable("npm", "ci")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if yarnLockExists {
|
||||
err = execRunner.RunExecutable("yarn", "install", "--frozen-lockfile")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.Entry().Warn("No package lock file found. " +
|
||||
"It is recommended to create a `package-lock.json` file by running `npm install` locally." +
|
||||
" Add this file to your version control. " +
|
||||
"By doing so, the builds of your application become more reliable.")
|
||||
err = execRunner.RunExecutable("npm", "install")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return npmExecutor.RunScriptsInAllPackages(config.RunScripts, nil, config.VirtualFrameBuffer)
|
||||
}
|
||||
|
@ -112,18 +112,18 @@ func npmExecuteScriptsMetadata() config.StepData {
|
||||
{
|
||||
Name: "defaultNpmRegistry",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Scope: []string{"PARAMETERS", "GENERAL", "STAGES", "STEPS"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
Aliases: []config.Alias{{Name: "npm/defaultNpmRegistry"}},
|
||||
},
|
||||
{
|
||||
Name: "sapNpmRegistry",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Scope: []string{"PARAMETERS", "GENERAL", "STAGES", "STEPS"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
Aliases: []config.Alias{{Name: "npm/sapNpmRegistry"}},
|
||||
},
|
||||
{
|
||||
Name: "virtualFrameBuffer",
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ type FilesMock struct {
|
||||
files map[string]*[]byte
|
||||
removedFiles map[string]*[]byte
|
||||
currentDir string
|
||||
Separator string
|
||||
}
|
||||
|
||||
func (f *FilesMock) init() {
|
||||
@ -27,25 +28,33 @@ func (f *FilesMock) init() {
|
||||
if f.removedFiles == nil {
|
||||
f.removedFiles = map[string]*[]byte{}
|
||||
}
|
||||
if f.Separator == "" {
|
||||
f.Separator = string(os.PathSeparator)
|
||||
}
|
||||
}
|
||||
|
||||
func (f *FilesMock) toAbsPath(path string) string {
|
||||
if !strings.HasPrefix(path, string(os.PathSeparator)) {
|
||||
path = string(os.PathSeparator) + filepath.Join(f.currentDir, path)
|
||||
if !strings.HasPrefix(path, f.Separator) {
|
||||
path = f.Separator + filepath.Join(f.currentDir, path)
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
// AddFile establishes the existence of a virtual file.
|
||||
func (f *FilesMock) AddFile(path string, contents []byte) {
|
||||
f.init()
|
||||
f.files[f.toAbsPath(path)] = &contents
|
||||
f.associateContent(path, &contents)
|
||||
}
|
||||
|
||||
// AddDir establishes the existence of a virtual directory.
|
||||
func (f *FilesMock) AddDir(path string) {
|
||||
f.associateContent(path, &dirContent)
|
||||
}
|
||||
|
||||
func (f *FilesMock) associateContent(path string, content *[]byte) {
|
||||
f.init()
|
||||
f.files[f.toAbsPath(path)] = &dirContent
|
||||
path = strings.ReplaceAll(path, "/", f.Separator)
|
||||
path = strings.ReplaceAll(path, "\\", f.Separator)
|
||||
f.files[f.toAbsPath(path)] = content
|
||||
}
|
||||
|
||||
// HasFile returns true if the virtual file system contains an entry for the given path.
|
||||
@ -69,7 +78,7 @@ func (f *FilesMock) FileExists(path string) (bool, error) {
|
||||
}
|
||||
content, exists := f.files[f.toAbsPath(path)]
|
||||
if !exists {
|
||||
return false, fmt.Errorf("'%s': %w", path, os.ErrNotExist)
|
||||
return false, nil
|
||||
}
|
||||
return content != &dirContent, nil
|
||||
}
|
||||
@ -81,9 +90,9 @@ func (f *FilesMock) DirExists(path string) (bool, error) {
|
||||
for entry, content := range f.files {
|
||||
var dirComponents []string
|
||||
if content == &dirContent {
|
||||
dirComponents = strings.Split(entry, string(os.PathSeparator))
|
||||
dirComponents = strings.Split(entry, f.Separator)
|
||||
} else {
|
||||
dirComponents = strings.Split(filepath.Dir(entry), string(os.PathSeparator))
|
||||
dirComponents = strings.Split(filepath.Dir(entry), f.Separator)
|
||||
}
|
||||
if len(dirComponents) > 0 {
|
||||
dir := ""
|
||||
@ -91,7 +100,7 @@ func (f *FilesMock) DirExists(path string) (bool, error) {
|
||||
if i == 0 {
|
||||
dir = component
|
||||
} else {
|
||||
dir = dir + string(os.PathSeparator) + component
|
||||
dir = dir + f.Separator + component
|
||||
}
|
||||
if dir == path {
|
||||
return true, nil
|
||||
@ -169,8 +178,8 @@ func (f *FilesMock) Glob(pattern string) ([]string, error) {
|
||||
return matches, nil
|
||||
}
|
||||
for path := range f.files {
|
||||
path = strings.TrimLeft(path, string(os.PathSeparator))
|
||||
matched, _ := doublestar.Match(pattern, path)
|
||||
path = strings.TrimLeft(path, f.Separator)
|
||||
matched, _ := doublestar.PathMatch(pattern, path)
|
||||
if matched {
|
||||
matches = append(matches, path)
|
||||
}
|
||||
@ -182,6 +191,7 @@ func (f *FilesMock) Glob(pattern string) ([]string, error) {
|
||||
|
||||
// Getwd returns the rooted current virtual working directory
|
||||
func (f *FilesMock) Getwd() (string, error) {
|
||||
f.init()
|
||||
return f.toAbsPath(""), nil
|
||||
}
|
||||
|
||||
@ -189,7 +199,7 @@ func (f *FilesMock) Getwd() (string, error) {
|
||||
// The directory needs to exist according to the files and directories via AddFile() and AddDirectory().
|
||||
// The implementation does not support relative path components such as "..".
|
||||
func (f *FilesMock) Chdir(path string) error {
|
||||
if path == "." || path == "."+string(os.PathSeparator) {
|
||||
if path == "." || path == "."+f.Separator {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -200,6 +210,6 @@ func (f *FilesMock) Chdir(path string) error {
|
||||
return fmt.Errorf("failed to change current directory into '%s': %w", path, os.ErrNotExist)
|
||||
}
|
||||
|
||||
f.currentDir = strings.TrimLeft(path, string(os.PathSeparator))
|
||||
f.currentDir = strings.TrimLeft(path, f.Separator)
|
||||
return nil
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ func TestFilesMockFileExists(t *testing.T) {
|
||||
err := files.Chdir("some")
|
||||
assert.NoError(t, err)
|
||||
exists, err := files.FileExists(path)
|
||||
assert.EqualError(t, err, "'"+path+"': file does not exist")
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, exists)
|
||||
})
|
||||
}
|
||||
|
289
pkg/npm/npm.go
289
pkg/npm/npm.go
@ -2,25 +2,87 @@ package npm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/SAP/jenkins-library/pkg/command"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/piperutils"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RegistryOptions holds the configured urls for npm registries
|
||||
type RegistryOptions struct {
|
||||
DefaultNpmRegistry string
|
||||
SapNpmRegistry string
|
||||
// Execute struct holds utils to enable mocking and common parameters
|
||||
type Execute struct {
|
||||
Utils Utils
|
||||
Options ExecutorOptions
|
||||
}
|
||||
|
||||
type execRunner interface {
|
||||
// Executor interface to enable mocking for testing
|
||||
type Executor interface {
|
||||
FindPackageJSONFiles() []string
|
||||
FindPackageJSONFilesWithScript(packageJSONFiles []string, script string) ([]string, error)
|
||||
RunScriptsInAllPackages(runScripts []string, runOptions []string, virtualFrameBuffer bool) error
|
||||
InstallAllDependencies(packageJSONFiles []string) error
|
||||
SetNpmRegistries() error
|
||||
}
|
||||
|
||||
// ExecutorOptions holds common parameters for functions of Executor
|
||||
type ExecutorOptions struct {
|
||||
DefaultNpmRegistry string
|
||||
SapNpmRegistry string
|
||||
ExecRunner ExecRunner
|
||||
}
|
||||
|
||||
// NewExecutor instantiates Execute struct and sets executeOptions
|
||||
func NewExecutor(executorOptions ExecutorOptions) Executor {
|
||||
utils := utilsBundle{Files: &piperutils.Files{}, execRunner: executorOptions.ExecRunner}
|
||||
return &Execute{
|
||||
Utils: &utils,
|
||||
Options: executorOptions,
|
||||
}
|
||||
}
|
||||
|
||||
// ExecRunner interface to enable mocking for testing
|
||||
type ExecRunner interface {
|
||||
SetEnv(e []string)
|
||||
Stdout(out io.Writer)
|
||||
Stderr(out io.Writer)
|
||||
RunExecutable(executable string, params ...string) error
|
||||
RunExecutableInBackground(executable string, params ...string) (command.Execution, error)
|
||||
}
|
||||
|
||||
// Utils interface for mocking
|
||||
type Utils interface {
|
||||
Chdir(path string) error
|
||||
FileExists(filename string) (bool, error)
|
||||
FileRead(path string) ([]byte, error)
|
||||
Getwd() (string, error)
|
||||
Glob(pattern string) (matches []string, err error)
|
||||
|
||||
GetExecRunner() ExecRunner
|
||||
}
|
||||
|
||||
type utilsBundle struct {
|
||||
*piperutils.Files
|
||||
execRunner ExecRunner
|
||||
}
|
||||
|
||||
// GetExecRunner returns an execRunner if it's not yet initialized
|
||||
func (u *utilsBundle) GetExecRunner() ExecRunner {
|
||||
if u.execRunner == nil {
|
||||
u.execRunner = &command.Command{}
|
||||
u.execRunner.Stdout(log.Writer())
|
||||
u.execRunner.Stderr(log.Writer())
|
||||
}
|
||||
return u.execRunner
|
||||
}
|
||||
|
||||
// SetNpmRegistries configures the given npm registries.
|
||||
// CAUTION: This will change the npm configuration in the user's home directory.
|
||||
func SetNpmRegistries(options *RegistryOptions, execRunner execRunner) error {
|
||||
func (exec *Execute) SetNpmRegistries() error {
|
||||
execRunner := exec.Utils.GetExecRunner()
|
||||
const sapRegistry = "@sap:registry"
|
||||
const npmRegistry = "registry"
|
||||
configurableRegistries := []string{npmRegistry, sapRegistry}
|
||||
@ -38,23 +100,22 @@ func SetNpmRegistries(options *RegistryOptions, execRunner execRunner) error {
|
||||
log.Entry().Info("Discovered pre-configured npm registry " + registry + " with value " + preConfiguredRegistry)
|
||||
}
|
||||
|
||||
if registry == npmRegistry && options.DefaultNpmRegistry != "" && registryRequiresConfiguration(preConfiguredRegistry, "https://registry.npmjs.org") {
|
||||
log.Entry().Info("npm registry " + registry + " was not configured, setting it to " + options.DefaultNpmRegistry)
|
||||
err = execRunner.RunExecutable("npm", "config", "set", registry, options.DefaultNpmRegistry)
|
||||
if registry == npmRegistry && exec.Options.DefaultNpmRegistry != "" && registryRequiresConfiguration(preConfiguredRegistry, "https://registry.npmjs.org") {
|
||||
log.Entry().Info("npm registry " + registry + " was not configured, setting it to " + exec.Options.DefaultNpmRegistry)
|
||||
err = execRunner.RunExecutable("npm", "config", "set", registry, exec.Options.DefaultNpmRegistry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if registry == sapRegistry && options.SapNpmRegistry != "" && registryRequiresConfiguration(preConfiguredRegistry, "https://npm.sap.com") {
|
||||
log.Entry().Info("npm registry " + registry + " was not configured, setting it to " + options.SapNpmRegistry)
|
||||
err = execRunner.RunExecutable("npm", "config", "set", registry, options.SapNpmRegistry)
|
||||
if registry == sapRegistry && exec.Options.SapNpmRegistry != "" && registryRequiresConfiguration(preConfiguredRegistry, "https://npm.sap.com") {
|
||||
log.Entry().Info("npm registry " + registry + " was not configured, setting it to " + exec.Options.SapNpmRegistry)
|
||||
err = execRunner.RunExecutable("npm", "config", "set", registry, exec.Options.SapNpmRegistry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -65,3 +126,205 @@ func registryIsNonEmpty(preConfiguredRegistry string) bool {
|
||||
func registryRequiresConfiguration(preConfiguredRegistry, url string) bool {
|
||||
return strings.HasPrefix(preConfiguredRegistry, "undefined") || strings.HasPrefix(preConfiguredRegistry, url)
|
||||
}
|
||||
|
||||
// RunScriptsInAllPackages runs all scripts defined in ExecuteOptions.RunScripts
|
||||
func (exec *Execute) RunScriptsInAllPackages(runScripts []string, runOptions []string, virtualFrameBuffer bool) error {
|
||||
packageJSONFiles := exec.FindPackageJSONFiles()
|
||||
execRunner := exec.Utils.GetExecRunner()
|
||||
|
||||
if virtualFrameBuffer {
|
||||
cmd, err := execRunner.RunExecutableInBackground("Xvfb", "-ac", ":99", "-screen", "0", "1280x1024x16")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to start virtual frame buffer%w", err)
|
||||
}
|
||||
defer cmd.Kill()
|
||||
execRunner.SetEnv([]string{"DISPLAY=:99"})
|
||||
}
|
||||
|
||||
for _, script := range runScripts {
|
||||
packagesWithScript, err := exec.FindPackageJSONFilesWithScript(packageJSONFiles, script)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(packagesWithScript) == 0 {
|
||||
log.Entry().Warnf("could not find any package.json file with script " + script)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, packageJSON := range packagesWithScript {
|
||||
err = exec.executeScript(packageJSON, script, runOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (exec *Execute) executeScript(packageJSON string, script string, runOptions []string) error {
|
||||
execRunner := exec.Utils.GetExecRunner()
|
||||
oldWorkingDirectory, err := exec.Utils.Getwd()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get current working directory before executing npm scripts: %w", err)
|
||||
}
|
||||
|
||||
dir := filepath.Dir(packageJSON)
|
||||
err = exec.Utils.Chdir(dir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to change into directory for executing script: %w", err)
|
||||
}
|
||||
|
||||
// set in each directory to respect existing config in rc fileUtils
|
||||
err = exec.SetNpmRegistries()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Entry().WithField("WorkingDirectory", dir).Info("run-script " + script)
|
||||
|
||||
npmRunArgs := []string{"run", script}
|
||||
if len(runOptions) > 0 {
|
||||
npmRunArgs = append(npmRunArgs, runOptions...)
|
||||
}
|
||||
|
||||
err = execRunner.RunExecutable("npm", npmRunArgs...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to run npm script %s: %w", script, err)
|
||||
}
|
||||
|
||||
err = exec.Utils.Chdir(oldWorkingDirectory)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to change back into original directory: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindPackageJSONFiles returns a list of all package.json fileUtils of the project excluding node_modules and gen/ directories
|
||||
func (exec *Execute) FindPackageJSONFiles() []string {
|
||||
unfilteredListOfPackageJSONFiles, _ := exec.Utils.Glob("**/package.json")
|
||||
|
||||
var packageJSONFiles []string
|
||||
|
||||
for _, file := range unfilteredListOfPackageJSONFiles {
|
||||
if strings.Contains(file, "node_modules") {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(file, "gen"+string(os.PathSeparator)) || strings.Contains(file, string(os.PathSeparator)+"gen"+string(os.PathSeparator)) {
|
||||
continue
|
||||
}
|
||||
|
||||
packageJSONFiles = append(packageJSONFiles, file)
|
||||
log.Entry().Info("Discovered package.json file " + file)
|
||||
}
|
||||
return packageJSONFiles
|
||||
}
|
||||
|
||||
// FindPackageJSONFilesWithScript returns a list of package.json fileUtils that contain the script
|
||||
func (exec *Execute) FindPackageJSONFilesWithScript(packageJSONFiles []string, script string) ([]string, error) {
|
||||
var packagesWithScript []string
|
||||
|
||||
for _, file := range packageJSONFiles {
|
||||
var packageJSON map[string]interface{}
|
||||
|
||||
packageRaw, err := exec.Utils.FileRead(file)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read %s to check for existence of %s script: %w", file, script, err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(packageRaw, &packageJSON)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal %s to check for existence of %s script: %w", file, script, err)
|
||||
}
|
||||
|
||||
scripts, ok := packageJSON["scripts"].(map[string]interface{})
|
||||
if ok {
|
||||
_, ok := scripts[script].(string)
|
||||
if ok {
|
||||
packagesWithScript = append(packagesWithScript, file)
|
||||
log.Entry().Info("Discovered " + script + " script in " + file)
|
||||
}
|
||||
}
|
||||
}
|
||||
return packagesWithScript, nil
|
||||
}
|
||||
|
||||
// InstallAllDependencies executes npm or yarn Install for all package.json fileUtils defined in packageJSONFiles
|
||||
func (exec *Execute) InstallAllDependencies(packageJSONFiles []string) error {
|
||||
for _, packageJSON := range packageJSONFiles {
|
||||
err := exec.install(packageJSON)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// install executes npm or yarn Install for package.json
|
||||
func (exec *Execute) install(packageJSON string) error {
|
||||
execRunner := exec.Utils.GetExecRunner()
|
||||
|
||||
oldWorkingDirectory, err := exec.Utils.Getwd()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get current working directory before executing npm scripts: %w", err)
|
||||
}
|
||||
|
||||
dir := filepath.Dir(packageJSON)
|
||||
err = exec.Utils.Chdir(dir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to change into directory for executing script: %w", err)
|
||||
}
|
||||
|
||||
err = exec.SetNpmRegistries()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
packageLockExists, yarnLockExists, err := exec.checkIfLockFilesExist()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Entry().WithField("WorkingDirectory", dir).Info("Running Install")
|
||||
if packageLockExists {
|
||||
err = execRunner.RunExecutable("npm", "ci")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if yarnLockExists {
|
||||
err = execRunner.RunExecutable("yarn", "install", "--frozen-lockfile")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.Entry().Warn("No package lock file found. " +
|
||||
"It is recommended to create a `package-lock.json` file by running `npm Install` locally." +
|
||||
" Add this file to your version control. " +
|
||||
"By doing so, the builds of your application become more reliable.")
|
||||
err = execRunner.RunExecutable("npm", "install")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = exec.Utils.Chdir(oldWorkingDirectory)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to change back into original directory: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkIfLockFilesExist checks if yarn/package lock fileUtils exist
|
||||
func (exec *Execute) checkIfLockFilesExist() (bool, bool, error) {
|
||||
packageLockExists, err := exec.Utils.FileExists("package-lock.json")
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
|
||||
yarnLockExists, err := exec.Utils.FileExists("yarn.lock")
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
return packageLockExists, yarnLockExists, nil
|
||||
}
|
||||
|
312
pkg/npm/npm_test.go
Normal file
312
pkg/npm/npm_test.go
Normal file
@ -0,0 +1,312 @@
|
||||
package npm
|
||||
|
||||
import (
|
||||
"github.com/SAP/jenkins-library/pkg/mock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type npmMockUtilsBundle struct {
|
||||
*mock.FilesMock
|
||||
execRunner *mock.ExecMockRunner
|
||||
}
|
||||
|
||||
func (u *npmMockUtilsBundle) GetExecRunner() ExecRunner {
|
||||
return u.execRunner
|
||||
}
|
||||
|
||||
func newNpmMockUtilsBundle() npmMockUtilsBundle {
|
||||
utils := npmMockUtilsBundle{FilesMock: &mock.FilesMock{}, execRunner: &mock.ExecMockRunner{}}
|
||||
return utils
|
||||
}
|
||||
|
||||
func TestNpm(t *testing.T) {
|
||||
t.Run("find package.json files with one package.json", func(t *testing.T) {
|
||||
utils := newNpmMockUtilsBundle()
|
||||
utils.AddFile("package.json", []byte("{\"name\": \"Test\" }"))
|
||||
|
||||
options := ExecutorOptions{}
|
||||
|
||||
exec := &Execute{
|
||||
Utils: &utils,
|
||||
Options: options,
|
||||
}
|
||||
|
||||
packageJSONFiles := exec.FindPackageJSONFiles()
|
||||
|
||||
assert.Equal(t, []string{"package.json"}, packageJSONFiles)
|
||||
})
|
||||
|
||||
t.Run("find package.json files with two package.json and filtered package.json", func(t *testing.T) {
|
||||
utils := newNpmMockUtilsBundle()
|
||||
utils.AddFile("package.json", []byte("{}"))
|
||||
utils.AddFile(filepath.Join("src", "package.json"), []byte("{}"))
|
||||
utils.AddFile(filepath.Join("node_modules", "package.json"), []byte("{}")) // is filtered out
|
||||
options := ExecutorOptions{}
|
||||
|
||||
exec := &Execute{
|
||||
Utils: &utils,
|
||||
Options: options,
|
||||
}
|
||||
|
||||
packageJSONFiles := exec.FindPackageJSONFiles()
|
||||
|
||||
assert.Equal(t, []string{"package.json", filepath.Join("src", "package.json")}, packageJSONFiles)
|
||||
})
|
||||
|
||||
t.Run("find package.json files with script", func(t *testing.T) {
|
||||
utils := newNpmMockUtilsBundle()
|
||||
utils.AddFile("package.json", []byte("{\"scripts\": { \"ci-lint\": \"exit 0\" } }"))
|
||||
utils.AddFile(filepath.Join("src", "package.json"), []byte("{ \"name\": \"test\" }"))
|
||||
utils.AddFile(filepath.Join("test", "package.json"), []byte("{ \"scripts\": { \"test\": \"exit 0\" } }"))
|
||||
|
||||
options := ExecutorOptions{}
|
||||
|
||||
exec := &Execute{
|
||||
Utils: &utils,
|
||||
Options: options,
|
||||
}
|
||||
|
||||
packageJSONFilesWithScript, err := exec.FindPackageJSONFilesWithScript([]string{"package.json", filepath.Join("src", "package.json"), filepath.Join("test", "package.json")}, "ci-lint")
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, []string{"package.json"}, packageJSONFilesWithScript)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Install deps for package.json with package-lock.json", func(t *testing.T) {
|
||||
utils := newNpmMockUtilsBundle()
|
||||
utils.AddFile("package.json", []byte("{\"scripts\": { \"ci-lint\": \"exit 0\" } }"))
|
||||
utils.AddFile("package-lock.json", []byte("{}"))
|
||||
|
||||
options := ExecutorOptions{}
|
||||
options.DefaultNpmRegistry = "foo.bar"
|
||||
|
||||
exec := &Execute{
|
||||
Utils: &utils,
|
||||
Options: options,
|
||||
}
|
||||
err := exec.install("package.json")
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
if assert.Equal(t, 3, len(utils.execRunner.Calls)) {
|
||||
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"ci"}}, utils.execRunner.Calls[2])
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Install deps for package.json without package-lock.json", func(t *testing.T) {
|
||||
utils := newNpmMockUtilsBundle()
|
||||
utils.AddFile("package.json", []byte("{\"scripts\": { \"ci-lint\": \"exit 0\" } }"))
|
||||
|
||||
options := ExecutorOptions{}
|
||||
options.DefaultNpmRegistry = "foo.bar"
|
||||
|
||||
exec := &Execute{
|
||||
Utils: &utils,
|
||||
Options: options,
|
||||
}
|
||||
err := exec.install("package.json")
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
if assert.Equal(t, 3, len(utils.execRunner.Calls)) {
|
||||
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"install"}}, utils.execRunner.Calls[2])
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Install deps for package.json with yarn.lock", func(t *testing.T) {
|
||||
utils := newNpmMockUtilsBundle()
|
||||
utils.AddFile("package.json", []byte("{\"scripts\": { \"ci-lint\": \"exit 0\" } }"))
|
||||
utils.AddFile("yarn.lock", []byte("{}"))
|
||||
|
||||
options := ExecutorOptions{}
|
||||
options.DefaultNpmRegistry = "foo.bar"
|
||||
|
||||
exec := &Execute{
|
||||
Utils: &utils,
|
||||
Options: options,
|
||||
}
|
||||
err := exec.install("package.json")
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
if assert.Equal(t, 3, len(utils.execRunner.Calls)) {
|
||||
assert.Equal(t, mock.ExecCall{Exec: "yarn", Params: []string{"install", "--frozen-lockfile"}}, utils.execRunner.Calls[2])
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Install all deps", func(t *testing.T) {
|
||||
utils := newNpmMockUtilsBundle()
|
||||
utils.AddFile("package.json", []byte("{\"scripts\": { \"ci-lint\": \"exit 0\" } }"))
|
||||
utils.AddFile("package-lock.json", []byte("{}"))
|
||||
utils.AddFile(filepath.Join("src", "package.json"), []byte("{\"scripts\": { \"ci-lint\": \"exit 0\" } }"))
|
||||
utils.AddFile(filepath.Join("src", "package-lock.json"), []byte("{}"))
|
||||
|
||||
options := ExecutorOptions{}
|
||||
options.DefaultNpmRegistry = "foo.bar"
|
||||
|
||||
exec := &Execute{
|
||||
Utils: &utils,
|
||||
Options: options,
|
||||
}
|
||||
err := exec.InstallAllDependencies([]string{"package.json", filepath.Join("src", "package.json")})
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
if assert.Equal(t, 6, len(utils.execRunner.Calls)) {
|
||||
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"ci"}}, utils.execRunner.Calls[2])
|
||||
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"ci"}}, utils.execRunner.Calls[5])
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("check if yarn.lock and package-lock exist", func(t *testing.T) {
|
||||
utils := newNpmMockUtilsBundle()
|
||||
utils.AddFile("package.json", []byte("{\"scripts\": { \"ci-lint\": \"exit 0\" } }"))
|
||||
utils.AddFile("yarn.lock", []byte("{}"))
|
||||
utils.AddFile("package-lock.json", []byte("{}"))
|
||||
|
||||
options := ExecutorOptions{}
|
||||
|
||||
exec := &Execute{
|
||||
Utils: &utils,
|
||||
Options: options,
|
||||
}
|
||||
packageLock, yarnLock, err := exec.checkIfLockFilesExist()
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
assert.True(t, packageLock)
|
||||
assert.True(t, yarnLock)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("check that yarn.lock and package-lock do not exist", func(t *testing.T) {
|
||||
utils := newNpmMockUtilsBundle()
|
||||
utils.AddFile("package.json", []byte("{\"scripts\": { \"ci-lint\": \"exit 0\" } }"))
|
||||
|
||||
options := ExecutorOptions{}
|
||||
options.SapNpmRegistry = "foo.sap"
|
||||
|
||||
exec := &Execute{
|
||||
Utils: &utils,
|
||||
Options: options,
|
||||
}
|
||||
packageLock, yarnLock, err := exec.checkIfLockFilesExist()
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
assert.False(t, packageLock)
|
||||
assert.False(t, yarnLock)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("check Execute script", func(t *testing.T) {
|
||||
utils := newNpmMockUtilsBundle()
|
||||
utils.AddFile("package.json", []byte("{\"scripts\": { \"ci-lint\": \"exit 0\" } }"))
|
||||
|
||||
options := ExecutorOptions{}
|
||||
|
||||
exec := &Execute{
|
||||
Utils: &utils,
|
||||
Options: options,
|
||||
}
|
||||
err := exec.executeScript("package.json", "ci-lint", []string{"--silent"})
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
if assert.Equal(t, 3, len(utils.execRunner.Calls)) {
|
||||
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run", "ci-lint", "--silent"}}, utils.execRunner.Calls[2])
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("check Execute all scripts", func(t *testing.T) {
|
||||
utils := newNpmMockUtilsBundle()
|
||||
utils.AddFile("package.json", []byte("{\"scripts\": { \"ci-lint\": \"exit 0\" } }"))
|
||||
utils.AddFile(filepath.Join("src", "package.json"), []byte("{\"scripts\": { \"ci-build\": \"exit 0\" } }"))
|
||||
|
||||
options := ExecutorOptions{}
|
||||
runScripts := []string{"ci-lint", "ci-build"}
|
||||
|
||||
exec := &Execute{
|
||||
Utils: &utils,
|
||||
Options: options,
|
||||
}
|
||||
err := exec.RunScriptsInAllPackages(runScripts, nil, false)
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
if assert.Equal(t, 6, len(utils.execRunner.Calls)) {
|
||||
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run", "ci-lint"}}, utils.execRunner.Calls[2])
|
||||
assert.Equal(t, mock.ExecCall{Exec: "npm", Params: []string{"run", "ci-build"}}, utils.execRunner.Calls[5])
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("check set npm registry", func(t *testing.T) {
|
||||
utils := newNpmMockUtilsBundle()
|
||||
utils.AddFile("package.json", []byte("{\"scripts\": { \"ci-lint\": \"exit 0\" } }"))
|
||||
utils.AddFile(filepath.Join("src", "package.json"), []byte("{\"scripts\": { \"ci-build\": \"exit 0\" } }"))
|
||||
utils.execRunner = &mock.ExecMockRunner{StdoutReturn: map[string]string{"npm config get registry": "undefined"}}
|
||||
options := ExecutorOptions{}
|
||||
options.DefaultNpmRegistry = "https://example.org/npm"
|
||||
|
||||
exec := &Execute{
|
||||
Utils: &utils,
|
||||
Options: options,
|
||||
}
|
||||
err := exec.SetNpmRegistries()
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
if assert.Equal(t, 3, 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", "set", "registry", exec.Options.DefaultNpmRegistry}}, utils.execRunner.Calls[1])
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("check set npm registry", func(t *testing.T) {
|
||||
utils := newNpmMockUtilsBundle()
|
||||
utils.AddFile("package.json", []byte("{\"scripts\": { \"ci-lint\": \"exit 0\" } }"))
|
||||
utils.AddFile(filepath.Join("src", "package.json"), []byte("{\"scripts\": { \"ci-build\": \"exit 0\" } }"))
|
||||
utils.execRunner = &mock.ExecMockRunner{StdoutReturn: map[string]string{"npm config get @sap:registry": "undefined"}}
|
||||
options := ExecutorOptions{}
|
||||
options.SapNpmRegistry = "https://example.sap/npm"
|
||||
|
||||
exec := &Execute{
|
||||
Utils: &utils,
|
||||
Options: options,
|
||||
}
|
||||
err := exec.SetNpmRegistries()
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
if assert.Equal(t, 3, len(utils.execRunner.Calls)) {
|
||||
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{"config", "set", "@sap:registry", exec.Options.SapNpmRegistry}}, utils.execRunner.Calls[2])
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Call run-scripts with virtual frame buffer", func(t *testing.T) {
|
||||
utils := newNpmMockUtilsBundle()
|
||||
utils.AddFile("package.json", []byte("{\"scripts\": { \"foo\": \"\" } }"))
|
||||
|
||||
options := ExecutorOptions{}
|
||||
|
||||
exec := &Execute{
|
||||
Utils: &utils,
|
||||
Options: options,
|
||||
}
|
||||
err := exec.RunScriptsInAllPackages([]string{"foo"}, nil, true)
|
||||
|
||||
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", "foo"}}, utils.execRunner.Calls[3])
|
||||
}
|
||||
})
|
||||
}
|
@ -28,16 +28,22 @@ spec:
|
||||
description: URL of the npm registry to use. Defaults to https://registry.npmjs.org/
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- GENERAL
|
||||
- STAGES
|
||||
- STEPS
|
||||
aliases:
|
||||
- name: npm/defaultNpmRegistry
|
||||
- name: sapNpmRegistry
|
||||
type: string
|
||||
description: The default npm registry URL to be used as the remote mirror for the SAP npm packages.
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- GENERAL
|
||||
- STAGES
|
||||
- STEPS
|
||||
default: https://npm.sap.com
|
||||
aliases:
|
||||
- name: npm/sapNpmRegistry
|
||||
- name: virtualFrameBuffer
|
||||
type: bool
|
||||
description: (Linux only) Start a virtual frame buffer in the background. This allows you to run a web browser without the need for an X server. Note that xvfb needs to be installed in the execution environment.
|
||||
|
Loading…
x
Reference in New Issue
Block a user