github.com/olli-ai/jx/v2@v2.0.400-0.20210921045218-14731b4dd448/pkg/gits/operations/pull_request_op_test.go (about)

     1  // +build unit
     2  
     3  package operations_test
     4  
     5  import (
     6  	"fmt"
     7  	"io/ioutil"
     8  	"net/http"
     9  	"net/http/httptest"
    10  	"os"
    11  	"path/filepath"
    12  	"strings"
    13  	"testing"
    14  
    15  	"github.com/acarl005/stripansi"
    16  	"github.com/jenkins-x/jx-logging/pkg/log"
    17  
    18  	"github.com/olli-ai/jx/v2/pkg/kube"
    19  
    20  	"k8s.io/helm/pkg/proto/hapi/chart"
    21  
    22  	"github.com/olli-ai/jx/v2/pkg/helm"
    23  
    24  	vault_test "github.com/olli-ai/jx/v2/pkg/vault/mocks"
    25  
    26  	helm_test "github.com/olli-ai/jx/v2/pkg/helm/mocks"
    27  
    28  	"github.com/olli-ai/jx/v2/pkg/tests"
    29  
    30  	"github.com/olli-ai/jx/v2/pkg/util"
    31  
    32  	"github.com/olli-ai/jx/v2/pkg/gits/operations"
    33  
    34  	"github.com/ghodss/yaml"
    35  	v1 "github.com/jenkins-x/jx-api/pkg/apis/jenkins.io/v1"
    36  	"github.com/jenkins-x/jx-api/pkg/client/clientset/versioned"
    37  	"github.com/olli-ai/jx/v2/pkg/cmd/clients/fake"
    38  	"github.com/olli-ai/jx/v2/pkg/cmd/opts"
    39  	"github.com/olli-ai/jx/v2/pkg/cmd/testhelpers"
    40  	"github.com/olli-ai/jx/v2/pkg/dependencymatrix"
    41  	"github.com/olli-ai/jx/v2/pkg/gits"
    42  	gits_test "github.com/olli-ai/jx/v2/pkg/gits/mocks"
    43  	resources_test "github.com/olli-ai/jx/v2/pkg/kube/resources/mocks"
    44  	"github.com/petergtz/pegomock"
    45  	"github.com/stretchr/testify/assert"
    46  	tektonclient "github.com/tektoncd/pipeline/pkg/client/clientset/versioned"
    47  	"k8s.io/apimachinery/pkg/runtime"
    48  	"k8s.io/client-go/kubernetes"
    49  )
    50  
    51  func setupTestPullRequestOperation(t *testing.T) operations.PullRequestOperation {
    52  	_, _, _, commonOpts, _ := getFakeClientsAndNs(t)
    53  
    54  	testOrgName := "testowner"
    55  	testRepoName := "testrepo"
    56  
    57  	commonOpts.SetGit(gits.NewGitFake())
    58  
    59  	o := operations.PullRequestOperation{
    60  		CommonOptions: &commonOpts,
    61  	}
    62  
    63  	gitter := gits_test.NewMockGitter()
    64  
    65  	fakeRepo, _ := gits.NewFakeRepository(testOrgName, testRepoName, nil, nil)
    66  	fakeGitProvider := gits.NewFakeProvider(fakeRepo)
    67  	fakeGitProvider.User.Username = testOrgName
    68  
    69  	testhelpers.ConfigureTestOptionsWithResources(o.CommonOptions,
    70  		[]runtime.Object{},
    71  		[]runtime.Object{},
    72  		gitter,
    73  		fakeGitProvider,
    74  		nil,
    75  		resources_test.NewMockInstaller(),
    76  	)
    77  
    78  	err := testhelpers.CreateTestEnvironmentDir(o.CommonOptions)
    79  	assert.NoError(t, err)
    80  
    81  	pegomock.When(gitter.HasChanges(pegomock.AnyString())).ThenReturn(true, nil)
    82  
    83  	return o
    84  }
    85  
    86  func TestCreatePullRequest(t *testing.T) {
    87  	prOpts := setupTestPullRequestOperation(t)
    88  
    89  	prOpts.GitURLs = []string{"testowner/testrepo"}
    90  	prOpts.SrcGitURL = "testowner/testrepo"
    91  	prOpts.Version = "3.0.0"
    92  
    93  	var results *gits.PullRequestInfo
    94  	var err error
    95  
    96  	logOutput := log.CaptureOutput(func() {
    97  		results, err = prOpts.CreatePullRequest("test", func(dir string, gitInfo *gits.GitRepository) (strings []string, e error) {
    98  			return []string{"1.0.0", "v1.0.1", "2.0.0"}, nil
    99  		})
   100  		assert.NoError(t, err)
   101  		assert.NotNil(t, results, "we must have results coming out of the PR creation")
   102  	})
   103  
   104  	assert.Contains(t, logOutput, "Added label updatebot to Pull Request https://fake.git/testowner/testrepo/pulls/1",
   105  		"Updatebot label should be added to the PR")
   106  
   107  	assert.Equal(t, "chore(deps): bump testowner/testrepo from 1.0.0, 2.0.0 and v1.0.1 to 3.0.0",
   108  		results.PullRequestArguments.Title, "The PR title should contain the old and new versions")
   109  }
   110  
   111  func TestCreatePullRequestsWithLabels(t *testing.T) {
   112  	prOpts := setupTestPullRequestOperation(t)
   113  
   114  	prOpts.GitURLs = []string{"testowner/testrepo"}
   115  	prOpts.SrcGitURL = "testowner/testrepo"
   116  	prOpts.Version = "2.0.0"
   117  	fromVersion := "1.0.0"
   118  
   119  	results, err := prOpts.CreatePullRequest("test", func(dir string, gitInfo *gits.GitRepository) (strings []string, e error) {
   120  		return []string{fromVersion}, nil
   121  	})
   122  	assert.NoError(t, err)
   123  	assert.NotNil(t, results, "we must have results coming out of the PR creation")
   124  
   125  	prNumber := 1
   126  	assert.Equal(t, prNumber, *results.PullRequest.Number, "This should be PR number %d", prNumber)
   127  
   128  	assert.Equal(t, fmt.Sprintf("chore(deps): bump %s from %s to %s", prOpts.SrcGitURL, fromVersion, prOpts.Version),
   129  		results.PullRequestArguments.Title, "The PR title should contain the old and new versions")
   130  
   131  	assert.Equal(t, 1, len(results.PullRequest.Labels), "One label expected")
   132  	assert.Equal(t, "updatebot", *results.PullRequest.Labels[0].Name, "updatebot label should exist")
   133  
   134  	//create second PR with additional label
   135  	prOpts.GitURLs = []string{"testowner/testrepo"}
   136  	prOpts.Version = "4.0.0"
   137  	prOpts.Labels = []string{"test-label"}
   138  
   139  	labelResults, err := prOpts.CreatePullRequest("test", func(dir string, gitInfo *gits.GitRepository) (strings []string, e error) {
   140  		return []string{fromVersion}, nil
   141  	})
   142  	assert.NoError(t, err)
   143  	assert.NotNil(t, labelResults, "we must have results coming out of the second PR creation")
   144  
   145  	prNumber = 2
   146  	assert.Equal(t, prNumber, *labelResults.PullRequest.Number, "This should be PR number %d", prNumber)
   147  
   148  	assert.Equal(t, fmt.Sprintf("chore(deps): bump %s from %s to %s", prOpts.SrcGitURL, fromVersion, prOpts.Version),
   149  		labelResults.PullRequestArguments.Title, "The PR title should contain the old and new versions")
   150  
   151  	assert.Equal(t, 2, len(labelResults.PullRequest.Labels), "Two labels expected")
   152  	prLabels := []string{}
   153  	for _, label := range labelResults.PullRequest.Labels {
   154  		prLabels = append(prLabels, *label.Name)
   155  	}
   156  	assert.Contains(t, prLabels, "updatebot", "updatebot label should exist")
   157  	assert.Contains(t, prLabels, prOpts.Labels[0], fmt.Sprintf("%s label should exist", prOpts.Labels[0]))
   158  }
   159  
   160  func TestCreatePullRequestWithMatrixUpdatePaths(t *testing.T) {
   161  
   162  	_, _, _, commonOpts, _ := getFakeClientsAndNs(t)
   163  
   164  	testOrgName := "testowner"
   165  	testRepoName := "testrepo"
   166  
   167  	commonOpts.SetGit(gits.NewGitFake())
   168  	o := operations.PullRequestOperation{
   169  		CommonOptions: &commonOpts,
   170  	}
   171  
   172  	viaRepo := "wiley"
   173  	toVersion := "3.0.0"
   174  	fromVersion := "1.0.0"
   175  	toTag := fmt.Sprintf("v%s", toVersion)
   176  	fromTag := fmt.Sprintf("v%s", fromVersion)
   177  	host := "fake.git"
   178  	updates := dependencymatrix.DependencyUpdates{
   179  		Updates: []v1.DependencyUpdate{
   180  			{
   181  				DependencyUpdateDetails: v1.DependencyUpdateDetails{
   182  					Host:               host,
   183  					Owner:              testOrgName,
   184  					Repo:               testRepoName,
   185  					URL:                fmt.Sprintf("https://%s/%s/%s.git", host, testOrgName, testRepoName),
   186  					ToReleaseHTMLURL:   fmt.Sprintf("https://%s/%s/%s/releases/%s", host, testOrgName, testRepoName, toTag),
   187  					ToVersion:          toVersion,
   188  					ToReleaseName:      toVersion,
   189  					FromReleaseHTMLURL: fmt.Sprintf("https://%s/%s/%s/releases/%s", host, testOrgName, testRepoName, fromTag),
   190  					FromReleaseName:    fromVersion,
   191  					FromVersion:        fromVersion,
   192  				},
   193  				Paths: []v1.DependencyUpdatePath{
   194  					{
   195  						{
   196  							Host:               host,
   197  							Owner:              testOrgName,
   198  							Repo:               viaRepo,
   199  							URL:                fmt.Sprintf("https://%s/%s/%s.git", host, testOrgName, viaRepo),
   200  							ToReleaseHTMLURL:   fmt.Sprintf("https://%s/%s/%s/releases/%s", host, testOrgName, viaRepo, toTag),
   201  							ToVersion:          toVersion,
   202  							ToReleaseName:      toVersion,
   203  							FromReleaseHTMLURL: fmt.Sprintf("https://%s/%s/%s/releases/%s", host, testOrgName, viaRepo, fromTag),
   204  							FromReleaseName:    fromVersion,
   205  							FromVersion:        fromVersion,
   206  						},
   207  					},
   208  				},
   209  			},
   210  		},
   211  	}
   212  
   213  	updateBytes, err := yaml.Marshal(updates)
   214  	assert.NoError(t, err)
   215  
   216  	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   217  		w.Header().Set("Content-Type", "application/yaml")
   218  		w.WriteHeader(200)
   219  		fmt.Fprintf(w, string(updateBytes))
   220  	}))
   221  
   222  	gitter := gits_test.NewMockGitter()
   223  
   224  	fakeRepo, _ := gits.NewFakeRepository(testOrgName, testRepoName, nil, nil)
   225  	fakeRepo.Releases = map[string]*gits.GitRelease{
   226  		"release-1": {
   227  			Name:    "Release 1",
   228  			TagName: "1.0.0",
   229  			HTMLURL: "fakeUrlv1",
   230  		},
   231  		"release-3": {
   232  			Name:    "Release 3",
   233  			TagName: "3.0.0",
   234  			HTMLURL: "fakeUrlv3",
   235  			Assets: &[]gits.GitReleaseAsset{
   236  				{
   237  					ID:                 1,
   238  					Name:               dependencymatrix.DependencyUpdatesAssetName,
   239  					BrowserDownloadURL: server.URL,
   240  					ContentType:        "application/json",
   241  				},
   242  			},
   243  		},
   244  	}
   245  	fakeGitProvider := gits.NewFakeProvider(fakeRepo)
   246  	fakeGitProvider.User.Username = testOrgName
   247  
   248  	testhelpers.ConfigureTestOptionsWithResources(o.CommonOptions,
   249  		[]runtime.Object{},
   250  		[]runtime.Object{},
   251  		gitter,
   252  		fakeGitProvider,
   253  		nil,
   254  		resources_test.NewMockInstaller(),
   255  	)
   256  
   257  	err = testhelpers.CreateTestEnvironmentDir(o.CommonOptions)
   258  	assert.NoError(t, err)
   259  
   260  	o.GitURLs = []string{"testowner/testrepo"}
   261  	o.SrcGitURL = "testowner/testrepo"
   262  	o.Version = "3.0.0"
   263  
   264  	pegomock.When(gitter.HasChanges(pegomock.AnyString())).ThenReturn(true, nil)
   265  
   266  	var results *gits.PullRequestInfo
   267  
   268  	logOutput := log.CaptureOutput(func() {
   269  		results, err = o.CreatePullRequest("test", func(dir string, gitInfo *gits.GitRepository) (strings []string, e error) {
   270  			return []string{"1.0.0", "v1.0.1", "2.0.0"}, nil
   271  		})
   272  		assert.NoError(t, err)
   273  		assert.NotNil(t, results)
   274  	})
   275  
   276  	assert.Contains(t, stripansi.Strip(logOutput), "Added label updatebot to Pull Request https://fake.git/testowner/testrepo/pulls/1",
   277  		"Updatebot label should be added to the PR")
   278  
   279  	assert.NotNil(t, results, "we must have results coming out of the PR creation")
   280  	assert.Equal(t, "chore(deps): bump testowner/testrepo from 1.0.0, 2.0.0 and v1.0.1 to 3.0.0",
   281  		results.PullRequestArguments.Title, "The PR title should contain the old and new versions")
   282  }
   283  
   284  func TestCreateDependencyUpdatePRDetails(t *testing.T) {
   285  	_, _, _, commonOpts, _ := getFakeClientsAndNs(t)
   286  
   287  	commonOpts.SetGit(gits.NewGitFake())
   288  	o := operations.PullRequestOperation{
   289  		CommonOptions: &commonOpts,
   290  	}
   291  
   292  	gitter := gits_test.NewMockGitter()
   293  
   294  	testOrgName := "testowner"
   295  	testRepoName := "testrepo"
   296  	gitRepo := fmt.Sprintf("%s/%s", testOrgName, testRepoName)
   297  	fakeRepo, _ := gits.NewFakeRepository(testOrgName, testRepoName, nil, nil)
   298  	fakeRepo.Releases = map[string]*gits.GitRelease{
   299  		"release-1": {
   300  			Name:    "Release 1",
   301  			TagName: "1.0.0",
   302  			HTMLURL: "fakeUrlv1",
   303  		},
   304  		"release-2": {
   305  			Name:    "Release 2",
   306  			TagName: "2.0.0",
   307  			HTMLURL: "fakeUrlv2",
   308  			Assets: &[]gits.GitReleaseAsset{
   309  				{
   310  					ID:                 1,
   311  					Name:               "Asset1",
   312  					BrowserDownloadURL: "fakeURL",
   313  					ContentType:        "application/json",
   314  				},
   315  			},
   316  		},
   317  	}
   318  	fakeGitProvider := gits.NewFakeProvider(fakeRepo)
   319  	fakeGitProvider.User.Username = testOrgName
   320  
   321  	testhelpers.ConfigureTestOptionsWithResources(o.CommonOptions,
   322  		[]runtime.Object{},
   323  		[]runtime.Object{},
   324  		gitter,
   325  		fakeGitProvider,
   326  		nil,
   327  		resources_test.NewMockInstaller(),
   328  	)
   329  
   330  	err := testhelpers.CreateTestEnvironmentDir(o.CommonOptions)
   331  	assert.NoError(t, err)
   332  
   333  	componentName := "testComponent"
   334  	fromVersion := "1.0.0"
   335  	toVersion := "2.0.0"
   336  	kind := "fakekind"
   337  	_, details, _, assets, err := o.CreateDependencyUpdatePRDetails(kind, gitRepo, "", fromVersion, toVersion, componentName)
   338  
   339  	assert.Contains(t, details.BranchName, fmt.Sprintf("bump-%s-version", kind))
   340  	assert.Contains(t, details.Message, fmt.Sprintf("Update [%s](%s):%s from [%s](fakeUrlv1) to [%s](fakeUrlv2)", gitRepo, gitRepo, componentName, fromVersion, toVersion))
   341  	assert.Len(t, assets, 1)
   342  }
   343  
   344  func TestAddDependencyMatrixUpdatePaths(t *testing.T) {
   345  	testOrgName := "testowner"
   346  	testRepoName := "testrepo"
   347  	viaRepo := "wiley"
   348  	toVersion := "3.0.0"
   349  	fromVersion := "1.0.0"
   350  	toTag := fmt.Sprintf("v%s", toVersion)
   351  	fromTag := fmt.Sprintf("v%s", fromVersion)
   352  	host := "fake.git"
   353  	updates := dependencymatrix.DependencyUpdates{
   354  		Updates: []v1.DependencyUpdate{
   355  			{
   356  				DependencyUpdateDetails: v1.DependencyUpdateDetails{
   357  					Host:               host,
   358  					Owner:              testOrgName,
   359  					Repo:               testRepoName,
   360  					URL:                fmt.Sprintf("https://%s/%s/%s.git", host, testOrgName, testRepoName),
   361  					ToReleaseHTMLURL:   fmt.Sprintf("https://%s/%s/%s/releases/%s", host, testOrgName, testRepoName, toTag),
   362  					ToVersion:          toVersion,
   363  					ToReleaseName:      toVersion,
   364  					FromReleaseHTMLURL: fmt.Sprintf("https://%s/%s/%s/releases/%s", host, testOrgName, testRepoName, fromTag),
   365  					FromReleaseName:    fromVersion,
   366  					FromVersion:        fromVersion,
   367  				},
   368  				Paths: []v1.DependencyUpdatePath{
   369  					{
   370  						{
   371  							Host:               host,
   372  							Owner:              testOrgName,
   373  							Repo:               viaRepo,
   374  							URL:                fmt.Sprintf("https://%s/%s/%s.git", host, testOrgName, viaRepo),
   375  							ToReleaseHTMLURL:   fmt.Sprintf("https://%s/%s/%s/releases/%s", host, testOrgName, viaRepo, toTag),
   376  							ToVersion:          toVersion,
   377  							ToReleaseName:      toVersion,
   378  							FromReleaseHTMLURL: fmt.Sprintf("https://%s/%s/%s/releases/%s", host, testOrgName, viaRepo, fromTag),
   379  							FromReleaseName:    fromVersion,
   380  							FromVersion:        fromVersion,
   381  						},
   382  					},
   383  				},
   384  			},
   385  		},
   386  	}
   387  
   388  	updateBytes, err := yaml.Marshal(updates)
   389  	assert.NoError(t, err)
   390  
   391  	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   392  		w.Header().Set("Content-Type", "application/yaml")
   393  		w.WriteHeader(200)
   394  		fmt.Fprintf(w, string(updateBytes))
   395  	}))
   396  
   397  	asset := &gits.GitReleaseAsset{
   398  		ID:                 1,
   399  		BrowserDownloadURL: server.URL,
   400  		ContentType:        "application/yaml",
   401  		Name:               dependencymatrix.DependencyUpdatesAssetName,
   402  	}
   403  
   404  	update := &v1.DependencyUpdate{
   405  		DependencyUpdateDetails: v1.DependencyUpdateDetails{
   406  			Host:               host,
   407  			Owner:              testOrgName,
   408  			Repo:               testRepoName,
   409  			URL:                fmt.Sprintf("https://%s/%s/%s.git", host, testOrgName, testRepoName),
   410  			ToReleaseHTMLURL:   fmt.Sprintf("https://%s/%s/%s/releases/%s", host, testOrgName, testRepoName, toTag),
   411  			ToVersion:          "2,0,0",
   412  			ToReleaseName:      "2,0,0",
   413  			FromReleaseHTMLURL: fmt.Sprintf("https://%s/%s/%s/releases/%s", host, testOrgName, testRepoName, fromTag),
   414  			FromReleaseName:    fromVersion,
   415  			FromVersion:        fromVersion,
   416  		},
   417  		Paths: []v1.DependencyUpdatePath{
   418  			{
   419  				{
   420  					Host:               host,
   421  					Owner:              testOrgName,
   422  					Repo:               viaRepo,
   423  					URL:                fmt.Sprintf("https://%s/%s/%s.git", host, testOrgName, viaRepo),
   424  					ToReleaseHTMLURL:   fmt.Sprintf("https://%s/%s/%s/releases/%s", host, testOrgName, viaRepo, toTag),
   425  					ToVersion:          "2,0,0",
   426  					ToReleaseName:      "2,0,0",
   427  					FromReleaseHTMLURL: fmt.Sprintf("https://%s/%s/%s/releases/%s", host, testOrgName, viaRepo, fromTag),
   428  					FromReleaseName:    fromVersion,
   429  					FromVersion:        fromVersion,
   430  				},
   431  			},
   432  		},
   433  	}
   434  
   435  	dependencyUpdate, err := operations.AddDependencyMatrixUpdatePaths(asset, update)
   436  	assert.NoError(t, err)
   437  	assert.Len(t, dependencyUpdate[0].Paths[0], 2)
   438  }
   439  
   440  // Helper method, not supposed to be a test by itself
   441  func getFakeClientsAndNs(t *testing.T) (versioned.Interface, tektonclient.Interface, kubernetes.Interface, opts.CommonOptions, string) {
   442  	commonOpts := opts.NewCommonOptionsWithFactory(fake.NewFakeFactory())
   443  	options := &commonOpts
   444  	testhelpers.ConfigureTestOptions(options, options.Git(), options.Helm())
   445  
   446  	jxClient, ns, err := options.JXClientAndDevNamespace()
   447  	assert.NoError(t, err, "There shouldn't be any error getting the fake JXClient and DevEnv")
   448  
   449  	tektonClient, _, err := options.TektonClient()
   450  	assert.NoError(t, err, "There shouldn't be any error getting the fake Tekton Client")
   451  
   452  	kubeClient, err := options.KubeClient()
   453  	assert.NoError(t, err, "There shouldn't be any error getting the fake Kube Client")
   454  
   455  	return jxClient, tektonClient, kubeClient, commonOpts, ns
   456  }
   457  
   458  func TestCreatePullRequestBuildersFn(t *testing.T) {
   459  	fn := operations.CreatePullRequestBuildersFn("1.0.1")
   460  	dir, err := ioutil.TempDir("", "")
   461  	defer func() {
   462  		err := os.RemoveAll(dir)
   463  		assert.NoError(t, err)
   464  	}()
   465  	assert.NoError(t, err)
   466  	err = util.CopyDir(filepath.Join("testdata", "CreatePullRequestBuildersFn"), dir, true)
   467  	assert.NoError(t, err)
   468  	var gitInfo *gits.GitRepository
   469  	result, err := fn(dir, gitInfo)
   470  	assert.NoError(t, err)
   471  	tests.AssertFileContains(t, filepath.Join(dir, "docker", "gcr.io", "jenkinsxio", "builder-cf.yml"), "version: 1.0.1")
   472  	tests.AssertFileContains(t, filepath.Join(dir, "docker", "gcr.io", "jenkinsxio", "builder-dlang.yml"), "version: 1.0.1")
   473  	tests.AssertFileContains(t, filepath.Join(dir, "docker", "gcr.io", "jenkinsxio", "builder-base.yml"), "version: 0.0.1")
   474  	assert.Contains(t, result, "0.0.1")
   475  	assert.Contains(t, result, "0.0.2")
   476  	assert.Len(t, result, 2)
   477  }
   478  
   479  func TestCreatePullRequestGitReleasesFn(t *testing.T) {
   480  	t.Run("found", func(t *testing.T) {
   481  		pegomock.RegisterMockTestingT(t)
   482  		commonOpts := &opts.CommonOptions{}
   483  		gitter := gits.NewGitCLI()
   484  		roadRunnerOrg, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
   485  			return ioutil.WriteFile(filepath.Join(dir, "README"), []byte("TODO"), 0600)
   486  		}, gitter)
   487  		assert.NoError(t, err)
   488  		gitProvider := gits.NewFakeProvider(roadRunnerOrg)
   489  		roadRunnerOrg.Releases["v1.2.3"] = &gits.GitRelease{
   490  			Name: "1.2.3",
   491  		}
   492  		helmer := helm_test.NewMockHelmer()
   493  
   494  		testhelpers.ConfigureTestOptionsWithResources(commonOpts,
   495  			[]runtime.Object{},
   496  			[]runtime.Object{
   497  				kube.NewPermanentEnvironment("EnvWhereApplicationIsDeployed"),
   498  			},
   499  			gitter,
   500  			gitProvider,
   501  			helmer,
   502  			resources_test.NewMockInstaller(),
   503  		)
   504  
   505  		pro := operations.PullRequestOperation{
   506  			CommonOptions: commonOpts,
   507  			SrcGitURL:     "",
   508  			Version:       "",
   509  		}
   510  
   511  		fn := pro.CreatePullRequestGitReleasesFn("fake.git/acme/roadrunner")
   512  		dir, err := ioutil.TempDir("", "")
   513  		defer func() {
   514  			err := os.RemoveAll(dir)
   515  			assert.NoError(t, err)
   516  		}()
   517  		assert.NoError(t, err)
   518  		err = util.CopyDir(filepath.Join("testdata", "CreatePullRequestGitReleasesFn"), dir, true)
   519  		assert.NoError(t, err)
   520  		oldVersions, err := fn(dir, nil)
   521  		assert.NoError(t, err)
   522  		assert.Len(t, oldVersions, 1)
   523  		assert.Equal(t, "1.2.2", oldVersions[0])
   524  		tests.AssertFileContains(t, filepath.Join(dir, "git", "fake.git", "acme", "roadrunner.yml"), "version: 1.2.3")
   525  	})
   526  	t.Run("not-found", func(t *testing.T) {
   527  		pegomock.RegisterMockTestingT(t)
   528  		commonOpts := &opts.CommonOptions{}
   529  		gitter := gits.NewGitCLI()
   530  		roadRunnerOrg, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
   531  			return ioutil.WriteFile(filepath.Join(dir, "README"), []byte("TODO"), 0600)
   532  		}, gitter)
   533  		assert.NoError(t, err)
   534  		gitProvider := gits.NewFakeProvider(roadRunnerOrg)
   535  		helmer := helm_test.NewMockHelmer()
   536  
   537  		testhelpers.ConfigureTestOptionsWithResources(commonOpts,
   538  			[]runtime.Object{},
   539  			[]runtime.Object{
   540  				kube.NewPermanentEnvironment("EnvWhereApplicationIsDeployed"),
   541  			},
   542  			gitter,
   543  			gitProvider,
   544  			helmer,
   545  			resources_test.NewMockInstaller(),
   546  		)
   547  
   548  		pro := operations.PullRequestOperation{
   549  			CommonOptions: commonOpts,
   550  			SrcGitURL:     "",
   551  			Version:       "",
   552  		}
   553  
   554  		fn := pro.CreatePullRequestGitReleasesFn("fake.git/acme/roadrunner")
   555  		dir, err := ioutil.TempDir("", "")
   556  		defer func() {
   557  			err := os.RemoveAll(dir)
   558  			assert.NoError(t, err)
   559  		}()
   560  		assert.NoError(t, err)
   561  		err = util.CopyDir(filepath.Join("testdata", "CreatePullRequestGitReleasesFn"), dir, true)
   562  		assert.NoError(t, err)
   563  		oldVersions, err := fn(dir, nil)
   564  		assert.Error(t, err)
   565  		assert.Len(t, oldVersions, 0)
   566  		tests.AssertFileContains(t, filepath.Join(dir, "git", "fake.git", "acme", "roadrunner.yml"), "version: 1.2.2")
   567  	})
   568  }
   569  
   570  func TestCreatePullRequestRegexFn(t *testing.T) {
   571  	t.Run("capture-groups", func(t *testing.T) {
   572  
   573  		dir, err := ioutil.TempDir("", "")
   574  		defer func() {
   575  			err := os.RemoveAll(dir)
   576  			assert.NoError(t, err)
   577  		}()
   578  		assert.NoError(t, err)
   579  		err = util.CopyDir(filepath.Join("testdata", "CreatePullRequestRegexFn"), dir, true)
   580  		assert.NoError(t, err)
   581  		fn, err := operations.CreatePullRequestRegexFn("1.0.1", "^version: (.*)$", "builder-dlang.yml")
   582  		assert.NoError(t, err)
   583  		var gitInfo *gits.GitRepository
   584  		result, err := fn(dir, gitInfo)
   585  		assert.NoError(t, err)
   586  		tests.AssertFileContains(t, filepath.Join(dir, "builder-dlang.yml"), "version: 1.0.1")
   587  		assert.Contains(t, result, "0.0.1")
   588  		assert.Len(t, result, 1)
   589  	})
   590  	t.Run("named-capture", func(t *testing.T) {
   591  
   592  		dir, err := ioutil.TempDir("", "")
   593  		defer func() {
   594  			err := os.RemoveAll(dir)
   595  			assert.NoError(t, err)
   596  		}()
   597  		assert.NoError(t, err)
   598  		err = util.CopyDir(filepath.Join("testdata", "CreatePullRequestRegexFn"), dir, true)
   599  		assert.NoError(t, err)
   600  		fn, err := operations.CreatePullRequestRegexFn("1.0.1", `^version: (?P<version>.*)$`, "builder-dlang.yml")
   601  		assert.NoError(t, err)
   602  		var gitInfo *gits.GitRepository
   603  		result, err := fn(dir, gitInfo)
   604  		assert.NoError(t, err)
   605  		tests.AssertFileContains(t, filepath.Join(dir, "builder-dlang.yml"), "version: 1.0.1")
   606  		assert.Contains(t, result, "0.0.1")
   607  		assert.Len(t, result, 1)
   608  	})
   609  	t.Run("multiple-named-capture", func(t *testing.T) {
   610  
   611  		dir, err := ioutil.TempDir("", "")
   612  		defer func() {
   613  			err := os.RemoveAll(dir)
   614  			assert.NoError(t, err)
   615  		}()
   616  		assert.NoError(t, err)
   617  		err = util.CopyDir(filepath.Join("testdata", "CreatePullRequestRegexFn"), dir, true)
   618  		assert.NoError(t, err)
   619  		fn, err := operations.CreatePullRequestRegexFn("1.0.1", `(?m)^(\s*)version: (?P<version>.*)$`, "builder-cf.yml")
   620  		assert.NoError(t, err)
   621  		var gitInfo *gits.GitRepository
   622  		result, err := fn(dir, gitInfo)
   623  		assert.NoError(t, err)
   624  		tests.AssertFileContains(t, filepath.Join(dir, "builder-cf.yml"), `abc:
   625    version: 1.0.1
   626  def:
   627    version: 1.0.1`)
   628  		assert.Contains(t, result, "0.0.1")
   629  		assert.Contains(t, result, "0.0.2")
   630  		assert.Len(t, result, 2)
   631  	})
   632  }
   633  
   634  func TestCreateChartChangeFilesFn(t *testing.T) {
   635  	t.Run("from-chart-sources", func(t *testing.T) {
   636  		pegomock.RegisterMockTestingT(t)
   637  		helmer := helm_test.NewMockHelmer()
   638  		helm_test.StubFetchChart("acme/roadrunner", "1.0.1", "", &chart.Chart{
   639  			Metadata: &chart.Metadata{
   640  				Name:    "roadrunner",
   641  				Version: "1.0.1",
   642  				Sources: []string{
   643  					"https://fake.git/acme/roadrunner",
   644  				},
   645  			},
   646  		}, helmer)
   647  		vaultClient := vault_test.NewMockClient()
   648  		pro := operations.PullRequestOperation{}
   649  		fn := operations.CreateChartChangeFilesFn("acme/roadrunner", "1.0.1", "charts", &pro, helmer, vaultClient, util.IOFileHandles{})
   650  		dir, err := ioutil.TempDir("", "")
   651  		defer func() {
   652  			err := os.RemoveAll(dir)
   653  			assert.NoError(t, err)
   654  		}()
   655  		assert.NoError(t, err)
   656  		err = util.CopyDir(filepath.Join("testdata/TestCreateChartChangeFilesFn"), dir, true)
   657  		assert.NoError(t, err)
   658  		answer, err := fn(dir, nil)
   659  		assert.NoError(t, err)
   660  		assert.Len(t, answer, 1)
   661  		assert.Contains(t, answer, "1.0.0")
   662  		tests.AssertFileContains(t, filepath.Join(dir, "charts", "acme", "roadrunner.yml"), "version: 1.0.1")
   663  		assert.Equal(t, "https://fake.git/acme/roadrunner", pro.SrcGitURL)
   664  		assert.Equal(t, "1.0.1", pro.Version)
   665  	})
   666  	t.Run("from-versions", func(t *testing.T) {
   667  		pegomock.RegisterMockTestingT(t)
   668  		helmer := helm_test.NewMockHelmer()
   669  		helm_test.StubFetchChart("acme/wile", "1.0.1", "", &chart.Chart{
   670  			Metadata: &chart.Metadata{
   671  				Name:    "wile",
   672  				Version: "1.0.1",
   673  			},
   674  		}, helmer)
   675  		vaultClient := vault_test.NewMockClient()
   676  		pro := operations.PullRequestOperation{}
   677  		fn := operations.CreateChartChangeFilesFn("acme/wile", "1.0.1", "charts", &pro, helmer, vaultClient, util.IOFileHandles{})
   678  		dir, err := ioutil.TempDir("", "")
   679  		defer func() {
   680  			err := os.RemoveAll(dir)
   681  			assert.NoError(t, err)
   682  		}()
   683  		assert.NoError(t, err)
   684  		err = util.CopyDir(filepath.Join("testdata/TestCreateChartChangeFilesFn"), dir, true)
   685  		assert.NoError(t, err)
   686  		answer, err := fn(dir, nil)
   687  		assert.NoError(t, err)
   688  		assert.Len(t, answer, 1)
   689  		assert.Contains(t, answer, "1.0.0")
   690  		tests.AssertFileContains(t, filepath.Join(dir, "charts", "acme", "wile.yml"), "version: 1.0.1")
   691  		assert.Equal(t, "https://fake.git/acme/wile", pro.SrcGitURL)
   692  		assert.Equal(t, "1.0.1", pro.Version)
   693  	})
   694  	t.Run("latest", func(t *testing.T) {
   695  		pegomock.RegisterMockTestingT(t)
   696  		helmer := helm_test.NewMockHelmer()
   697  		pegomock.When(helmer.SearchCharts(pegomock.EqString("acme/wile"), pegomock.EqBool(true))).ThenReturn(pegomock.ReturnValue([]helm.ChartSummary{
   698  			{
   699  				Name:         "wile",
   700  				ChartVersion: "1.0.1",
   701  				AppVersion:   "1.0.1",
   702  				Description:  "",
   703  			},
   704  			{
   705  				Name:         "wile",
   706  				ChartVersion: "1.0.0",
   707  				AppVersion:   "1.0.0",
   708  				Description:  "",
   709  			},
   710  		}), pegomock.ReturnValue(nil))
   711  		helm_test.StubFetchChart("acme/wile", "1.0.1", "", &chart.Chart{
   712  			Metadata: &chart.Metadata{
   713  				Name:    "wile",
   714  				Version: "1.0.1",
   715  			},
   716  		}, helmer)
   717  		pegomock.When(helmer.IsRepoMissing("https://acme.com/charts")).ThenReturn(pegomock.ReturnValue(false), pegomock.ReturnValue("acme"), pegomock.ReturnValue(nil))
   718  		vaultClient := vault_test.NewMockClient()
   719  		pro := operations.PullRequestOperation{}
   720  		fn := operations.CreateChartChangeFilesFn("acme/wile", "", "charts", &pro, helmer, vaultClient, util.IOFileHandles{})
   721  		dir, err := ioutil.TempDir("", "")
   722  		defer func() {
   723  			err := os.RemoveAll(dir)
   724  			assert.NoError(t, err)
   725  		}()
   726  		assert.NoError(t, err)
   727  		err = util.CopyDir(filepath.Join("testdata/TestCreateChartChangeFilesFn"), dir, true)
   728  		assert.NoError(t, err)
   729  		answer, err := fn(dir, nil)
   730  		assert.NoError(t, err)
   731  		assert.Len(t, answer, 1)
   732  		assert.Contains(t, answer, "1.0.0")
   733  		tests.AssertFileContains(t, filepath.Join(dir, "charts", "acme", "wile.yml"), "version: 1.0.1")
   734  		assert.Equal(t, "https://fake.git/acme/wile", pro.SrcGitURL)
   735  		assert.Equal(t, "1.0.1", pro.Version)
   736  	})
   737  
   738  }
   739  
   740  func TestPullRequestOperation_WrapChangeFilesWithCommitFn(t *testing.T) {
   741  
   742  	commonOpts := &opts.CommonOptions{}
   743  	gitter := gits.NewGitCLI()
   744  	roadRunnerOrg, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
   745  		return ioutil.WriteFile(filepath.Join(dir, "README"), []byte("TODO"), 0600)
   746  	}, gitter)
   747  	assert.NoError(t, err)
   748  	wileOrg, err := gits.NewFakeRepository("acme", "wile", func(dir string) error {
   749  		return ioutil.WriteFile(filepath.Join(dir, "README"), []byte("TODO"), 0600)
   750  	}, gitter)
   751  	assert.NoError(t, err)
   752  	gitProvider := gits.NewFakeProvider(roadRunnerOrg, wileOrg)
   753  	helmer := helm_test.NewMockHelmer()
   754  
   755  	testhelpers.ConfigureTestOptionsWithResources(commonOpts,
   756  		[]runtime.Object{},
   757  		[]runtime.Object{
   758  			kube.NewPermanentEnvironment("EnvWhereApplicationIsDeployed"),
   759  		},
   760  		gitter,
   761  		gitProvider,
   762  		helmer,
   763  		resources_test.NewMockInstaller(),
   764  	)
   765  
   766  	wrapped := func(dir string, gitInfo *gits.GitRepository) ([]string, error) {
   767  		return []string{"1.2.2"}, ioutil.WriteFile(filepath.Join(dir, "test.yml"), []byte("version: 1.2.3"), 0600)
   768  	}
   769  	pro := operations.PullRequestOperation{
   770  		CommonOptions: commonOpts,
   771  		SrcGitURL:     "https://fake.git/acme/wile.git",
   772  		Version:       "1.2.3",
   773  	}
   774  
   775  	dir, err := ioutil.TempDir("", "")
   776  	defer func() {
   777  		err := os.RemoveAll(dir)
   778  		assert.NoError(t, err)
   779  	}()
   780  	assert.NoError(t, err)
   781  	err = gitter.Init(dir)
   782  	assert.NoError(t, err)
   783  	err = ioutil.WriteFile(filepath.Join(dir, "test.yml"), []byte("1.2.2"), 0600)
   784  	assert.NoError(t, err)
   785  	err = gitter.Add(dir, "*")
   786  	assert.NoError(t, err)
   787  	err = gitter.CommitDir(dir, "Initial commit")
   788  	assert.NoError(t, err)
   789  
   790  	gitInfo, err := gits.ParseGitURL("https://fake.git/acme/roadrunner.git")
   791  	assert.NoError(t, err)
   792  
   793  	fn := pro.WrapChangeFilesWithCommitFn("charts", wrapped)
   794  	result, err := fn(dir, gitInfo)
   795  	assert.NoError(t, err)
   796  	assert.Len(t, result, 0)
   797  	tests.AssertFileContains(t, filepath.Join(dir, "test.yml"), "1.2.3")
   798  	msg, err := gitter.GetLatestCommitMessage(dir)
   799  	assert.NoError(t, err)
   800  	assert.True(t, strings.HasPrefix(msg, "chore(deps): bump acme/wile from 1.2.2 to 1.2.3"))
   801  	// Without AuthorName and AuthorEmail, there shouldn't be a Signed-off-by message.
   802  	assert.False(t, strings.Contains(msg, "Signed-off-by:"))
   803  
   804  	// Wrap another commit, but this time with AuthorName and AuthorEmail set.
   805  	wrappedWithAuthor := func(dir string, gitInfo *gits.GitRepository) ([]string, error) {
   806  		return []string{"1.2.3"}, ioutil.WriteFile(filepath.Join(dir, "test.yml"), []byte("version: 1.2.4"), 0600)
   807  	}
   808  	pro.AuthorEmail = "someone@example.com"
   809  	pro.AuthorName = "Some Author"
   810  	pro.Version = "1.2.4"
   811  	fnWithAuthor := pro.WrapChangeFilesWithCommitFn("charts", wrappedWithAuthor)
   812  	resultWithAuthor, err := fnWithAuthor(dir, gitInfo)
   813  	assert.NoError(t, err)
   814  	assert.Len(t, resultWithAuthor, 0)
   815  	tests.AssertFileContains(t, filepath.Join(dir, "test.yml"), "1.2.4")
   816  	msgWithAuthor, err := gitter.GetLatestCommitMessage(dir)
   817  	assert.NoError(t, err)
   818  	assert.True(t, strings.HasPrefix(msgWithAuthor, "chore(deps): bump acme/wile from 1.2.3 to 1.2.4"))
   819  	assert.True(t, strings.HasSuffix(msgWithAuthor, "Signed-off-by: Some Author <someone@example.com>"))
   820  }