diff --git a/pkg/mock/fileUtils.go b/pkg/mock/fileUtils.go index 636f3c450..efd89386f 100644 --- a/pkg/mock/fileUtils.go +++ b/pkg/mock/fileUtils.go @@ -339,11 +339,15 @@ func (f *FilesMock) FileRename(oldPath, newPath string) error { } // TempDir create a temp-styled directory in the in-memory, so that this path is established to exist. -func (f *FilesMock) TempDir(_, pattern string) (string, error) { - tmpDir := "/tmp/test" +func (f *FilesMock) TempDir(baseDir string, pattern string) (string, error) { + if len(baseDir) == 0 { + baseDir = "/tmp" + } + + tmpDir := baseDir if pattern != "" { - tmpDir = fmt.Sprintf("/tmp/%stest", pattern) + tmpDir = fmt.Sprintf("%s/%stest", baseDir, pattern) } err := f.MkdirAll(tmpDir, 0755) diff --git a/pkg/mock/fileUtils_test.go b/pkg/mock/fileUtils_test.go index 4c698d604..53d6ab77f 100644 --- a/pkg/mock/fileUtils_test.go +++ b/pkg/mock/fileUtils_test.go @@ -628,8 +628,8 @@ func TestFilesMockTempDir(t *testing.T) { files := FilesMock{} dir, err := files.TempDir("", "") assert.NoError(t, err) - assert.Equal(t, "/tmp/test", dir) - ok, err := files.DirExists("/tmp/test") + assert.Equal(t, "/tmp", dir) + ok, err := files.DirExists("/tmp") assert.NoError(t, err) assert.True(t, ok) }) diff --git a/pkg/mock/runner.go b/pkg/mock/runner.go index 196203b75..c3bfcc90a 100644 --- a/pkg/mock/runner.go +++ b/pkg/mock/runner.go @@ -20,6 +20,7 @@ type ExecMockRunner struct { stdin io.Reader stdout io.Writer stderr io.Writer + Stub func(call string, stdoutReturn map[string]string, shouldFailOnCommand map[string]error, stdout io.Writer) error StdoutReturn map[string]string ShouldFailOnCommand map[string]error } @@ -67,7 +68,7 @@ func (m *ExecMockRunner) RunExecutable(e string, p ...string) error { c := strings.Join(append([]string{e}, p...), " ") - return handleCall(c, m.StdoutReturn, m.ShouldFailOnCommand, m.stdout) + return m.handleCall(c, m.StdoutReturn, m.ShouldFailOnCommand, m.stdout) } func (m *ExecMockRunner) GetExitCode() int { @@ -82,7 +83,7 @@ func (m *ExecMockRunner) RunExecutableInBackground(e string, p ...string) (comma c := strings.Join(append([]string{e}, p...), " ") - err := handleCall(c, m.StdoutReturn, m.ShouldFailOnCommand, m.stdout) + err := m.handleCall(c, m.StdoutReturn, m.ShouldFailOnCommand, m.stdout) if err != nil { return nil, err } @@ -109,6 +110,14 @@ func (m *ExecMockRunner) GetStderr() io.Writer { return m.stderr } +func (m *ExecMockRunner) handleCall(call string, stdoutReturn map[string]string, shouldFailOnCommand map[string]error, stdout io.Writer) error { + if m.Stub != nil { + return m.Stub(call, stdoutReturn, shouldFailOnCommand, stdout) + } else { + return handleCall(call, stdoutReturn, shouldFailOnCommand, stdout) + } +} + func (m *ShellMockRunner) SetDir(d string) { m.Dir = d } diff --git a/pkg/npm/config.go b/pkg/npm/config.go index 553bb7d3e..06f09e895 100644 --- a/pkg/npm/config.go +++ b/pkg/npm/config.go @@ -10,17 +10,19 @@ import ( ) const ( - configFilename = ".piperNpmrc" + defaultConfigFilename = ".piperNpmrc" // default by npm ) var ( - propertiesLoadFile = properties.LoadFile + propertiesLoadFile = properties.LoadFile + propertiesWriteFile = ioutil.WriteFile ) func NewNPMRC(path string) NPMRC { - if !strings.HasSuffix(path, configFilename) { - path = filepath.Join(path, configFilename) + if !strings.HasSuffix(path, defaultConfigFilename) { + path = filepath.Join(path, defaultConfigFilename) } + return NPMRC{filepath: path, values: properties.NewProperties()} } @@ -30,7 +32,7 @@ type NPMRC struct { } func (rc *NPMRC) Write() error { - if err := ioutil.WriteFile(rc.filepath, []byte(rc.values.String()), 0644); err != nil { + if err := propertiesWriteFile(rc.filepath, []byte(rc.values.String()), 0644); err != nil { return errors.Wrapf(err, "failed to write %s", rc.filepath) } return nil diff --git a/pkg/npm/config_test.go b/pkg/npm/config_test.go index c180d51e6..01d787d2f 100644 --- a/pkg/npm/config_test.go +++ b/pkg/npm/config_test.go @@ -20,7 +20,7 @@ func TestNewNPMRC(t *testing.T) { args args want string }{ - {name: "current dir", args: args{""}, want: configFilename}, + {name: "current dir", args: args{""}, want: defaultConfigFilename}, {name: "sub dir", args: args{mock.Anything}, want: filepath.Join(mock.Anything, ".piperNpmrc")}, {name: "file path in current dir", args: args{".piperNpmrc"}, want: ".piperNpmrc"}, {name: "file path in sub dir", args: args{filepath.Join(mock.Anything, ".piperNpmrc")}, want: filepath.Join(mock.Anything, ".piperNpmrc")}, diff --git a/pkg/npm/ignore.go b/pkg/npm/ignore.go index e86a88e10..330ac3c9b 100644 --- a/pkg/npm/ignore.go +++ b/pkg/npm/ignore.go @@ -14,6 +14,10 @@ const ( ignoreFilename = ".npmignore" ) +var ( + writeIgnoreFile = ioutil.WriteFile +) + func NewNPMIgnore(path string) NPMIgnore { if !strings.HasSuffix(path, ignoreFilename) { path = filepath.Join(path, ignoreFilename) @@ -29,7 +33,7 @@ type NPMIgnore struct { func (ignorefile *NPMIgnore) Write() error { content := strings.Join(ignorefile.values, "\n") - if err := ioutil.WriteFile(ignorefile.filepath, []byte(content+"\n"), 0644); err != nil { + if err := writeIgnoreFile(ignorefile.filepath, []byte(content+"\n"), 0644); err != nil { return errors.Wrapf(err, "failed to write %s", ignorefile.filepath) } return nil diff --git a/pkg/npm/npm.go b/pkg/npm/npm.go index 3593c7039..19d7dc427 100644 --- a/pkg/npm/npm.go +++ b/pkg/npm/npm.go @@ -57,11 +57,7 @@ type ExecRunner interface { // 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) + piperutils.FileUtils GetExecRunner() ExecRunner } diff --git a/pkg/npm/publish.go b/pkg/npm/publish.go index b03126560..fc1e1f64c 100644 --- a/pkg/npm/publish.go +++ b/pkg/npm/publish.go @@ -2,15 +2,12 @@ package npm import ( "fmt" - "io/ioutil" - "os" "path/filepath" "github.com/pkg/errors" "github.com/SAP/jenkins-library/pkg/log" CredentialUtils "github.com/SAP/jenkins-library/pkg/piperutils" - FileUtils "github.com/SAP/jenkins-library/pkg/piperutils" ) // PublishAllPackages executes npm publish for all package.json files defined in packageJSONFiles list @@ -37,7 +34,7 @@ func (exec *Execute) publish(packageJSON, registry, username, password string, p execRunner := exec.Utils.GetExecRunner() npmignore := NewNPMIgnore(filepath.Dir(packageJSON)) - if exists, err := FileUtils.FileExists(npmignore.filepath); exists { + if exists, err := exec.Utils.FileExists(npmignore.filepath); exists { if err != nil { return errors.Wrapf(err, "failed to check for existing %s file", npmignore.filepath) } @@ -65,7 +62,7 @@ func (exec *Execute) publish(packageJSON, registry, username, password string, p // update .piperNpmrc if len(registry) > 0 { // check existing .npmrc file - if exists, err := FileUtils.FileExists(npmrc.filepath); exists { + if exists, err := exec.Utils.FileExists(npmrc.filepath); exists { if err != nil { return errors.Wrapf(err, "failed to check for existing %s file", npmrc.filepath) } @@ -94,36 +91,46 @@ func (exec *Execute) publish(packageJSON, registry, username, password string, p } if packBeforePublish { - tmpDirectory := getTempDirForNpmTarBall() - defer os.RemoveAll(tmpDirectory) + tmpDirectory, err := exec.Utils.TempDir(".", "temp-") - err := execRunner.RunExecutable("npm", "pack", "--pack-destination", tmpDirectory) + if err != nil { + return errors.Wrap(err, "creating temp directory failed") + } + + defer exec.Utils.RemoveAll(tmpDirectory) + + err = execRunner.RunExecutable("npm", "pack", "--pack-destination", tmpDirectory) if err != nil { return err } - _, err = FileUtils.Copy(npmrc.filepath, filepath.Join(tmpDirectory, ".piperNpmrc")) + _, err = exec.Utils.Copy(npmrc.filepath, filepath.Join(tmpDirectory, ".piperNpmrc")) if err != nil { return fmt.Errorf("error copying piperNpmrc file from %v to %v with error: %w", npmrc.filepath, filepath.Join(tmpDirectory, ".piperNpmrc"), err) } - tarballFileName := "" - err = filepath.Walk(tmpDirectory, func(path string, info os.FileInfo, err error) error { - if filepath.Ext(path) == ".tgz" { - tarballFileName = "." + string(filepath.Separator) + path - log.Entry().Debugf("found tarball file at %v", tarballFileName) - } - return nil - }) + tarballs, err := exec.Utils.Glob(filepath.Join(tmpDirectory, "*.tgz")) + if err != nil { return err } - // rename the .npmrc file since it interferes with publish - err = os.Rename(filepath.Join(filepath.Dir(packageJSON), ".npmrc"), filepath.Join(filepath.Dir(packageJSON), ".tmpNpmrc")) - if err != nil { - return fmt.Errorf("error when renaming current .npmrc file : %w", err) + if len(tarballs) != 1 { + return fmt.Errorf("found more tarballs than expected: %v", tarballs) + } + + tarballFileName := tarballs[0] + + projectNpmrc := filepath.Join(filepath.Dir(packageJSON), ".npmrc") + projectNpmrcExists, _ := exec.Utils.FileExists(projectNpmrc) + + if projectNpmrcExists { + // rename the .npmrc file since it interferes with publish + err = exec.Utils.FileRename(projectNpmrc, projectNpmrc+".tmp") + if err != nil { + return fmt.Errorf("error when renaming current .npmrc file : %w", err) + } } err = execRunner.RunExecutable("npm", "publish", "--tarball", tarballFileName, "--userconfig", filepath.Join(tmpDirectory, ".piperNpmrc"), "--registry", registry) @@ -131,10 +138,12 @@ func (exec *Execute) publish(packageJSON, registry, username, password string, p return err } - // undo the renaming ot the .npmrc to keep the workspace like before - err = os.Rename(filepath.Join(filepath.Dir(packageJSON), ".tmpNpmrc"), filepath.Join(filepath.Dir(packageJSON), ".npmrc")) - if err != nil { - log.Entry().Warnf("unable to rename the .npmrc file : %v", err) + if projectNpmrcExists { + // undo the renaming ot the .npmrc to keep the workspace like before + err = exec.Utils.FileRename(projectNpmrc+".tmp", projectNpmrc) + if err != nil { + log.Entry().Warnf("unable to rename the .npmrc file : %v", err) + } } } else { err := execRunner.RunExecutable("npm", "publish", "--userconfig", npmrc.filepath, "--registry", registry) @@ -145,11 +154,3 @@ func (exec *Execute) publish(packageJSON, registry, username, password string, p return nil } - -func getTempDirForNpmTarBall() string { - tmpFolder, err := ioutil.TempDir(".", "temp-") - if err != nil { - log.Entry().WithError(err).WithField("path", tmpFolder).Debug("Creating temp directory failed") - } - return tmpFolder -} diff --git a/pkg/npm/publish_test.go b/pkg/npm/publish_test.go new file mode 100644 index 000000000..0990ec13f --- /dev/null +++ b/pkg/npm/publish_test.go @@ -0,0 +1,341 @@ +package npm + +import ( + "io" + "path/filepath" + "regexp" + "testing" + + "github.com/SAP/jenkins-library/pkg/piperutils" + "github.com/magiconair/properties" + "github.com/stretchr/testify/assert" +) + +func TestNpmPublish(t *testing.T) { + tt := []struct { + name string + + files map[string]string + + packageDescriptors []string + registryURL string + registryUser string + registryPassword string + packBeforePublish bool + + expectedPublishConfigPath string + expectedPublishConfig string + expectedError string + }{ + // project in root folder + { + name: "success - single project, publish normal, unpacked package - target registry in npmrc", + + files: map[string]string{ + "package.json": `{"name": "piper-project", "version": "0.0.1"}`, + ".piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/", + }, + + packageDescriptors: []string{"package.json"}, + + expectedPublishConfigPath: `\.piperNpmrc`, + expectedPublishConfig: "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/", + }, + { + name: "success - single project, publish normal, unpacked package - target registry from pipeline", + + files: map[string]string{ + "package.json": `{"name": "piper-project", "version": "0.0.1"}`, + }, + + packageDescriptors: []string{"package.json"}, + + expectedPublishConfigPath: `\.piperNpmrc`, + expectedPublishConfig: "registry = https://my.private.npm.registry/\n_auth = VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nalways-auth = true\n", + + registryURL: "https://my.private.npm.registry/", + registryUser: "ThisIsTheUser", + registryPassword: "AndHereIsThePassword", + }, + { + name: "success - single project, publish normal, unpacked package - target registry from pipeline (precedence over npmrc)", + + files: map[string]string{ + "package.json": `{"name": "piper-project", "version": "0.0.1"}`, + ".piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/", + }, + + packageDescriptors: []string{"package.json"}, + + expectedPublishConfigPath: `\.piperNpmrc`, + expectedPublishConfig: "_auth = VGhpc0lzVGhlT3RoZXJVc2VyOkFuZEhlcmVJc1RoZU90aGVyUGFzc3dvcmQ=\nregistry = https://my.other.private.npm.registry/\nalways-auth = true\n", + + registryURL: "https://my.other.private.npm.registry/", + registryUser: "ThisIsTheOtherUser", + registryPassword: "AndHereIsTheOtherPassword", + }, + { + name: "success - single project, publish normal, packed - target registry in npmrc", + + files: map[string]string{ + "package.json": `{"name": "piper-project", "version": "0.0.1"}`, + ".piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/", + }, + + packageDescriptors: []string{"package.json"}, + + packBeforePublish: true, + + expectedPublishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`, + expectedPublishConfig: "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/", + }, + { + name: "success - single project, publish normal, packed - target registry from pipeline", + + files: map[string]string{ + "package.json": `{"name": "piper-project", "version": "0.0.1"}`, + }, + + packageDescriptors: []string{"package.json"}, + + packBeforePublish: true, + + expectedPublishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`, + expectedPublishConfig: "registry = https://my.private.npm.registry/\n_auth = VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nalways-auth = true\n", + + registryURL: "https://my.private.npm.registry/", + registryUser: "ThisIsTheUser", + registryPassword: "AndHereIsThePassword", + }, + { + name: "success - single project, publish normal, packed - target registry from pipeline", + + files: map[string]string{ + "package.json": `{"name": "piper-project", "version": "0.0.1"}`, + ".piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/", + }, + + packageDescriptors: []string{"package.json"}, + + packBeforePublish: true, + + expectedPublishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`, + expectedPublishConfig: "_auth = VGhpc0lzVGhlT3RoZXJVc2VyOkFuZEhlcmVJc1RoZU90aGVyUGFzc3dvcmQ=\nregistry = https://my.other.private.npm.registry/\nalways-auth = true\n", + + registryURL: "https://my.other.private.npm.registry/", + registryUser: "ThisIsTheOtherUser", + registryPassword: "AndHereIsTheOtherPassword", + }, + // project in a subfolder + { + name: "success - single project, publish normal, unpacked package - target registry in npmrc", + + files: map[string]string{ + "sub/package.json": `{"name": "piper-project", "version": "0.0.1"}`, + "sub/.piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/", + }, + + packageDescriptors: []string{"sub/package.json"}, + + expectedPublishConfigPath: `sub/\.piperNpmrc`, + expectedPublishConfig: "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/", + }, + { + name: "success - single project, publish normal, unpacked package - target registry from pipeline", + + files: map[string]string{ + "sub/package.json": `{"name": "piper-project", "version": "0.0.1"}`, + }, + + packageDescriptors: []string{"sub/package.json"}, + + expectedPublishConfigPath: `sub/\.piperNpmrc`, + expectedPublishConfig: "registry = https://my.private.npm.registry/\n_auth = VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nalways-auth = true\n", + + registryURL: "https://my.private.npm.registry/", + registryUser: "ThisIsTheUser", + registryPassword: "AndHereIsThePassword", + }, + { + name: "success - single project, publish normal, unpacked package - target registry from pipeline (precedence over npmrc)", + + files: map[string]string{ + "sub/package.json": `{"name": "piper-project", "version": "0.0.1"}`, + "sub/.piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/", + }, + + packageDescriptors: []string{"sub/package.json"}, + + expectedPublishConfigPath: `sub/\.piperNpmrc`, + expectedPublishConfig: "_auth = VGhpc0lzVGhlT3RoZXJVc2VyOkFuZEhlcmVJc1RoZU90aGVyUGFzc3dvcmQ=\nregistry = https://my.other.private.npm.registry/\nalways-auth = true\n", + + registryURL: "https://my.other.private.npm.registry/", + registryUser: "ThisIsTheOtherUser", + registryPassword: "AndHereIsTheOtherPassword", + }, + { + name: "success - single project, publish normal, packed - target registry in npmrc", + + files: map[string]string{ + "sub/package.json": `{"name": "piper-project", "version": "0.0.1"}`, + "sub/.piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/", + }, + + packageDescriptors: []string{"sub/package.json"}, + + packBeforePublish: true, + + expectedPublishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`, + expectedPublishConfig: "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/", + }, + { + name: "success - single project, publish normal, packed - target registry from pipeline", + + files: map[string]string{ + "sub/package.json": `{"name": "piper-project", "version": "0.0.1"}`, + }, + + packageDescriptors: []string{"sub/package.json"}, + + packBeforePublish: true, + + expectedPublishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`, + expectedPublishConfig: "registry = https://my.private.npm.registry/\n_auth = VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nalways-auth = true\n", + + registryURL: "https://my.private.npm.registry/", + registryUser: "ThisIsTheUser", + registryPassword: "AndHereIsThePassword", + }, + { + name: "success - single project, publish normal, packed - target registry from pipeline", + + files: map[string]string{ + "sub/package.json": `{"name": "piper-project", "version": "0.0.1"}`, + "sub/.piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/", + }, + + packageDescriptors: []string{"sub/package.json"}, + + packBeforePublish: true, + + expectedPublishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`, + expectedPublishConfig: "_auth = VGhpc0lzVGhlT3RoZXJVc2VyOkFuZEhlcmVJc1RoZU90aGVyUGFzc3dvcmQ=\nregistry = https://my.other.private.npm.registry/\nalways-auth = true\n", + + registryURL: "https://my.other.private.npm.registry/", + registryUser: "ThisIsTheOtherUser", + registryPassword: "AndHereIsTheOtherPassword", + }, + // TODO multiple projects + // TODO scoped packages + /*{ + name: "success - publish scoped, packed - target registry in npmrc", + + files: map[string]string{ + "package.json": `{"name": "@piper/project", "version": "0.0.1"}`, + ".piperNpmrc": testNpmrc.String(), + }, + + packageDescriptors: []string{"package.json"}, + + packBeforePublish: true, + + expectedPublishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`, + expectedPublishConfig: testNpmrc, + }, + { + name: "success - publish scoped, packed - target registry from pipeline", + + files: map[string]string{ + "package.json": `{"name": "@piper/project", "version": "0.0.1"}`, + ".piperNpmrc": testNpmrc.String(), + }, + + packageDescriptors: []string{"package.json"}, + + packBeforePublish: true, + + expectedPublishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`, + expectedPublishConfig: testNpmrc, + + registryURL: "https://my.private.npm.registry/", + registryUser: "ThisIsTheUser", + registryPassword: "AndHereIsThePassword", + },*/ + } + + for _, test := range tt { + t.Run(test.name, func(t *testing.T) { + utils := newNpmMockUtilsBundle() + + for path, content := range test.files { + utils.AddFile(path, []byte(content)) + } + + options := ExecutorOptions{} + + exec := &Execute{ + Utils: &utils, + Options: options, + } + + propertiesLoadFile = func(filename string, enc properties.Encoding) (*properties.Properties, error) { + p := properties.NewProperties() + + b, err := utils.FileRead(filename) + + if err != nil { + return nil, err + } + + err = p.Load(b, properties.UTF8) + return p, err + } + + propertiesWriteFile = utils.FileWrite + writeIgnoreFile = utils.FileWrite + + // This stub simulates the behavior of npm pack and puts a tgz into the requested + utils.execRunner.Stub = func(call string, stdoutReturn map[string]string, shouldFailOnCommand map[string]error, stdout io.Writer) error { + r := regexp.MustCompile(`npm\s+pack\s+.*--pack-destination\s+(?P[^\s]+).*`) + + matches := r.FindStringSubmatch(call) + + if len(matches) == 0 { + return nil + } + + packDestination := matches[1] + + utils.AddFile(filepath.Join(packDestination, "package.tgz"), []byte("this is a tgz file")) + + return nil + } + + err := exec.PublishAllPackages(test.packageDescriptors, test.registryURL, test.registryUser, test.registryPassword, test.packBeforePublish) + + if len(test.expectedError) == 0 && assert.NoError(t, err) { + if assert.NotEmpty(t, utils.execRunner.Calls) { + // last call is expected to be npm publish + publishCmd := utils.execRunner.Calls[len(utils.execRunner.Calls)-1] + + assert.Equal(t, "npm", publishCmd.Exec) + assert.Equal(t, "publish", publishCmd.Params[0]) + + if assert.Contains(t, publishCmd.Params, "--userconfig") { + effectivePublishConfigPath := publishCmd.Params[piperutils.FindString(publishCmd.Params, "--userconfig")+1] + + assert.Regexp(t, test.expectedPublishConfigPath, effectivePublishConfigPath) + + effectiveConfig, err := utils.FileRead(effectivePublishConfigPath) + + if assert.NoError(t, err) { + assert.Equal(t, test.expectedPublishConfig, string(effectiveConfig)) + } + } + } + } else { + assert.EqualError(t, err, test.expectedError) + } + }) + } +} diff --git a/pkg/piperutils/slices.go b/pkg/piperutils/slices.go index 386aeba49..268b205d4 100644 --- a/pkg/piperutils/slices.go +++ b/pkg/piperutils/slices.go @@ -16,12 +16,18 @@ func ContainsInt(s []int, e int) bool { //ContainsString checks whether the element is part of the slice func ContainsString(s []string, e string) bool { - for _, a := range s { + return FindString(s, e) >= 0 +} + +//FindString returns the position of element e in the given slice or -1 if it's not in +func FindString(s []string, e string) int { + for i, a := range s { if a == e { - return true + return i } } - return false + + return -1 } //ContainsStringPart checks whether the element is contained as part of one of the elements of the slice diff --git a/pkg/piperutils/slices_test.go b/pkg/piperutils/slices_test.go index f6688457e..f076e057a 100644 --- a/pkg/piperutils/slices_test.go +++ b/pkg/piperutils/slices_test.go @@ -29,6 +29,18 @@ func TestContainsString(t *testing.T) { assert.False(t, ContainsString(stringList, "baz")) } +func TestFindString(t *testing.T) { + var stringList []string + assert.Equal(t, -1, FindString(stringList, "test")) + assert.Equal(t, -1, FindString(stringList, "")) + + stringList = append(stringList, "", "foo", "bar", "foo") + assert.Equal(t, 0, FindString(stringList, "")) + assert.Equal(t, 2, FindString(stringList, "bar")) + assert.Equal(t, 1, FindString(stringList, "foo")) + assert.Equal(t, -1, FindString(stringList, "baz")) +} + func TestRemoveAll(t *testing.T) { t.Parallel() t.Run("empty array", func(t *testing.T) {