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 }