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

     1  // +build unit
     2  
     3  package gits_test
     4  
     5  import (
     6  	"fmt"
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  	"strconv"
    11  	"strings"
    12  	"testing"
    13  
    14  	"github.com/olli-ai/jx/v2/pkg/config"
    15  	"github.com/olli-ai/jx/v2/pkg/util"
    16  
    17  	"github.com/olli-ai/jx/v2/pkg/tests"
    18  
    19  	"github.com/google/uuid"
    20  	"github.com/olli-ai/jx/v2/pkg/gits"
    21  	"github.com/pkg/errors"
    22  	"github.com/stretchr/testify/assert"
    23  )
    24  
    25  const (
    26  	initialReadme       = "Cheesy!"
    27  	commit1Readme       = "Yet more cheese!"
    28  	commit2Contributing = "Even more cheese!"
    29  	commit3License      = "It's cheesy!"
    30  	contributing        = "CONTRIBUTING"
    31  	readme              = "README"
    32  	license             = "LICENSE"
    33  )
    34  
    35  func TestGetRemoteForURL(t *testing.T) {
    36  	gitter := gits.NewGitCLI()
    37  
    38  	repoDir, err := ioutil.TempDir("", "get-remote-for-url")
    39  	assert.NoError(t, err)
    40  	defer func() {
    41  		_ = os.RemoveAll(repoDir)
    42  	}()
    43  
    44  	err = gitter.Init(repoDir)
    45  	assert.NoError(t, err)
    46  
    47  	remote, err := gits.GetRemoteForURL(repoDir, "http://github.com/acme/foo.git", gitter)
    48  	assert.NoError(t, err)
    49  	assert.Empty(t, remote)
    50  
    51  	err = gitter.AddRemote(repoDir, "origin", "http://github.com/acme/foo.git")
    52  	assert.NoError(t, err)
    53  
    54  	err = gitter.AddRemote(repoDir, "upstream", "http://github.com/acme/bar.git")
    55  	assert.NoError(t, err)
    56  
    57  	remote, err = gits.GetRemoteForURL(repoDir, "http://github.com/acme/foo.git", gitter)
    58  	assert.NoError(t, err)
    59  	assert.Equal(t, "origin", remote)
    60  
    61  	remote, err = gits.GetRemoteForURL(repoDir, "http://github.com/acme/bar.git", gitter)
    62  	assert.NoError(t, err)
    63  	assert.Equal(t, "upstream", remote)
    64  }
    65  
    66  func TestFetchAndMergeOneSHA(t *testing.T) {
    67  	// This forkAndPullTest only uses local repos, so it's safe to use real git
    68  	env := prepareFetchAndMergeTests(t)
    69  	defer env.Cleanup()
    70  	// Test merging one commit
    71  	err := gits.FetchAndMergeSHAs([]string{env.Sha1}, "master", env.BaseSha, "origin", env.LocalDir, env.Gitter)
    72  	assert.NoError(t, err)
    73  	readmeFile, err := ioutil.ReadFile(env.ReadmePath)
    74  	assert.NoError(t, err)
    75  	assert.Equal(t, commit1Readme, string(readmeFile))
    76  }
    77  
    78  func TestFetchAndMergeMultipleSHAs(t *testing.T) {
    79  	// This forkAndPullTest only uses local repos, so it's safe to use real git
    80  	env := prepareFetchAndMergeTests(t)
    81  	defer env.Cleanup()
    82  
    83  	// Test merging two commit
    84  	err := gits.FetchAndMergeSHAs([]string{env.Sha1, env.Sha2}, "master", env.BaseSha, "origin", env.LocalDir,
    85  		env.Gitter)
    86  	assert.NoError(t, err)
    87  	localContributingPath := filepath.Join(env.LocalDir, contributing)
    88  	readmeFile, err := ioutil.ReadFile(env.ReadmePath)
    89  	assert.NoError(t, err)
    90  	assert.Equal(t, commit1Readme, string(readmeFile))
    91  	contributingFile, err := ioutil.ReadFile(localContributingPath)
    92  	assert.NoError(t, err)
    93  	assert.Equal(t, commit2Contributing, string(contributingFile))
    94  }
    95  
    96  func TestFetchAndMergeSHAAgainstNonHEADSHA(t *testing.T) {
    97  	// This forkAndPullTest only uses local repos, so it's safe to use real git
    98  	env := prepareFetchAndMergeTests(t)
    99  	defer env.Cleanup()
   100  
   101  	// Test merging two commit
   102  	err := gits.FetchAndMergeSHAs([]string{env.Sha3}, "master", env.Sha1, "origin", env.LocalDir,
   103  		env.Gitter)
   104  	assert.NoError(t, err)
   105  
   106  	readmeFile, err := ioutil.ReadFile(env.ReadmePath)
   107  	assert.NoError(t, err)
   108  	assert.Equal(t, commit1Readme, string(readmeFile))
   109  
   110  	localContributingPath := filepath.Join(env.LocalDir, contributing)
   111  	_, err = os.Stat(localContributingPath)
   112  	assert.True(t, os.IsNotExist(err))
   113  
   114  	localLicensePath := filepath.Join(env.LocalDir, license)
   115  	licenseFile, err := ioutil.ReadFile(localLicensePath)
   116  	assert.NoError(t, err)
   117  	assert.Equal(t, commit3License, string(licenseFile))
   118  }
   119  
   120  type FetchAndMergeTestEnv struct {
   121  	Gitter     *gits.GitCLI
   122  	BaseSha    string
   123  	LocalDir   string
   124  	Sha1       string
   125  	Sha2       string
   126  	Sha3       string
   127  	ReadmePath string
   128  	Cleanup    func()
   129  }
   130  
   131  func prepareFetchAndMergeTests(t *testing.T) FetchAndMergeTestEnv {
   132  	gitter := gits.NewGitCLI()
   133  
   134  	// Prepare a git repo to forkAndPullTest - this is our "remote"
   135  	remoteDir, err := ioutil.TempDir("", "remote")
   136  	assert.NoError(t, err)
   137  	err = gitter.Init(remoteDir)
   138  	assert.NoError(t, err)
   139  
   140  	readmePath := filepath.Join(remoteDir, readme)
   141  	contributingPath := filepath.Join(remoteDir, contributing)
   142  	licensePath := filepath.Join(remoteDir, license)
   143  	err = ioutil.WriteFile(readmePath, []byte(initialReadme), 0600)
   144  	assert.NoError(t, err)
   145  	err = gitter.Add(remoteDir, readme)
   146  	assert.NoError(t, err)
   147  	err = gitter.CommitDir(remoteDir, "Initial Commit")
   148  	assert.NoError(t, err)
   149  
   150  	// Prepare another git repo, this is local repo
   151  	localDir, err := ioutil.TempDir("", "local")
   152  	assert.NoError(t, err)
   153  	err = gitter.Init(localDir)
   154  	assert.NoError(t, err)
   155  	// Set up the remote
   156  	err = gitter.AddRemote(localDir, "origin", remoteDir)
   157  	assert.NoError(t, err)
   158  	err = gitter.FetchBranch(localDir, "origin", "master")
   159  	assert.NoError(t, err)
   160  	err = gitter.Merge(localDir, "origin/master")
   161  	assert.NoError(t, err)
   162  
   163  	localReadmePath := filepath.Join(localDir, readme)
   164  	readmeFile, err := ioutil.ReadFile(localReadmePath)
   165  	assert.NoError(t, err)
   166  	assert.Equal(t, initialReadme, string(readmeFile))
   167  	baseSha, err := gitter.GetLatestCommitSha(localDir)
   168  	assert.NoError(t, err)
   169  
   170  	err = ioutil.WriteFile(readmePath, []byte(commit1Readme), 0600)
   171  	assert.NoError(t, err)
   172  	err = gitter.Add(remoteDir, readme)
   173  	assert.NoError(t, err)
   174  	err = gitter.CommitDir(remoteDir, "More Cheese")
   175  	assert.NoError(t, err)
   176  	sha1, err := gitter.GetLatestCommitSha(remoteDir)
   177  	assert.NoError(t, err)
   178  
   179  	err = ioutil.WriteFile(contributingPath, []byte(commit2Contributing), 0600)
   180  	assert.NoError(t, err)
   181  	err = gitter.Add(remoteDir, contributing)
   182  	assert.NoError(t, err)
   183  	err = gitter.CommitDir(remoteDir, "Even More Cheese")
   184  	assert.NoError(t, err)
   185  	sha2, err := gitter.GetLatestCommitSha(remoteDir)
   186  	assert.NoError(t, err)
   187  
   188  	// Put some commits on a branch
   189  	branchNameUUID, err := uuid.NewUUID()
   190  	assert.NoError(t, err)
   191  	branchName := branchNameUUID.String()
   192  	err = gitter.CreateBranchFrom(remoteDir, branchName, baseSha)
   193  	assert.NoError(t, err)
   194  	err = gitter.Checkout(remoteDir, branchName)
   195  	assert.NoError(t, err)
   196  
   197  	err = ioutil.WriteFile(licensePath, []byte(commit3License), 0600)
   198  	assert.NoError(t, err)
   199  	err = gitter.Add(remoteDir, license)
   200  	assert.NoError(t, err)
   201  	err = gitter.CommitDir(remoteDir, "Even More Cheese")
   202  	assert.NoError(t, err)
   203  	sha3, err := gitter.GetLatestCommitSha(remoteDir)
   204  	assert.NoError(t, err)
   205  
   206  	return FetchAndMergeTestEnv{
   207  		Gitter:     gitter,
   208  		BaseSha:    baseSha,
   209  		LocalDir:   localDir,
   210  		Sha1:       sha1,
   211  		Sha2:       sha2,
   212  		Sha3:       sha3,
   213  		ReadmePath: localReadmePath,
   214  		Cleanup: func() {
   215  			err := os.RemoveAll(localDir)
   216  			assert.NoError(t, err)
   217  			err = os.RemoveAll(remoteDir)
   218  			assert.NoError(t, err)
   219  		},
   220  	}
   221  }
   222  
   223  func TestIsUnadvertisedObjectError(t *testing.T) {
   224  	// Text copied from an error log
   225  	err := errors.New("failed to clone three times it's likely things wont recover so lets kill the process after 3 attempts, last error: failed to fetch [pull/4042/head:PR-4042 3e1a943c00186c8aa364498201974c9ab734b353] from https://github.com/jenkins-x/jx.git in directory /tmp/git599291101: git output: error: Server does not allow request for unadvertised object 3e1a943c00186c8aa364498201974c9ab734b353: failed to run 'git fetch origin --depth=1 pull/4042/head:PR-4042 3e1a943c00186c8aa364498201974c9ab734b353' command in directory '/tmp/git599291101', output: 'error: Server does not allow request for unadvertised object 3e1a943c00186c8aa364498201974c9ab734b353'")
   226  	assert.True(t, gits.IsUnadvertisedObjectError(err))
   227  	err1 := errors.New("ipsum lorem")
   228  	assert.False(t, gits.IsUnadvertisedObjectError(err1))
   229  }
   230  
   231  type forkAndPullTestArgs struct {
   232  	gitURL     string
   233  	dir        string
   234  	baseRef    string
   235  	branchName string
   236  	provider   *gits.FakeProvider
   237  	gitter     gits.Gitter
   238  	initFn     func(args *forkAndPullTestArgs) error // initFn allows us to run some code at the start of the forkAndPullTest
   239  	cleanFn    func(args *forkAndPullTestArgs)
   240  }
   241  
   242  type forkAndPullTest struct {
   243  	name         string
   244  	args         forkAndPullTestArgs
   245  	dir          string
   246  	baseRef      string
   247  	upstreamInfo *gits.GitRepository
   248  	forkInfo     *gits.GitRepository
   249  	wantErr      bool
   250  	postFn       func(args *forkAndPullTestArgs, test *forkAndPullTest) error
   251  }
   252  
   253  func TestNoForkAndNewDir(t *testing.T) {
   254  
   255  	runForkAndPullTestCase(t, forkAndPullTest{
   256  		name: "noForkAndNewDir",
   257  		args: forkAndPullTestArgs{
   258  			gitter: gits.NewGitCLI(),
   259  			initFn: func(args *forkAndPullTestArgs) error {
   260  				acmeRepo, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
   261  					err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("Hello there!"), 0600)
   262  					if err != nil {
   263  						return errors.WithStack(err)
   264  					}
   265  					return nil
   266  				}, args.gitter)
   267  				assert.NoError(t, err)
   268  				args.provider = gits.NewFakeProvider(acmeRepo)
   269  				uuid, err := uuid.NewUUID()
   270  				assert.NoError(t, err)
   271  				args.dir = filepath.Join(os.TempDir(), fmt.Sprintf("git-dir-%s", uuid.String()))
   272  				return nil
   273  			},
   274  			cleanFn: func(args *forkAndPullTestArgs) {
   275  				for _, o := range args.provider.Repositories {
   276  					for _, r := range o {
   277  						if r.BaseDir != "" {
   278  							err := os.RemoveAll(r.BaseDir)
   279  							assert.NoError(t, err)
   280  						}
   281  					}
   282  				}
   283  				err := os.RemoveAll(args.dir)
   284  				assert.NoError(t, err)
   285  			},
   286  			gitURL:     fmt.Sprintf("https://fake.git/acme/roadrunner.git"),
   287  			dir:        "",  // set by initFn
   288  			provider:   nil, // set by initFn
   289  			branchName: "master",
   290  			baseRef:    "master",
   291  		},
   292  		baseRef: "master",
   293  		upstreamInfo: &gits.GitRepository{
   294  			Name:         "roadrunner",
   295  			URL:          "https://fake.git/acme/roadrunner.git",
   296  			HTMLURL:      "https://fake.git/acme/roadrunner",
   297  			Scheme:       "https",
   298  			Host:         "fake.git",
   299  			Organisation: "acme",
   300  			Fork:         false,
   301  		},
   302  		postFn: func(args *forkAndPullTestArgs, test *forkAndPullTest) error {
   303  			// Need to dynamically set the directories as we make them up in the init
   304  			test.dir = args.dir
   305  			test.upstreamInfo.CloneURL = fmt.Sprintf("file://%s/acme", args.provider.Repositories["acme"][0].BaseDir)
   306  			return nil
   307  		},
   308  	})
   309  }
   310  func TestNewForkAndNewDir(t *testing.T) {
   311  
   312  	runForkAndPullTestCase(t, forkAndPullTest{
   313  		name: "newForkAndNewDir",
   314  		args: forkAndPullTestArgs{
   315  			gitter: gits.NewGitCLI(),
   316  			initFn: func(args *forkAndPullTestArgs) error {
   317  				acmeRepo, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
   318  					err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("Hello there!"), 0600)
   319  					if err != nil {
   320  						return errors.WithStack(err)
   321  					}
   322  					return nil
   323  				}, args.gitter)
   324  				args.provider = gits.NewFakeProvider(acmeRepo)
   325  				// Set the provider username to wile in order to create a fork
   326  				args.provider.User.Username = "wile"
   327  				uuid, err := uuid.NewUUID()
   328  				assert.NoError(t, err)
   329  				args.dir = filepath.Join(os.TempDir(), fmt.Sprintf("git-dir-%s", uuid.String()))
   330  				return nil
   331  			},
   332  			cleanFn: func(args *forkAndPullTestArgs) {
   333  				for _, o := range args.provider.Repositories {
   334  					for _, r := range o {
   335  						if r.BaseDir != "" {
   336  							err := os.RemoveAll(r.BaseDir)
   337  							assert.NoError(t, err)
   338  						}
   339  					}
   340  				}
   341  				err := os.RemoveAll(args.dir)
   342  				assert.NoError(t, err)
   343  			},
   344  			gitURL:     fmt.Sprintf("https://fake.git/acme/roadrunner.git"),
   345  			dir:        "",  // set by initFn
   346  			provider:   nil, // set by initFn
   347  			branchName: "master",
   348  			baseRef:    "master",
   349  		},
   350  		baseRef: "master",
   351  		upstreamInfo: &gits.GitRepository{
   352  			Name:         "roadrunner",
   353  			URL:          "https://fake.git/acme/roadrunner.git",
   354  			HTMLURL:      "https://fake.git/acme/roadrunner",
   355  			Scheme:       "https",
   356  			Host:         "fake.git",
   357  			Organisation: "acme",
   358  			Fork:         false,
   359  		},
   360  		forkInfo: &gits.GitRepository{
   361  			Name:         "roadrunner",
   362  			URL:          "https://fake.git/wile/roadrunner.git",
   363  			HTMLURL:      "https://fake.git/wile/roadrunner",
   364  			Scheme:       "https",
   365  			Host:         "fake.git",
   366  			Organisation: "wile",
   367  			Project:      "wile",
   368  			Fork:         true,
   369  		},
   370  		postFn: func(args *forkAndPullTestArgs, test *forkAndPullTest) error {
   371  			test.dir = args.dir //make sure we end up with the same dir we start with
   372  			test.upstreamInfo.CloneURL = fmt.Sprintf("file://%s/acme", args.provider.Repositories["acme"][0].BaseDir)
   373  			test.forkInfo.CloneURL = fmt.Sprintf("file://%s/wile", args.provider.Repositories["acme"][0].BaseDir)
   374  			remotes, err := args.gitter.Remotes(args.dir)
   375  			assert.NoError(t, err)
   376  			assert.Len(t, remotes, 2)
   377  			assert.Contains(t, remotes, "origin")
   378  			assert.Contains(t, remotes, "upstream")
   379  			return nil
   380  		},
   381  	})
   382  }
   383  func TestNoFormAndExistingDir(t *testing.T) {
   384  
   385  	runForkAndPullTestCase(t, forkAndPullTest{
   386  		name: "noForkAndExistingDir",
   387  		args: forkAndPullTestArgs{
   388  			gitter: gits.NewGitCLI(),
   389  			initFn: func(args *forkAndPullTestArgs) error {
   390  				acmeRepo, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
   391  					err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("Hello there!"), 0600)
   392  					if err != nil {
   393  						return errors.WithStack(err)
   394  					}
   395  					return nil
   396  				}, args.gitter)
   397  				assert.NoError(t, err)
   398  				args.provider = gits.NewFakeProvider(acmeRepo)
   399  
   400  				args.dir, err = ioutil.TempDir("", "")
   401  				assert.NoError(t, err)
   402  				return nil
   403  			},
   404  			cleanFn: func(args *forkAndPullTestArgs) {
   405  				for _, o := range args.provider.Repositories {
   406  					for _, r := range o {
   407  						if r.BaseDir != "" {
   408  							err := os.RemoveAll(r.BaseDir)
   409  							assert.NoError(t, err)
   410  						}
   411  					}
   412  				}
   413  				err := os.RemoveAll(args.dir)
   414  				assert.NoError(t, err)
   415  			},
   416  			gitURL:     fmt.Sprintf("https://fake.git/acme/roadrunner.git"),
   417  			dir:        "",  // set by initFn
   418  			provider:   nil, // set by initFn
   419  			branchName: "master",
   420  			baseRef:    "master",
   421  		},
   422  		baseRef: "master",
   423  		upstreamInfo: &gits.GitRepository{
   424  			Name:         "roadrunner",
   425  			URL:          "https://fake.git/acme/roadrunner.git",
   426  			HTMLURL:      "https://fake.git/acme/roadrunner",
   427  			Scheme:       "https",
   428  			Host:         "fake.git",
   429  			Organisation: "acme",
   430  			Fork:         false,
   431  		},
   432  		postFn: func(args *forkAndPullTestArgs, test *forkAndPullTest) error {
   433  			// Need to dynamically set the directories as we make them up in the init
   434  			test.dir = args.dir
   435  			test.upstreamInfo.CloneURL = fmt.Sprintf("file://%s/acme", args.provider.Repositories["acme"][0].BaseDir)
   436  			return nil
   437  		},
   438  	})
   439  }
   440  
   441  func TestNewForkAndExistingDir(t *testing.T) {
   442  
   443  	runForkAndPullTestCase(t, forkAndPullTest{
   444  		name: "newForkAndExistingDir",
   445  		args: forkAndPullTestArgs{
   446  			gitter: gits.NewGitCLI(),
   447  			initFn: func(args *forkAndPullTestArgs) error {
   448  				acmeRepo, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
   449  					err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("Hello there!"), 0600)
   450  					if err != nil {
   451  						return errors.WithStack(err)
   452  					}
   453  					return nil
   454  				}, args.gitter)
   455  				args.provider = gits.NewFakeProvider(acmeRepo)
   456  				// Set the provider username to wile in order to create a fork
   457  				args.provider.User.Username = "wile"
   458  
   459  				args.dir, err = ioutil.TempDir("", "")
   460  				assert.NoError(t, err)
   461  				return nil
   462  			},
   463  			cleanFn: func(args *forkAndPullTestArgs) {
   464  				for _, o := range args.provider.Repositories {
   465  					for _, r := range o {
   466  						if r.BaseDir != "" {
   467  							err := os.RemoveAll(r.BaseDir)
   468  							assert.NoError(t, err)
   469  						}
   470  					}
   471  				}
   472  				err := os.RemoveAll(args.dir)
   473  				assert.NoError(t, err)
   474  			},
   475  			gitURL:     fmt.Sprintf("https://fake.git/acme/roadrunner.git"),
   476  			dir:        "",  // set by initFn
   477  			provider:   nil, // set by initFn
   478  			branchName: "master",
   479  			baseRef:    "master",
   480  		},
   481  		baseRef: "master",
   482  		upstreamInfo: &gits.GitRepository{
   483  			Name:         "roadrunner",
   484  			URL:          "https://fake.git/acme/roadrunner.git",
   485  			HTMLURL:      "https://fake.git/acme/roadrunner",
   486  			Scheme:       "https",
   487  			Host:         "fake.git",
   488  			Organisation: "acme",
   489  			Fork:         false,
   490  		},
   491  		forkInfo: &gits.GitRepository{
   492  			Name:         "roadrunner",
   493  			URL:          "https://fake.git/wile/roadrunner.git",
   494  			HTMLURL:      "https://fake.git/wile/roadrunner",
   495  			Scheme:       "https",
   496  			Host:         "fake.git",
   497  			Organisation: "wile",
   498  			Project:      "wile",
   499  			Fork:         true,
   500  		},
   501  		postFn: func(args *forkAndPullTestArgs, test *forkAndPullTest) error {
   502  			test.dir = args.dir //make sure we end up with the same dir we start with
   503  			test.upstreamInfo.CloneURL = fmt.Sprintf("file://%s/acme", args.provider.Repositories["acme"][0].BaseDir)
   504  			test.forkInfo.CloneURL = fmt.Sprintf("file://%s/wile", args.provider.Repositories["acme"][0].BaseDir)
   505  			return nil
   506  		},
   507  	})
   508  }
   509  func TestExistingForkAndNewDir(t *testing.T) {
   510  
   511  	runForkAndPullTestCase(t, forkAndPullTest{
   512  		name: "existingForkAndNewDir",
   513  		args: forkAndPullTestArgs{
   514  			gitter: gits.NewGitCLI(),
   515  			initFn: func(args *forkAndPullTestArgs) error {
   516  				acmeRepo, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
   517  					err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("Hello there!"), 0600)
   518  					if err != nil {
   519  						return errors.WithStack(err)
   520  					}
   521  					return nil
   522  				}, args.gitter)
   523  				args.provider = gits.NewFakeProvider(acmeRepo)
   524  				fork, err := args.provider.ForkRepository("acme", "roadrunner", "wile")
   525  				assert.NoError(t, err)
   526  
   527  				// Add a commit to the fork that isn't on the upstream to validate later. Let's use a temp clone and push it.
   528  				dir, err := ioutil.TempDir("", "")
   529  				assert.NoError(t, err)
   530  				err = args.gitter.Clone(fork.CloneURL, dir)
   531  				assert.NoError(t, err)
   532  				err = ioutil.WriteFile(filepath.Join(dir, "CONTRIBUTING"), []byte("Welcome!"), 0600)
   533  				assert.NoError(t, err)
   534  				err = args.gitter.Add(dir, "CONTRIBUTING")
   535  				assert.NoError(t, err)
   536  				err = args.gitter.CommitDir(dir, "Second commit")
   537  				assert.NoError(t, err)
   538  				err = args.gitter.Push(dir, "origin", false, "HEAD")
   539  				assert.NoError(t, err)
   540  
   541  				// Set the provider username to wile in order to use the fork
   542  				args.provider.User.Username = "wile"
   543  				uuid, err := uuid.NewUUID()
   544  				assert.NoError(t, err)
   545  				args.dir = filepath.Join(os.TempDir(), fmt.Sprintf("git-dir-%s", uuid.String()))
   546  				return nil
   547  			},
   548  			cleanFn: func(args *forkAndPullTestArgs) {
   549  				for _, o := range args.provider.Repositories {
   550  					for _, r := range o {
   551  						if r.BaseDir != "" {
   552  							err := os.RemoveAll(r.BaseDir)
   553  							assert.NoError(t, err)
   554  						}
   555  					}
   556  				}
   557  				err := os.RemoveAll(args.dir)
   558  				assert.NoError(t, err)
   559  			},
   560  			gitURL:     fmt.Sprintf("https://fake.git/acme/roadrunner.git"),
   561  			dir:        "",  // set by initFn
   562  			provider:   nil, // set by initFn
   563  			branchName: "master",
   564  			baseRef:    "master",
   565  		},
   566  		baseRef: "master",
   567  		upstreamInfo: &gits.GitRepository{
   568  			Name:         "roadrunner",
   569  			URL:          "https://fake.git/acme/roadrunner.git",
   570  			HTMLURL:      "https://fake.git/acme/roadrunner",
   571  			Scheme:       "https",
   572  			Host:         "fake.git",
   573  			Organisation: "acme",
   574  			Fork:         false,
   575  		},
   576  		forkInfo: &gits.GitRepository{
   577  			Name:         "roadrunner",
   578  			URL:          "https://fake.git/wile/roadrunner.git",
   579  			HTMLURL:      "https://fake.git/wile/roadrunner",
   580  			Scheme:       "https",
   581  			Host:         "fake.git",
   582  			Organisation: "wile",
   583  			Project:      "wile",
   584  			Fork:         true,
   585  		},
   586  		postFn: func(args *forkAndPullTestArgs, test *forkAndPullTest) error {
   587  			test.dir = args.dir //make sure we end up with the same dir we start with
   588  			test.upstreamInfo.CloneURL = fmt.Sprintf("file://%s/acme", args.provider.Repositories["acme"][0].BaseDir)
   589  			test.forkInfo.CloneURL = fmt.Sprintf("file://%s/wile", args.provider.Repositories["acme"][0].BaseDir)
   590  			_, gitConf, err := args.gitter.FindGitConfigDir(args.dir)
   591  			assert.NoError(t, err)
   592  			remotes, err := args.gitter.Remotes(args.dir)
   593  			assert.NoError(t, err)
   594  			assert.Len(t, remotes, 2)
   595  			assert.Contains(t, remotes, "origin")
   596  			assert.Contains(t, remotes, "upstream")
   597  			originURL, err := args.gitter.DiscoverRemoteGitURL(gitConf)
   598  			assert.NoError(t, err)
   599  			upstreamURL, err := args.gitter.DiscoverUpstreamGitURL(gitConf)
   600  			assert.NoError(t, err)
   601  			assert.Equal(t, fmt.Sprintf("file://%s/wile", args.provider.Repositories["acme"][0].BaseDir), originURL)
   602  			assert.Equal(t, fmt.Sprintf("file://%s/acme", args.provider.Repositories["acme"][0].BaseDir), upstreamURL)
   603  			assert.FileExists(t, filepath.Join(args.dir, "CONTRIBUTING"))
   604  			return nil
   605  		},
   606  	})
   607  }
   608  func TestExistingForkAndExistingDir(t *testing.T) {
   609  
   610  	runForkAndPullTestCase(t, forkAndPullTest{
   611  		name: "existingForkAndExistingDir",
   612  		args: forkAndPullTestArgs{
   613  			gitter: gits.NewGitCLI(),
   614  			initFn: func(args *forkAndPullTestArgs) error {
   615  				acmeRepo, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
   616  					err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("Hello there!"), 0600)
   617  					if err != nil {
   618  						return errors.WithStack(err)
   619  					}
   620  					return nil
   621  				}, args.gitter)
   622  				args.provider = gits.NewFakeProvider(acmeRepo)
   623  				fork, err := args.provider.ForkRepository("acme", "roadrunner", "wile")
   624  				assert.NoError(t, err)
   625  
   626  				// Add a commit to the fork that isn't on the upstream to validate later. Let's use a temp clone and push it.
   627  				dir, err := ioutil.TempDir("", "")
   628  				assert.NoError(t, err)
   629  				err = args.gitter.Clone(fork.CloneURL, dir)
   630  				assert.NoError(t, err)
   631  				err = ioutil.WriteFile(filepath.Join(dir, "CONTRIBUTING"), []byte("Welcome!"), 0600)
   632  				assert.NoError(t, err)
   633  				err = args.gitter.Add(dir, "CONTRIBUTING")
   634  				assert.NoError(t, err)
   635  				err = args.gitter.CommitDir(dir, "Second commit")
   636  				assert.NoError(t, err)
   637  				err = args.gitter.Push(dir, "origin", false, "HEAD")
   638  				assert.NoError(t, err)
   639  
   640  				// Set the provider username to wile in order to use the fork
   641  				args.provider.User.Username = "wile"
   642  				args.dir, err = ioutil.TempDir("", "")
   643  				assert.NoError(t, err)
   644  				return nil
   645  			},
   646  			cleanFn: func(args *forkAndPullTestArgs) {
   647  				for _, o := range args.provider.Repositories {
   648  					for _, r := range o {
   649  						if r.BaseDir != "" {
   650  							err := os.RemoveAll(r.BaseDir)
   651  							assert.NoError(t, err)
   652  						}
   653  					}
   654  				}
   655  				err := os.RemoveAll(args.dir)
   656  				assert.NoError(t, err)
   657  			},
   658  			gitURL:     fmt.Sprintf("https://fake.git/acme/roadrunner.git"),
   659  			dir:        "",  // set by initFn
   660  			provider:   nil, // set by initFn
   661  			branchName: "master",
   662  			baseRef:    "master",
   663  		},
   664  		baseRef: "master",
   665  		upstreamInfo: &gits.GitRepository{
   666  			Name:         "roadrunner",
   667  			URL:          "https://fake.git/acme/roadrunner.git",
   668  			HTMLURL:      "https://fake.git/acme/roadrunner",
   669  			Scheme:       "https",
   670  			Host:         "fake.git",
   671  			Organisation: "acme",
   672  			Fork:         false,
   673  		},
   674  		forkInfo: &gits.GitRepository{
   675  			Name:         "roadrunner",
   676  			URL:          "https://fake.git/wile/roadrunner.git",
   677  			HTMLURL:      "https://fake.git/wile/roadrunner",
   678  			Scheme:       "https",
   679  			Host:         "fake.git",
   680  			Organisation: "wile",
   681  			Project:      "wile",
   682  			Fork:         true,
   683  		},
   684  		postFn: func(args *forkAndPullTestArgs, test *forkAndPullTest) error {
   685  			test.dir = args.dir //make sure we end up with the same dir we start with
   686  			test.upstreamInfo.CloneURL = fmt.Sprintf("file://%s/acme", args.provider.Repositories["acme"][0].BaseDir)
   687  			test.forkInfo.CloneURL = fmt.Sprintf("file://%s/wile", args.provider.Repositories["acme"][0].BaseDir)
   688  			_, gitConf, err := args.gitter.FindGitConfigDir(args.dir)
   689  			assert.NoError(t, err)
   690  			remotes, err := args.gitter.Remotes(args.dir)
   691  			assert.NoError(t, err)
   692  			assert.Len(t, remotes, 2)
   693  			assert.Contains(t, remotes, "origin")
   694  			assert.Contains(t, remotes, "upstream")
   695  			originURL, err := args.gitter.DiscoverRemoteGitURL(gitConf)
   696  			assert.NoError(t, err)
   697  			upstreamURL, err := args.gitter.DiscoverUpstreamGitURL(gitConf)
   698  			assert.NoError(t, err)
   699  			assert.Equal(t, fmt.Sprintf("file://%s/wile", args.provider.Repositories["acme"][0].BaseDir), originURL)
   700  			assert.Equal(t, fmt.Sprintf("file://%s/acme", args.provider.Repositories["acme"][0].BaseDir), upstreamURL)
   701  			assert.FileExists(t, filepath.Join(args.dir, "CONTRIBUTING"))
   702  			return nil
   703  		},
   704  	})
   705  }
   706  func TestExistingForkAndExistingCheckout(t *testing.T) {
   707  
   708  	runForkAndPullTestCase(t, forkAndPullTest{
   709  		name: "existingForkAndExistingCheckout",
   710  		args: forkAndPullTestArgs{
   711  			gitter: gits.NewGitCLI(),
   712  			initFn: func(args *forkAndPullTestArgs) error {
   713  				acmeRepo, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
   714  					err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("Hello there!"), 0600)
   715  					if err != nil {
   716  						return errors.WithStack(err)
   717  					}
   718  					return nil
   719  				}, args.gitter)
   720  				args.provider = gits.NewFakeProvider(acmeRepo)
   721  				fork, err := args.provider.ForkRepository("acme", "roadrunner", "wile")
   722  				assert.NoError(t, err)
   723  
   724  				// Add a commit to the fork that isn't on the upstream to validate later. Let's use a temp clone and push it.
   725  				dir, err := ioutil.TempDir("", "")
   726  				assert.NoError(t, err)
   727  				err = args.gitter.Clone(fork.CloneURL, dir)
   728  				assert.NoError(t, err)
   729  				err = ioutil.WriteFile(filepath.Join(dir, "CONTRIBUTING"), []byte("Welcome!"), 0600)
   730  				assert.NoError(t, err)
   731  				err = args.gitter.Add(dir, "CONTRIBUTING")
   732  				assert.NoError(t, err)
   733  				err = args.gitter.CommitDir(dir, "Second commit")
   734  				assert.NoError(t, err)
   735  				err = args.gitter.Push(dir, "origin", false, "HEAD")
   736  				assert.NoError(t, err)
   737  
   738  				// Set the provider username to wile in order to use the fork
   739  				args.provider.User.Username = "wile"
   740  
   741  				// Let's checkout our fork
   742  				args.dir, err = ioutil.TempDir("", "")
   743  				assert.NoError(t, err)
   744  				err = args.gitter.Clone(fork.CloneURL, args.dir)
   745  				assert.NoError(t, err)
   746  
   747  				return nil
   748  			},
   749  			cleanFn: func(args *forkAndPullTestArgs) {
   750  				for _, o := range args.provider.Repositories {
   751  					for _, r := range o {
   752  						if r.BaseDir != "" {
   753  							err := os.RemoveAll(r.BaseDir)
   754  							assert.NoError(t, err)
   755  						}
   756  					}
   757  				}
   758  				err := os.RemoveAll(args.dir)
   759  				assert.NoError(t, err)
   760  			},
   761  			gitURL:     fmt.Sprintf("https://fake.git/acme/roadrunner.git"),
   762  			dir:        "",  // set by initFn
   763  			provider:   nil, // set by initFn
   764  			branchName: "master",
   765  			baseRef:    "master",
   766  		},
   767  		baseRef: "master",
   768  		upstreamInfo: &gits.GitRepository{
   769  			Name:         "roadrunner",
   770  			URL:          "https://fake.git/acme/roadrunner.git",
   771  			HTMLURL:      "https://fake.git/acme/roadrunner",
   772  			Scheme:       "https",
   773  			Host:         "fake.git",
   774  			Organisation: "acme",
   775  			Fork:         false,
   776  		},
   777  		forkInfo: &gits.GitRepository{
   778  			Name:         "roadrunner",
   779  			URL:          "https://fake.git/wile/roadrunner.git",
   780  			HTMLURL:      "https://fake.git/wile/roadrunner",
   781  			Scheme:       "https",
   782  			Host:         "fake.git",
   783  			Organisation: "wile",
   784  			Project:      "wile",
   785  			Fork:         true,
   786  		},
   787  		postFn: func(args *forkAndPullTestArgs, test *forkAndPullTest) error {
   788  			test.dir = args.dir //make sure we end up with the same dir we start with
   789  			test.upstreamInfo.CloneURL = fmt.Sprintf("file://%s/acme", args.provider.Repositories["acme"][0].BaseDir)
   790  			test.forkInfo.CloneURL = fmt.Sprintf("file://%s/wile", args.provider.Repositories["acme"][0].BaseDir)
   791  			_, gitConf, err := args.gitter.FindGitConfigDir(args.dir)
   792  			assert.NoError(t, err)
   793  			remotes, err := args.gitter.Remotes(args.dir)
   794  			assert.NoError(t, err)
   795  			assert.Len(t, remotes, 2)
   796  			assert.Contains(t, remotes, "origin")
   797  			assert.Contains(t, remotes, "upstream")
   798  			originURL, err := args.gitter.DiscoverRemoteGitURL(gitConf)
   799  			assert.NoError(t, err)
   800  			upstreamURL, err := args.gitter.DiscoverUpstreamGitURL(gitConf)
   801  			assert.NoError(t, err)
   802  			assert.Equal(t, fmt.Sprintf("file://%s/wile", args.provider.Repositories["acme"][0].BaseDir), originURL)
   803  			assert.Equal(t, fmt.Sprintf("file://%s/acme", args.provider.Repositories["acme"][0].BaseDir), upstreamURL)
   804  			assert.FileExists(t, filepath.Join(args.dir, "CONTRIBUTING"))
   805  			return nil
   806  		},
   807  	})
   808  }
   809  func TestExistingForkAndExistingCheckoutWithDifferentBaseRef(t *testing.T) {
   810  
   811  	runForkAndPullTestCase(t, forkAndPullTest{
   812  		name: "existingForkAndExistingCheckoutWithDifferentBaseRef",
   813  		args: forkAndPullTestArgs{
   814  			gitter: gits.NewGitCLI(),
   815  			initFn: func(args *forkAndPullTestArgs) error {
   816  				acmeRepo, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
   817  					err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("Hello there!"), 0600)
   818  					if err != nil {
   819  						return errors.WithStack(err)
   820  					}
   821  					return nil
   822  				}, args.gitter)
   823  				args.provider = gits.NewFakeProvider(acmeRepo)
   824  				fork, err := args.provider.ForkRepository("acme", "roadrunner", "wile")
   825  				assert.NoError(t, err)
   826  
   827  				// Add a commit to the upstream on a different branch to validate later. Let's use a temp clone and push it.
   828  				dir, err := ioutil.TempDir("", "")
   829  				assert.NoError(t, err)
   830  				err = args.gitter.Clone(acmeRepo.GitRepo.CloneURL, dir)
   831  				assert.NoError(t, err)
   832  				err = ioutil.WriteFile(filepath.Join(dir, "CONTRIBUTING"), []byte("Welcome!"), 0600)
   833  				assert.NoError(t, err)
   834  				err = args.gitter.Add(dir, "CONTRIBUTING")
   835  				assert.NoError(t, err)
   836  				err = args.gitter.CommitDir(dir, "Second commit")
   837  				assert.NoError(t, err)
   838  				err = args.gitter.ForcePushBranch(dir, "HEAD", "other")
   839  				assert.NoError(t, err)
   840  
   841  				// Set the provider username to wile in order to use the fork
   842  				args.provider.User.Username = "wile"
   843  
   844  				// Let's checkout our fork
   845  				args.dir, err = ioutil.TempDir("", "")
   846  				assert.NoError(t, err)
   847  				err = args.gitter.Clone(fork.CloneURL, args.dir)
   848  				assert.NoError(t, err)
   849  
   850  				return nil
   851  			},
   852  			cleanFn: func(args *forkAndPullTestArgs) {
   853  				for _, o := range args.provider.Repositories {
   854  					for _, r := range o {
   855  						if r.BaseDir != "" {
   856  							err := os.RemoveAll(r.BaseDir)
   857  							assert.NoError(t, err)
   858  						}
   859  					}
   860  				}
   861  				err := os.RemoveAll(args.dir)
   862  				assert.NoError(t, err)
   863  			},
   864  			gitURL:     fmt.Sprintf("https://fake.git/acme/roadrunner.git"),
   865  			dir:        "",  // set by initFn
   866  			provider:   nil, // set by initFn
   867  			branchName: "master",
   868  			baseRef:    "other",
   869  		},
   870  		baseRef: "other",
   871  		upstreamInfo: &gits.GitRepository{
   872  			Name:         "roadrunner",
   873  			URL:          "https://fake.git/acme/roadrunner.git",
   874  			HTMLURL:      "https://fake.git/acme/roadrunner",
   875  			Scheme:       "https",
   876  			Host:         "fake.git",
   877  			Organisation: "acme",
   878  			Fork:         false,
   879  		},
   880  		forkInfo: &gits.GitRepository{
   881  			Name:         "roadrunner",
   882  			URL:          "https://fake.git/wile/roadrunner.git",
   883  			HTMLURL:      "https://fake.git/wile/roadrunner",
   884  			Scheme:       "https",
   885  			Host:         "fake.git",
   886  			Organisation: "wile",
   887  			Project:      "wile",
   888  			Fork:         true,
   889  		},
   890  		postFn: func(args *forkAndPullTestArgs, test *forkAndPullTest) error {
   891  			test.dir = args.dir //make sure we end up with the same dir we start with
   892  			test.upstreamInfo.CloneURL = fmt.Sprintf("file://%s/acme", args.provider.Repositories["acme"][0].BaseDir)
   893  			test.forkInfo.CloneURL = fmt.Sprintf("file://%s/wile", args.provider.Repositories["acme"][0].BaseDir)
   894  			_, gitConf, err := args.gitter.FindGitConfigDir(args.dir)
   895  			assert.NoError(t, err)
   896  			remotes, err := args.gitter.Remotes(args.dir)
   897  			assert.NoError(t, err)
   898  			assert.Len(t, remotes, 2)
   899  			assert.Contains(t, remotes, "origin")
   900  			assert.Contains(t, remotes, "upstream")
   901  			originURL, err := args.gitter.DiscoverRemoteGitURL(gitConf)
   902  			assert.NoError(t, err)
   903  			upstreamURL, err := args.gitter.DiscoverUpstreamGitURL(gitConf)
   904  			assert.NoError(t, err)
   905  			assert.Equal(t, fmt.Sprintf("file://%s/wile", args.provider.Repositories["acme"][0].BaseDir), originURL)
   906  			assert.Equal(t, fmt.Sprintf("file://%s/acme", args.provider.Repositories["acme"][0].BaseDir), upstreamURL)
   907  			assert.FileExists(t, filepath.Join(args.dir, "CONTRIBUTING"))
   908  			return nil
   909  		},
   910  	})
   911  }
   912  func TestExistingForkAndExistingCheckoutWithLocalModifications(t *testing.T) {
   913  
   914  	runForkAndPullTestCase(t, forkAndPullTest{
   915  		name: "existingForkAndExistingCheckoutWithLocalModifications",
   916  		args: forkAndPullTestArgs{
   917  			gitter: gits.NewGitCLI(),
   918  			initFn: func(args *forkAndPullTestArgs) error {
   919  				acmeRepo, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
   920  					err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("Hello there!"), 0600)
   921  					if err != nil {
   922  						return errors.WithStack(err)
   923  					}
   924  					return nil
   925  				}, args.gitter)
   926  				args.provider = gits.NewFakeProvider(acmeRepo)
   927  				fork, err := args.provider.ForkRepository("acme", "roadrunner", "wile")
   928  				assert.NoError(t, err)
   929  
   930  				// Add a commit to the fork that isn't on the upstream to validate later. Let's use a temp clone and push it.
   931  				dir, err := ioutil.TempDir("", "")
   932  				assert.NoError(t, err)
   933  				err = args.gitter.Clone(fork.CloneURL, dir)
   934  				assert.NoError(t, err)
   935  				err = ioutil.WriteFile(filepath.Join(dir, "CONTRIBUTING"), []byte("Welcome!"), 0600)
   936  				assert.NoError(t, err)
   937  				err = args.gitter.Add(dir, "CONTRIBUTING")
   938  				assert.NoError(t, err)
   939  				err = args.gitter.CommitDir(dir, "Second commit")
   940  				assert.NoError(t, err)
   941  				err = args.gitter.Push(dir, "origin", false, "HEAD")
   942  				assert.NoError(t, err)
   943  
   944  				// Set the provider username to wile in order to use the fork
   945  				args.provider.User.Username = "wile"
   946  
   947  				// Let's checkout our fork
   948  				args.dir, err = ioutil.TempDir("", "")
   949  				assert.NoError(t, err)
   950  				err = args.gitter.Clone(fork.CloneURL, args.dir)
   951  				assert.NoError(t, err)
   952  				// Let's add some local modifications that don't conflict
   953  				err = ioutil.WriteFile(filepath.Join(args.dir, "LICENSE"), []byte("TODO ;-)"), 0600)
   954  				assert.NoError(t, err)
   955  
   956  				return nil
   957  			},
   958  			cleanFn: func(args *forkAndPullTestArgs) {
   959  				for _, o := range args.provider.Repositories {
   960  					for _, r := range o {
   961  						if r.BaseDir != "" {
   962  							err := os.RemoveAll(r.BaseDir)
   963  							assert.NoError(t, err)
   964  						}
   965  					}
   966  				}
   967  				err := os.RemoveAll(args.dir)
   968  				assert.NoError(t, err)
   969  			},
   970  			gitURL:     fmt.Sprintf("https://fake.git/acme/roadrunner.git"),
   971  			dir:        "",  // set by initFn
   972  			provider:   nil, // set by initFn
   973  			branchName: "master",
   974  			baseRef:    "master",
   975  		},
   976  		baseRef: "master",
   977  		upstreamInfo: &gits.GitRepository{
   978  			Name:         "roadrunner",
   979  			URL:          "https://fake.git/acme/roadrunner.git",
   980  			HTMLURL:      "https://fake.git/acme/roadrunner",
   981  			Scheme:       "https",
   982  			Host:         "fake.git",
   983  			Organisation: "acme",
   984  			Fork:         false,
   985  		},
   986  		forkInfo: &gits.GitRepository{
   987  			Name:         "roadrunner",
   988  			URL:          "https://fake.git/wile/roadrunner.git",
   989  			HTMLURL:      "https://fake.git/wile/roadrunner",
   990  			Scheme:       "https",
   991  			Host:         "fake.git",
   992  			Organisation: "wile",
   993  			Project:      "wile",
   994  			Fork:         true,
   995  		},
   996  		postFn: func(args *forkAndPullTestArgs, test *forkAndPullTest) error {
   997  			test.dir = args.dir //make sure we end up with the same dir we start with
   998  			test.upstreamInfo.CloneURL = fmt.Sprintf("file://%s/acme", args.provider.Repositories["acme"][0].BaseDir)
   999  			test.forkInfo.CloneURL = fmt.Sprintf("file://%s/wile", args.provider.Repositories["acme"][0].BaseDir)
  1000  			_, gitConf, err := args.gitter.FindGitConfigDir(args.dir)
  1001  			assert.NoError(t, err)
  1002  			remotes, err := args.gitter.Remotes(args.dir)
  1003  			assert.NoError(t, err)
  1004  			assert.Len(t, remotes, 2)
  1005  			assert.Contains(t, remotes, "origin")
  1006  			assert.Contains(t, remotes, "upstream")
  1007  			originURL, err := args.gitter.DiscoverRemoteGitURL(gitConf)
  1008  			assert.NoError(t, err)
  1009  			upstreamURL, err := args.gitter.DiscoverUpstreamGitURL(gitConf)
  1010  			assert.NoError(t, err)
  1011  			assert.Equal(t, fmt.Sprintf("file://%s/wile", args.provider.Repositories["acme"][0].BaseDir), originURL)
  1012  			assert.Equal(t, fmt.Sprintf("file://%s/acme", args.provider.Repositories["acme"][0].BaseDir), upstreamURL)
  1013  			assert.FileExists(t, filepath.Join(args.dir, "CONTRIBUTING"))
  1014  			assert.FileExists(t, filepath.Join(args.dir, "LICENSE"))
  1015  			return nil
  1016  		},
  1017  	})
  1018  }
  1019  func TestExistingForkAndExistingCheckoutWithNonConflictingLocalModifications(t *testing.T) {
  1020  
  1021  	runForkAndPullTestCase(t, forkAndPullTest{
  1022  		name: "existingForkAndExistingCheckoutWithNonConflictingLocalModifications",
  1023  		args: forkAndPullTestArgs{
  1024  			gitter: gits.NewGitCLI(),
  1025  			initFn: func(args *forkAndPullTestArgs) error {
  1026  				acmeRepo, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
  1027  					err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("Hello there!"), 0600)
  1028  					if err != nil {
  1029  						return errors.WithStack(err)
  1030  					}
  1031  					return nil
  1032  				}, args.gitter)
  1033  				args.provider = gits.NewFakeProvider(acmeRepo)
  1034  				fork, err := args.provider.ForkRepository("acme", "roadrunner", "wile")
  1035  				assert.NoError(t, err)
  1036  
  1037  				// Add a commit to the fork that isn't on the upstream to validate later. Let's use a temp clone and push it.
  1038  				dir, err := ioutil.TempDir("", "")
  1039  				assert.NoError(t, err)
  1040  				err = args.gitter.Clone(fork.CloneURL, dir)
  1041  				assert.NoError(t, err)
  1042  				err = ioutil.WriteFile(filepath.Join(dir, "CONTRIBUTING"), []byte("Welcome!"), 0600)
  1043  				assert.NoError(t, err)
  1044  				err = args.gitter.Add(dir, "CONTRIBUTING")
  1045  				assert.NoError(t, err)
  1046  				err = args.gitter.CommitDir(dir, "Second commit")
  1047  				assert.NoError(t, err)
  1048  				err = args.gitter.Push(dir, "origin", false, "HEAD")
  1049  				assert.NoError(t, err)
  1050  
  1051  				// Set the provider username to wile in order to use the fork
  1052  				args.provider.User.Username = "wile"
  1053  
  1054  				// Let's checkout our fork
  1055  				args.dir, err = ioutil.TempDir("", "")
  1056  				assert.NoError(t, err)
  1057  				err = args.gitter.Clone(fork.CloneURL, args.dir)
  1058  				assert.NoError(t, err)
  1059  				// Let's add some local modifications that don't conflict
  1060  				err = ioutil.WriteFile(filepath.Join(args.dir, "CONTRIBUTING"), []byte("TODO ;-)"), 0600)
  1061  				assert.NoError(t, err)
  1062  
  1063  				return nil
  1064  			},
  1065  			cleanFn: func(args *forkAndPullTestArgs) {
  1066  				for _, o := range args.provider.Repositories {
  1067  					for _, r := range o {
  1068  						if r.BaseDir != "" {
  1069  							err := os.RemoveAll(r.BaseDir)
  1070  							assert.NoError(t, err)
  1071  						}
  1072  					}
  1073  				}
  1074  				err := os.RemoveAll(args.dir)
  1075  				assert.NoError(t, err)
  1076  			},
  1077  			gitURL:     fmt.Sprintf("https://fake.git/acme/roadrunner.git"),
  1078  			dir:        "",  // set by initFn
  1079  			provider:   nil, // set by initFn
  1080  			branchName: "master",
  1081  			baseRef:    "master",
  1082  		},
  1083  		baseRef: "master",
  1084  		upstreamInfo: &gits.GitRepository{
  1085  			Name:         "roadrunner",
  1086  			URL:          "https://fake.git/acme/roadrunner.git",
  1087  			HTMLURL:      "https://fake.git/acme/roadrunner",
  1088  			Scheme:       "https",
  1089  			Host:         "fake.git",
  1090  			Organisation: "acme",
  1091  			Fork:         false,
  1092  		},
  1093  		forkInfo: &gits.GitRepository{
  1094  			Name:         "roadrunner",
  1095  			URL:          "https://fake.git/wile/roadrunner.git",
  1096  			HTMLURL:      "https://fake.git/wile/roadrunner",
  1097  			Scheme:       "https",
  1098  			Host:         "fake.git",
  1099  			Organisation: "wile",
  1100  			Project:      "wile",
  1101  			Fork:         true,
  1102  		},
  1103  		postFn: func(args *forkAndPullTestArgs, test *forkAndPullTest) error {
  1104  			test.dir = args.dir //make sure we end up with the same dir we start with
  1105  			test.upstreamInfo.CloneURL = fmt.Sprintf("file://%s/acme", args.provider.Repositories["acme"][0].BaseDir)
  1106  			test.forkInfo.CloneURL = fmt.Sprintf("file://%s/wile", args.provider.Repositories["acme"][0].BaseDir)
  1107  			_, gitConf, err := args.gitter.FindGitConfigDir(args.dir)
  1108  			assert.NoError(t, err)
  1109  			remotes, err := args.gitter.Remotes(args.dir)
  1110  			assert.NoError(t, err)
  1111  			assert.Len(t, remotes, 2)
  1112  			assert.Contains(t, remotes, "origin")
  1113  			assert.Contains(t, remotes, "upstream")
  1114  			originURL, err := args.gitter.DiscoverRemoteGitURL(gitConf)
  1115  			assert.NoError(t, err)
  1116  			upstreamURL, err := args.gitter.DiscoverUpstreamGitURL(gitConf)
  1117  			assert.NoError(t, err)
  1118  			assert.Equal(t, fmt.Sprintf("file://%s/wile", args.provider.Repositories["acme"][0].BaseDir), originURL)
  1119  			assert.Equal(t, fmt.Sprintf("file://%s/acme", args.provider.Repositories["acme"][0].BaseDir), upstreamURL)
  1120  			assert.FileExists(t, filepath.Join(args.dir, "CONTRIBUTING"))
  1121  			tests.AssertFileContains(t, filepath.Join(args.dir, "CONTRIBUTING"), "TODO ;-)")
  1122  			return nil
  1123  		},
  1124  	})
  1125  }
  1126  
  1127  func runForkAndPullTestCase(t *testing.T, tt forkAndPullTest) {
  1128  	err := tt.args.initFn(&tt.args)
  1129  	assert.NoError(t, err)
  1130  	dir, baseRef, upstreamInfo, forkInfo, err := gits.ForkAndPullRepo(tt.args.gitURL, tt.args.dir, tt.args.baseRef, tt.args.branchName, tt.args.provider, tt.args.gitter, "")
  1131  	err2 := tt.postFn(&tt.args, &tt)
  1132  	assert.NoError(t, err2)
  1133  
  1134  	if tt.wantErr {
  1135  		assert.Error(t, err)
  1136  	} else {
  1137  		assert.NoError(t, err)
  1138  	}
  1139  
  1140  	//validate the returned data
  1141  	assert.Equal(t, tt.dir, dir)
  1142  	assert.Equal(t, tt.baseRef, baseRef)
  1143  	assert.Equal(t, tt.upstreamInfo, upstreamInfo)
  1144  	assert.Equal(t, tt.forkInfo, forkInfo)
  1145  
  1146  	//validate the forked repo has the right files in it
  1147  	files, err := filepath.Glob(fmt.Sprintf("%s/README", dir))
  1148  	assert.NoError(t, err)
  1149  	assert.Len(t, files, 1)
  1150  
  1151  	if len(files) == 1 {
  1152  		// validate the content is correct
  1153  		data, err := ioutil.ReadFile(files[0])
  1154  		assert.NoError(t, err)
  1155  		assert.Equal(t, []byte("Hello there!"), data)
  1156  	}
  1157  	tt.args.cleanFn(&tt.args)
  1158  }
  1159  
  1160  func TestDuplicateGitRepoFromCommitish(t *testing.T) {
  1161  	gitter := gits.NewGitCLI()
  1162  	originalRepo, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
  1163  		err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("Hello!"), 0600)
  1164  		if err != nil {
  1165  			return errors.Wrapf(err, "writing README")
  1166  		}
  1167  		return nil
  1168  	}, gitter)
  1169  	assert.NoError(t, err)
  1170  	otherProviderRepo, err := gits.NewFakeRepository("foo", "bar", func(dir string) error {
  1171  		err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("Goodbye!"), 0600)
  1172  		if err != nil {
  1173  			return errors.Wrapf(err, "writing README")
  1174  		}
  1175  		return nil
  1176  	}, gitter)
  1177  	assert.NoError(t, err)
  1178  
  1179  	dir, err := ioutil.TempDir("", "")
  1180  	assert.NoError(t, err)
  1181  	err = gitter.Clone(originalRepo.GitRepo.CloneURL, dir)
  1182  	assert.NoError(t, err)
  1183  
  1184  	err = gitter.CreateBranch(dir, "other")
  1185  	assert.NoError(t, err)
  1186  
  1187  	err = gitter.Checkout(dir, "other")
  1188  	assert.NoError(t, err)
  1189  
  1190  	err = ioutil.WriteFile(filepath.Join(dir, "LICENSE"), []byte("TODO"), 0600)
  1191  	assert.NoError(t, err)
  1192  
  1193  	err = gitter.Add(dir, "LICENSE")
  1194  	assert.NoError(t, err)
  1195  
  1196  	err = gitter.CommitDir(dir, "add license")
  1197  	assert.NoError(t, err)
  1198  
  1199  	err = gitter.Push(dir, "origin", false, "HEAD")
  1200  	assert.NoError(t, err)
  1201  
  1202  	err = gitter.CreateBranch(dir, "release")
  1203  	assert.NoError(t, err)
  1204  
  1205  	err = gitter.Checkout(dir, "release")
  1206  	assert.NoError(t, err)
  1207  
  1208  	err = ioutil.WriteFile(filepath.Join(dir, "CONTRIBUTING"), []byte("Welcome!"), 0600)
  1209  	assert.NoError(t, err)
  1210  
  1211  	err = gitter.Add(dir, "CONTRIBUTING")
  1212  	assert.NoError(t, err)
  1213  
  1214  	err = gitter.CommitDir(dir, "add contributing")
  1215  	assert.NoError(t, err)
  1216  
  1217  	err = gitter.CreateTag(dir, "v1.0.0", "1.0.0")
  1218  	assert.NoError(t, err)
  1219  
  1220  	err = gitter.Push(dir, "origin", false, "HEAD")
  1221  	assert.NoError(t, err)
  1222  
  1223  	err = gitter.PushTag(dir, "v1.0.0")
  1224  	assert.NoError(t, err)
  1225  	type args struct {
  1226  		toOrg         string
  1227  		toName        string
  1228  		fromGitURL    string
  1229  		fromCommitish string
  1230  		toBranch      string
  1231  		gitter        gits.Gitter
  1232  	}
  1233  	tests := []struct {
  1234  		provider         *gits.FakeProvider
  1235  		useOtherProvider bool
  1236  		name             string
  1237  		args             args
  1238  		want             *gits.GitRepository
  1239  		wantFiles        map[string][]byte
  1240  		wantErr          string
  1241  	}{
  1242  		{
  1243  			name: "sameOrg",
  1244  			args: args{
  1245  				toOrg:         "acme",
  1246  				toName:        "wile",
  1247  				fromGitURL:    "https://fake.git/acme/roadrunner.git",
  1248  				fromCommitish: "master",
  1249  				toBranch:      "master",
  1250  				gitter:        gitter,
  1251  			},
  1252  			want: &gits.GitRepository{
  1253  				Name:             "wile",
  1254  				AllowMergeCommit: false,
  1255  				HTMLURL:          "https://fake.git/acme/wile",
  1256  				CloneURL:         "",
  1257  				SSHURL:           "",
  1258  				Language:         "",
  1259  				Fork:             false,
  1260  				Stars:            0,
  1261  				URL:              "https://fake.git/acme/wile.git",
  1262  				Scheme:           "https",
  1263  				Host:             "fake.git",
  1264  				Organisation:     "acme",
  1265  				Project:          "",
  1266  				Private:          false,
  1267  			},
  1268  			wantFiles: map[string][]byte{
  1269  				"README": []byte("Hello!"),
  1270  			},
  1271  		},
  1272  		{
  1273  			name: "differentOrg",
  1274  			args: args{
  1275  				toOrg:         "coyote",
  1276  				toName:        "wile",
  1277  				fromGitURL:    "https://fake.git/acme/roadrunner.git",
  1278  				fromCommitish: "master",
  1279  				toBranch:      "master",
  1280  				gitter:        gitter,
  1281  			},
  1282  			want: &gits.GitRepository{
  1283  				Name:             "wile",
  1284  				AllowMergeCommit: false,
  1285  				HTMLURL:          "https://fake.git/coyote/wile",
  1286  				CloneURL:         "",
  1287  				SSHURL:           "",
  1288  				Language:         "",
  1289  				Fork:             false,
  1290  				Stars:            0,
  1291  				URL:              "https://fake.git/coyote/wile.git",
  1292  				Scheme:           "https",
  1293  				Host:             "fake.git",
  1294  				Organisation:     "coyote",
  1295  				Project:          "",
  1296  				Private:          false,
  1297  			},
  1298  			wantFiles: map[string][]byte{
  1299  				"README": []byte("Hello!"),
  1300  			},
  1301  		},
  1302  		{
  1303  			name: "differentProvider",
  1304  			args: args{
  1305  				toOrg:         "coyote",
  1306  				toName:        "wile",
  1307  				fromGitURL:    "https://fake.git/foo/bar.git",
  1308  				fromCommitish: "master",
  1309  				toBranch:      "master",
  1310  				gitter:        gitter,
  1311  			},
  1312  			useOtherProvider: true,
  1313  			want: &gits.GitRepository{
  1314  				Name:             "wile",
  1315  				AllowMergeCommit: false,
  1316  				HTMLURL:          "https://fake.git/coyote/wile",
  1317  				CloneURL:         "",
  1318  				SSHURL:           "",
  1319  				Language:         "",
  1320  				Fork:             false,
  1321  				Stars:            0,
  1322  				URL:              "https://fake.git/coyote/wile.git",
  1323  				Scheme:           "https",
  1324  				Host:             "fake.git",
  1325  				Organisation:     "coyote",
  1326  				Project:          "",
  1327  				Private:          false,
  1328  			},
  1329  			wantFiles: map[string][]byte{
  1330  				"README": []byte("Goodbye!"),
  1331  			},
  1332  		},
  1333  		{
  1334  			name: "tag",
  1335  			args: args{
  1336  				toOrg:         "coyote",
  1337  				toName:        "wile",
  1338  				fromGitURL:    "https://fake.git/acme/roadrunner.git",
  1339  				fromCommitish: "v1.0.0",
  1340  				toBranch:      "master",
  1341  				gitter:        gitter,
  1342  			},
  1343  			want: &gits.GitRepository{
  1344  				Name:             "wile",
  1345  				AllowMergeCommit: false,
  1346  				HTMLURL:          "https://fake.git/coyote/wile",
  1347  				CloneURL:         "",
  1348  				SSHURL:           "",
  1349  				Language:         "",
  1350  				Fork:             false,
  1351  				Stars:            0,
  1352  				URL:              "https://fake.git/coyote/wile.git",
  1353  				Scheme:           "https",
  1354  				Host:             "fake.git",
  1355  				Organisation:     "coyote",
  1356  				Project:          "",
  1357  				Private:          false,
  1358  			},
  1359  			wantFiles: map[string][]byte{
  1360  				"README":       []byte("Hello!"),
  1361  				"CONTRIBUTING": []byte("Welcome!"),
  1362  			},
  1363  		}, {
  1364  			name: "branch",
  1365  			args: args{
  1366  				toOrg:         "coyote",
  1367  				toName:        "wile",
  1368  				fromGitURL:    "https://fake.git/acme/roadrunner.git",
  1369  				fromCommitish: "origin/other",
  1370  				toBranch:      "master",
  1371  				gitter:        gitter,
  1372  			},
  1373  			want: &gits.GitRepository{
  1374  				Name:             "wile",
  1375  				AllowMergeCommit: false,
  1376  				HTMLURL:          "https://fake.git/coyote/wile",
  1377  				CloneURL:         "",
  1378  				SSHURL:           "",
  1379  				Language:         "",
  1380  				Fork:             false,
  1381  				Stars:            0,
  1382  				URL:              "https://fake.git/coyote/wile.git",
  1383  				Scheme:           "https",
  1384  				Host:             "fake.git",
  1385  				Organisation:     "coyote",
  1386  				Project:          "",
  1387  				Private:          false,
  1388  			},
  1389  			wantFiles: map[string][]byte{
  1390  				"README":  []byte("Hello!"),
  1391  				"LICENSE": []byte("TODO"),
  1392  			},
  1393  		}, {
  1394  			name: "destinationBranch",
  1395  			args: args{
  1396  				toOrg:         "coyote",
  1397  				toName:        "wile",
  1398  				fromGitURL:    "https://fake.git/acme/roadrunner.git",
  1399  				fromCommitish: "origin/other",
  1400  				toBranch:      "another",
  1401  				gitter:        gitter,
  1402  			},
  1403  			want: &gits.GitRepository{
  1404  				Name:             "wile",
  1405  				AllowMergeCommit: false,
  1406  				HTMLURL:          "https://fake.git/coyote/wile",
  1407  				CloneURL:         "",
  1408  				SSHURL:           "",
  1409  				Language:         "",
  1410  				Fork:             false,
  1411  				Stars:            0,
  1412  				URL:              "https://fake.git/coyote/wile.git",
  1413  				Scheme:           "https",
  1414  				Host:             "fake.git",
  1415  				Organisation:     "coyote",
  1416  				Project:          "",
  1417  				Private:          false,
  1418  			},
  1419  			wantFiles: map[string][]byte{
  1420  				"README":  []byte("Hello!"),
  1421  				"LICENSE": []byte("TODO"),
  1422  			},
  1423  		}, {
  1424  			name: "badFromUrl",
  1425  			args: args{
  1426  				toOrg:         "coyote",
  1427  				toName:        "wile",
  1428  				fromGitURL:    "https://fake.git/other/roadrunner.git",
  1429  				fromCommitish: "origin/other",
  1430  				toBranch:      "another",
  1431  				gitter:        gitter,
  1432  			},
  1433  			want: &gits.GitRepository{
  1434  				Name:             "wile",
  1435  				AllowMergeCommit: false,
  1436  				HTMLURL:          "https://fake.git/coyote/wile",
  1437  				CloneURL:         "",
  1438  				SSHURL:           "",
  1439  				Language:         "",
  1440  				Fork:             false,
  1441  				Stars:            0,
  1442  				URL:              "https://fake.git/coyote/wile.git",
  1443  				Scheme:           "https",
  1444  				Host:             "fake.git",
  1445  				Organisation:     "coyote",
  1446  				Project:          "",
  1447  				Private:          false,
  1448  			},
  1449  			wantErr: "organization 'other' not found",
  1450  			wantFiles: map[string][]byte{
  1451  				"README":  []byte("Hello!"),
  1452  				"LICENSE": []byte("TODO"),
  1453  			},
  1454  		},
  1455  	}
  1456  	for _, tt := range tests {
  1457  		t.Run(tt.name, func(t *testing.T) {
  1458  			provider := gits.NewFakeProvider(originalRepo)
  1459  			provider.Gitter = gitter
  1460  			provider.CreateRepositoryAddFiles = func(dir string) error {
  1461  				err := ioutil.WriteFile(filepath.Join(dir, ".gitkeep"), []byte(""), 0600)
  1462  				assert.NoError(t, err)
  1463  				err = gitter.Add(dir, filepath.Join(dir, ".gitkeep"))
  1464  				assert.NoError(t, err)
  1465  				return nil
  1466  			}
  1467  			tt.provider = provider
  1468  
  1469  			var fromRepo *gits.GitRepository
  1470  			if tt.useOtherProvider {
  1471  				fromRepo = otherProviderRepo.GitRepo
  1472  			}
  1473  
  1474  			got, err := gits.DuplicateGitRepoFromCommitish(tt.args.toOrg, tt.args.toName, tt.args.fromGitURL, tt.args.fromCommitish, tt.args.toBranch, false, tt.provider, tt.args.gitter, fromRepo)
  1475  			if tt.wantErr != "" {
  1476  				assert.Error(t, err)
  1477  				assert.Contains(t, err.Error(), tt.wantErr)
  1478  				return
  1479  			} else {
  1480  				assert.NoError(t, err)
  1481  				if err != nil {
  1482  					return
  1483  				}
  1484  			}
  1485  			baseDir := ""
  1486  			for _, r := range tt.provider.Repositories[got.Organisation] {
  1487  				if r.Name() == got.Name {
  1488  					baseDir = r.BaseDir
  1489  				}
  1490  			}
  1491  			tt.want.CloneURL = fmt.Sprintf("file://%s/%s", baseDir, got.Organisation)
  1492  			assert.Equal(t, tt.want, got)
  1493  
  1494  			// Make a clone
  1495  			dir, err := ioutil.TempDir("", "")
  1496  			assert.NoError(t, err)
  1497  			err = gitter.Clone(got.CloneURL, dir)
  1498  			assert.NoError(t, err)
  1499  
  1500  			err = gitter.FetchBranch(dir, "origin", tt.args.toBranch)
  1501  			assert.NoError(t, err)
  1502  
  1503  			err = gitter.CheckoutRemoteBranch(dir, tt.args.toBranch)
  1504  			assert.NoError(t, err)
  1505  
  1506  			for relPath, content := range tt.wantFiles {
  1507  				path := filepath.Join(dir, relPath)
  1508  				assert.FileExists(t, path)
  1509  				data, err := ioutil.ReadFile(path)
  1510  				assert.NoError(t, err)
  1511  				assert.Equal(t, content, data)
  1512  			}
  1513  		})
  1514  	}
  1515  }
  1516  
  1517  func Test_DuplicateGitRepoFromCommitish_returns_error_if_target_repo_exists(t *testing.T) {
  1518  	gitter := gits.NewGitCLI()
  1519  	originalRepo, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
  1520  		err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("Hello!"), 0600)
  1521  		if err != nil {
  1522  			return errors.Wrapf(err, "writing README")
  1523  		}
  1524  		return nil
  1525  	}, gitter)
  1526  	assert.NoError(t, err)
  1527  
  1528  	targetRepo, err := gits.NewFakeRepository("acme", "coyote", func(dir string) error {
  1529  		err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("World!"), 0600)
  1530  		if err != nil {
  1531  			return errors.Wrapf(err, "writing README")
  1532  		}
  1533  		return nil
  1534  	}, gitter)
  1535  	assert.NoError(t, err)
  1536  
  1537  	provider := gits.NewFakeProvider(originalRepo, targetRepo)
  1538  	provider.Gitter = gitter
  1539  
  1540  	repo, err := gits.DuplicateGitRepoFromCommitish(targetRepo.GitRepo.Organisation, targetRepo.GitRepo.Name, originalRepo.GitRepo.CloneURL, "origin/foo", "bar", false, provider, gitter, nil)
  1541  	assert.Error(t, err)
  1542  	assert.Equal(t, "repository acme/coyote already exists", err.Error())
  1543  	assert.Nil(t, repo)
  1544  }
  1545  
  1546  func TestPushRepoAndCreatePullRequest(t *testing.T) {
  1547  	type args struct {
  1548  		gitURL     string
  1549  		forkGitURL string
  1550  		dir        string
  1551  		commit     bool
  1552  		push       bool
  1553  		autoMerge  bool
  1554  		dryRun     bool
  1555  		commitMsg  string
  1556  		branch     string
  1557  		labels     []string
  1558  		filter     *gits.PullRequestFilter
  1559  		provider   *gits.FakeProvider
  1560  		gitter     gits.Gitter
  1561  		initFn     func(args *args) error // initFn allows us to run some code at the start of the forkAndPullTest
  1562  		cleanFn    func(args *args)
  1563  	}
  1564  	type test struct {
  1565  		name         string
  1566  		args         args
  1567  		wantErr      bool
  1568  		wantBranch   string
  1569  		wantPRNumber int
  1570  		postFn       func(args *args, test *test) error
  1571  	}
  1572  	tests := []test{
  1573  		{
  1574  			name: "CreatePullRequestDoingCommitAndPush",
  1575  			args: args{
  1576  				gitter: gits.NewGitCLI(),
  1577  				initFn: func(args *args) error {
  1578  					acmeRepo, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
  1579  						err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("Hello there!"), 0600)
  1580  						if err != nil {
  1581  							return errors.WithStack(err)
  1582  						}
  1583  						return nil
  1584  					}, args.gitter)
  1585  					args.provider = gits.NewFakeProvider(acmeRepo)
  1586  					args.dir, err = ioutil.TempDir("", "")
  1587  					assert.NoError(t, err)
  1588  
  1589  					// Let's clone the repo to dir and write a file
  1590  					err = os.MkdirAll(args.dir, 0755)
  1591  					assert.NoError(t, err)
  1592  					err = args.gitter.Clone(acmeRepo.GitRepo.CloneURL, args.dir)
  1593  					assert.NoError(t, err)
  1594  					err = ioutil.WriteFile(filepath.Join(args.dir, "CONTRIBUTING"), []byte("Welcome!"), 0600)
  1595  					assert.NoError(t, err)
  1596  					return nil
  1597  				},
  1598  				cleanFn: func(args *args) {
  1599  					for _, o := range args.provider.Repositories {
  1600  						for _, r := range o {
  1601  							if r.BaseDir != "" {
  1602  								err := os.RemoveAll(r.BaseDir)
  1603  								assert.NoError(t, err)
  1604  							}
  1605  						}
  1606  					}
  1607  					err := os.RemoveAll(args.dir)
  1608  					assert.NoError(t, err)
  1609  				},
  1610  				gitURL:   fmt.Sprintf("https://fake.git/acme/roadrunner.git"),
  1611  				dir:      "",  // set by initFn
  1612  				provider: nil, // set by initFn
  1613  				push:     true,
  1614  				commit:   true,
  1615  			},
  1616  			postFn: func(args *args, test *test) error {
  1617  
  1618  				return nil
  1619  			},
  1620  		},
  1621  		{
  1622  			name: "CreatePullRequestWithExistingCommitAndPush",
  1623  			args: args{
  1624  				gitter: gits.NewGitCLI(),
  1625  				initFn: func(args *args) error {
  1626  					acmeRepo, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
  1627  						err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("Hello there!"), 0600)
  1628  						if err != nil {
  1629  							return errors.WithStack(err)
  1630  						}
  1631  						return nil
  1632  					}, args.gitter)
  1633  					args.provider = gits.NewFakeProvider(acmeRepo)
  1634  					args.dir, err = ioutil.TempDir("", "")
  1635  					assert.NoError(t, err)
  1636  
  1637  					// Let's clone the repo to dir and write a file, and commit it
  1638  					err = os.MkdirAll(args.dir, 0755)
  1639  					assert.NoError(t, err)
  1640  					err = args.gitter.Clone(acmeRepo.GitRepo.CloneURL, args.dir)
  1641  					assert.NoError(t, err)
  1642  					err = ioutil.WriteFile(filepath.Join(args.dir, "CONTRIBUTING"), []byte("Welcome!"), 0600)
  1643  					assert.NoError(t, err)
  1644  					err = args.gitter.Add(args.dir, "CONTRIBUTING")
  1645  					assert.NoError(t, err)
  1646  					err = args.gitter.CommitDir(args.dir, "commit")
  1647  					assert.NoError(t, err)
  1648  					return nil
  1649  				},
  1650  				cleanFn: func(args *args) {
  1651  					for _, o := range args.provider.Repositories {
  1652  						for _, r := range o {
  1653  							if r.BaseDir != "" {
  1654  								err := os.RemoveAll(r.BaseDir)
  1655  								assert.NoError(t, err)
  1656  							}
  1657  						}
  1658  					}
  1659  					err := os.RemoveAll(args.dir)
  1660  					assert.NoError(t, err)
  1661  				},
  1662  				gitURL:    fmt.Sprintf("https://fake.git/acme/roadrunner.git"),
  1663  				dir:       "",  // set by initFn
  1664  				provider:  nil, // set by initFn
  1665  				push:      true,
  1666  				commitMsg: "commit",
  1667  			},
  1668  			postFn: func(args *args, test *test) error {
  1669  
  1670  				return nil
  1671  			},
  1672  		},
  1673  		{
  1674  			name: "CreatePullRequestWithExistingCommitAndExistingPush",
  1675  			args: args{
  1676  				gitter: gits.NewGitCLI(),
  1677  				initFn: func(args *args) error {
  1678  					acmeRepo, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
  1679  						err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("Hello there!"), 0600)
  1680  						if err != nil {
  1681  							return errors.WithStack(err)
  1682  						}
  1683  						return nil
  1684  					}, args.gitter)
  1685  					args.provider = gits.NewFakeProvider(acmeRepo)
  1686  					args.dir, err = ioutil.TempDir("", "")
  1687  					assert.NoError(t, err)
  1688  
  1689  					// Let's clone the repo to dir and write a file, and commit it
  1690  					err = os.MkdirAll(args.dir, 0755)
  1691  					assert.NoError(t, err)
  1692  					err = args.gitter.Clone(acmeRepo.GitRepo.CloneURL, args.dir)
  1693  					assert.NoError(t, err)
  1694  					err = args.gitter.CreateBranch(args.dir, "other")
  1695  					assert.NoError(t, err)
  1696  					err = args.gitter.Checkout(args.dir, "other")
  1697  					assert.NoError(t, err)
  1698  					err = ioutil.WriteFile(filepath.Join(args.dir, "CONTRIBUTING"), []byte("Welcome!"), 0600)
  1699  					assert.NoError(t, err)
  1700  					err = args.gitter.Add(args.dir, "CONTRIBUTING")
  1701  					assert.NoError(t, err)
  1702  					err = args.gitter.CommitDir(args.dir, "commit")
  1703  					assert.NoError(t, err)
  1704  					err = args.gitter.Push(args.dir, "origin", false, "HEAD")
  1705  					assert.NoError(t, err)
  1706  					return nil
  1707  				},
  1708  				cleanFn: func(args *args) {
  1709  					for _, o := range args.provider.Repositories {
  1710  						for _, r := range o {
  1711  							if r.BaseDir != "" {
  1712  								err := os.RemoveAll(r.BaseDir)
  1713  								assert.NoError(t, err)
  1714  							}
  1715  						}
  1716  					}
  1717  					err := os.RemoveAll(args.dir)
  1718  					assert.NoError(t, err)
  1719  				},
  1720  				gitURL:    fmt.Sprintf("https://fake.git/acme/roadrunner.git"),
  1721  				dir:       "",  // set by initFn
  1722  				provider:  nil, // set by initFn
  1723  				push:      false,
  1724  				commitMsg: "commit",
  1725  				branch:    "other",
  1726  			},
  1727  			postFn: func(args *args, test *test) error {
  1728  
  1729  				return nil
  1730  			},
  1731  		},
  1732  		{
  1733  			name: "UpdatePullRequestDoingCommitAndPush",
  1734  			args: args{
  1735  				gitter: gits.NewGitCLI(),
  1736  				initFn: func(args *args) error {
  1737  					acmeRepo, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
  1738  						err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("Hello there!"), 0600)
  1739  						if err != nil {
  1740  							return errors.WithStack(err)
  1741  						}
  1742  						return nil
  1743  					}, args.gitter)
  1744  					args.provider = gits.NewFakeProvider(acmeRepo)
  1745  					args.dir, err = ioutil.TempDir("", "")
  1746  					assert.NoError(t, err)
  1747  
  1748  					// Let's create a pull request
  1749  
  1750  					// Let's clone the repo to dir and write a file
  1751  					err = os.MkdirAll(args.dir, 0755)
  1752  					assert.NoError(t, err)
  1753  					err = args.gitter.Clone(acmeRepo.GitRepo.CloneURL, args.dir)
  1754  					assert.NoError(t, err)
  1755  					err = ioutil.WriteFile(filepath.Join(args.dir, "CONTRIBUTING"), []byte("Welcome!"), 0600)
  1756  					assert.NoError(t, err)
  1757  					return nil
  1758  				},
  1759  				cleanFn: func(args *args) {
  1760  					for _, o := range args.provider.Repositories {
  1761  						for _, r := range o {
  1762  							if r.BaseDir != "" {
  1763  								err := os.RemoveAll(r.BaseDir)
  1764  								assert.NoError(t, err)
  1765  							}
  1766  						}
  1767  					}
  1768  					err := os.RemoveAll(args.dir)
  1769  					assert.NoError(t, err)
  1770  				},
  1771  				gitURL:   fmt.Sprintf("https://fake.git/acme/roadrunner.git"),
  1772  				dir:      "",  // set by initFn
  1773  				provider: nil, // set by initFn
  1774  				push:     true,
  1775  				commit:   true,
  1776  			},
  1777  			postFn: func(args *args, test *test) error {
  1778  
  1779  				return nil
  1780  			},
  1781  		},
  1782  		{
  1783  			name: "CreatePullRequestWithExistingCommitAndPush",
  1784  			args: args{
  1785  				gitter: gits.NewGitCLI(),
  1786  				initFn: func(args *args) error {
  1787  					acmeRepo, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
  1788  						err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("Hello there!"), 0600)
  1789  						if err != nil {
  1790  							return errors.WithStack(err)
  1791  						}
  1792  						return nil
  1793  					}, args.gitter)
  1794  					args.provider = gits.NewFakeProvider(acmeRepo)
  1795  					args.dir, err = ioutil.TempDir("", "")
  1796  					assert.NoError(t, err)
  1797  
  1798  					// Let's clone the repo to dir and write a file, and commit it
  1799  					err = os.MkdirAll(args.dir, 0755)
  1800  					assert.NoError(t, err)
  1801  					err = args.gitter.Clone(acmeRepo.GitRepo.CloneURL, args.dir)
  1802  					assert.NoError(t, err)
  1803  					err = ioutil.WriteFile(filepath.Join(args.dir, "CONTRIBUTING"), []byte("Welcome!"), 0600)
  1804  					assert.NoError(t, err)
  1805  					err = args.gitter.Add(args.dir, "CONTRIBUTING")
  1806  					assert.NoError(t, err)
  1807  					err = args.gitter.CommitDir(args.dir, "commit")
  1808  					assert.NoError(t, err)
  1809  					return nil
  1810  				},
  1811  				cleanFn: func(args *args) {
  1812  					for _, o := range args.provider.Repositories {
  1813  						for _, r := range o {
  1814  							if r.BaseDir != "" {
  1815  								err := os.RemoveAll(r.BaseDir)
  1816  								assert.NoError(t, err)
  1817  							}
  1818  						}
  1819  					}
  1820  					err := os.RemoveAll(args.dir)
  1821  					assert.NoError(t, err)
  1822  				},
  1823  				gitURL:    fmt.Sprintf("https://fake.git/acme/roadrunner.git"),
  1824  				dir:       "",  // set by initFn
  1825  				provider:  nil, // set by initFn
  1826  				push:      true,
  1827  				commitMsg: "commit",
  1828  			},
  1829  			postFn: func(args *args, test *test) error {
  1830  
  1831  				return nil
  1832  			},
  1833  		},
  1834  		{
  1835  			name: "CreatePullRequestWithExistingCommitAndExistingPush",
  1836  			args: args{
  1837  				gitter: gits.NewGitCLI(),
  1838  				initFn: func(args *args) error {
  1839  					acmeRepo, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
  1840  						err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("Hello there!"), 0600)
  1841  						if err != nil {
  1842  							return errors.WithStack(err)
  1843  						}
  1844  						return nil
  1845  					}, args.gitter)
  1846  					args.provider = gits.NewFakeProvider(acmeRepo)
  1847  					args.dir, err = ioutil.TempDir("", "")
  1848  					assert.NoError(t, err)
  1849  
  1850  					// Let's clone the repo to dir and write a file, and commit it
  1851  					err = os.MkdirAll(args.dir, 0755)
  1852  					assert.NoError(t, err)
  1853  					err = args.gitter.Clone(acmeRepo.GitRepo.CloneURL, args.dir)
  1854  					assert.NoError(t, err)
  1855  					err = args.gitter.CreateBranch(args.dir, "other")
  1856  					assert.NoError(t, err)
  1857  					err = args.gitter.Checkout(args.dir, "other")
  1858  					assert.NoError(t, err)
  1859  					err = ioutil.WriteFile(filepath.Join(args.dir, "CONTRIBUTING"), []byte("Welcome!"), 0600)
  1860  					assert.NoError(t, err)
  1861  					err = args.gitter.Add(args.dir, "CONTRIBUTING")
  1862  					assert.NoError(t, err)
  1863  					err = args.gitter.CommitDir(args.dir, "commit")
  1864  					assert.NoError(t, err)
  1865  					err = args.gitter.Push(args.dir, "origin", false, "HEAD")
  1866  					assert.NoError(t, err)
  1867  					return nil
  1868  				},
  1869  				cleanFn: func(args *args) {
  1870  					for _, o := range args.provider.Repositories {
  1871  						for _, r := range o {
  1872  							if r.BaseDir != "" {
  1873  								err := os.RemoveAll(r.BaseDir)
  1874  								assert.NoError(t, err)
  1875  							}
  1876  						}
  1877  					}
  1878  					err := os.RemoveAll(args.dir)
  1879  					assert.NoError(t, err)
  1880  				},
  1881  				gitURL:    fmt.Sprintf("https://fake.git/acme/roadrunner.git"),
  1882  				dir:       "",  // set by initFn
  1883  				provider:  nil, // set by initFn
  1884  				push:      false,
  1885  				commitMsg: "commit",
  1886  				branch:    "other",
  1887  			},
  1888  			postFn: func(args *args, test *test) error {
  1889  
  1890  				return nil
  1891  			},
  1892  		}, {
  1893  			name: "CreatePullRequestWithExistingPRFromAnotherFork",
  1894  			args: args{
  1895  				gitter: gits.NewGitCLI(),
  1896  				initFn: func(args *args) error {
  1897  					acmeRepo, err := gits.NewFakeRepository("acme", "roadrunner", func(dir string) error {
  1898  						err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("Hello there!"), 0600)
  1899  						if err != nil {
  1900  							return errors.WithStack(err)
  1901  						}
  1902  						return nil
  1903  					}, args.gitter)
  1904  					tmpDir, err := ioutil.TempDir("", "")
  1905  					assert.NoError(t, err)
  1906  					args.provider = gits.NewFakeProvider(acmeRepo)
  1907  					personalRepo, err := args.provider.ForkRepository("acme", "roadrunner", "personal")
  1908  					assert.NoError(t, err)
  1909  					_, err = args.provider.ForkRepository("acme", "roadrunner", "personal2")
  1910  					assert.NoError(t, err)
  1911  
  1912  					// Let's clone the repo to dir and write a file, and commit it
  1913  					err = os.MkdirAll(tmpDir, 0755)
  1914  					assert.NoError(t, err)
  1915  					err = args.gitter.Clone(personalRepo.CloneURL, tmpDir)
  1916  					assert.NoError(t, err)
  1917  					err = args.gitter.CreateBranch(tmpDir, "other")
  1918  					assert.NoError(t, err)
  1919  					err = args.gitter.Checkout(tmpDir, "other")
  1920  					assert.NoError(t, err)
  1921  					err = ioutil.WriteFile(filepath.Join(tmpDir, "CONTRIBUTING"), []byte("Welcome!!!!"), 0600)
  1922  					assert.NoError(t, err)
  1923  					err = args.gitter.Add(tmpDir, "CONTRIBUTING")
  1924  					assert.NoError(t, err)
  1925  					prDetails := gits.PullRequestDetails{
  1926  						BranchName: "other",
  1927  						Title:      fmt.Sprintf("Initial Commit!"),
  1928  						Message:    fmt.Sprintf("Initial Commit!"),
  1929  						Labels:     []string{"updatebot"},
  1930  					}
  1931  					_, err = gits.PushRepoAndCreatePullRequest(tmpDir, acmeRepo.GitRepo, personalRepo, "master", &prDetails, nil, true, "Initial Commit", true, false, args.gitter, args.provider)
  1932  					assert.NoError(t, err)
  1933  					// Let's clone the repo to dir and write a file
  1934  					args.dir, err = ioutil.TempDir("", "")
  1935  					assert.NoError(t, err)
  1936  					err = os.MkdirAll(args.dir, 0755)
  1937  					assert.NoError(t, err)
  1938  					err = args.gitter.Clone(acmeRepo.GitRepo.CloneURL, args.dir)
  1939  					assert.NoError(t, err)
  1940  					err = ioutil.WriteFile(filepath.Join(args.dir, "CONTRIBUTING"), []byte("Welcome!"), 0600)
  1941  					assert.NoError(t, err)
  1942  					return nil
  1943  				},
  1944  				cleanFn: func(args *args) {
  1945  					for _, o := range args.provider.Repositories {
  1946  						for _, r := range o {
  1947  							if r.BaseDir != "" {
  1948  								err := os.RemoveAll(r.BaseDir)
  1949  								assert.NoError(t, err)
  1950  							}
  1951  						}
  1952  					}
  1953  					err := os.RemoveAll(args.dir)
  1954  					assert.NoError(t, err)
  1955  				},
  1956  				gitURL:     fmt.Sprintf("https://fake.git/acme/roadrunner.git"),
  1957  				forkGitURL: fmt.Sprintf("https://fake.git/personal2/roadrunner.git"),
  1958  				dir:        "",  // set by initFn
  1959  				provider:   nil, // set by initFn
  1960  				commit:     true,
  1961  				push:       true,
  1962  				branch:     "other",
  1963  				filter: &gits.PullRequestFilter{
  1964  					Labels: []string{
  1965  						"updatebot",
  1966  					},
  1967  				},
  1968  			},
  1969  			wantBranch:   "personal2:other",
  1970  			wantPRNumber: 2,
  1971  			postFn: func(args *args, test *test) error {
  1972  
  1973  				return nil
  1974  			},
  1975  		},
  1976  	}
  1977  	for _, tt := range tests {
  1978  		t.Run(tt.name, func(t *testing.T) {
  1979  			err := tt.args.initFn(&tt.args)
  1980  			assert.NoError(t, err)
  1981  			upstreamRepo, err := gits.ParseGitURL(tt.args.gitURL)
  1982  			assert.NoError(t, err)
  1983  			// Need to do this to make sure the CloneURL is correct
  1984  			upstreamRepo, err = tt.args.provider.GetRepository(upstreamRepo.Organisation, upstreamRepo.Name)
  1985  			assert.NoError(t, err)
  1986  			var forkRepo *gits.GitRepository
  1987  			if tt.args.forkGitURL != "" {
  1988  				forkRepo, err = gits.ParseGitURL(tt.args.forkGitURL)
  1989  				assert.NoError(t, err)
  1990  				forkRepo, err = tt.args.provider.GetRepository(forkRepo.Organisation, forkRepo.Name)
  1991  				assert.NoError(t, err)
  1992  			}
  1993  			uuid, err := uuid.NewUUID()
  1994  			assert.NoError(t, err)
  1995  			if tt.args.branch == "" {
  1996  				tt.args.branch = uuid.String()
  1997  			}
  1998  			prDetails := gits.PullRequestDetails{
  1999  				BranchName: tt.args.branch,
  2000  				Title:      fmt.Sprintf("chore: bump %s", uuid.String()),
  2001  				Message:    fmt.Sprintf("bump %s", uuid.String()),
  2002  				Labels:     tt.args.labels,
  2003  			}
  2004  			if tt.wantBranch == "" {
  2005  				tt.wantBranch = tt.args.branch
  2006  			}
  2007  			if tt.wantPRNumber == 0 {
  2008  				tt.wantPRNumber = 1
  2009  			}
  2010  			commitMsg := fmt.Sprintf("chore(deps): blah")
  2011  			if tt.args.commitMsg != "" {
  2012  				commitMsg = tt.args.commitMsg
  2013  			}
  2014  
  2015  			prInfo, err := gits.PushRepoAndCreatePullRequest(tt.args.dir, upstreamRepo, forkRepo, "master", &prDetails, tt.args.filter, tt.args.commit, commitMsg, tt.args.push, tt.args.dryRun, tt.args.gitter, tt.args.provider)
  2016  			err2 := tt.postFn(&tt.args, &tt)
  2017  			assert.NoError(t, err2)
  2018  
  2019  			if tt.wantErr {
  2020  				assert.Error(t, err)
  2021  				return
  2022  			}
  2023  			assert.NoError(t, err)
  2024  			if err != nil {
  2025  				return
  2026  			}
  2027  			//validate the returned data
  2028  			assert.Equal(t, prDetails.Title, prInfo.PullRequest.Title)
  2029  			assert.Equal(t, prDetails.Message, prInfo.PullRequest.Body)
  2030  			assert.Equal(t, tt.wantBranch, util.DereferenceString(prInfo.PullRequest.HeadRef))
  2031  			assert.Equal(t, prDetails.Title, prInfo.PullRequestArguments.Title)
  2032  			assert.Equal(t, prDetails.Message, prInfo.PullRequestArguments.Body)
  2033  			assert.Equal(t, tt.wantBranch, prInfo.PullRequestArguments.Head)
  2034  			assert.Equal(t, tt.args.gitURL, prInfo.PullRequestArguments.GitRepository.URL)
  2035  			if tt.args.autoMerge {
  2036  				assert.Contains(t, prInfo.PullRequest.Labels, "updatebot")
  2037  			}
  2038  
  2039  			pr, err := tt.args.provider.GetPullRequest("acme", upstreamRepo, tt.wantPRNumber)
  2040  			assert.NoError(t, err)
  2041  			assert.Equal(t, prDetails.Title, pr.Title)
  2042  			assert.Equal(t, prDetails.Message, pr.Body)
  2043  			assert.Equal(t, tt.wantBranch, util.DereferenceString(pr.HeadRef))
  2044  
  2045  			// reclone the repo and check CONTRIBUTING.md is there
  2046  			// Do this regardless as the tests will either have the function under forkAndPullTest do this or will do it themselves
  2047  			dir, err := ioutil.TempDir("", "")
  2048  			assert.NoError(t, err)
  2049  			org := "acme"
  2050  			if forkRepo != nil {
  2051  				org = forkRepo.Organisation
  2052  			}
  2053  			parts := strings.Split(tt.wantBranch, ":")
  2054  			var branch string
  2055  			if len(parts) == 2 {
  2056  				branch = parts[1]
  2057  			} else {
  2058  				branch = parts[0]
  2059  			}
  2060  			gitInfo, err := tt.args.provider.GetRepository(org, "roadrunner")
  2061  			assert.NoError(t, err)
  2062  			err = tt.args.gitter.Clone(gitInfo.CloneURL, dir)
  2063  			assert.NoError(t, err)
  2064  			err = tt.args.gitter.FetchBranch(dir, "origin")
  2065  			assert.NoError(t, err)
  2066  			branches, err := tt.args.gitter.RemoteBranches(dir)
  2067  			assert.NoError(t, err)
  2068  			assert.Contains(t, branches, fmt.Sprintf("origin/%s", branch))
  2069  			err = tt.args.gitter.CheckoutRemoteBranch(dir, fmt.Sprintf("%s", branch))
  2070  			assert.NoError(t, err)
  2071  			assert.FileExists(t, filepath.Join(dir, "CONTRIBUTING"))
  2072  			data, err := ioutil.ReadFile(filepath.Join(dir, "CONTRIBUTING"))
  2073  			assert.NoError(t, err)
  2074  			assert.Equal(t, "Welcome!", string(data))
  2075  			msg, err := tt.args.gitter.GetLatestCommitMessage(dir)
  2076  			assert.NoError(t, err)
  2077  			assert.Equal(t, commitMsg, msg)
  2078  
  2079  			// validate the files exist
  2080  			tt.args.cleanFn(&tt.args)
  2081  		})
  2082  	}
  2083  }
  2084  
  2085  func TestGetGitInfoFromDirectory(t *testing.T) {
  2086  	t.Parallel()
  2087  	gitter := gits.NewGitCLI()
  2088  	owner := "fakeowner"
  2089  	repo := "fakerepo"
  2090  	originalRepo, err := gits.NewFakeRepository(owner, repo, func(dir string) error {
  2091  		err := ioutil.WriteFile(filepath.Join(dir, "README"), []byte("Hello!"), 0600)
  2092  		if err != nil {
  2093  			return errors.Wrapf(err, "writing README")
  2094  		}
  2095  		return nil
  2096  	}, gitter)
  2097  	defer os.RemoveAll(originalRepo.BaseDir)
  2098  
  2099  	assert.NoError(t, err)
  2100  	dir, err := ioutil.TempDir("", "")
  2101  	defer os.RemoveAll(dir)
  2102  	assert.NoError(t, err)
  2103  	err = gitter.Clone(originalRepo.GitRepo.CloneURL, dir)
  2104  	assert.NoError(t, err)
  2105  	err = gitter.UpdateRemote(dir, fmt.Sprintf("git@github.com:%s/%s.git", owner, repo))
  2106  	assert.NoError(t, err)
  2107  
  2108  	url, ref, err := gits.GetGitInfoFromDirectory(dir, gitter)
  2109  	assert.NoError(t, err)
  2110  
  2111  	assert.Equal(t, fmt.Sprintf("https://github.com/%s/%s", owner, repo), url)
  2112  	assert.Equal(t, "master", ref)
  2113  }
  2114  
  2115  func TestGetGitInfoFromDirectoryNoGit(t *testing.T) {
  2116  	t.Parallel()
  2117  	gitter := gits.NewGitCLI()
  2118  	dir, err := ioutil.TempDir("", "")
  2119  	defer os.RemoveAll(dir)
  2120  	assert.NoError(t, err)
  2121  
  2122  	_, _, err = gits.GetGitInfoFromDirectory(dir, gitter)
  2123  	assert.Error(t, err)
  2124  
  2125  	assert.Equal(t, fmt.Sprintf("there was a problem obtaining the remote Git URL of directory %s: failed to unmarshal  due to no GitConfDir defined", dir), err.Error())
  2126  }
  2127  
  2128  func Test_SquashIntoSingleCommit_success(t *testing.T) {
  2129  	gitDir, err := ioutil.TempDir("", "test-repo")
  2130  	assert.NoError(t, err)
  2131  	defer func() {
  2132  		_ = os.RemoveAll(gitDir)
  2133  	}()
  2134  
  2135  	gitter := gits.NewGitCLI()
  2136  
  2137  	err = gitter.Init(gitDir)
  2138  	assert.NoError(t, err)
  2139  
  2140  	readmePath := filepath.Join(gitDir, readme)
  2141  	err = ioutil.WriteFile(readmePath, []byte("readme"), 0600)
  2142  	assert.NoError(t, err)
  2143  	err = gitter.Add(gitDir, readme)
  2144  	assert.NoError(t, err)
  2145  	err = gitter.CommitDir(gitDir, "adding readme")
  2146  	assert.NoError(t, err)
  2147  
  2148  	contributingPath := filepath.Join(gitDir, contributing)
  2149  	err = ioutil.WriteFile(contributingPath, []byte("contribute"), 0600)
  2150  	assert.NoError(t, err)
  2151  	err = gitter.Add(gitDir, contributing)
  2152  	assert.NoError(t, err)
  2153  	err = gitter.CommitDir(gitDir, "adding contribute")
  2154  	assert.NoError(t, err)
  2155  
  2156  	assert.Equal(t, 2, commitCount(t, gitDir))
  2157  
  2158  	err = gits.SquashIntoSingleCommit(gitDir, "squashed", gitter)
  2159  	assert.NoError(t, err)
  2160  
  2161  	assert.Equal(t, 1, commitCount(t, gitDir))
  2162  	assert.FileExists(t, filepath.Join(gitDir, readme))
  2163  	assert.FileExists(t, filepath.Join(gitDir, contributing))
  2164  }
  2165  
  2166  func Test_SquashIntoSingleCommit_with_only_one_commit(t *testing.T) {
  2167  	gitDir, err := ioutil.TempDir("", "test-repo")
  2168  	assert.NoError(t, err)
  2169  	defer func() {
  2170  		_ = os.RemoveAll(gitDir)
  2171  	}()
  2172  
  2173  	gitter := gits.NewGitCLI()
  2174  
  2175  	err = gitter.Init(gitDir)
  2176  	assert.NoError(t, err)
  2177  
  2178  	readmePath := filepath.Join(gitDir, readme)
  2179  	err = ioutil.WriteFile(readmePath, []byte("readme"), 0600)
  2180  	assert.NoError(t, err)
  2181  	err = gitter.Add(gitDir, readme)
  2182  	assert.NoError(t, err)
  2183  	err = gitter.CommitDir(gitDir, "adding readme")
  2184  	assert.NoError(t, err)
  2185  
  2186  	assert.Equal(t, 1, commitCount(t, gitDir))
  2187  
  2188  	err = gits.SquashIntoSingleCommit(gitDir, "squashed", gitter)
  2189  	assert.NoError(t, err)
  2190  
  2191  	assert.Equal(t, 1, commitCount(t, gitDir))
  2192  	assert.FileExists(t, filepath.Join(gitDir, readme))
  2193  	msg, err := gitter.GetLatestCommitMessage(gitDir)
  2194  	assert.NoError(t, err)
  2195  	assert.Equal(t, "squashed", msg)
  2196  }
  2197  
  2198  func Test_SquashIntoSingleCommit_with_no_git_dir_returns_error(t *testing.T) {
  2199  	gitDir, err := ioutil.TempDir("", "test-repo")
  2200  	assert.NoError(t, err)
  2201  	defer func() {
  2202  		_ = os.RemoveAll(gitDir)
  2203  	}()
  2204  
  2205  	gitter := gits.NewGitCLI()
  2206  
  2207  	err = gits.SquashIntoSingleCommit(gitDir, "squashed", gitter)
  2208  	assert.Error(t, err)
  2209  
  2210  	err = gits.SquashIntoSingleCommit("", "squashed", gitter)
  2211  	assert.Error(t, err)
  2212  }
  2213  
  2214  func commitCount(t *testing.T, repoDir string) int {
  2215  	args := []string{"rev-list", "--count", "HEAD"}
  2216  	cmd := util.Command{
  2217  		Dir:  repoDir,
  2218  		Name: "git",
  2219  		Args: args,
  2220  	}
  2221  	out, err := cmd.RunWithoutRetry()
  2222  	assert.NoError(t, err)
  2223  
  2224  	count, err := strconv.Atoi(out)
  2225  	assert.NoError(t, err)
  2226  	return count
  2227  }
  2228  
  2229  func TestIsCouldntFindRemoteRefErrorHandlesUppercaseRef(t *testing.T) {
  2230  	error := errors.New(" fatal: couldn't find remote ref add-app-your-app-0.0.0-SNAPSHOT-PR-1234-1:")
  2231  	ref := "add-app-your-app-0.0.0-SNAPSHOT-PR-1234-1"
  2232  	assert.True(t, gits.IsCouldntFindRemoteRefError(error, ref))
  2233  }
  2234  
  2235  func TestIsDefaultBootConfigURL(t *testing.T) {
  2236  	wrongURL := "https://github.com/something-else/jenkins-x-boot-config.git"
  2237  
  2238  	var rightURLWithDotGit string
  2239  	var rightURLWithoutDotGit string
  2240  
  2241  	if strings.HasSuffix(config.DefaultBootRepository, ".git") {
  2242  		rightURLWithDotGit = config.DefaultBootRepository
  2243  		rightURLWithoutDotGit = strings.TrimSuffix(config.DefaultBootRepository, ".git")
  2244  	} else {
  2245  		rightURLWithoutDotGit = config.DefaultBootRepository
  2246  		rightURLWithDotGit = config.DefaultBootRepository + ".git"
  2247  	}
  2248  
  2249  	withWrongURL, err := gits.IsDefaultBootConfigURL(wrongURL)
  2250  	assert.NoError(t, err)
  2251  	assert.False(t, withWrongURL)
  2252  
  2253  	withRightURLDotGit, err := gits.IsDefaultBootConfigURL(rightURLWithDotGit)
  2254  	assert.NoError(t, err)
  2255  	assert.True(t, withRightURLDotGit)
  2256  
  2257  	withRightURLNoDotGit, err := gits.IsDefaultBootConfigURL(rightURLWithoutDotGit)
  2258  	assert.NoError(t, err)
  2259  	assert.True(t, withRightURLNoDotGit)
  2260  }