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

chore(npmExecuteScripts): config@2 support (#3607)

This commit is contained in:
Christian Volk
2022-03-04 10:26:46 +01:00
committed by GitHub
parent 0de06c6207
commit 5821a311cc
6 changed files with 565 additions and 149 deletions

View File

@@ -228,6 +228,21 @@ func (f *FilesMock) Copy(src, dst string) (int64, error) {
return int64(len(*props.content)), nil
}
// Move moves a file to the given destination
func (f *FilesMock) Move(src, dst string) error {
if exists, err := f.FileExists(src); err != nil {
return err
} else if !exists {
return fmt.Errorf("file doesn't exist: %s", src)
}
if _, err := f.Copy(src, dst); err != nil {
return err
}
return f.FileRemove(src)
}
// FileRead returns the content previously associated with the given path via AddFile(), or an error if no
// content has been associated.
func (f *FilesMock) FileRead(path string) ([]byte, error) {

View File

@@ -1,11 +1,12 @@
package npm
import (
"fmt"
"io/ioutil"
"path/filepath"
"regexp"
"strings"
"github.com/magiconair/properties"
"github.com/pkg/errors"
)
@@ -14,7 +15,7 @@ const (
)
var (
propertiesLoadFile = properties.LoadFile
propertiesLoadFile = ioutil.ReadFile
propertiesWriteFile = ioutil.WriteFile
)
@@ -23,30 +24,38 @@ func NewNPMRC(path string) NPMRC {
path = filepath.Join(path, defaultConfigFilename)
}
return NPMRC{filepath: path, values: properties.NewProperties()}
return NPMRC{filepath: path}
}
type NPMRC struct {
filepath string
values *properties.Properties
content string
}
func (rc *NPMRC) Write() error {
if err := propertiesWriteFile(rc.filepath, []byte(rc.values.String()), 0644); err != nil {
if err := propertiesWriteFile(rc.filepath, []byte(rc.content), 0644); err != nil {
return errors.Wrapf(err, "failed to write %s", rc.filepath)
}
return nil
}
func (rc *NPMRC) Load() error {
values, err := propertiesLoadFile(rc.filepath, properties.UTF8)
bytes, err := propertiesLoadFile(rc.filepath)
if err != nil {
return err
}
rc.values = values
rc.content = string(bytes)
return nil
}
func (rc *NPMRC) Set(key, value string) {
rc.values.Set(key, value)
r := regexp.MustCompile(fmt.Sprintf(`(?m)^\s*%s\s*=.*$`, key))
keyValue := fmt.Sprintf("%s=%s", key, value)
if r.MatchString(rc.content) {
rc.content = r.ReplaceAllString(rc.content, keyValue)
} else {
rc.content += keyValue + "\n"
}
}

View File

@@ -2,58 +2,163 @@ package npm
import (
"path/filepath"
"reflect"
"testing"
"github.com/magiconair/properties"
filesmock "github.com/SAP/jenkins-library/pkg/mock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
func TestNewNPMRC(t *testing.T) {
type args struct {
path string
}
type want struct {
path string
errLoad string
errWrite string
files map[string]string
}
tests := []struct {
name string
args args
want string
name string
args args
files map[string]string
want want
}{
{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")},
{
name: "success - path pointing to no dir - no content",
args: args{""},
files: map[string]string{
defaultConfigFilename: "",
},
want: want{
path: defaultConfigFilename,
files: map[string]string{
defaultConfigFilename: "",
},
},
},
{
name: "success - path pointing to cwd - no content",
args: args{"."},
files: map[string]string{
defaultConfigFilename: "",
},
want: want{
path: defaultConfigFilename,
files: map[string]string{
defaultConfigFilename: "",
},
},
},
{
name: "success - path pointing to sub dir - no content",
args: args{mock.Anything},
files: map[string]string{
filepath.Join(mock.Anything, ".piperNpmrc"): "",
},
want: want{
path: filepath.Join(mock.Anything, ".piperNpmrc"),
files: map[string]string{
filepath.Join(mock.Anything, ".piperNpmrc"): "",
},
},
},
{
name: "success - path pointing to file in current folder - no content",
args: args{".piperNpmrc"},
files: map[string]string{
".piperNpmrc": "",
},
want: want{
path: ".piperNpmrc",
files: map[string]string{
".piperNpmrc": "",
},
},
},
{
name: "success - path pointing to file in sub folder - no content",
args: args{filepath.Join(mock.Anything, ".piperNpmrc")},
files: map[string]string{
filepath.Join(mock.Anything, ".piperNpmrc"): "",
},
want: want{
path: filepath.Join(mock.Anything, ".piperNpmrc"),
files: map[string]string{
filepath.Join(mock.Anything, ".piperNpmrc"): "",
},
},
},
{
name: "success - doesn't modify existing content",
args: args{filepath.Join(mock.Anything, ".piperNpmrc")},
files: map[string]string{
filepath.Join(mock.Anything, ".piperNpmrc"): `
_auth=dGVzdDp0ZXN0
registry=https://my.private.registry/
@piper:registry=https://my.scoped.private.registry/
//my.private.registry/:_auth=dGVzdDp0ZXN0
//my.scoped.private.registry/:_auth=dGVzdDp0ZXN0
`,
},
want: want{
path: filepath.Join(mock.Anything, ".piperNpmrc"),
files: map[string]string{
filepath.Join(mock.Anything, ".piperNpmrc"): `
_auth=dGVzdDp0ZXN0
registry=https://my.private.registry/
@piper:registry=https://my.scoped.private.registry/
//my.private.registry/:_auth=dGVzdDp0ZXN0
//my.scoped.private.registry/:_auth=dGVzdDp0ZXN0
`,
},
},
},
{
name: "failure - path pointing to sth which doesnt exist",
args: args{"./this/path/doesnt/exist/.piperNpmrc"},
files: map[string]string{},
want: want{
path: "./this/path/doesnt/exist/.piperNpmrc",
errLoad: "could not read './this/path/doesnt/exist/.piperNpmrc'",
},
},
}
for _, tt := range tests {
files := filesmock.FilesMock{}
for path, content := range tt.files {
files.AddFile(path, []byte(content))
}
propertiesLoadFile = files.FileRead
propertiesWriteFile = files.FileWrite
t.Run(tt.name, func(t *testing.T) {
if got := NewNPMRC(tt.args.path); !reflect.DeepEqual(got.filepath, tt.want) {
t.Errorf("NewNPMRC().filepath = %v, want %v", got.filepath, tt.want)
uut := NewNPMRC(tt.args.path)
assert.Equal(t, tt.want.path, uut.filepath)
if err := uut.Load(); len(tt.want.errLoad) == 0 {
assert.NoError(t, err)
} else {
assert.EqualError(t, err, tt.want.errLoad)
}
if err := uut.Write(); len(tt.want.errWrite) == 0 {
assert.NoError(t, err)
} else {
assert.EqualError(t, err, tt.want.errWrite)
}
for wantFile, wantContent := range tt.want.files {
if actualContent, err := files.FileRead(wantFile); assert.NoError(t, err) {
assert.Equal(t, wantContent, string(actualContent))
}
}
})
}
}
func mockLoadProperties(t *testing.T, result *properties.Properties, err error) func(filename string, enc properties.Encoding) (*properties.Properties, error) {
return func(filename string, enc properties.Encoding) (*properties.Properties, error) {
return result, err
}
}
func TestLoad(t *testing.T) {
// init
config := NewNPMRC("")
new := properties.NewProperties()
new.Set("test", "anything")
propertiesLoadFile = mockLoadProperties(t, new, nil)
require.NotEmpty(t, new.Keys())
require.Empty(t, config.values.Keys())
// test
err := config.Load()
// assert
assert.NoError(t, err)
assert.NotEmpty(t, config.values.Keys())
}

View File

@@ -1,8 +1,10 @@
package npm
import (
"encoding/json"
"fmt"
"path/filepath"
"regexp"
"github.com/pkg/errors"
@@ -10,9 +12,28 @@ import (
CredentialUtils "github.com/SAP/jenkins-library/pkg/piperutils"
)
type npmMinimalPackageDescriptor struct {
Name string `json:version`
Version string `json:version`
}
func (pd *npmMinimalPackageDescriptor) Scope() string {
r := regexp.MustCompile(`^(?:(?P<scope>@[^\/]+)\/)?(?P<package>.+)$`)
matches := r.FindStringSubmatch(pd.Name)
if len(matches) == 0 {
return ""
}
return matches[1]
}
// PublishAllPackages executes npm publish for all package.json files defined in packageJSONFiles list
func (exec *Execute) PublishAllPackages(packageJSONFiles []string, registry, username, password string, packBeforePublish bool) error {
for _, packageJSON := range packageJSONFiles {
log.Entry().Infof("triggering publish for %s", packageJSON)
fileExists, err := exec.Utils.FileExists(packageJSON)
if err != nil {
return fmt.Errorf("cannot check if '%s' exists: %w", packageJSON, err)
@@ -33,6 +54,12 @@ func (exec *Execute) PublishAllPackages(packageJSONFiles []string, registry, use
func (exec *Execute) publish(packageJSON, registry, username, password string, packBeforePublish bool) error {
execRunner := exec.Utils.GetExecRunner()
scope, err := exec.readPackageScope(packageJSON)
if err != nil {
return errors.Wrapf(err, "error reading package scope from %s", packageJSON)
}
npmignore := NewNPMIgnore(filepath.Dir(packageJSON))
if exists, err := exec.Utils.FileExists(npmignore.filepath); exists {
if err != nil {
@@ -76,6 +103,11 @@ func (exec *Execute) publish(packageJSON, registry, username, password string, p
// set registry
log.Entry().Debugf("adding registry %s", registry)
npmrc.Set("registry", registry)
if len(scope) > 0 {
npmrc.Set(fmt.Sprintf("%s:registry", scope), registry)
}
// set registry auth
if len(username) > 0 && len(password) > 0 {
log.Entry().Debug("adding registry credentials")
@@ -120,7 +152,11 @@ func (exec *Execute) publish(packageJSON, registry, username, password string, p
return fmt.Errorf("found more tarballs than expected: %v", tarballs)
}
tarballFileName := tarballs[0]
tarballFilePath, err := exec.Utils.Abs(tarballs[0])
if err != nil {
return err
}
projectNpmrc := filepath.Join(filepath.Dir(packageJSON), ".npmrc")
projectNpmrcExists, _ := exec.Utils.FileExists(projectNpmrc)
@@ -133,9 +169,9 @@ func (exec *Execute) publish(packageJSON, registry, username, password string, p
}
}
err = execRunner.RunExecutable("npm", "publish", "--tarball", tarballFileName, "--userconfig", filepath.Join(tmpDirectory, ".piperNpmrc"), "--registry", registry)
err = execRunner.RunExecutable("npm", "publish", "--tarball", tarballFilePath, "--userconfig", filepath.Join(tmpDirectory, ".piperNpmrc"), "--registry", registry)
if err != nil {
return err
return errors.Wrap(err, "failed publishing artifact")
}
if projectNpmrcExists {
@@ -148,9 +184,23 @@ func (exec *Execute) publish(packageJSON, registry, username, password string, p
} else {
err := execRunner.RunExecutable("npm", "publish", "--userconfig", npmrc.filepath, "--registry", registry)
if err != nil {
return err
return errors.Wrap(err, "failed publishing artifact")
}
}
return nil
}
func (exec *Execute) readPackageScope(packageJSON string) (string, error) {
b, err := exec.Utils.FileRead(packageJSON)
if err != nil {
return "", err
}
var pd npmMinimalPackageDescriptor
json.Unmarshal(b, &pd)
return pd.Scope(), nil
}

View File

@@ -7,11 +7,19 @@ import (
"testing"
"github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/magiconair/properties"
"github.com/stretchr/testify/assert"
)
func TestNpmPublish(t *testing.T) {
type wants struct {
publishConfigPath string
publishConfig string
tarballPath string
err string
}
tt := []struct {
name string
@@ -23,9 +31,7 @@ func TestNpmPublish(t *testing.T) {
registryPassword string
packBeforePublish bool
expectedPublishConfigPath string
expectedPublishConfig string
expectedError string
wants wants
}{
// project in root folder
{
@@ -33,13 +39,15 @@ func TestNpmPublish(t *testing.T) {
files: map[string]string{
"package.json": `{"name": "piper-project", "version": "0.0.1"}`,
".piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/",
".piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/\n",
},
packageDescriptors: []string{"package.json"},
expectedPublishConfigPath: `\.piperNpmrc`,
expectedPublishConfig: "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/",
wants: wants{
publishConfigPath: `\.piperNpmrc`,
publishConfig: "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/\n",
},
},
{
name: "success - single project, publish normal, unpacked package - target registry from pipeline",
@@ -50,44 +58,51 @@ func TestNpmPublish(t *testing.T) {
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",
wants: wants{
publishConfigPath: `\.piperNpmrc`,
publishConfig: "registry=https://my.private.npm.registry/\n_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nalways-auth=true\n",
},
},
{
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/",
".piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/\n",
},
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",
wants: wants{
publishConfigPath: `\.piperNpmrc`,
publishConfig: "_auth=VGhpc0lzVGhlT3RoZXJVc2VyOkFuZEhlcmVJc1RoZU90aGVyUGFzc3dvcmQ=\nregistry=https://my.other.private.npm.registry/\nalways-auth=true\n",
},
},
{
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/",
".piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/\n",
},
packageDescriptors: []string{"package.json"},
packBeforePublish: true,
expectedPublishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
expectedPublishConfig: "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/",
wants: wants{
publishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
publishConfig: "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/\n",
tarballPath: "/temp-test/package.tgz",
},
},
{
name: "success - single project, publish normal, packed - target registry from pipeline",
@@ -100,48 +115,170 @@ func TestNpmPublish(t *testing.T) {
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",
wants: wants{
publishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
publishConfig: "registry=https://my.private.npm.registry/\n_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nalways-auth=true\n",
tarballPath: "/temp-test/package.tgz",
},
},
{
name: "success - single project, publish normal, packed - target registry from pipeline",
name: "success - single project, publish normal, packed - 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/",
".piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/\n",
},
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",
wants: wants{
publishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
publishConfig: "_auth=VGhpc0lzVGhlT3RoZXJVc2VyOkFuZEhlcmVJc1RoZU90aGVyUGFzc3dvcmQ=\nregistry=https://my.other.private.npm.registry/\nalways-auth=true\n",
tarballPath: "/temp-test/package.tgz",
},
},
// scoped project
{
name: "success - single project, publish scoped, 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/\n@piper:registry=https://my.private.npm.registry/\n",
},
packageDescriptors: []string{"package.json"},
wants: wants{
publishConfigPath: `\.piperNpmrc`,
publishConfig: "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/\n@piper:registry=https://my.private.npm.registry/\n",
},
},
{
name: "success - single project, publish scoped, unpacked package - target registry from pipeline",
files: map[string]string{
"package.json": `{"name": "@piper/project", "version": "0.0.1"}`,
},
packageDescriptors: []string{"package.json"},
registryURL: "https://my.private.npm.registry/",
registryUser: "ThisIsTheUser",
registryPassword: "AndHereIsThePassword",
wants: wants{
publishConfigPath: `\.piperNpmrc`,
publishConfig: "registry=https://my.private.npm.registry/\n@piper:registry=https://my.private.npm.registry/\n_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nalways-auth=true\n",
},
},
{
name: "success - single project, publish scoped, 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/\n",
},
packageDescriptors: []string{"package.json"},
registryURL: "https://my.other.private.npm.registry/",
registryUser: "ThisIsTheOtherUser",
registryPassword: "AndHereIsTheOtherPassword",
wants: wants{
publishConfigPath: `\.piperNpmrc`,
publishConfig: "_auth=VGhpc0lzVGhlT3RoZXJVc2VyOkFuZEhlcmVJc1RoZU90aGVyUGFzc3dvcmQ=\nregistry=https://my.other.private.npm.registry/\n@piper:registry=https://my.other.private.npm.registry/\nalways-auth=true\n",
},
},
{
name: "success - single project, publish scoped, packed - target registry in npmrc",
files: map[string]string{
"package.json": `{"name": "@piper/project", "version": "0.0.1"}`,
".piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\n@piper:registry=https://my.private.npm.registry/\n",
},
packageDescriptors: []string{"package.json"},
packBeforePublish: true,
wants: wants{
publishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
publishConfig: "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\n@piper:registry=https://my.private.npm.registry/\n",
tarballPath: "/temp-test/package.tgz",
},
},
{
name: "success - single project, publish scoped, packed - target registry from pipeline",
files: map[string]string{
"package.json": `{"name": "@piper/project", "version": "0.0.1"}`,
},
packageDescriptors: []string{"package.json"},
packBeforePublish: true,
registryURL: "https://my.private.npm.registry/",
registryUser: "ThisIsTheUser",
registryPassword: "AndHereIsThePassword",
wants: wants{
publishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
publishConfig: "registry=https://my.private.npm.registry/\n@piper:registry=https://my.private.npm.registry/\n_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nalways-auth=true\n",
tarballPath: "/temp-test/package.tgz",
},
},
{
name: "success - single project, publish scoped, packed - 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/\n",
},
packageDescriptors: []string{"package.json"},
packBeforePublish: true,
registryURL: "https://my.other.private.npm.registry/",
registryUser: "ThisIsTheOtherUser",
registryPassword: "AndHereIsTheOtherPassword",
wants: wants{
publishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
publishConfig: "_auth=VGhpc0lzVGhlT3RoZXJVc2VyOkFuZEhlcmVJc1RoZU90aGVyUGFzc3dvcmQ=\nregistry=https://my.other.private.npm.registry/\n@piper:registry=https://my.other.private.npm.registry/\nalways-auth=true\n",
tarballPath: "/temp-test/package.tgz",
},
},
// project in a subfolder
{
name: "success - single project, publish normal, unpacked package - target registry in npmrc",
name: "success - single project in subfolder, 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/",
"sub/.piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/\n",
},
packageDescriptors: []string{"sub/package.json"},
expectedPublishConfigPath: `sub/\.piperNpmrc`,
expectedPublishConfig: "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/",
wants: wants{
publishConfigPath: `sub/\.piperNpmrc`,
publishConfig: "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/\n",
},
},
{
name: "success - single project, publish normal, unpacked package - target registry from pipeline",
name: "success - single project in subfolder, publish normal, unpacked package - target registry from pipeline",
files: map[string]string{
"sub/package.json": `{"name": "piper-project", "version": "0.0.1"}`,
@@ -149,47 +286,54 @@ func TestNpmPublish(t *testing.T) {
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",
wants: wants{
publishConfigPath: `sub/\.piperNpmrc`,
publishConfig: "registry=https://my.private.npm.registry/\n_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nalways-auth=true\n",
},
},
{
name: "success - single project, publish normal, unpacked package - target registry from pipeline (precedence over npmrc)",
name: "success - single project in subfolder, 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/",
"sub/.piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/\n",
},
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",
wants: wants{
publishConfigPath: `sub/\.piperNpmrc`,
publishConfig: "_auth=VGhpc0lzVGhlT3RoZXJVc2VyOkFuZEhlcmVJc1RoZU90aGVyUGFzc3dvcmQ=\nregistry=https://my.other.private.npm.registry/\nalways-auth=true\n",
},
},
{
name: "success - single project, publish normal, packed - target registry in npmrc",
name: "success - single project in subfolder, 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/",
"sub/.piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/\n",
},
packageDescriptors: []string{"sub/package.json"},
packBeforePublish: true,
expectedPublishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
expectedPublishConfig: "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/",
wants: wants{
publishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
publishConfig: "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/\n",
tarballPath: "/temp-test/package.tgz",
},
},
{
name: "success - single project, publish normal, packed - target registry from pipeline",
name: "success - single project in subfolder, publish normal, packed - target registry from pipeline",
files: map[string]string{
"sub/package.json": `{"name": "piper-project", "version": "0.0.1"}`,
@@ -199,68 +343,153 @@ func TestNpmPublish(t *testing.T) {
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",
wants: wants{
publishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
publishConfig: "registry=https://my.private.npm.registry/\n_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nalways-auth=true\n",
tarballPath: "/temp-test/package.tgz",
},
},
{
name: "success - single project, publish normal, packed - target registry from pipeline",
name: "success - single project in subfolder, publish normal, packed - 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/",
"sub/.piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/\n",
},
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",
wants: wants{
publishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
publishConfig: "_auth=VGhpc0lzVGhlT3RoZXJVc2VyOkFuZEhlcmVJc1RoZU90aGVyUGFzc3dvcmQ=\nregistry=https://my.other.private.npm.registry/\nalways-auth=true\n",
tarballPath: "/temp-test/package.tgz",
},
},
// scoped project in a subfolder
{
name: "success - single project in subfolder, publish scoped, 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/\n@piper:registry=https://my.private.npm.registry/\n",
},
packageDescriptors: []string{"sub/package.json"},
wants: wants{
publishConfigPath: `\.piperNpmrc`,
publishConfig: "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/\n@piper:registry=https://my.private.npm.registry/\n",
},
},
{
name: "success - single project in subfolder, publish scoped, 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"},
registryURL: "https://my.private.npm.registry/",
registryUser: "ThisIsTheUser",
registryPassword: "AndHereIsThePassword",
wants: wants{
publishConfigPath: `\.piperNpmrc`,
publishConfig: "registry=https://my.private.npm.registry/\n@piper:registry=https://my.private.npm.registry/\n_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nalways-auth=true\n",
},
},
{
name: "success - single project in subfolder, publish scoped, 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/\n",
},
packageDescriptors: []string{"sub/package.json"},
registryURL: "https://my.other.private.npm.registry/",
registryUser: "ThisIsTheOtherUser",
registryPassword: "AndHereIsTheOtherPassword",
wants: wants{
publishConfigPath: `\.piperNpmrc`,
publishConfig: "_auth=VGhpc0lzVGhlT3RoZXJVc2VyOkFuZEhlcmVJc1RoZU90aGVyUGFzc3dvcmQ=\nregistry=https://my.other.private.npm.registry/\n@piper:registry=https://my.other.private.npm.registry/\nalways-auth=true\n",
},
},
{
name: "success - single project in subfolder, publish scoped, packed - target registry in npmrc",
files: map[string]string{
"sub/package.json": `{"name": "@piper/project", "version": "0.0.1"}`,
"sub/.piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\n@piper:registry=https://my.private.npm.registry/\n",
},
packageDescriptors: []string{"sub/package.json"},
packBeforePublish: true,
wants: wants{
publishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
publishConfig: "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\n@piper:registry=https://my.private.npm.registry/\n",
tarballPath: "/temp-test/package.tgz",
},
},
{
name: "success - single project in subfolder, publish scoped, 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,
registryURL: "https://my.private.npm.registry/",
registryUser: "ThisIsTheUser",
registryPassword: "AndHereIsThePassword",
wants: wants{
publishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
publishConfig: "registry=https://my.private.npm.registry/\n@piper:registry=https://my.private.npm.registry/\n_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nalways-auth=true\n",
tarballPath: "/temp-test/package.tgz",
},
},
{
name: "success - single project in subfolder, publish scoped, packed - 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/\n",
},
packageDescriptors: []string{"sub/package.json"},
packBeforePublish: true,
registryURL: "https://my.other.private.npm.registry/",
registryUser: "ThisIsTheOtherUser",
registryPassword: "AndHereIsTheOtherPassword",
wants: wants{
publishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
publishConfig: "_auth=VGhpc0lzVGhlT3RoZXJVc2VyOkFuZEhlcmVJc1RoZU90aGVyUGFzc3dvcmQ=\nregistry=https://my.other.private.npm.registry/\n@piper:registry=https://my.other.private.npm.registry/\nalways-auth=true\n",
tarballPath: "/temp-test/package.tgz",
},
},
// 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 {
@@ -278,19 +507,7 @@ func TestNpmPublish(t *testing.T) {
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
}
propertiesLoadFile = utils.FileRead
propertiesWriteFile = utils.FileWrite
writeIgnoreFile = utils.FileWrite
@@ -313,7 +530,7 @@ func TestNpmPublish(t *testing.T) {
err := exec.PublishAllPackages(test.packageDescriptors, test.registryURL, test.registryUser, test.registryPassword, test.packBeforePublish)
if len(test.expectedError) == 0 && assert.NoError(t, err) {
if len(test.wants.err) == 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]
@@ -321,20 +538,25 @@ func TestNpmPublish(t *testing.T) {
assert.Equal(t, "npm", publishCmd.Exec)
assert.Equal(t, "publish", publishCmd.Params[0])
if len(test.wants.tarballPath) > 0 && assert.Contains(t, publishCmd.Params, "--tarball") {
tarballPath := publishCmd.Params[piperutils.FindString(publishCmd.Params, "--tarball")+1]
assert.Equal(t, test.wants.tarballPath, tarballPath)
}
if assert.Contains(t, publishCmd.Params, "--userconfig") {
effectivePublishConfigPath := publishCmd.Params[piperutils.FindString(publishCmd.Params, "--userconfig")+1]
assert.Regexp(t, test.expectedPublishConfigPath, effectivePublishConfigPath)
assert.Regexp(t, test.wants.publishConfigPath, effectivePublishConfigPath)
effectiveConfig, err := utils.FileRead(effectivePublishConfigPath)
if assert.NoError(t, err) {
assert.Equal(t, test.expectedPublishConfig, string(effectiveConfig))
assert.Equal(t, test.wants.publishConfig, string(effectiveConfig))
}
}
}
} else {
assert.EqualError(t, err, test.expectedError)
assert.EqualError(t, err, test.wants.err)
}
})
}

View File

@@ -22,6 +22,7 @@ type FileUtils interface {
DirExists(path string) (bool, error)
FileExists(filename string) (bool, error)
Copy(src, dest string) (int64, error)
Move(src, dest string) error
FileRead(path string) ([]byte, error)
FileWrite(path string, content []byte, perm os.FileMode) error
FileRemove(path string) error
@@ -113,6 +114,20 @@ func (f Files) Copy(src, dst string) (int64, error) {
return nBytes, err
}
func (f Files) Move(src, dst string) error {
if exists, err := f.FileExists(src); err != nil {
return err
} else if !exists {
return fmt.Errorf("file doesn't exist: %s", src)
}
if _, err := f.Copy(src, dst); err != nil {
return err
}
return f.FileRemove(src)
}
//Chmod is a wrapper for os.Chmod().
func (f Files) Chmod(path string, mode os.FileMode) error {
return os.Chmod(path, mode)