1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-14 11:03:09 +02:00
sap-jenkins-library/cmd/artifactPrepareVersion_test.go

890 lines
31 KiB
Go
Raw Normal View History

//go:build unit
// +build unit
package cmd
import (
"fmt"
"net/http"
"testing"
"time"
"github.com/SAP/jenkins-library/pkg/mock"
"github.com/SAP/jenkins-library/pkg/orchestrator"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/SAP/jenkins-library/pkg/versioning"
"github.com/ghodss/yaml"
"github.com/stretchr/testify/assert"
"helm.sh/helm/v3/pkg/chart"
"github.com/go-git/go-git/v5"
gitConfig "github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
gitHttp "github.com/go-git/go-git/v5/plumbing/transport/http"
"github.com/go-git/go-git/v5/plumbing/transport/ssh"
)
type artifactVersioningMock struct {
originalVersion string
newVersion string
getVersionError string
setVersionError string
versioningScheme string
coordinates versioning.Coordinates
coordinatesError error
}
func (a *artifactVersioningMock) VersioningScheme() string {
return a.versioningScheme
}
func (a *artifactVersioningMock) GetVersion() (string, error) {
if len(a.getVersionError) > 0 {
return "", fmt.Errorf(a.getVersionError)
}
return a.originalVersion, nil
}
func (a *artifactVersioningMock) SetVersion(version string) error {
if len(a.setVersionError) > 0 {
return fmt.Errorf(a.setVersionError)
}
a.newVersion = version
return nil
}
func (a *artifactVersioningMock) GetCoordinates() (versioning.Coordinates, error) {
if a.coordinatesError != nil {
return versioning.Coordinates{}, a.coordinatesError
}
return a.coordinates, nil
}
type gitRepositoryMock struct {
createRemoteConfigs []*gitConfig.RemoteConfig
createRemoteCalls int
createRemoteError []string
deleteRemoteNames []string
deleteRemoteCalls int
deleteRemoteError []string
pushCalled bool
pushOptions *git.PushOptions
pushError string
remote *git.Remote
remoteError string
revision string
revisionHash plumbing.Hash
revisionError string
tag string
tagHash plumbing.Hash
tagError string
worktree *git.Worktree
worktreeError string
commitObjectHash string
}
func (r *gitRepositoryMock) CommitObject(hash plumbing.Hash) (*object.Commit, error) {
r.commitObjectHash = hash.String()
return &object.Commit{Hash: hash, Message: "Test commit message"}, nil
}
func (r *gitRepositoryMock) CreateTag(name string, hash plumbing.Hash, opts *git.CreateTagOptions) (*plumbing.Reference, error) {
if len(r.tagError) > 0 {
return nil, fmt.Errorf(r.tagError)
}
r.tag = name
r.tagHash = hash
return nil, nil
}
func (r *gitRepositoryMock) CreateRemote(config *gitConfig.RemoteConfig) (*git.Remote, error) {
r.createRemoteCalls++
if len(r.createRemoteError) >= r.createRemoteCalls && len(r.createRemoteError[r.createRemoteCalls-1]) > 0 {
return nil, fmt.Errorf(r.createRemoteError[r.createRemoteCalls-1])
}
r.createRemoteConfigs = append(r.createRemoteConfigs, config)
return nil, nil
}
func (r *gitRepositoryMock) DeleteRemote(name string) error {
r.deleteRemoteCalls++
if len(r.deleteRemoteError) >= r.deleteRemoteCalls && len(r.deleteRemoteError[r.deleteRemoteCalls-1]) > 0 {
return fmt.Errorf(r.deleteRemoteError[r.deleteRemoteCalls-1])
}
r.deleteRemoteNames = append(r.deleteRemoteNames, name)
return nil
}
func (r *gitRepositoryMock) Push(o *git.PushOptions) error {
if len(r.pushError) > 0 {
return fmt.Errorf(r.pushError)
}
r.pushCalled = true
r.pushOptions = o
return nil
}
func (r *gitRepositoryMock) Remote(name string) (*git.Remote, error) {
if len(r.remoteError) > 0 {
return &git.Remote{}, fmt.Errorf(r.remoteError)
}
return r.remote, nil
}
func (r *gitRepositoryMock) ResolveRevision(rev plumbing.Revision) (*plumbing.Hash, error) {
if len(r.revisionError) > 0 {
return nil, fmt.Errorf(r.revisionError)
}
r.revision = rev.String()
return &r.revisionHash, nil
}
func (r *gitRepositoryMock) Worktree() (*git.Worktree, error) {
if len(r.worktreeError) > 0 {
return nil, fmt.Errorf(r.worktreeError)
}
return r.worktree, nil
}
type gitWorktreeMock struct {
checkoutError string
checkoutOpts *git.CheckoutOptions
commitHash plumbing.Hash
commitMsg string
commitOpts *git.CommitOptions
commitError string
}
func (w *gitWorktreeMock) Checkout(opts *git.CheckoutOptions) error {
if len(w.checkoutError) > 0 {
return fmt.Errorf(w.checkoutError)
}
w.checkoutOpts = opts
return nil
}
func (w *gitWorktreeMock) Commit(msg string, opts *git.CommitOptions) (plumbing.Hash, error) {
if len(w.commitError) > 0 {
return plumbing.Hash{}, fmt.Errorf(w.commitError)
}
w.commitMsg = msg
w.commitOpts = opts
return w.commitHash, nil
}
type artifactPrepareVersionMockUtils struct {
*mock.ExecMockRunner
*mock.FilesMock
*mock.HttpClientMock
}
func newArtifactPrepareVersionMockUtils() *artifactPrepareVersionMockUtils {
utils := artifactPrepareVersionMockUtils{
ExecMockRunner: &mock.ExecMockRunner{},
FilesMock: &mock.FilesMock{},
}
return &utils
}
func (a *artifactPrepareVersionMockUtils) DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error {
// so far no dedicated logic required for testing
return nil
}
func (a *artifactPrepareVersionMockUtils) GetConfigProvider() (orchestrator.ConfigProvider, error) {
return &orchestrator.UnknownOrchestratorConfigProvider{}, nil
}
func TestRunArtifactPrepareVersion(t *testing.T) {
t.Run("success case - cloud", func(t *testing.T) {
config := artifactPrepareVersionOptions{
BuildTool: "maven",
IncludeCommitID: true,
Password: "****",
TagPrefix: "v",
Username: "testUser",
VersioningType: "cloud",
}
telemetryData := telemetry.CustomData{}
cpe := artifactPrepareVersionCommonPipelineEnvironment{}
versioningMock := artifactVersioningMock{
originalVersion: "1.2.3",
versioningScheme: "maven",
}
utils := newArtifactPrepareVersionMockUtils()
worktree := gitWorktreeMock{
commitHash: plumbing.ComputeHash(plumbing.CommitObject, []byte{2, 3, 4}),
}
conf := gitConfig.RemoteConfig{Name: "origin", URLs: []string{"https://my.test.server"}}
repo := gitRepositoryMock{
revisionHash: plumbing.ComputeHash(plumbing.CommitObject, []byte{1, 2, 3}),
remote: git.NewRemote(nil, &conf),
}
err := runArtifactPrepareVersion(&config, &telemetryData, &cpe, &versioningMock, utils, &repo, func(r gitRepository) (gitWorktree, error) { return &worktree, nil })
assert.NoError(t, err)
assert.Contains(t, versioningMock.newVersion, "1.2.3")
assert.Contains(t, versioningMock.newVersion, fmt.Sprintf("_%v", repo.revisionHash.String()))
assert.Equal(t, "HEAD", repo.revision)
assert.Contains(t, repo.tag, "v1.2.3")
assert.Equal(t, &git.CheckoutOptions{Hash: repo.revisionHash, Keep: true}, worktree.checkoutOpts)
assert.True(t, repo.pushCalled)
assert.Contains(t, cpe.artifactVersion, "1.2.3")
assert.Contains(t, cpe.originalArtifactVersion, "1.2.3")
assert.Equal(t, worktree.commitHash.String(), cpe.git.commitID)
assert.Equal(t, "Test commit message", cpe.git.commitMessage)
assert.Equal(t, telemetry.CustomData{Custom1Label: "buildTool", Custom1: "maven", Custom2Label: "filePath", Custom2: ""}, telemetryData)
})
t.Run("success case - cloud_noTag", func(t *testing.T) {
config := artifactPrepareVersionOptions{
BuildTool: "maven",
IncludeCommitID: true,
Password: "****",
TagPrefix: "v",
Username: "testUser",
VersioningType: "cloud_noTag",
}
telemetryData := telemetry.CustomData{}
cpe := artifactPrepareVersionCommonPipelineEnvironment{}
versioningMock := artifactVersioningMock{
originalVersion: "1.2.3",
versioningScheme: "maven",
}
utils := newArtifactPrepareVersionMockUtils()
worktree := gitWorktreeMock{
commitHash: plumbing.ComputeHash(plumbing.CommitObject, []byte{2, 3, 4}),
}
conf := gitConfig.RemoteConfig{Name: "origin", URLs: []string{"https://my.test.server"}}
repo := gitRepositoryMock{
revisionHash: plumbing.ComputeHash(plumbing.CommitObject, []byte{1, 2, 3}),
remote: git.NewRemote(nil, &conf),
}
err := runArtifactPrepareVersion(&config, &telemetryData, &cpe, &versioningMock, utils, &repo, func(r gitRepository) (gitWorktree, error) { return &worktree, nil })
assert.NoError(t, err)
assert.False(t, repo.pushCalled)
assert.Contains(t, cpe.artifactVersion, "1.2.3")
assert.Contains(t, cpe.originalArtifactVersion, "1.2.3")
assert.Equal(t, repo.revisionHash.String(), cpe.git.commitID)
})
t.Run("success case - compatibility", func(t *testing.T) {
config := artifactPrepareVersionOptions{
BuildTool: "maven",
VersioningType: "cloud",
VersioningTemplate: "${version}",
}
cpe := artifactPrepareVersionCommonPipelineEnvironment{}
versioningMock := artifactVersioningMock{
originalVersion: "1.2.3",
versioningScheme: "maven",
}
worktree := gitWorktreeMock{}
repo := gitRepositoryMock{}
err := runArtifactPrepareVersion(&config, &telemetry.CustomData{}, &cpe, &versioningMock, nil, &repo, func(r gitRepository) (gitWorktree, error) { return &worktree, nil })
assert.NoError(t, err)
assert.Equal(t, "1.2.3", cpe.artifactVersion)
})
t.Run("success case - library", func(t *testing.T) {
config := artifactPrepareVersionOptions{
BuildTool: "maven",
VersioningType: "library",
}
cpe := artifactPrepareVersionCommonPipelineEnvironment{}
versioningMock := artifactVersioningMock{
originalVersion: "1.2.3",
versioningScheme: "maven",
}
worktree := gitWorktreeMock{
commitHash: plumbing.ComputeHash(plumbing.CommitObject, []byte{2, 3, 4}),
}
repo := gitRepositoryMock{
revisionHash: plumbing.ComputeHash(plumbing.CommitObject, []byte{1, 2, 3}),
}
err := runArtifactPrepareVersion(&config, &telemetry.CustomData{}, &cpe, &versioningMock, nil, &repo, func(r gitRepository) (gitWorktree, error) { return &worktree, nil })
assert.NoError(t, err)
assert.Equal(t, "1.2.3", cpe.artifactVersion)
assert.Equal(t, repo.revisionHash.String(), cpe.git.commitID)
})
t.Run("success case - coordinates", func(t *testing.T) {
config := artifactPrepareVersionOptions{
BuildTool: "maven",
VersioningType: "library",
FetchCoordinates: true,
}
cpe := artifactPrepareVersionCommonPipelineEnvironment{}
versioningMock := artifactVersioningMock{
originalVersion: "1.2.3",
versioningScheme: "maven",
coordinates: versioning.Coordinates{GroupID: "my.testGroup", ArtifactID: "testArtifact", Packaging: "testPackaging"},
}
worktree := gitWorktreeMock{
commitHash: plumbing.ComputeHash(plumbing.CommitObject, []byte{2, 3, 4}),
}
repo := gitRepositoryMock{
revisionHash: plumbing.ComputeHash(plumbing.CommitObject, []byte{1, 2, 3}),
}
err := runArtifactPrepareVersion(&config, &telemetry.CustomData{}, &cpe, &versioningMock, nil, &repo, func(r gitRepository) (gitWorktree, error) { return &worktree, nil })
assert.NoError(t, err)
assert.Equal(t, "testArtifact", cpe.artifactID)
assert.Equal(t, "my.testGroup", cpe.groupID)
assert.Equal(t, "testPackaging", cpe.packaging)
})
t.Run("error - failed to retrieve version", func(t *testing.T) {
config := artifactPrepareVersionOptions{}
versioningMock := artifactVersioningMock{
getVersionError: "getVersion error",
}
err := runArtifactPrepareVersion(&config, &telemetry.CustomData{}, nil, &versioningMock, nil, nil, nil)
assert.EqualError(t, err, "failed to retrieve version: getVersion error")
})
t.Run("error - failed to retrieve git commit ID", func(t *testing.T) {
config := artifactPrepareVersionOptions{}
versioningMock := artifactVersioningMock{
originalVersion: "1.2.3",
versioningScheme: "maven",
}
repo := gitRepositoryMock{revisionError: "revision error"}
err := runArtifactPrepareVersion(&config, &telemetry.CustomData{}, nil, &versioningMock, nil, &repo, nil)
assert.EqualError(t, err, "failed to retrieve git commit ID: revision error")
})
t.Run("error - versioning template", func(t *testing.T) {
config := artifactPrepareVersionOptions{
VersioningType: "cloud",
}
versioningMock := artifactVersioningMock{
originalVersion: "1.2.3",
versioningScheme: "notSupported",
}
utils := newArtifactPrepareVersionMockUtils()
repo := gitRepositoryMock{}
err := runArtifactPrepareVersion(&config, &telemetry.CustomData{}, &artifactPrepareVersionCommonPipelineEnvironment{}, &versioningMock, utils, &repo, nil)
assert.Contains(t, fmt.Sprint(err), "failed to get versioning template for scheme 'notSupported'")
})
t.Run("error - failed to retrieve git worktree", func(t *testing.T) {
config := artifactPrepareVersionOptions{
VersioningType: "cloud",
}
versioningMock := artifactVersioningMock{
originalVersion: "1.2.3",
versioningScheme: "maven",
}
utils := newArtifactPrepareVersionMockUtils()
repo := gitRepositoryMock{}
err := runArtifactPrepareVersion(&config, &telemetry.CustomData{}, &artifactPrepareVersionCommonPipelineEnvironment{}, &versioningMock, utils, &repo, func(r gitRepository) (gitWorktree, error) { return nil, fmt.Errorf("worktree error") })
assert.EqualError(t, err, "failed to retrieve git worktree: worktree error")
})
t.Run("error - failed to initialize git worktree: ", func(t *testing.T) {
config := artifactPrepareVersionOptions{
VersioningType: "cloud",
}
versioningMock := artifactVersioningMock{
originalVersion: "1.2.3",
versioningScheme: "maven",
}
utils := newArtifactPrepareVersionMockUtils()
worktree := gitWorktreeMock{checkoutError: "checkout error"}
repo := gitRepositoryMock{}
err := runArtifactPrepareVersion(&config, &telemetry.CustomData{}, &artifactPrepareVersionCommonPipelineEnvironment{}, &versioningMock, utils, &repo, func(r gitRepository) (gitWorktree, error) { return &worktree, nil })
assert.EqualError(t, err, "failed to initialize worktree: checkout error")
})
t.Run("error - failed to set version", func(t *testing.T) {
config := artifactPrepareVersionOptions{
VersioningType: "cloud",
}
versioningMock := artifactVersioningMock{
originalVersion: "1.2.3",
setVersionError: "setVersion error",
versioningScheme: "maven",
}
utils := newArtifactPrepareVersionMockUtils()
worktree := gitWorktreeMock{}
repo := gitRepositoryMock{}
err := runArtifactPrepareVersion(&config, &telemetry.CustomData{}, &artifactPrepareVersionCommonPipelineEnvironment{}, &versioningMock, utils, &repo, func(r gitRepository) (gitWorktree, error) { return &worktree, nil })
assert.EqualError(t, err, "failed to write version: setVersion error")
})
t.Run("error - failed to push changes", func(t *testing.T) {
config := artifactPrepareVersionOptions{
VersioningType: "cloud",
}
versioningMock := artifactVersioningMock{
originalVersion: "1.2.3",
versioningScheme: "maven",
}
utils := newArtifactPrepareVersionMockUtils()
worktree := gitWorktreeMock{}
repo := gitRepositoryMock{}
err := runArtifactPrepareVersion(&config, &telemetry.CustomData{}, &artifactPrepareVersionCommonPipelineEnvironment{}, &versioningMock, utils, &repo, func(r gitRepository) (gitWorktree, error) { return &worktree, nil })
assert.Contains(t, fmt.Sprint(err), "failed to push changes for version '1.2.3")
})
t.Run("error - failed to get coordinates", func(t *testing.T) {
config := artifactPrepareVersionOptions{
BuildTool: "maven",
VersioningType: "library",
FetchCoordinates: true,
}
cpe := artifactPrepareVersionCommonPipelineEnvironment{}
versioningMock := artifactVersioningMock{
originalVersion: "1.2.3",
versioningScheme: "maven",
coordinatesError: fmt.Errorf("coordinatesError"),
}
utils := newArtifactPrepareVersionMockUtils()
worktree := gitWorktreeMock{
commitHash: plumbing.ComputeHash(plumbing.CommitObject, []byte{2, 3, 4}),
}
repo := gitRepositoryMock{
revisionHash: plumbing.ComputeHash(plumbing.CommitObject, []byte{1, 2, 3}),
}
err := runArtifactPrepareVersion(&config, &telemetry.CustomData{}, &cpe, &versioningMock, utils, &repo, func(r gitRepository) (gitWorktree, error) { return &worktree, nil })
assert.EqualError(t, err, "failed to get coordinates: coordinatesError")
})
t.Run("warning - failed to get coordinates", func(t *testing.T) {
config := artifactPrepareVersionOptions{
BuildTool: "maven",
VersioningType: "library",
FetchCoordinates: false,
}
cpe := artifactPrepareVersionCommonPipelineEnvironment{}
versioningMock := artifactVersioningMock{
originalVersion: "1.2.3",
versioningScheme: "maven",
coordinatesError: fmt.Errorf("coordinatesError"),
}
utils := newArtifactPrepareVersionMockUtils()
worktree := gitWorktreeMock{
commitHash: plumbing.ComputeHash(plumbing.CommitObject, []byte{2, 3, 4}),
}
repo := gitRepositoryMock{
revisionHash: plumbing.ComputeHash(plumbing.CommitObject, []byte{1, 2, 3}),
}
err := runArtifactPrepareVersion(&config, &telemetry.CustomData{}, &cpe, &versioningMock, utils, &repo, func(r gitRepository) (gitWorktree, error) { return &worktree, nil })
assert.NoError(t, err)
})
}
func TestVersioningTemplate(t *testing.T) {
tt := []struct {
scheme string
expected string
expectedErr string
}{
{scheme: "maven", expected: "{{.Version}}{{if .Timestamp}}-{{.Timestamp}}{{if .CommitID}}_{{.CommitID}}{{end}}{{end}}"},
{scheme: "semver2", expected: "{{.Version}}{{if .Timestamp}}-{{.Timestamp}}{{if .CommitID}}+{{.CommitID}}{{end}}{{end}}"},
{scheme: "pep440", expected: "{{.Version}}{{if .Timestamp}}.{{.Timestamp}}{{if .CommitID}}+{{.CommitID}}{{end}}{{end}}"},
{scheme: "notSupported", expected: "", expectedErr: "versioning scheme 'notSupported' not supported"},
}
for _, test := range tt {
scheme, err := versioningTemplate(test.scheme)
assert.Equal(t, test.expected, scheme)
if len(test.expectedErr) == 0 {
assert.NoError(t, err)
} else {
assert.EqualError(t, err, test.expectedErr)
}
}
}
func TestCalculateNewVersion(t *testing.T) {
currentVersion := "1.2.3"
testTime := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
commitID := plumbing.ComputeHash(plumbing.CommitObject, []byte{1, 2, 3}).String()
tt := []struct {
versioningTemplate string
includeCommitID bool
shortCommitID bool
unixTimestamp bool
expected string
expectedErr string
}{
{versioningTemplate: "", expectedErr: "failed calculate version, new version is ''"},
{versioningTemplate: "{{.Version}}{{if .Timestamp}}-{{.Timestamp}}{{if .CommitID}}+{{.CommitID}}{{end}}{{end}}", expected: "1.2.3-20200101000000"},
{versioningTemplate: "{{.Version}}{{if .Timestamp}}-{{.Timestamp}}{{if .CommitID}}+{{.CommitID}}{{end}}{{end}}", includeCommitID: true, expected: "1.2.3-20200101000000+428ecf70bc22df0ba3dcf194b5ce53e769abab07"},
{versioningTemplate: "{{.Version}}{{if .Timestamp}}-{{.Timestamp}}{{if .CommitID}}+{{.CommitID}}{{end}}{{end}}", includeCommitID: true, shortCommitID: true, expected: "1.2.3-20200101000000+428ecf7"},
{versioningTemplate: "{{.Version}}{{if .Timestamp}}-{{.Timestamp}}{{if .CommitID}}+{{.CommitID}}{{end}}{{end}}", includeCommitID: true, unixTimestamp: true, expected: "1.2.3-1577836800+428ecf70bc22df0ba3dcf194b5ce53e769abab07"},
}
for _, test := range tt {
version, err := calculateNewVersion(test.versioningTemplate, currentVersion, commitID, test.includeCommitID, test.shortCommitID, test.unixTimestamp, testTime)
assert.Equal(t, test.expected, version)
if len(test.expectedErr) == 0 {
assert.NoError(t, err)
} else {
assert.EqualError(t, err, test.expectedErr)
}
}
}
func TestPushChanges(t *testing.T) {
newVersion := "1.2.3"
testTime := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
conf := gitConfig.RemoteConfig{Name: "origin", URLs: []string{"https://my.test.server"}}
remote := git.NewRemote(nil, &conf)
t.Run("success - username/password", func(t *testing.T) {
config := artifactPrepareVersionOptions{Username: "testUser", Password: "****", CommitUserName: "Project Piper"}
repo := gitRepositoryMock{remote: remote}
worktree := gitWorktreeMock{commitHash: plumbing.ComputeHash(plumbing.CommitObject, []byte{1, 2, 3})}
commitID, err := pushChanges(&config, newVersion, &repo, &worktree, testTime, nil)
assert.NoError(t, err)
assert.Equal(t, "428ecf70bc22df0ba3dcf194b5ce53e769abab07", commitID)
assert.Equal(t, "update version 1.2.3", worktree.commitMsg)
assert.Equal(t, &git.CommitOptions{All: true, Author: &object.Signature{Name: "Project Piper", When: testTime}}, worktree.commitOpts)
assert.Equal(t, "1.2.3", repo.tag)
assert.Equal(t, "428ecf70bc22df0ba3dcf194b5ce53e769abab07", repo.tagHash.String())
assert.Equal(t, &git.PushOptions{RefSpecs: []gitConfig.RefSpec{"refs/tags/1.2.3:refs/tags/1.2.3"}, Auth: &gitHttp.BasicAuth{Username: config.Username, Password: config.Password}}, repo.pushOptions)
})
t.Run("success - ssh fallback", func(t *testing.T) {
config := artifactPrepareVersionOptions{CommitUserName: "Project Piper"}
repo := gitRepositoryMock{remote: remote}
worktree := gitWorktreeMock{commitHash: plumbing.ComputeHash(plumbing.CommitObject, []byte{1, 2, 3})}
customCerts := []byte("custom certs")
originalSSHAgentAuth := sshAgentAuth
sshAgentAuth = func(u string) (*ssh.PublicKeysCallback, error) { return &ssh.PublicKeysCallback{}, nil }
commitID, err := pushChanges(&config, newVersion, &repo, &worktree, testTime, customCerts)
sshAgentAuth = originalSSHAgentAuth
assert.NoError(t, err)
assert.Equal(t, "428ecf70bc22df0ba3dcf194b5ce53e769abab07", commitID)
assert.Equal(t, "update version 1.2.3", worktree.commitMsg)
assert.Equal(t, &git.CommitOptions{All: true, Author: &object.Signature{Name: "Project Piper", When: testTime}}, worktree.commitOpts)
assert.Equal(t, "1.2.3", repo.tag)
assert.Equal(t, "428ecf70bc22df0ba3dcf194b5ce53e769abab07", repo.tagHash.String())
assert.Equal(t, &git.PushOptions{RefSpecs: []gitConfig.RefSpec{"refs/tags/1.2.3:refs/tags/1.2.3"}, Auth: &ssh.PublicKeysCallback{}, CABundle: customCerts}, repo.pushOptions)
})
t.Run("success - ssh", func(t *testing.T) {
confSSH := gitConfig.RemoteConfig{Name: "origin", URLs: []string{"git@my.test.server"}}
remoteSSH := git.NewRemote(nil, &confSSH)
config := artifactPrepareVersionOptions{}
repo := gitRepositoryMock{remote: remoteSSH}
worktree := gitWorktreeMock{commitHash: plumbing.ComputeHash(plumbing.CommitObject, []byte{1, 2, 3})}
originalSSHAgentAuth := sshAgentAuth
sshAgentAuth = func(u string) (*ssh.PublicKeysCallback, error) { return &ssh.PublicKeysCallback{}, nil }
commitID, err := pushChanges(&config, newVersion, &repo, &worktree, testTime, nil)
sshAgentAuth = originalSSHAgentAuth
assert.NoError(t, err)
assert.Equal(t, "428ecf70bc22df0ba3dcf194b5ce53e769abab07", commitID)
assert.Equal(t, &git.PushOptions{RefSpecs: []gitConfig.RefSpec{"refs/tags/1.2.3:refs/tags/1.2.3"}, Auth: &ssh.PublicKeysCallback{}}, repo.pushOptions)
})
t.Run("error - commit", func(t *testing.T) {
config := artifactPrepareVersionOptions{}
repo := gitRepositoryMock{}
worktree := gitWorktreeMock{commitError: "commit error", commitHash: plumbing.ComputeHash(plumbing.CommitObject, []byte{1, 2, 3})}
commitID, err := pushChanges(&config, newVersion, &repo, &worktree, testTime, nil)
assert.Equal(t, "0000000000000000000000000000000000000000", commitID)
assert.EqualError(t, err, "failed to commit new version: commit error")
})
t.Run("error - create tag", func(t *testing.T) {
config := artifactPrepareVersionOptions{}
repo := gitRepositoryMock{tagError: "tag error"}
worktree := gitWorktreeMock{commitHash: plumbing.ComputeHash(plumbing.CommitObject, []byte{1, 2, 3})}
commitID, err := pushChanges(&config, newVersion, &repo, &worktree, testTime, nil)
assert.Equal(t, "428ecf70bc22df0ba3dcf194b5ce53e769abab07", commitID)
assert.EqualError(t, err, "tag error")
})
t.Run("error - no remote url", func(t *testing.T) {
config := artifactPrepareVersionOptions{}
repo := gitRepositoryMock{}
worktree := gitWorktreeMock{commitHash: plumbing.ComputeHash(plumbing.CommitObject, []byte{1, 2, 3})}
commitID, err := pushChanges(&config, newVersion, &repo, &worktree, testTime, nil)
assert.Equal(t, "428ecf70bc22df0ba3dcf194b5ce53e769abab07", commitID)
assert.EqualError(t, err, "no remote url maintained")
})
t.Run("error - ssh fallback", func(t *testing.T) {
config := artifactPrepareVersionOptions{}
worktree := gitWorktreeMock{commitHash: plumbing.ComputeHash(plumbing.CommitObject, []byte{1, 2, 3})}
sshSuccess := func(u string) (*ssh.PublicKeysCallback, error) { return nil, nil }
sshFailure := func(u string) (*ssh.PublicKeysCallback, error) { return nil, fmt.Errorf("ssh error") }
tt := []struct {
repo gitRepositoryMock
sshAgentAuth func(string) (*ssh.PublicKeysCallback, error)
expectedError string
}{
{repo: gitRepositoryMock{remote: remote, deleteRemoteError: []string{"delete error"}}, sshAgentAuth: sshSuccess, expectedError: "failed to update remote origin - remove: delete error"},
{repo: gitRepositoryMock{remote: remote, createRemoteError: []string{"update error"}}, sshAgentAuth: sshSuccess, expectedError: "failed to update remote origin - create: update error"},
{repo: gitRepositoryMock{remote: remote}, sshAgentAuth: sshFailure, expectedError: "failed to retrieve ssh authentication: ssh error"},
{repo: gitRepositoryMock{remote: remote, deleteRemoteError: []string{"", "delete error"}}, sshAgentAuth: sshSuccess, expectedError: "failed to restore remote origin - remove: delete error"},
{repo: gitRepositoryMock{remote: remote, createRemoteError: []string{"", "update error"}}, sshAgentAuth: sshSuccess, expectedError: "failed to restore remote origin - create: update error"},
}
originalSSHAgentAuth := sshAgentAuth
for _, test := range tt {
sshAgentAuth = test.sshAgentAuth
commitID, err := pushChanges(&config, newVersion, &test.repo, &worktree, testTime, nil)
sshAgentAuth = originalSSHAgentAuth
assert.Equal(t, "428ecf70bc22df0ba3dcf194b5ce53e769abab07", commitID)
assert.EqualError(t, err, test.expectedError)
}
})
t.Run("error - push", func(t *testing.T) {
config := artifactPrepareVersionOptions{Username: "testUser", Password: "****"}
repo := gitRepositoryMock{remote: remote, pushError: "push error"}
worktree := gitWorktreeMock{commitHash: plumbing.ComputeHash(plumbing.CommitObject, []byte{1, 2, 3})}
commitID, err := pushChanges(&config, newVersion, &repo, &worktree, testTime, nil)
assert.Equal(t, "428ecf70bc22df0ba3dcf194b5ce53e769abab07", commitID)
assert.EqualError(t, err, "push error")
})
}
func TestTemplateCompatibility(t *testing.T) {
tt := []struct {
groovy string
versioningType string
timestamp bool
commitID bool
}{
{groovy: `${version}`, versioningType: "library", timestamp: false, commitID: false},
{groovy: `${version}-${timestamp}`, versioningType: "cloud", timestamp: true, commitID: false},
{groovy: `${version}-${timestamp}${commitId?"_"+commitId:""`, versioningType: "cloud", timestamp: true, commitID: true},
}
for _, test := range tt {
versioningType, timestamp, commitID := templateCompatibility(test.groovy)
assert.Equal(t, test.versioningType, versioningType)
assert.Equal(t, test.timestamp, timestamp)
assert.Equal(t, test.commitID, commitID)
}
}
func TestConvertHTTPToSSHURL(t *testing.T) {
tt := []struct {
httpURL string
expected string
}{
{httpURL: "https://my.test.server/owner/repo.git", expected: "git@my.test.server:owner/repo.git"},
}
for _, test := range tt {
assert.Equal(t, test.expected, convertHTTPToSSHURL(test.httpURL))
}
}
func TestPropagateVersion(t *testing.T) {
t.Parallel()
gitCommitID := "theGitCommitId"
testTime := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC) //20200101000000
t.Run("success case", func(t *testing.T) {
config := artifactPrepareVersionOptions{
VersioningType: "cloud",
AdditionalTargetTools: []string{"helm"},
}
chartMetadata := chart.Metadata{Version: "1.2.3"}
content, err := yaml.Marshal(chartMetadata)
assert.NoError(t, err)
utils := newArtifactPrepareVersionMockUtils()
utils.AddFile("myChart/Chart.yaml", content)
artifactOpts := versioning.Options{}
err = propagateVersion(&config, utils, &artifactOpts, "1.2.4", gitCommitID, testTime)
assert.NoError(t, err)
})
t.Run("success case - dedicated build descriptors", func(t *testing.T) {
config := artifactPrepareVersionOptions{
VersioningType: "cloud",
AdditionalTargetTools: []string{"helm"},
AdditionalTargetDescriptors: []string{"myChart/Chart.yaml"},
IncludeCommitID: true,
}
chartMetadata := chart.Metadata{Version: "1.2.3"}
content, err := yaml.Marshal(chartMetadata)
assert.NoError(t, err)
utils := newArtifactPrepareVersionMockUtils()
utils.AddFile("myChart/Chart.yaml", content)
artifactOpts := versioning.Options{}
err = propagateVersion(&config, utils, &artifactOpts, "1.2.4", gitCommitID, testTime)
assert.NoError(t, err)
chartContent, err := utils.FileRead("myChart/Chart.yaml")
assert.NoError(t, err)
chartMeta := chart.Metadata{}
err = yaml.Unmarshal(chartContent, &chartMeta)
assert.NoError(t, err)
assert.Equal(t, "1.2.4-20200101000000_theGitCommitId", chartMeta.AppVersion)
assert.Equal(t, "1.2.4-20200101000000+theGitCommitId", chartMeta.Version)
})
t.Run("success case - dedicated build descriptors / no cloud", func(t *testing.T) {
config := artifactPrepareVersionOptions{
VersioningType: "library",
AdditionalTargetTools: []string{"helm"},
AdditionalTargetDescriptors: []string{"myChart/Chart.yaml"},
}
chartMetadata := chart.Metadata{Version: "1.2.3"}
content, err := yaml.Marshal(chartMetadata)
assert.NoError(t, err)
utils := newArtifactPrepareVersionMockUtils()
utils.AddFile("myChart/Chart.yaml", content)
artifactOpts := versioning.Options{}
err = propagateVersion(&config, utils, &artifactOpts, "1.2.4", gitCommitID, testTime)
assert.NoError(t, err)
chartContent, err := utils.FileRead("myChart/Chart.yaml")
assert.NoError(t, err)
chartMeta := chart.Metadata{}
err = yaml.Unmarshal(chartContent, &chartMeta)
assert.NoError(t, err)
assert.Equal(t, "1.2.4", chartMeta.AppVersion)
assert.Equal(t, "1.2.4", chartMeta.Version)
})
t.Run("success case - noop", func(t *testing.T) {
config := artifactPrepareVersionOptions{}
utils := newArtifactPrepareVersionMockUtils()
artifactOpts := versioning.Options{}
err := propagateVersion(&config, utils, &artifactOpts, "1.2.4", gitCommitID, testTime)
assert.NoError(t, err)
})
t.Run("error case - wrong config", func(t *testing.T) {
config := artifactPrepareVersionOptions{
AdditionalTargetDescriptors: []string{"pom.xml"},
AdditionalTargetTools: []string{"maven", "helm"},
}
utils := newArtifactPrepareVersionMockUtils()
artifactOpts := versioning.Options{}
err := propagateVersion(&config, utils, &artifactOpts, "1.2.4", gitCommitID, testTime)
assert.EqualError(t, err, "additionalTargetDescriptors cannot have a different number of entries than additionalTargetTools")
})
t.Run("error case - wrong target tool", func(t *testing.T) {
config := artifactPrepareVersionOptions{
AdditionalTargetTools: []string{"notKnown"},
}
utils := newArtifactPrepareVersionMockUtils()
artifactOpts := versioning.Options{}
err := propagateVersion(&config, utils, &artifactOpts, "1.2.4", gitCommitID, testTime)
assert.Contains(t, fmt.Sprint(err), "failed to retrieve artifact")
})
}