fork of go-git with some jj specific features
at main 85 kB view raw
1package git 2 3import ( 4 "bytes" 5 "context" 6 "errors" 7 "fmt" 8 "io" 9 "os" 10 "os/exec" 11 "os/user" 12 "path" 13 "path/filepath" 14 "regexp" 15 "strings" 16 "testing" 17 "time" 18 19 fixtures "github.com/go-git/go-git-fixtures/v4" 20 "github.com/stretchr/testify/assert" 21 "github.com/stretchr/testify/suite" 22 23 "github.com/ProtonMail/go-crypto/openpgp" 24 "github.com/ProtonMail/go-crypto/openpgp/armor" 25 openpgperr "github.com/ProtonMail/go-crypto/openpgp/errors" 26 27 "github.com/go-git/go-git/v5/config" 28 "github.com/go-git/go-git/v5/plumbing" 29 "github.com/go-git/go-git/v5/plumbing/cache" 30 "github.com/go-git/go-git/v5/plumbing/object" 31 "github.com/go-git/go-git/v5/plumbing/protocol/packp" 32 "github.com/go-git/go-git/v5/plumbing/storer" 33 "github.com/go-git/go-git/v5/plumbing/transport" 34 "github.com/go-git/go-git/v5/storage" 35 "github.com/go-git/go-git/v5/storage/filesystem" 36 "github.com/go-git/go-git/v5/storage/memory" 37 38 "github.com/go-git/go-billy/v5" 39 "github.com/go-git/go-billy/v5/memfs" 40 "github.com/go-git/go-billy/v5/osfs" 41 "github.com/go-git/go-billy/v5/util" 42) 43 44type RepositorySuite struct { 45 suite.Suite 46 BaseSuite 47} 48 49func TestRepositorySuite(t *testing.T) { 50 suite.Run(t, new(RepositorySuite)) 51} 52 53func (s *RepositorySuite) TestInit() { 54 r, err := Init(memory.NewStorage(), memfs.New()) 55 s.NoError(err) 56 s.NotNil(r) 57 58 cfg, err := r.Config() 59 s.NoError(err) 60 s.False(cfg.Core.IsBare) 61 62 // check the HEAD to see what the default branch is 63 createCommit(s, r) 64 ref, err := r.Head() 65 s.NoError(err) 66 s.Equal(plumbing.Master.String(), ref.Name().String()) 67} 68 69func (s *RepositorySuite) TestInitWithOptions() { 70 r, err := InitWithOptions(memory.NewStorage(), memfs.New(), InitOptions{ 71 DefaultBranch: "refs/heads/foo", 72 }) 73 s.NoError(err) 74 s.NotNil(r) 75 createCommit(s, r) 76 77 ref, err := r.Head() 78 s.NoError(err) 79 s.Equal("refs/heads/foo", ref.Name().String()) 80 81} 82 83func (s *RepositorySuite) TestInitWithInvalidDefaultBranch() { 84 _, err := InitWithOptions(memory.NewStorage(), memfs.New(), InitOptions{ 85 DefaultBranch: "foo", 86 }) 87 s.NotNil(err) 88} 89 90func createCommit(s *RepositorySuite, r *Repository) plumbing.Hash { 91 // Create a commit so there is a HEAD to check 92 wt, err := r.Worktree() 93 s.NoError(err) 94 95 rm, err := wt.Filesystem.Create("foo.txt") 96 s.NoError(err) 97 98 _, err = rm.Write([]byte("foo text")) 99 s.NoError(err) 100 101 _, err = wt.Add("foo.txt") 102 s.NoError(err) 103 104 author := object.Signature{ 105 Name: "go-git", 106 Email: "go-git@fake.local", 107 When: time.Now(), 108 } 109 110 h, err := wt.Commit("test commit message", &CommitOptions{ 111 All: true, 112 Author: &author, 113 Committer: &author, 114 AllowEmptyCommits: true, 115 }) 116 s.NoError(err) 117 return h 118} 119 120func (s *RepositorySuite) TestInitNonStandardDotGit() { 121 dir, err := os.MkdirTemp("", "") 122 s.NoError(err) 123 124 fs := osfs.New(dir) 125 dot, _ := fs.Chroot("storage") 126 st := filesystem.NewStorage(dot, cache.NewObjectLRUDefault()) 127 128 wt, _ := fs.Chroot("worktree") 129 r, err := Init(st, wt) 130 s.NoError(err) 131 s.NotNil(r) 132 133 f, err := fs.Open(fs.Join("worktree", ".git")) 134 s.NoError(err) 135 defer func() { _ = f.Close() }() 136 137 all, err := io.ReadAll(f) 138 s.NoError(err) 139 s.Equal(string(all), fmt.Sprintf("gitdir: %s\n", filepath.Join("..", "storage"))) 140 141 cfg, err := r.Config() 142 s.NoError(err) 143 s.Equal(cfg.Core.Worktree, filepath.Join("..", "worktree")) 144} 145 146func (s *RepositorySuite) TestInitStandardDotGit() { 147 dir, err := os.MkdirTemp("", "") 148 s.NoError(err) 149 150 fs := osfs.New(dir) 151 dot, _ := fs.Chroot(".git") 152 st := filesystem.NewStorage(dot, cache.NewObjectLRUDefault()) 153 154 r, err := Init(st, fs) 155 s.NoError(err) 156 s.NotNil(r) 157 158 l, err := fs.ReadDir(".git") 159 s.NoError(err) 160 s.True(len(l) > 0) 161 162 cfg, err := r.Config() 163 s.NoError(err) 164 s.Equal("", cfg.Core.Worktree) 165} 166 167func (s *RepositorySuite) TestInitBare() { 168 r, err := Init(memory.NewStorage(), nil) 169 s.NoError(err) 170 s.NotNil(r) 171 172 cfg, err := r.Config() 173 s.NoError(err) 174 s.True(cfg.Core.IsBare) 175} 176 177func (s *RepositorySuite) TestInitAlreadyExists() { 178 st := memory.NewStorage() 179 180 r, err := Init(st, nil) 181 s.NoError(err) 182 s.NotNil(r) 183 184 r, err = Init(st, nil) 185 s.ErrorIs(err, ErrRepositoryAlreadyExists) 186 s.Nil(r) 187} 188 189func (s *RepositorySuite) TestOpen() { 190 st := memory.NewStorage() 191 192 r, err := Init(st, memfs.New()) 193 s.NoError(err) 194 s.NotNil(r) 195 196 r, err = Open(st, memfs.New()) 197 s.NoError(err) 198 s.NotNil(r) 199} 200 201func (s *RepositorySuite) TestOpenBare() { 202 st := memory.NewStorage() 203 204 r, err := Init(st, nil) 205 s.NoError(err) 206 s.NotNil(r) 207 208 r, err = Open(st, nil) 209 s.NoError(err) 210 s.NotNil(r) 211} 212 213func (s *RepositorySuite) TestOpenBareMissingWorktree() { 214 st := memory.NewStorage() 215 216 r, err := Init(st, memfs.New()) 217 s.NoError(err) 218 s.NotNil(r) 219 220 r, err = Open(st, nil) 221 s.NoError(err) 222 s.NotNil(r) 223} 224 225func (s *RepositorySuite) TestOpenNotExists() { 226 r, err := Open(memory.NewStorage(), nil) 227 s.ErrorIs(err, ErrRepositoryNotExists) 228 s.Nil(r) 229} 230 231func (s *RepositorySuite) TestClone() { 232 r, err := Clone(memory.NewStorage(), nil, &CloneOptions{ 233 URL: s.GetBasicLocalRepositoryURL(), 234 }) 235 236 s.NoError(err) 237 238 remotes, err := r.Remotes() 239 s.NoError(err) 240 s.Len(remotes, 1) 241} 242 243func (s *RepositorySuite) TestCloneContext() { 244 ctx, cancel := context.WithCancel(context.Background()) 245 cancel() 246 247 r, err := CloneContext(ctx, memory.NewStorage(), nil, &CloneOptions{ 248 URL: s.GetBasicLocalRepositoryURL(), 249 }) 250 251 s.NotNil(r) 252 s.ErrorIs(err, context.Canceled) 253} 254 255func (s *RepositorySuite) TestCloneMirror() { 256 r, err := Clone(memory.NewStorage(), nil, &CloneOptions{ 257 URL: fixtures.Basic().One().URL, 258 Mirror: true, 259 }) 260 261 s.NoError(err) 262 263 refs, err := r.References() 264 var count int 265 refs.ForEach(func(r *plumbing.Reference) error { s.T().Log(r); count++; return nil }) 266 s.NoError(err) 267 // 6 refs total from github.com/git-fixtures/basic.git: 268 // - HEAD 269 // - refs/heads/master 270 // - refs/heads/branch 271 // - refs/pull/1/head 272 // - refs/pull/2/head 273 // - refs/pull/2/merge 274 s.Equal(6, count) 275 276 cfg, err := r.Config() 277 s.NoError(err) 278 279 s.True(cfg.Core.IsBare) 280 s.Nil(cfg.Remotes[DefaultRemoteName].Validate()) 281 s.True(cfg.Remotes[DefaultRemoteName].Mirror) 282} 283 284func (s *RepositorySuite) TestCloneWithTags() { 285 url := s.GetLocalRepositoryURL( 286 fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), 287 ) 288 289 r, err := Clone(memory.NewStorage(), nil, &CloneOptions{URL: url, Tags: NoTags}) 290 s.NoError(err) 291 292 remotes, err := r.Remotes() 293 s.NoError(err) 294 s.Len(remotes, 1) 295 296 i, err := r.References() 297 s.NoError(err) 298 299 var count int 300 i.ForEach(func(r *plumbing.Reference) error { count++; return nil }) 301 302 s.Equal(3, count) 303} 304 305func (s *RepositorySuite) TestCloneSparse() { 306 fs := memfs.New() 307 r, err := Clone(memory.NewStorage(), fs, &CloneOptions{ 308 URL: s.GetBasicLocalRepositoryURL(), 309 NoCheckout: true, 310 }) 311 s.NoError(err) 312 313 w, err := r.Worktree() 314 s.NoError(err) 315 316 sparseCheckoutDirectories := []string{"go", "json", "php"} 317 s.NoError(w.Checkout(&CheckoutOptions{ 318 Branch: "refs/heads/master", 319 SparseCheckoutDirectories: sparseCheckoutDirectories, 320 })) 321 322 fis, err := fs.ReadDir(".") 323 s.NoError(err) 324 for _, fi := range fis { 325 s.True(fi.IsDir()) 326 var oneOfSparseCheckoutDirs bool 327 328 for _, sparseCheckoutDirectory := range sparseCheckoutDirectories { 329 if strings.HasPrefix(fi.Name(), sparseCheckoutDirectory) { 330 oneOfSparseCheckoutDirs = true 331 } 332 } 333 s.True(oneOfSparseCheckoutDirs) 334 } 335} 336 337func (s *RepositorySuite) TestCreateRemoteAndRemote() { 338 r, _ := Init(memory.NewStorage(), nil) 339 remote, err := r.CreateRemote(&config.RemoteConfig{ 340 Name: "foo", 341 URLs: []string{"http://foo/foo.git"}, 342 }) 343 344 s.NoError(err) 345 s.Equal("foo", remote.Config().Name) 346 347 alt, err := r.Remote("foo") 348 s.NoError(err) 349 s.NotSame(remote, alt) 350 s.Equal("foo", alt.Config().Name) 351} 352 353func (s *RepositorySuite) TestCreateRemoteInvalid() { 354 r, _ := Init(memory.NewStorage(), nil) 355 remote, err := r.CreateRemote(&config.RemoteConfig{}) 356 357 s.ErrorIs(err, config.ErrRemoteConfigEmptyName) 358 s.Nil(remote) 359} 360 361func (s *RepositorySuite) TestCreateRemoteAnonymous() { 362 r, _ := Init(memory.NewStorage(), nil) 363 remote, err := r.CreateRemoteAnonymous(&config.RemoteConfig{ 364 Name: "anonymous", 365 URLs: []string{"http://foo/foo.git"}, 366 }) 367 368 s.NoError(err) 369 s.Equal("anonymous", remote.Config().Name) 370} 371 372func (s *RepositorySuite) TestCreateRemoteAnonymousInvalidName() { 373 r, _ := Init(memory.NewStorage(), nil) 374 remote, err := r.CreateRemoteAnonymous(&config.RemoteConfig{ 375 Name: "not_anonymous", 376 URLs: []string{"http://foo/foo.git"}, 377 }) 378 379 s.ErrorIs(err, ErrAnonymousRemoteName) 380 s.Nil(remote) 381} 382 383func (s *RepositorySuite) TestCreateRemoteAnonymousInvalid() { 384 r, _ := Init(memory.NewStorage(), nil) 385 remote, err := r.CreateRemoteAnonymous(&config.RemoteConfig{}) 386 387 s.ErrorIs(err, config.ErrRemoteConfigEmptyName) 388 s.Nil(remote) 389} 390 391func (s *RepositorySuite) TestDeleteRemote() { 392 r, _ := Init(memory.NewStorage(), nil) 393 _, err := r.CreateRemote(&config.RemoteConfig{ 394 Name: "foo", 395 URLs: []string{"http://foo/foo.git"}, 396 }) 397 398 s.NoError(err) 399 400 err = r.DeleteRemote("foo") 401 s.NoError(err) 402 403 alt, err := r.Remote("foo") 404 s.ErrorIs(err, ErrRemoteNotFound) 405 s.Nil(alt) 406} 407 408func (s *RepositorySuite) TestEmptyCreateBranch() { 409 r, _ := Init(memory.NewStorage(), nil) 410 err := r.CreateBranch(&config.Branch{}) 411 412 s.NotNil(err) 413} 414 415func (s *RepositorySuite) TestInvalidCreateBranch() { 416 r, _ := Init(memory.NewStorage(), nil) 417 err := r.CreateBranch(&config.Branch{ 418 Name: "-foo", 419 }) 420 421 s.NotNil(err) 422} 423 424func (s *RepositorySuite) TestCreateBranchAndBranch() { 425 r, _ := Init(memory.NewStorage(), nil) 426 testBranch := &config.Branch{ 427 Name: "foo", 428 Remote: "origin", 429 Merge: "refs/heads/foo", 430 } 431 err := r.CreateBranch(testBranch) 432 433 s.NoError(err) 434 cfg, err := r.Config() 435 s.NoError(err) 436 s.Len(cfg.Branches, 1) 437 branch := cfg.Branches["foo"] 438 s.Equal(testBranch.Name, branch.Name) 439 s.Equal(testBranch.Remote, branch.Remote) 440 s.Equal(testBranch.Merge, branch.Merge) 441 442 branch, err = r.Branch("foo") 443 s.NoError(err) 444 s.Equal(testBranch.Name, branch.Name) 445 s.Equal(testBranch.Remote, branch.Remote) 446 s.Equal(testBranch.Merge, branch.Merge) 447} 448 449func (s *RepositorySuite) TestMergeFF() { 450 r, err := Init(memory.NewStorage(), memfs.New()) 451 s.NoError(err) 452 s.NotNil(r) 453 454 createCommit(s, r) 455 createCommit(s, r) 456 createCommit(s, r) 457 lastCommit := createCommit(s, r) 458 459 wt, err := r.Worktree() 460 s.NoError(err) 461 462 targetBranch := plumbing.NewBranchReferenceName("foo") 463 err = wt.Checkout(&CheckoutOptions{ 464 Hash: lastCommit, 465 Create: true, 466 Branch: targetBranch, 467 }) 468 s.NoError(err) 469 470 createCommit(s, r) 471 fooHash := createCommit(s, r) 472 473 // Checkout the master branch so that we can try to merge foo into it. 474 err = wt.Checkout(&CheckoutOptions{ 475 Branch: plumbing.Master, 476 }) 477 s.NoError(err) 478 479 head, err := r.Head() 480 s.NoError(err) 481 s.Equal(lastCommit, head.Hash()) 482 483 targetRef := plumbing.NewHashReference(targetBranch, fooHash) 484 s.NotNil(targetRef) 485 486 err = r.Merge(*targetRef, MergeOptions{ 487 Strategy: FastForwardMerge, 488 }) 489 s.NoError(err) 490 491 head, err = r.Head() 492 s.NoError(err) 493 s.Equal(fooHash, head.Hash()) 494} 495 496func (s *RepositorySuite) TestMergeFF_Invalid() { 497 r, err := Init(memory.NewStorage(), memfs.New()) 498 s.NoError(err) 499 s.NotNil(r) 500 501 // Keep track of the first commit, which will be the 502 // reference to create the target branch so that we 503 // can simulate a non-ff merge. 504 firstCommit := createCommit(s, r) 505 createCommit(s, r) 506 createCommit(s, r) 507 lastCommit := createCommit(s, r) 508 509 wt, err := r.Worktree() 510 s.NoError(err) 511 512 targetBranch := plumbing.NewBranchReferenceName("foo") 513 err = wt.Checkout(&CheckoutOptions{ 514 Hash: firstCommit, 515 Create: true, 516 Branch: targetBranch, 517 }) 518 519 s.NoError(err) 520 521 createCommit(s, r) 522 h := createCommit(s, r) 523 524 // Checkout the master branch so that we can try to merge foo into it. 525 err = wt.Checkout(&CheckoutOptions{ 526 Branch: plumbing.Master, 527 }) 528 s.NoError(err) 529 530 head, err := r.Head() 531 s.NoError(err) 532 s.Equal(lastCommit, head.Hash()) 533 534 targetRef := plumbing.NewHashReference(targetBranch, h) 535 s.NotNil(targetRef) 536 537 err = r.Merge(*targetRef, MergeOptions{ 538 Strategy: MergeStrategy(10), 539 }) 540 s.ErrorIs(err, ErrUnsupportedMergeStrategy) 541 542 // Failed merge operations must not change HEAD. 543 head, err = r.Head() 544 s.NoError(err) 545 s.Equal(lastCommit, head.Hash()) 546 547 err = r.Merge(*targetRef, MergeOptions{}) 548 s.ErrorIs(err, ErrFastForwardMergeNotPossible) 549 550 head, err = r.Head() 551 s.NoError(err) 552 s.Equal(lastCommit, head.Hash()) 553} 554 555func (s *RepositorySuite) TestCreateBranchUnmarshal() { 556 r, _ := Init(memory.NewStorage(), nil) 557 558 expected := []byte(`[core] 559 bare = true 560[remote "foo"] 561 url = http://foo/foo.git 562 fetch = +refs/heads/*:refs/remotes/foo/* 563[branch "foo"] 564 remote = origin 565 merge = refs/heads/foo 566[branch "master"] 567 remote = origin 568 merge = refs/heads/master 569`) 570 571 _, err := r.CreateRemote(&config.RemoteConfig{ 572 Name: "foo", 573 URLs: []string{"http://foo/foo.git"}, 574 }) 575 s.NoError(err) 576 testBranch1 := &config.Branch{ 577 Name: "master", 578 Remote: "origin", 579 Merge: "refs/heads/master", 580 } 581 testBranch2 := &config.Branch{ 582 Name: "foo", 583 Remote: "origin", 584 Merge: "refs/heads/foo", 585 } 586 err = r.CreateBranch(testBranch1) 587 s.NoError(err) 588 err = r.CreateBranch(testBranch2) 589 s.NoError(err) 590 591 cfg, err := r.Config() 592 s.NoError(err) 593 marshaled, err := cfg.Marshal() 594 s.NoError(err) 595 s.Equal(string(marshaled), string(expected)) 596} 597 598func (s *RepositorySuite) TestBranchInvalid() { 599 r, _ := Init(memory.NewStorage(), nil) 600 branch, err := r.Branch("foo") 601 602 s.NotNil(err) 603 s.Nil(branch) 604} 605 606func (s *RepositorySuite) TestCreateBranchInvalid() { 607 r, _ := Init(memory.NewStorage(), nil) 608 err := r.CreateBranch(&config.Branch{}) 609 610 s.NotNil(err) 611 612 testBranch := &config.Branch{ 613 Name: "foo", 614 Remote: "origin", 615 Merge: "refs/heads/foo", 616 } 617 err = r.CreateBranch(testBranch) 618 s.NoError(err) 619 err = r.CreateBranch(testBranch) 620 s.NotNil(err) 621} 622 623func (s *RepositorySuite) TestDeleteBranch() { 624 r, _ := Init(memory.NewStorage(), nil) 625 testBranch := &config.Branch{ 626 Name: "foo", 627 Remote: "origin", 628 Merge: "refs/heads/foo", 629 } 630 err := r.CreateBranch(testBranch) 631 632 s.NoError(err) 633 634 err = r.DeleteBranch("foo") 635 s.NoError(err) 636 637 b, err := r.Branch("foo") 638 s.ErrorIs(err, ErrBranchNotFound) 639 s.Nil(b) 640 641 err = r.DeleteBranch("foo") 642 s.ErrorIs(err, ErrBranchNotFound) 643} 644 645func (s *RepositorySuite) TestPlainInit() { 646 dir, err := os.MkdirTemp("", "") 647 s.NoError(err) 648 649 r, err := PlainInit(dir, true) 650 s.NoError(err) 651 s.NotNil(r) 652 653 cfg, err := r.Config() 654 s.NoError(err) 655 s.True(cfg.Core.IsBare) 656} 657 658func (s *RepositorySuite) TestPlainInitWithOptions() { 659 dir, err := os.MkdirTemp("", "") 660 s.NoError(err) 661 662 r, err := PlainInitWithOptions(dir, &PlainInitOptions{ 663 InitOptions: InitOptions{ 664 DefaultBranch: "refs/heads/foo", 665 }, 666 Bare: false, 667 }) 668 s.NoError(err) 669 s.NotNil(r) 670 671 cfg, err := r.Config() 672 s.NoError(err) 673 s.False(cfg.Core.IsBare) 674 675 createCommit(s, r) 676 677 ref, err := r.Head() 678 s.NoError(err) 679 s.Equal("refs/heads/foo", ref.Name().String()) 680} 681 682func (s *RepositorySuite) TestPlainInitAlreadyExists() { 683 dir, err := os.MkdirTemp("", "") 684 s.NoError(err) 685 686 r, err := PlainInit(dir, true) 687 s.NoError(err) 688 s.NotNil(r) 689 690 r, err = PlainInit(dir, true) 691 s.ErrorIs(err, ErrRepositoryAlreadyExists) 692 s.Nil(r) 693} 694 695func (s *RepositorySuite) TestPlainOpen() { 696 dir, err := os.MkdirTemp("", "") 697 s.NoError(err) 698 699 r, err := PlainInit(dir, false) 700 s.NoError(err) 701 s.NotNil(r) 702 703 r, err = PlainOpen(dir) 704 s.NoError(err) 705 s.NotNil(r) 706} 707 708func (s *RepositorySuite) TestPlainOpenTildePath() { 709 dir, clean := s.TemporalHomeDir() 710 defer clean() 711 712 r, err := PlainInit(dir, false) 713 s.NoError(err) 714 s.NotNil(r) 715 716 currentUser, err := user.Current() 717 s.NoError(err) 718 // remove domain for windows 719 username := currentUser.Username[strings.Index(currentUser.Username, "\\")+1:] 720 721 homes := []string{"~/", "~" + username + "/"} 722 for _, home := range homes { 723 path := strings.Replace(dir, strings.Split(dir, ".tmp")[0], home, 1) 724 725 r, err = PlainOpen(path) 726 s.NoError(err) 727 s.NotNil(r) 728 } 729} 730 731func (s *RepositorySuite) TestPlainOpenBare() { 732 dir, err := os.MkdirTemp("", "") 733 s.NoError(err) 734 735 r, err := PlainInit(dir, true) 736 s.NoError(err) 737 s.NotNil(r) 738 739 r, err = PlainOpen(dir) 740 s.NoError(err) 741 s.NotNil(r) 742} 743 744func (s *RepositorySuite) TestPlainOpenNotBare() { 745 dir, err := os.MkdirTemp("", "") 746 s.NoError(err) 747 748 r, err := PlainInit(dir, false) 749 s.NoError(err) 750 s.NotNil(r) 751 752 r, err = PlainOpen(filepath.Join(dir, ".git")) 753 s.NoError(err) 754 s.NotNil(r) 755} 756 757func (s *RepositorySuite) testPlainOpenGitFile(f func(string, string) string) { 758 fs := s.TemporalFilesystem() 759 760 dir, err := util.TempDir(fs, "", "plain-open") 761 s.NoError(err) 762 763 r, err := PlainInit(fs.Join(fs.Root(), dir), true) 764 s.NoError(err) 765 s.NotNil(r) 766 767 altDir, err := util.TempDir(fs, "", "plain-open") 768 s.NoError(err) 769 770 err = util.WriteFile(fs, fs.Join(altDir, ".git"), 771 []byte(f(fs.Join(fs.Root(), dir), fs.Join(fs.Root(), altDir))), 772 0o644, 773 ) 774 775 s.NoError(err) 776 777 r, err = PlainOpen(fs.Join(fs.Root(), altDir)) 778 s.NoError(err) 779 s.NotNil(r) 780} 781 782func (s *RepositorySuite) TestPlainOpenBareAbsoluteGitDirFile() { 783 s.testPlainOpenGitFile(func(dir, altDir string) string { 784 return fmt.Sprintf("gitdir: %s\n", dir) 785 }) 786} 787 788func (s *RepositorySuite) TestPlainOpenBareAbsoluteGitDirFileNoEOL() { 789 s.testPlainOpenGitFile(func(dir, altDir string) string { 790 return fmt.Sprintf("gitdir: %s", dir) 791 }) 792} 793 794func (s *RepositorySuite) TestPlainOpenBareRelativeGitDirFile() { 795 s.testPlainOpenGitFile(func(dir, altDir string) string { 796 dir, err := filepath.Rel(altDir, dir) 797 s.NoError(err) 798 return fmt.Sprintf("gitdir: %s\n", dir) 799 }) 800} 801 802func (s *RepositorySuite) TestPlainOpenBareRelativeGitDirFileNoEOL() { 803 s.testPlainOpenGitFile(func(dir, altDir string) string { 804 dir, err := filepath.Rel(altDir, dir) 805 s.NoError(err) 806 return fmt.Sprintf("gitdir: %s\n", dir) 807 }) 808} 809 810func (s *RepositorySuite) TestPlainOpenBareRelativeGitDirFileTrailingGarbage() { 811 fs := s.TemporalFilesystem() 812 813 dir, err := util.TempDir(fs, "", "") 814 s.NoError(err) 815 816 r, err := PlainInit(dir, true) 817 s.NoError(err) 818 s.NotNil(r) 819 820 altDir, err := util.TempDir(fs, "", "") 821 s.NoError(err) 822 823 err = util.WriteFile(fs, fs.Join(altDir, ".git"), 824 []byte(fmt.Sprintf("gitdir: %s\nTRAILING", fs.Join(fs.Root(), altDir))), 825 0o644, 826 ) 827 s.NoError(err) 828 829 r, err = PlainOpen(altDir) 830 s.ErrorIs(err, ErrRepositoryNotExists) 831 s.Nil(r) 832} 833 834func (s *RepositorySuite) TestPlainOpenBareRelativeGitDirFileBadPrefix() { 835 fs := s.TemporalFilesystem() 836 837 dir, err := util.TempDir(fs, "", "") 838 s.NoError(err) 839 840 r, err := PlainInit(fs.Join(fs.Root(), dir), true) 841 s.NoError(err) 842 s.NotNil(r) 843 844 altDir, err := util.TempDir(fs, "", "") 845 s.NoError(err) 846 847 err = util.WriteFile(fs, fs.Join(altDir, ".git"), []byte( 848 fmt.Sprintf("xgitdir: %s\n", fs.Join(fs.Root(), dir)), 849 ), 0o644) 850 851 s.NoError(err) 852 853 r, err = PlainOpen(fs.Join(fs.Root(), altDir)) 854 s.ErrorContains(err, "gitdir") 855 s.Nil(r) 856} 857 858func (s *RepositorySuite) TestPlainOpenNotExists() { 859 r, err := PlainOpen("/not-exists/") 860 s.ErrorIs(err, ErrRepositoryNotExists) 861 s.Nil(r) 862} 863 864func (s *RepositorySuite) TestPlainOpenDetectDotGit() { 865 fs := s.TemporalFilesystem() 866 867 dir, err := util.TempDir(fs, "", "") 868 s.NoError(err) 869 870 subdir := filepath.Join(dir, "a", "b") 871 err = fs.MkdirAll(subdir, 0755) 872 s.NoError(err) 873 874 file := fs.Join(subdir, "file.txt") 875 f, err := fs.Create(file) 876 s.NoError(err) 877 f.Close() 878 879 r, err := PlainInit(fs.Join(fs.Root(), dir), false) 880 s.NoError(err) 881 s.NotNil(r) 882 883 opt := &PlainOpenOptions{DetectDotGit: true} 884 r, err = PlainOpenWithOptions(fs.Join(fs.Root(), subdir), opt) 885 s.NoError(err) 886 s.NotNil(r) 887 888 r, err = PlainOpenWithOptions(fs.Join(fs.Root(), file), opt) 889 s.NoError(err) 890 s.NotNil(r) 891 892 optnodetect := &PlainOpenOptions{DetectDotGit: false} 893 r, err = PlainOpenWithOptions(fs.Join(fs.Root(), file), optnodetect) 894 s.NotNil(err) 895 s.Nil(r) 896} 897 898func (s *RepositorySuite) TestPlainOpenNotExistsDetectDotGit() { 899 dir, err := os.MkdirTemp("", "") 900 s.NoError(err) 901 902 opt := &PlainOpenOptions{DetectDotGit: true} 903 r, err := PlainOpenWithOptions(dir, opt) 904 s.ErrorIs(err, ErrRepositoryNotExists) 905 s.Nil(r) 906} 907 908func (s *RepositorySuite) TestPlainClone() { 909 dir, err := os.MkdirTemp("", "") 910 s.NoError(err) 911 912 r, err := PlainClone(dir, false, &CloneOptions{ 913 URL: s.GetBasicLocalRepositoryURL(), 914 }) 915 916 s.NoError(err) 917 918 remotes, err := r.Remotes() 919 s.NoError(err) 920 s.Len(remotes, 1) 921 cfg, err := r.Config() 922 s.NoError(err) 923 s.Len(cfg.Branches, 1) 924 s.Equal("master", cfg.Branches["master"].Name) 925} 926 927func (s *RepositorySuite) TestPlainCloneBareAndShared() { 928 dir, err := os.MkdirTemp("", "") 929 s.NoError(err) 930 931 remote := s.GetBasicLocalRepositoryURL() 932 933 r, err := PlainClone(dir, true, &CloneOptions{ 934 URL: remote, 935 Shared: true, 936 }) 937 s.NoError(err) 938 939 altpath := path.Join(dir, "objects", "info", "alternates") 940 _, err = os.Stat(altpath) 941 s.NoError(err) 942 943 data, err := os.ReadFile(altpath) 944 s.NoError(err) 945 946 line := path.Join(remote, GitDirName, "objects") + "\n" 947 s.Equal(line, string(data)) 948 949 cfg, err := r.Config() 950 s.NoError(err) 951 s.Len(cfg.Branches, 1) 952 s.Equal("master", cfg.Branches["master"].Name) 953} 954 955func (s *RepositorySuite) TestPlainCloneShared() { 956 dir, err := os.MkdirTemp("", "") 957 s.NoError(err) 958 959 remote := s.GetBasicLocalRepositoryURL() 960 961 r, err := PlainClone(dir, false, &CloneOptions{ 962 URL: remote, 963 Shared: true, 964 }) 965 s.NoError(err) 966 967 altpath := path.Join(dir, GitDirName, "objects", "info", "alternates") 968 _, err = os.Stat(altpath) 969 s.NoError(err) 970 971 data, err := os.ReadFile(altpath) 972 s.NoError(err) 973 974 line := path.Join(remote, GitDirName, "objects") + "\n" 975 s.Equal(line, string(data)) 976 977 cfg, err := r.Config() 978 s.NoError(err) 979 s.Len(cfg.Branches, 1) 980 s.Equal("master", cfg.Branches["master"].Name) 981} 982 983func (s *RepositorySuite) TestPlainCloneSharedHttpShouldReturnError() { 984 dir, err := os.MkdirTemp("", "") 985 s.NoError(err) 986 987 remote := "http://somerepo" 988 989 _, err = PlainClone(dir, false, &CloneOptions{ 990 URL: remote, 991 Shared: true, 992 }) 993 s.ErrorIs(err, ErrAlternatePathNotSupported) 994} 995 996func (s *RepositorySuite) TestPlainCloneSharedHttpsShouldReturnError() { 997 dir, err := os.MkdirTemp("", "") 998 s.NoError(err) 999 1000 remote := "https://somerepo" 1001 1002 _, err = PlainClone(dir, false, &CloneOptions{ 1003 URL: remote, 1004 Shared: true, 1005 }) 1006 s.ErrorIs(err, ErrAlternatePathNotSupported) 1007} 1008 1009func (s *RepositorySuite) TestPlainCloneSharedSSHShouldReturnError() { 1010 dir, err := os.MkdirTemp("", "") 1011 s.NoError(err) 1012 1013 remote := "ssh://somerepo" 1014 1015 _, err = PlainClone(dir, false, &CloneOptions{ 1016 URL: remote, 1017 Shared: true, 1018 }) 1019 s.ErrorIs(err, ErrAlternatePathNotSupported) 1020} 1021 1022func (s *RepositorySuite) TestPlainCloneWithRemoteName() { 1023 dir, err := os.MkdirTemp("", "") 1024 s.NoError(err) 1025 1026 r, err := PlainClone(dir, false, &CloneOptions{ 1027 URL: s.GetBasicLocalRepositoryURL(), 1028 RemoteName: "test", 1029 }) 1030 1031 s.NoError(err) 1032 1033 remote, err := r.Remote("test") 1034 s.NoError(err) 1035 s.NotNil(remote) 1036} 1037 1038func (s *RepositorySuite) TestPlainCloneOverExistingGitDirectory() { 1039 dir, err := os.MkdirTemp("", "") 1040 s.NoError(err) 1041 1042 r, err := PlainInit(dir, false) 1043 s.NotNil(r) 1044 s.NoError(err) 1045 1046 r, err = PlainClone(dir, false, &CloneOptions{ 1047 URL: s.GetBasicLocalRepositoryURL(), 1048 }) 1049 s.Nil(r) 1050 s.ErrorIs(err, ErrRepositoryAlreadyExists) 1051} 1052 1053func (s *RepositorySuite) TestPlainCloneContextCancel() { 1054 ctx, cancel := context.WithCancel(context.Background()) 1055 cancel() 1056 1057 dir, err := os.MkdirTemp("", "") 1058 s.NoError(err) 1059 1060 r, err := PlainCloneContext(ctx, dir, false, &CloneOptions{ 1061 URL: s.GetBasicLocalRepositoryURL(), 1062 }) 1063 1064 s.NotNil(r) 1065 s.ErrorIs(err, context.Canceled) 1066} 1067 1068func (s *RepositorySuite) TestPlainCloneContextNonExistentWithExistentDir() { 1069 ctx, cancel := context.WithCancel(context.Background()) 1070 defer cancel() 1071 1072 fs := s.TemporalFilesystem() 1073 1074 dir, err := util.TempDir(fs, "", "") 1075 s.NoError(err) 1076 1077 r, err := PlainCloneContext(ctx, dir, false, &CloneOptions{ 1078 URL: "incorrectOnPurpose", 1079 }) 1080 s.NotNil(r) 1081 s.ErrorIs(err, transport.ErrRepositoryNotFound) 1082 1083 _, err = fs.Stat(dir) 1084 s.False(os.IsNotExist(err)) 1085 1086 names, err := fs.ReadDir(dir) 1087 s.NoError(err) 1088 s.Len(names, 0) 1089} 1090 1091func (s *RepositorySuite) TestPlainCloneContextNonExistentWithNonExistentDir() { 1092 ctx, cancel := context.WithCancel(context.Background()) 1093 defer cancel() 1094 1095 fs := s.TemporalFilesystem() 1096 1097 tmpDir, err := util.TempDir(fs, "", "") 1098 s.NoError(err) 1099 1100 repoDir := filepath.Join(tmpDir, "repoDir") 1101 1102 r, err := PlainCloneContext(ctx, repoDir, false, &CloneOptions{ 1103 URL: "incorrectOnPurpose", 1104 }) 1105 s.NotNil(r) 1106 s.ErrorIs(err, transport.ErrRepositoryNotFound) 1107 1108 _, err = fs.Stat(repoDir) 1109 s.True(os.IsNotExist(err)) 1110} 1111 1112func (s *RepositorySuite) TestPlainCloneContextNonExistentWithNotDir() { 1113 ctx, cancel := context.WithCancel(context.Background()) 1114 cancel() 1115 1116 fs := s.TemporalFilesystem() 1117 1118 tmpDir, err := util.TempDir(fs, "", "") 1119 s.NoError(err) 1120 1121 repoDir := fs.Join(tmpDir, "repoDir") 1122 1123 f, err := fs.Create(repoDir) 1124 s.NoError(err) 1125 s.Nil(f.Close()) 1126 1127 r, err := PlainCloneContext(ctx, fs.Join(fs.Root(), repoDir), false, &CloneOptions{ 1128 URL: "incorrectOnPurpose", 1129 }) 1130 s.Nil(r) 1131 s.ErrorContains(err, "not a directory") 1132 1133 fi, err := fs.Stat(repoDir) 1134 s.NoError(err) 1135 s.False(fi.IsDir()) 1136} 1137 1138func (s *RepositorySuite) TestPlainCloneContextNonExistentWithNotEmptyDir() { 1139 ctx, cancel := context.WithCancel(context.Background()) 1140 defer cancel() 1141 1142 fs := s.TemporalFilesystem() 1143 1144 tmpDir, err := util.TempDir(fs, "", "") 1145 s.NoError(err) 1146 1147 repoDir := filepath.Join(tmpDir, "repoDir") 1148 err = fs.MkdirAll(repoDir, 0777) 1149 s.NoError(err) 1150 1151 dummyFile := filepath.Join(repoDir, "dummyFile") 1152 err = util.WriteFile(fs, dummyFile, []byte("dummyContent"), 0644) 1153 s.NoError(err) 1154 1155 r, err := PlainCloneContext(ctx, fs.Join(fs.Root(), repoDir), false, &CloneOptions{ 1156 URL: "incorrectOnPurpose", 1157 }) 1158 s.NotNil(r) 1159 s.ErrorIs(err, transport.ErrRepositoryNotFound) 1160 1161 _, err = fs.Stat(dummyFile) 1162 s.NoError(err) 1163 1164} 1165 1166func (s *RepositorySuite) TestPlainCloneContextNonExistingOverExistingGitDirectory() { 1167 ctx, cancel := context.WithCancel(context.Background()) 1168 defer cancel() 1169 1170 dir, err := os.MkdirTemp("", "") 1171 s.NoError(err) 1172 1173 r, err := PlainInit(dir, false) 1174 s.NotNil(r) 1175 s.NoError(err) 1176 1177 r, err = PlainCloneContext(ctx, dir, false, &CloneOptions{ 1178 URL: "incorrectOnPurpose", 1179 }) 1180 s.Nil(r) 1181 s.ErrorIs(err, ErrRepositoryAlreadyExists) 1182} 1183 1184func (s *RepositorySuite) TestPlainCloneWithRecurseSubmodules() { 1185 if testing.Short() { 1186 s.T().Skip("skipping test in short mode.") 1187 } 1188 1189 dir, err := os.MkdirTemp("", "") 1190 s.NoError(err) 1191 1192 path := fixtures.ByTag("submodule").One().Worktree().Root() 1193 r, err := PlainClone(dir, false, &CloneOptions{ 1194 URL: path, 1195 RecurseSubmodules: DefaultSubmoduleRecursionDepth, 1196 }) 1197 1198 s.NoError(err) 1199 1200 cfg, err := r.Config() 1201 s.NoError(err) 1202 s.Len(cfg.Remotes, 1) 1203 s.Len(cfg.Branches, 1) 1204 s.Len(cfg.Submodules, 2) 1205} 1206 1207func (s *RepositorySuite) TestPlainCloneWithShallowSubmodules() { 1208 if testing.Short() { 1209 s.T().Skip("skipping test in short mode.") 1210 } 1211 1212 dir, err := os.MkdirTemp("", "") 1213 s.NoError(err) 1214 1215 path := fixtures.ByTag("submodule").One().Worktree().Root() 1216 mainRepo, err := PlainClone(dir, false, &CloneOptions{ 1217 URL: path, 1218 RecurseSubmodules: 1, 1219 ShallowSubmodules: true, 1220 }) 1221 s.NoError(err) 1222 1223 mainWorktree, err := mainRepo.Worktree() 1224 s.NoError(err) 1225 1226 submodule, err := mainWorktree.Submodule("basic") 1227 s.NoError(err) 1228 1229 subRepo, err := submodule.Repository() 1230 s.NoError(err) 1231 1232 lr, err := subRepo.Log(&LogOptions{}) 1233 s.NoError(err) 1234 1235 commitCount := 0 1236 for _, err := lr.Next(); err == nil; _, err = lr.Next() { 1237 commitCount++ 1238 } 1239 s.NoError(err) 1240 1241 s.Equal(1, commitCount) 1242} 1243 1244func (s *RepositorySuite) TestPlainCloneNoCheckout() { 1245 dir, err := os.MkdirTemp("", "") 1246 s.NoError(err) 1247 1248 path := fixtures.ByTag("submodule").One().Worktree().Root() 1249 r, err := PlainClone(dir, false, &CloneOptions{ 1250 URL: path, 1251 NoCheckout: true, 1252 RecurseSubmodules: DefaultSubmoduleRecursionDepth, 1253 }) 1254 s.NoError(err) 1255 1256 h, err := r.Head() 1257 s.NoError(err) 1258 s.Equal("b685400c1f9316f350965a5993d350bc746b0bf4", h.Hash().String()) 1259 1260 fi, err := osfs.New(dir).ReadDir("") 1261 s.NoError(err) 1262 s.Len(fi, 1) // .git 1263} 1264 1265func (s *RepositorySuite) TestFetch() { 1266 r, _ := Init(memory.NewStorage(), nil) 1267 _, err := r.CreateRemote(&config.RemoteConfig{ 1268 Name: DefaultRemoteName, 1269 URLs: []string{s.GetBasicLocalRepositoryURL()}, 1270 }) 1271 s.NoError(err) 1272 s.Nil(r.Fetch(&FetchOptions{})) 1273 1274 remotes, err := r.Remotes() 1275 s.NoError(err) 1276 s.Len(remotes, 1) 1277 1278 _, err = r.Head() 1279 s.ErrorIs(err, plumbing.ErrReferenceNotFound) 1280 1281 branch, err := r.Reference("refs/remotes/origin/master", false) 1282 s.NoError(err) 1283 s.NotNil(branch) 1284 s.Equal(plumbing.HashReference, branch.Type()) 1285 s.Equal("6ecf0ef2c2dffb796033e5a02219af86ec6584e5", branch.Hash().String()) 1286} 1287 1288func (s *RepositorySuite) TestFetchContext() { 1289 r, _ := Init(memory.NewStorage(), nil) 1290 _, err := r.CreateRemote(&config.RemoteConfig{ 1291 Name: DefaultRemoteName, 1292 URLs: []string{s.GetBasicLocalRepositoryURL()}, 1293 }) 1294 s.NoError(err) 1295 1296 ctx, cancel := context.WithCancel(context.Background()) 1297 cancel() 1298 1299 s.NotNil(r.FetchContext(ctx, &FetchOptions{})) 1300} 1301 1302func (s *RepositorySuite) TestFetchWithFilters() { 1303 r, _ := Init(memory.NewStorage(), nil) 1304 _, err := r.CreateRemote(&config.RemoteConfig{ 1305 Name: DefaultRemoteName, 1306 URLs: []string{s.GetBasicLocalRepositoryURL()}, 1307 }) 1308 s.NoError(err) 1309 1310 err = r.Fetch(&FetchOptions{ 1311 Filter: packp.FilterBlobNone(), 1312 }) 1313 s.ErrorIs(err, ErrFilterNotSupported) 1314 1315} 1316func (s *RepositorySuite) TestFetchWithFiltersReal() { 1317 r, _ := Init(memory.NewStorage(), nil) 1318 _, err := r.CreateRemote(&config.RemoteConfig{ 1319 Name: DefaultRemoteName, 1320 URLs: []string{"https://github.com/git-fixtures/basic.git"}, 1321 }) 1322 s.NoError(err) 1323 err = r.Fetch(&FetchOptions{ 1324 Filter: packp.FilterBlobNone(), 1325 }) 1326 s.NoError(err) 1327 blob, err := r.BlobObject(plumbing.NewHash("9a48f23120e880dfbe41f7c9b7b708e9ee62a492")) 1328 s.NotNil(err) 1329 s.Nil(blob) 1330 1331} 1332func (s *RepositorySuite) TestCloneWithProgress() { 1333 fs := memfs.New() 1334 1335 buf := bytes.NewBuffer(nil) 1336 _, err := Clone(memory.NewStorage(), fs, &CloneOptions{ 1337 URL: s.GetBasicLocalRepositoryURL(), 1338 Progress: buf, 1339 }) 1340 1341 s.NoError(err) 1342 s.NotEqual(0, buf.Len()) 1343} 1344 1345func (s *RepositorySuite) TestCloneDeep() { 1346 fs := memfs.New() 1347 r, _ := Init(memory.NewStorage(), fs) 1348 1349 head, err := r.Head() 1350 s.ErrorIs(err, plumbing.ErrReferenceNotFound) 1351 s.Nil(head) 1352 1353 err = r.clone(context.Background(), &CloneOptions{ 1354 URL: s.GetBasicLocalRepositoryURL(), 1355 }) 1356 1357 s.NoError(err) 1358 1359 remotes, err := r.Remotes() 1360 s.NoError(err) 1361 s.Len(remotes, 1) 1362 1363 head, err = r.Reference(plumbing.HEAD, false) 1364 s.NoError(err) 1365 s.NotNil(head) 1366 s.Equal(plumbing.SymbolicReference, head.Type()) 1367 s.Equal("refs/heads/master", head.Target().String()) 1368 1369 branch, err := r.Reference(head.Target(), false) 1370 s.NoError(err) 1371 s.NotNil(branch) 1372 s.Equal("6ecf0ef2c2dffb796033e5a02219af86ec6584e5", branch.Hash().String()) 1373 1374 branch, err = r.Reference("refs/remotes/origin/master", false) 1375 s.NoError(err) 1376 s.NotNil(branch) 1377 s.Equal(plumbing.HashReference, branch.Type()) 1378 s.Equal("6ecf0ef2c2dffb796033e5a02219af86ec6584e5", branch.Hash().String()) 1379 1380 fi, err := fs.ReadDir("") 1381 s.NoError(err) 1382 s.Len(fi, 8) 1383} 1384 1385func (s *RepositorySuite) TestCloneConfig() { 1386 r, _ := Init(memory.NewStorage(), nil) 1387 1388 head, err := r.Head() 1389 s.ErrorIs(err, plumbing.ErrReferenceNotFound) 1390 s.Nil(head) 1391 1392 err = r.clone(context.Background(), &CloneOptions{ 1393 URL: s.GetBasicLocalRepositoryURL(), 1394 }) 1395 1396 s.NoError(err) 1397 1398 cfg, err := r.Config() 1399 s.NoError(err) 1400 1401 s.True(cfg.Core.IsBare) 1402 s.Len(cfg.Remotes, 1) 1403 s.Equal("origin", cfg.Remotes["origin"].Name) 1404 s.Len(cfg.Remotes["origin"].URLs, 1) 1405 s.Len(cfg.Branches, 1) 1406 s.Equal("master", cfg.Branches["master"].Name) 1407} 1408 1409func (s *RepositorySuite) TestCloneSingleBranchAndNonHEAD() { 1410 s.testCloneSingleBranchAndNonHEADReference("refs/heads/branch") 1411} 1412 1413func (s *RepositorySuite) TestCloneSingleBranchAndNonHEADAndNonFull() { 1414 s.testCloneSingleBranchAndNonHEADReference("branch") 1415} 1416 1417func (s *RepositorySuite) testCloneSingleBranchAndNonHEADReference(ref string) { 1418 r, _ := Init(memory.NewStorage(), nil) 1419 1420 head, err := r.Head() 1421 s.ErrorIs(err, plumbing.ErrReferenceNotFound) 1422 s.Nil(head) 1423 1424 err = r.clone(context.Background(), &CloneOptions{ 1425 URL: s.GetBasicLocalRepositoryURL(), 1426 ReferenceName: plumbing.ReferenceName(ref), 1427 SingleBranch: true, 1428 }) 1429 1430 s.NoError(err) 1431 1432 remotes, err := r.Remotes() 1433 s.NoError(err) 1434 s.Len(remotes, 1) 1435 1436 cfg, err := r.Config() 1437 s.NoError(err) 1438 s.Len(cfg.Branches, 1) 1439 s.Equal("branch", cfg.Branches["branch"].Name) 1440 s.Equal("origin", cfg.Branches["branch"].Remote) 1441 s.Equal(plumbing.ReferenceName("refs/heads/branch"), cfg.Branches["branch"].Merge) 1442 1443 head, err = r.Reference(plumbing.HEAD, false) 1444 s.NoError(err) 1445 s.NotNil(head) 1446 s.Equal(plumbing.SymbolicReference, head.Type()) 1447 s.Equal("refs/heads/branch", head.Target().String()) 1448 1449 branch, err := r.Reference(head.Target(), false) 1450 s.NoError(err) 1451 s.NotNil(branch) 1452 s.Equal("e8d3ffab552895c19b9fcf7aa264d277cde33881", branch.Hash().String()) 1453 1454 branch, err = r.Reference("refs/remotes/origin/branch", false) 1455 s.NoError(err) 1456 s.NotNil(branch) 1457 s.Equal(plumbing.HashReference, branch.Type()) 1458 s.Equal("e8d3ffab552895c19b9fcf7aa264d277cde33881", branch.Hash().String()) 1459} 1460 1461func (s *RepositorySuite) TestCloneSingleBranchHEADMain() { 1462 r, _ := Init(memory.NewStorage(), nil) 1463 1464 head, err := r.Head() 1465 s.ErrorIs(err, plumbing.ErrReferenceNotFound) 1466 s.Nil(head) 1467 1468 err = r.clone(context.Background(), &CloneOptions{ 1469 URL: s.GetLocalRepositoryURL(fixtures.ByTag("no-master-head").One()), 1470 SingleBranch: true, 1471 }) 1472 1473 s.NoError(err) 1474 1475 remotes, err := r.Remotes() 1476 s.NoError(err) 1477 s.Len(remotes, 1) 1478 1479 cfg, err := r.Config() 1480 s.NoError(err) 1481 s.Len(cfg.Branches, 1) 1482 s.Equal("main", cfg.Branches["main"].Name) 1483 s.Equal("origin", cfg.Branches["main"].Remote) 1484 s.Equal(plumbing.ReferenceName("refs/heads/main"), cfg.Branches["main"].Merge) 1485 1486 head, err = r.Reference(plumbing.HEAD, false) 1487 s.NoError(err) 1488 s.NotNil(head) 1489 s.Equal(plumbing.SymbolicReference, head.Type()) 1490 s.Equal("refs/heads/main", head.Target().String()) 1491 1492 branch, err := r.Reference(head.Target(), false) 1493 s.NoError(err) 1494 s.NotNil(branch) 1495 s.Equal("786dafbd351e587da1ae97e5fb9fbdf868b4a28f", branch.Hash().String()) 1496 1497 branch, err = r.Reference("refs/remotes/origin/HEAD", false) 1498 s.NoError(err) 1499 s.NotNil(branch) 1500 s.Equal(plumbing.HashReference, branch.Type()) 1501 s.Equal("786dafbd351e587da1ae97e5fb9fbdf868b4a28f", branch.Hash().String()) 1502} 1503 1504func (s *RepositorySuite) TestCloneSingleBranch() { 1505 r, _ := Init(memory.NewStorage(), nil) 1506 1507 head, err := r.Head() 1508 s.ErrorIs(err, plumbing.ErrReferenceNotFound) 1509 s.Nil(head) 1510 1511 err = r.clone(context.Background(), &CloneOptions{ 1512 URL: s.GetBasicLocalRepositoryURL(), 1513 SingleBranch: true, 1514 }) 1515 1516 s.NoError(err) 1517 1518 remotes, err := r.Remotes() 1519 s.NoError(err) 1520 s.Len(remotes, 1) 1521 1522 cfg, err := r.Config() 1523 s.NoError(err) 1524 s.Len(cfg.Branches, 1) 1525 s.Equal("master", cfg.Branches["master"].Name) 1526 s.Equal("origin", cfg.Branches["master"].Remote) 1527 s.Equal(plumbing.ReferenceName("refs/heads/master"), cfg.Branches["master"].Merge) 1528 1529 head, err = r.Reference(plumbing.HEAD, false) 1530 s.NoError(err) 1531 s.NotNil(head) 1532 s.Equal(plumbing.SymbolicReference, head.Type()) 1533 s.Equal("refs/heads/master", head.Target().String()) 1534 1535 branch, err := r.Reference(head.Target(), false) 1536 s.NoError(err) 1537 s.NotNil(branch) 1538 s.Equal("6ecf0ef2c2dffb796033e5a02219af86ec6584e5", branch.Hash().String()) 1539} 1540 1541func (s *RepositorySuite) TestCloneSingleTag() { 1542 r, _ := Init(memory.NewStorage(), nil) 1543 1544 url := s.GetLocalRepositoryURL( 1545 fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), 1546 ) 1547 1548 err := r.clone(context.Background(), &CloneOptions{ 1549 URL: url, 1550 SingleBranch: true, 1551 ReferenceName: plumbing.ReferenceName("refs/tags/commit-tag"), 1552 }) 1553 s.NoError(err) 1554 1555 branch, err := r.Reference("refs/tags/commit-tag", false) 1556 s.NoError(err) 1557 s.NotNil(branch) 1558 1559 conf, err := r.Config() 1560 s.NoError(err) 1561 originRemote := conf.Remotes["origin"] 1562 s.NotNil(originRemote) 1563 s.Len(originRemote.Fetch, 1) 1564 s.Equal("+refs/tags/commit-tag:refs/tags/commit-tag", originRemote.Fetch[0].String()) 1565} 1566 1567func (s *RepositorySuite) TestCloneDetachedHEAD() { 1568 r, _ := Init(memory.NewStorage(), nil) 1569 err := r.clone(context.Background(), &CloneOptions{ 1570 URL: s.GetBasicLocalRepositoryURL(), 1571 ReferenceName: plumbing.ReferenceName("refs/tags/v1.0.0"), 1572 }) 1573 s.NoError(err) 1574 1575 cfg, err := r.Config() 1576 s.NoError(err) 1577 s.Len(cfg.Branches, 0) 1578 1579 head, err := r.Reference(plumbing.HEAD, false) 1580 s.NoError(err) 1581 s.NotNil(head) 1582 s.Equal(plumbing.HashReference, head.Type()) 1583 s.Equal("6ecf0ef2c2dffb796033e5a02219af86ec6584e5", head.Hash().String()) 1584 1585 count := 0 1586 objects, err := r.Objects() 1587 s.NoError(err) 1588 objects.ForEach(func(object.Object) error { count++; return nil }) 1589 s.Equal(28, count) 1590} 1591 1592func (s *RepositorySuite) TestCloneDetachedHEADAndSingle() { 1593 r, _ := Init(memory.NewStorage(), nil) 1594 err := r.clone(context.Background(), &CloneOptions{ 1595 URL: s.GetBasicLocalRepositoryURL(), 1596 ReferenceName: plumbing.ReferenceName("refs/tags/v1.0.0"), 1597 SingleBranch: true, 1598 }) 1599 s.NoError(err) 1600 1601 cfg, err := r.Config() 1602 s.NoError(err) 1603 s.Len(cfg.Branches, 0) 1604 1605 head, err := r.Reference(plumbing.HEAD, false) 1606 s.NoError(err) 1607 s.NotNil(head) 1608 s.Equal(plumbing.HashReference, head.Type()) 1609 s.Equal("6ecf0ef2c2dffb796033e5a02219af86ec6584e5", head.Hash().String()) 1610 1611 count := 0 1612 objects, err := r.Objects() 1613 s.NoError(err) 1614 objects.ForEach(func(object.Object) error { count++; return nil }) 1615 s.Equal(28, count) 1616} 1617 1618func (s *RepositorySuite) TestCloneDetachedHEADAndShallow() { 1619 r, _ := Init(memory.NewStorage(), memfs.New()) 1620 err := r.clone(context.Background(), &CloneOptions{ 1621 URL: s.GetBasicLocalRepositoryURL(), 1622 ReferenceName: plumbing.ReferenceName("refs/tags/v1.0.0"), 1623 Depth: 1, 1624 }) 1625 1626 s.NoError(err) 1627 1628 cfg, err := r.Config() 1629 s.NoError(err) 1630 s.Len(cfg.Branches, 0) 1631 1632 head, err := r.Reference(plumbing.HEAD, false) 1633 s.NoError(err) 1634 s.NotNil(head) 1635 s.Equal(plumbing.HashReference, head.Type()) 1636 s.Equal("6ecf0ef2c2dffb796033e5a02219af86ec6584e5", head.Hash().String()) 1637 1638 count := 0 1639 objects, err := r.Objects() 1640 s.NoError(err) 1641 objects.ForEach(func(object.Object) error { count++; return nil }) 1642 s.Equal(15, count) 1643} 1644 1645func (s *RepositorySuite) TestCloneDetachedHEADAnnotatedTag() { 1646 r, _ := Init(memory.NewStorage(), nil) 1647 err := r.clone(context.Background(), &CloneOptions{ 1648 URL: s.GetLocalRepositoryURL(fixtures.ByTag("tags").One()), 1649 ReferenceName: plumbing.ReferenceName("refs/tags/annotated-tag"), 1650 }) 1651 s.NoError(err) 1652 1653 cfg, err := r.Config() 1654 s.NoError(err) 1655 s.Len(cfg.Branches, 0) 1656 1657 head, err := r.Reference(plumbing.HEAD, false) 1658 s.NoError(err) 1659 s.NotNil(head) 1660 s.Equal(plumbing.HashReference, head.Type()) 1661 s.Equal("f7b877701fbf855b44c0a9e86f3fdce2c298b07f", head.Hash().String()) 1662 1663 count := 0 1664 objects, err := r.Objects() 1665 s.NoError(err) 1666 objects.ForEach(func(object.Object) error { count++; return nil }) 1667 s.Equal(7, count) 1668} 1669 1670func (s *RepositorySuite) TestCloneWithFilter() { 1671 r, _ := Init(memory.NewStorage(), nil) 1672 1673 err := r.clone(context.Background(), &CloneOptions{ 1674 URL: "https://github.com/git-fixtures/basic.git", 1675 Filter: packp.FilterTreeDepth(0), 1676 }) 1677 s.NoError(err) 1678 blob, err := r.BlobObject(plumbing.NewHash("9a48f23120e880dfbe41f7c9b7b708e9ee62a492")) 1679 s.NotNil(err) 1680 s.Nil(blob) 1681} 1682func (s *RepositorySuite) TestPush() { 1683 url, err := os.MkdirTemp("", "") 1684 s.NoError(err) 1685 1686 server, err := PlainInit(url, true) 1687 s.NoError(err) 1688 1689 _, err = s.Repository.CreateRemote(&config.RemoteConfig{ 1690 Name: "test", 1691 URLs: []string{url}, 1692 }) 1693 s.NoError(err) 1694 1695 err = s.Repository.Push(&PushOptions{ 1696 RemoteName: "test", 1697 }) 1698 s.NoError(err) 1699 1700 AssertReferences(s.T(), server, map[string]string{ 1701 "refs/heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 1702 "refs/heads/branch": "e8d3ffab552895c19b9fcf7aa264d277cde33881", 1703 }) 1704 1705 AssertReferences(s.T(), s.Repository, map[string]string{ 1706 "refs/remotes/test/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 1707 "refs/remotes/test/branch": "e8d3ffab552895c19b9fcf7aa264d277cde33881", 1708 }) 1709} 1710 1711func (s *RepositorySuite) TestPushContext() { 1712 url, err := os.MkdirTemp("", "") 1713 s.NoError(err) 1714 1715 _, err = PlainInit(url, true) 1716 s.NoError(err) 1717 1718 _, err = s.Repository.CreateRemote(&config.RemoteConfig{ 1719 Name: "foo", 1720 URLs: []string{url}, 1721 }) 1722 s.NoError(err) 1723 1724 ctx, cancel := context.WithCancel(context.Background()) 1725 cancel() 1726 1727 err = s.Repository.PushContext(ctx, &PushOptions{ 1728 RemoteName: "foo", 1729 }) 1730 s.NotNil(err) 1731} 1732 1733// installPreReceiveHook installs a pre-receive hook in the .git 1734// directory at path which prints message m before exiting 1735// successfully. 1736func installPreReceiveHook(s *RepositorySuite, fs billy.Filesystem, path, m string) { 1737 hooks := fs.Join(path, "hooks") 1738 err := fs.MkdirAll(hooks, 0777) 1739 s.NoError(err) 1740 1741 err = util.WriteFile(fs, fs.Join(hooks, "pre-receive"), preReceiveHook(m), 0777) 1742 s.NoError(err) 1743} 1744 1745func (s *RepositorySuite) TestPushWithProgress() { 1746 fs := s.TemporalFilesystem() 1747 1748 path, err := util.TempDir(fs, "", "") 1749 s.NoError(err) 1750 1751 url := fs.Join(fs.Root(), path) 1752 1753 server, err := PlainInit(url, true) 1754 s.NoError(err) 1755 1756 m := "Receiving..." 1757 installPreReceiveHook(s, fs, path, m) 1758 1759 _, err = s.Repository.CreateRemote(&config.RemoteConfig{ 1760 Name: "bar", 1761 URLs: []string{url}, 1762 }) 1763 s.NoError(err) 1764 1765 var p bytes.Buffer 1766 err = s.Repository.Push(&PushOptions{ 1767 RemoteName: "bar", 1768 Progress: &p, 1769 }) 1770 s.NoError(err) 1771 1772 AssertReferences(s.T(), server, map[string]string{ 1773 "refs/heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 1774 "refs/heads/branch": "e8d3ffab552895c19b9fcf7aa264d277cde33881", 1775 }) 1776 1777 s.Equal([]byte(m), (&p).Bytes()) 1778} 1779 1780func (s *RepositorySuite) TestPushDepth() { 1781 url, err := os.MkdirTemp("", "") 1782 s.NoError(err) 1783 1784 server, err := PlainClone(url, true, &CloneOptions{ 1785 URL: fixtures.Basic().One().DotGit().Root(), 1786 }) 1787 1788 s.NoError(err) 1789 1790 r, err := Clone(memory.NewStorage(), memfs.New(), &CloneOptions{ 1791 URL: url, 1792 Depth: 1, 1793 }) 1794 s.NoError(err) 1795 1796 err = util.WriteFile(r.wt, "foo", nil, 0755) 1797 s.NoError(err) 1798 1799 w, err := r.Worktree() 1800 s.NoError(err) 1801 1802 _, err = w.Add("foo") 1803 s.NoError(err) 1804 1805 hash, err := w.Commit("foo", &CommitOptions{ 1806 Author: defaultSignature(), 1807 Committer: defaultSignature(), 1808 }) 1809 s.NoError(err) 1810 1811 err = r.Push(&PushOptions{}) 1812 s.NoError(err) 1813 1814 AssertReferences(s.T(), server, map[string]string{ 1815 "refs/heads/master": hash.String(), 1816 }) 1817 1818 AssertReferences(s.T(), r, map[string]string{ 1819 "refs/remotes/origin/master": hash.String(), 1820 }) 1821} 1822 1823func (s *RepositorySuite) TestPushNonExistentRemote() { 1824 srcFs := fixtures.Basic().One().DotGit() 1825 sto := filesystem.NewStorage(srcFs, cache.NewObjectLRUDefault()) 1826 1827 r, err := Open(sto, srcFs) 1828 s.NoError(err) 1829 1830 err = r.Push(&PushOptions{RemoteName: "myremote"}) 1831 s.ErrorContains(err, "remote not found") 1832} 1833 1834func (s *RepositorySuite) TestLog() { 1835 r, _ := Init(memory.NewStorage(), nil) 1836 err := r.clone(context.Background(), &CloneOptions{ 1837 URL: s.GetBasicLocalRepositoryURL(), 1838 }) 1839 1840 s.NoError(err) 1841 1842 cIter, err := r.Log(&LogOptions{ 1843 From: plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"), 1844 }) 1845 1846 s.NoError(err) 1847 1848 commitOrder := []plumbing.Hash{ 1849 plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"), 1850 plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"), 1851 } 1852 1853 for _, o := range commitOrder { 1854 commit, err := cIter.Next() 1855 s.NoError(err) 1856 s.Equal(o, commit.Hash) 1857 } 1858 _, err = cIter.Next() 1859 s.ErrorIs(err, io.EOF) 1860} 1861 1862func (s *RepositorySuite) TestLogAll() { 1863 r, _ := Init(memory.NewStorage(), nil) 1864 err := r.clone(context.Background(), &CloneOptions{ 1865 URL: s.GetBasicLocalRepositoryURL(), 1866 }) 1867 s.NoError(err) 1868 1869 rIter, err := r.Storer.IterReferences() 1870 s.NoError(err) 1871 1872 refCount := 0 1873 err = rIter.ForEach(func(ref *plumbing.Reference) error { 1874 refCount++ 1875 return nil 1876 }) 1877 s.NoError(err) 1878 s.Equal(5, refCount) 1879 1880 cIter, err := r.Log(&LogOptions{ 1881 All: true, 1882 }) 1883 s.NoError(err) 1884 1885 commitOrder := []plumbing.Hash{ 1886 plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), 1887 plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881"), 1888 plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"), 1889 plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"), 1890 plumbing.NewHash("1669dce138d9b841a518c64b10914d88f5e488ea"), 1891 plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), 1892 plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"), 1893 plumbing.NewHash("a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69"), 1894 plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"), 1895 } 1896 1897 for _, o := range commitOrder { 1898 commit, err := cIter.Next() 1899 s.NoError(err) 1900 s.Equal(o, commit.Hash) 1901 } 1902 _, err = cIter.Next() 1903 s.ErrorIs(err, io.EOF) 1904 cIter.Close() 1905} 1906 1907func (s *RepositorySuite) TestLogAllMissingReferences() { 1908 r, _ := Init(memory.NewStorage(), nil) 1909 err := r.clone(context.Background(), &CloneOptions{ 1910 URL: s.GetBasicLocalRepositoryURL(), 1911 }) 1912 s.NoError(err) 1913 err = r.Storer.RemoveReference(plumbing.HEAD) 1914 s.NoError(err) 1915 1916 rIter, err := r.Storer.IterReferences() 1917 s.NoError(err) 1918 1919 refCount := 0 1920 err = rIter.ForEach(func(ref *plumbing.Reference) error { 1921 refCount++ 1922 return nil 1923 }) 1924 s.NoError(err) 1925 s.Equal(4, refCount) 1926 1927 err = r.Storer.SetReference(plumbing.NewHashReference(plumbing.ReferenceName("DUMMY"), plumbing.NewHash("DUMMY"))) 1928 s.NoError(err) 1929 1930 rIter, err = r.Storer.IterReferences() 1931 s.NoError(err) 1932 1933 refCount = 0 1934 err = rIter.ForEach(func(ref *plumbing.Reference) error { 1935 refCount++ 1936 return nil 1937 }) 1938 s.NoError(err) 1939 s.Equal(5, refCount) 1940 1941 cIter, err := r.Log(&LogOptions{ 1942 All: true, 1943 }) 1944 s.NotNil(cIter) 1945 s.NoError(err) 1946 1947 cCount := 0 1948 cIter.ForEach(func(c *object.Commit) error { 1949 cCount++ 1950 return nil 1951 }) 1952 s.Equal(9, cCount) 1953 1954 _, err = cIter.Next() 1955 s.ErrorIs(err, io.EOF) 1956 cIter.Close() 1957} 1958 1959func (s *RepositorySuite) TestLogAllOrderByTime() { 1960 r, _ := Init(memory.NewStorage(), nil) 1961 err := r.clone(context.Background(), &CloneOptions{ 1962 URL: s.GetBasicLocalRepositoryURL(), 1963 }) 1964 1965 s.NoError(err) 1966 1967 cIter, err := r.Log(&LogOptions{ 1968 Order: LogOrderCommitterTime, 1969 All: true, 1970 }) 1971 s.NoError(err) 1972 1973 commitOrder := []plumbing.Hash{ 1974 plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), 1975 plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881"), 1976 plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"), 1977 plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"), 1978 plumbing.NewHash("1669dce138d9b841a518c64b10914d88f5e488ea"), 1979 plumbing.NewHash("a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69"), 1980 plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), 1981 plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"), 1982 plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"), 1983 } 1984 1985 for _, o := range commitOrder { 1986 commit, err := cIter.Next() 1987 s.NoError(err) 1988 s.Equal(o, commit.Hash) 1989 } 1990 _, err = cIter.Next() 1991 s.ErrorIs(err, io.EOF) 1992 cIter.Close() 1993} 1994 1995func (s *RepositorySuite) TestLogHead() { 1996 r, _ := Init(memory.NewStorage(), nil) 1997 err := r.clone(context.Background(), &CloneOptions{ 1998 URL: s.GetBasicLocalRepositoryURL(), 1999 }) 2000 2001 s.NoError(err) 2002 2003 cIter, err := r.Log(&LogOptions{}) 2004 2005 s.NoError(err) 2006 2007 commitOrder := []plumbing.Hash{ 2008 plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), 2009 plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"), 2010 plumbing.NewHash("af2d6a6954d532f8ffb47615169c8fdf9d383a1a"), 2011 plumbing.NewHash("1669dce138d9b841a518c64b10914d88f5e488ea"), 2012 plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), 2013 plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"), 2014 plumbing.NewHash("a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69"), 2015 plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47"), 2016 } 2017 2018 for _, o := range commitOrder { 2019 commit, err := cIter.Next() 2020 s.NoError(err) 2021 s.Equal(o, commit.Hash) 2022 } 2023 _, err = cIter.Next() 2024 s.ErrorIs(err, io.EOF) 2025} 2026 2027func (s *RepositorySuite) TestLogError() { 2028 r, _ := Init(memory.NewStorage(), nil) 2029 err := r.clone(context.Background(), &CloneOptions{ 2030 URL: s.GetBasicLocalRepositoryURL(), 2031 }) 2032 2033 s.NoError(err) 2034 2035 _, err = r.Log(&LogOptions{ 2036 From: plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), 2037 }) 2038 s.NotNil(err) 2039} 2040 2041func (s *RepositorySuite) TestLogFileNext() { 2042 r, _ := Init(memory.NewStorage(), nil) 2043 err := r.clone(context.Background(), &CloneOptions{ 2044 URL: s.GetBasicLocalRepositoryURL(), 2045 }) 2046 2047 s.NoError(err) 2048 2049 fileName := "vendor/foo.go" 2050 cIter, err := r.Log(&LogOptions{FileName: &fileName}) 2051 2052 s.NoError(err) 2053 2054 commitOrder := []plumbing.Hash{ 2055 plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), 2056 } 2057 2058 for _, o := range commitOrder { 2059 commit, err := cIter.Next() 2060 s.NoError(err) 2061 s.Equal(o, commit.Hash) 2062 } 2063 _, err = cIter.Next() 2064 s.ErrorIs(err, io.EOF) 2065} 2066 2067func (s *RepositorySuite) TestLogFileForEach() { 2068 r, _ := Init(memory.NewStorage(), nil) 2069 err := r.clone(context.Background(), &CloneOptions{ 2070 URL: s.GetBasicLocalRepositoryURL(), 2071 }) 2072 2073 s.NoError(err) 2074 2075 fileName := "php/crappy.php" 2076 cIter, err := r.Log(&LogOptions{FileName: &fileName}) 2077 s.NoError(err) 2078 defer cIter.Close() 2079 2080 commitOrder := []plumbing.Hash{ 2081 plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"), 2082 } 2083 2084 expectedIndex := 0 2085 err = cIter.ForEach(func(commit *object.Commit) error { 2086 expectedCommitHash := commitOrder[expectedIndex] 2087 s.Equal(expectedCommitHash.String(), commit.Hash.String()) 2088 expectedIndex++ 2089 return nil 2090 }) 2091 s.NoError(err) 2092 s.Equal(1, expectedIndex) 2093} 2094 2095func (s *RepositorySuite) TestLogNonHeadFile() { 2096 r, _ := Init(memory.NewStorage(), nil) 2097 err := r.clone(context.Background(), &CloneOptions{ 2098 URL: s.GetBasicLocalRepositoryURL(), 2099 }) 2100 2101 s.NoError(err) 2102 2103 fileName := "README" 2104 cIter, err := r.Log(&LogOptions{FileName: &fileName}) 2105 s.NoError(err) 2106 defer cIter.Close() 2107 2108 _, err = cIter.Next() 2109 s.ErrorIs(err, io.EOF) 2110} 2111 2112func (s *RepositorySuite) TestLogAllFileForEach() { 2113 r, _ := Init(memory.NewStorage(), nil) 2114 err := r.clone(context.Background(), &CloneOptions{ 2115 URL: s.GetBasicLocalRepositoryURL(), 2116 }) 2117 2118 s.NoError(err) 2119 2120 fileName := "README" 2121 cIter, err := r.Log(&LogOptions{FileName: &fileName, All: true}) 2122 s.NoError(err) 2123 defer cIter.Close() 2124 2125 commitOrder := []plumbing.Hash{ 2126 plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881"), 2127 } 2128 2129 expectedIndex := 0 2130 err = cIter.ForEach(func(commit *object.Commit) error { 2131 expectedCommitHash := commitOrder[expectedIndex] 2132 s.Equal(expectedCommitHash.String(), commit.Hash.String()) 2133 expectedIndex++ 2134 return nil 2135 }) 2136 s.NoError(err) 2137 s.Equal(1, expectedIndex) 2138} 2139 2140func (s *RepositorySuite) TestLogInvalidFile() { 2141 r, _ := Init(memory.NewStorage(), nil) 2142 err := r.clone(context.Background(), &CloneOptions{ 2143 URL: s.GetBasicLocalRepositoryURL(), 2144 }) 2145 s.NoError(err) 2146 2147 // Throwing in a file that does not exist 2148 fileName := "vendor/foo12.go" 2149 cIter, err := r.Log(&LogOptions{FileName: &fileName}) 2150 // Not raising an error since `git log -- vendor/foo12.go` responds silently 2151 s.NoError(err) 2152 defer cIter.Close() 2153 2154 _, err = cIter.Next() 2155 s.ErrorIs(err, io.EOF) 2156} 2157 2158func (s *RepositorySuite) TestLogFileInitialCommit() { 2159 r, _ := Init(memory.NewStorage(), nil) 2160 err := r.clone(context.Background(), &CloneOptions{ 2161 URL: s.GetBasicLocalRepositoryURL(), 2162 }) 2163 s.NoError(err) 2164 2165 fileName := "LICENSE" 2166 cIter, err := r.Log(&LogOptions{ 2167 Order: LogOrderCommitterTime, 2168 FileName: &fileName, 2169 }) 2170 s.NoError(err) 2171 defer cIter.Close() 2172 2173 commitOrder := []plumbing.Hash{ 2174 plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d"), 2175 } 2176 2177 expectedIndex := 0 2178 err = cIter.ForEach(func(commit *object.Commit) error { 2179 expectedCommitHash := commitOrder[expectedIndex] 2180 s.Equal(expectedCommitHash.String(), commit.Hash.String()) 2181 expectedIndex++ 2182 return nil 2183 }) 2184 s.NoError(err) 2185 s.Equal(1, expectedIndex) 2186} 2187 2188func (s *RepositorySuite) TestLogFileWithOtherParamsFail() { 2189 r, _ := Init(memory.NewStorage(), nil) 2190 err := r.clone(context.Background(), &CloneOptions{ 2191 URL: s.GetBasicLocalRepositoryURL(), 2192 }) 2193 s.NoError(err) 2194 2195 fileName := "vendor/foo.go" 2196 cIter, err := r.Log(&LogOptions{ 2197 Order: LogOrderCommitterTime, 2198 FileName: &fileName, 2199 From: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), 2200 }) 2201 s.NoError(err) 2202 defer cIter.Close() 2203 2204 _, iterErr := cIter.Next() 2205 s.Equal(io.EOF, iterErr) 2206} 2207 2208func (s *RepositorySuite) TestLogFileWithOtherParamsPass() { 2209 r, _ := Init(memory.NewStorage(), nil) 2210 err := r.clone(context.Background(), &CloneOptions{ 2211 URL: s.GetBasicLocalRepositoryURL(), 2212 }) 2213 s.NoError(err) 2214 2215 fileName := "LICENSE" 2216 cIter, err := r.Log(&LogOptions{ 2217 Order: LogOrderCommitterTime, 2218 FileName: &fileName, 2219 From: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), 2220 }) 2221 s.NoError(err) 2222 commitVal, iterErr := cIter.Next() 2223 s.Equal(nil, iterErr) 2224 s.Equal("b029517f6300c2da0f4b651b8642506cd6aaf45d", commitVal.Hash.String()) 2225 2226 _, iterErr = cIter.Next() 2227 s.Equal(io.EOF, iterErr) 2228} 2229 2230type mockErrCommitIter struct{} 2231 2232func (m *mockErrCommitIter) Next() (*object.Commit, error) { 2233 return nil, errors.New("mock next error") 2234} 2235 2236func (m *mockErrCommitIter) ForEach(func(*object.Commit) error) error { 2237 return errors.New("mock foreach error") 2238} 2239 2240func (m *mockErrCommitIter) Close() {} 2241 2242func (s *RepositorySuite) TestLogFileWithError() { 2243 fileName := "README" 2244 cIter := object.NewCommitFileIterFromIter(fileName, &mockErrCommitIter{}, false) 2245 defer cIter.Close() 2246 2247 err := cIter.ForEach(func(commit *object.Commit) error { 2248 return nil 2249 }) 2250 s.NotNil(err) 2251} 2252 2253func (s *RepositorySuite) TestLogPathWithError() { 2254 fileName := "README" 2255 pathIter := func(path string) bool { 2256 return path == fileName 2257 } 2258 cIter := object.NewCommitPathIterFromIter(pathIter, &mockErrCommitIter{}, false) 2259 defer cIter.Close() 2260 2261 err := cIter.ForEach(func(commit *object.Commit) error { 2262 return nil 2263 }) 2264 s.NotNil(err) 2265} 2266 2267func (s *RepositorySuite) TestLogPathRegexpWithError() { 2268 pathRE := regexp.MustCompile("R.*E") 2269 pathIter := func(path string) bool { 2270 return pathRE.MatchString(path) 2271 } 2272 cIter := object.NewCommitPathIterFromIter(pathIter, &mockErrCommitIter{}, false) 2273 defer cIter.Close() 2274 2275 err := cIter.ForEach(func(commit *object.Commit) error { 2276 return nil 2277 }) 2278 s.NotNil(err) 2279} 2280 2281func (s *RepositorySuite) TestLogPathFilterRegexp() { 2282 pathRE := regexp.MustCompile(`.*\.go`) 2283 pathIter := func(path string) bool { 2284 return pathRE.MatchString(path) 2285 } 2286 2287 r, _ := Init(memory.NewStorage(), nil) 2288 err := r.clone(context.Background(), &CloneOptions{ 2289 URL: s.GetBasicLocalRepositoryURL(), 2290 }) 2291 s.NoError(err) 2292 2293 expectedCommitIDs := []string{ 2294 "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 2295 "918c48b83bd081e863dbe1b80f8998f058cd8294", 2296 } 2297 commitIDs := []string{} 2298 2299 cIter, err := r.Log(&LogOptions{ 2300 PathFilter: pathIter, 2301 From: plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), 2302 }) 2303 s.NoError(err) 2304 defer cIter.Close() 2305 2306 cIter.ForEach(func(commit *object.Commit) error { 2307 commitIDs = append(commitIDs, commit.ID().String()) 2308 return nil 2309 }) 2310 s.Equal( 2311 strings.Join(expectedCommitIDs, ", "), 2312 strings.Join(commitIDs, ", "), 2313 ) 2314} 2315 2316func (s *RepositorySuite) TestLogLimitNext() { 2317 r, _ := Init(memory.NewStorage(), nil) 2318 err := r.clone(context.Background(), &CloneOptions{ 2319 URL: s.GetBasicLocalRepositoryURL(), 2320 }) 2321 2322 s.NoError(err) 2323 2324 since := time.Date(2015, 4, 1, 0, 0, 0, 0, time.UTC) 2325 cIter, err := r.Log(&LogOptions{Since: &since}) 2326 2327 s.NoError(err) 2328 2329 commitOrder := []plumbing.Hash{ 2330 plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), 2331 } 2332 2333 for _, o := range commitOrder { 2334 commit, err := cIter.Next() 2335 s.NoError(err) 2336 s.Equal(o, commit.Hash) 2337 } 2338 _, err = cIter.Next() 2339 s.ErrorIs(err, io.EOF) 2340} 2341 2342func (s *RepositorySuite) TestLogLimitForEach() { 2343 r, _ := Init(memory.NewStorage(), nil) 2344 err := r.clone(context.Background(), &CloneOptions{ 2345 URL: s.GetBasicLocalRepositoryURL(), 2346 }) 2347 2348 s.NoError(err) 2349 2350 since := time.Date(2015, 3, 31, 11, 54, 0, 0, time.UTC) 2351 until := time.Date(2015, 4, 1, 0, 0, 0, 0, time.UTC) 2352 cIter, err := r.Log(&LogOptions{Since: &since, Until: &until}) 2353 s.NoError(err) 2354 defer cIter.Close() 2355 2356 commitOrder := []plumbing.Hash{ 2357 plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"), 2358 } 2359 2360 expectedIndex := 0 2361 err = cIter.ForEach(func(commit *object.Commit) error { 2362 expectedCommitHash := commitOrder[expectedIndex] 2363 s.Equal(expectedCommitHash.String(), commit.Hash.String()) 2364 expectedIndex++ 2365 return nil 2366 }) 2367 s.NoError(err) 2368 s.Equal(1, expectedIndex) 2369} 2370 2371func (s *RepositorySuite) TestLogAllLimitForEach() { 2372 r, _ := Init(memory.NewStorage(), nil) 2373 err := r.clone(context.Background(), &CloneOptions{ 2374 URL: s.GetBasicLocalRepositoryURL(), 2375 }) 2376 2377 s.NoError(err) 2378 2379 since := time.Date(2015, 3, 31, 11, 54, 0, 0, time.UTC) 2380 until := time.Date(2015, 4, 1, 0, 0, 0, 0, time.UTC) 2381 cIter, err := r.Log(&LogOptions{Since: &since, Until: &until, All: true}) 2382 s.NoError(err) 2383 defer cIter.Close() 2384 2385 commitOrder := []plumbing.Hash{ 2386 plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881"), 2387 plumbing.NewHash("918c48b83bd081e863dbe1b80f8998f058cd8294"), 2388 } 2389 2390 expectedIndex := 0 2391 err = cIter.ForEach(func(commit *object.Commit) error { 2392 expectedCommitHash := commitOrder[expectedIndex] 2393 s.Equal(expectedCommitHash.String(), commit.Hash.String()) 2394 expectedIndex++ 2395 return nil 2396 }) 2397 s.NoError(err) 2398 s.Equal(2, expectedIndex) 2399} 2400 2401func (s *RepositorySuite) TestLogLimitWithOtherParamsFail() { 2402 r, _ := Init(memory.NewStorage(), nil) 2403 err := r.clone(context.Background(), &CloneOptions{ 2404 URL: s.GetBasicLocalRepositoryURL(), 2405 }) 2406 s.NoError(err) 2407 2408 since := time.Date(2015, 3, 31, 11, 54, 0, 0, time.UTC) 2409 cIter, err := r.Log(&LogOptions{ 2410 Order: LogOrderCommitterTime, 2411 Since: &since, 2412 From: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), 2413 }) 2414 s.NoError(err) 2415 defer cIter.Close() 2416 2417 _, iterErr := cIter.Next() 2418 s.Equal(io.EOF, iterErr) 2419} 2420 2421func (s *RepositorySuite) TestLogLimitWithOtherParamsPass() { 2422 r, _ := Init(memory.NewStorage(), nil) 2423 err := r.clone(context.Background(), &CloneOptions{ 2424 URL: s.GetBasicLocalRepositoryURL(), 2425 }) 2426 s.NoError(err) 2427 2428 until := time.Date(2015, 3, 31, 11, 43, 0, 0, time.UTC) 2429 cIter, err := r.Log(&LogOptions{ 2430 Order: LogOrderCommitterTime, 2431 Until: &until, 2432 From: plumbing.NewHash("35e85108805c84807bc66a02d91535e1e24b38b9"), 2433 }) 2434 s.NoError(err) 2435 defer cIter.Close() 2436 2437 commitVal, iterErr := cIter.Next() 2438 s.Equal(nil, iterErr) 2439 s.Equal("b029517f6300c2da0f4b651b8642506cd6aaf45d", commitVal.Hash.String()) 2440 2441 _, iterErr = cIter.Next() 2442 s.Equal(io.EOF, iterErr) 2443} 2444 2445func (s *RepositorySuite) TestConfigScoped() { 2446 r, _ := Init(memory.NewStorage(), nil) 2447 err := r.clone(context.Background(), &CloneOptions{ 2448 URL: s.GetBasicLocalRepositoryURL(), 2449 }) 2450 s.NoError(err) 2451 2452 cfg, err := r.ConfigScoped(config.LocalScope) 2453 s.NoError(err) 2454 s.Equal("", cfg.User.Email) 2455 2456 cfg, err = r.ConfigScoped(config.SystemScope) 2457 s.NoError(err) 2458 s.NotEqual("", cfg.User.Email) 2459} 2460 2461func (s *RepositorySuite) TestCommit() { 2462 r, _ := Init(memory.NewStorage(), nil) 2463 err := r.clone(context.Background(), &CloneOptions{ 2464 URL: s.GetBasicLocalRepositoryURL(), 2465 }) 2466 2467 s.NoError(err) 2468 2469 hash := plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47") 2470 commit, err := r.CommitObject(hash) 2471 s.NoError(err) 2472 2473 s.False(commit.Hash.IsZero()) 2474 s.Equal(commit.ID(), commit.Hash) 2475 s.Equal(hash, commit.Hash) 2476 s.Equal(plumbing.CommitObject, commit.Type()) 2477 2478 tree, err := commit.Tree() 2479 s.NoError(err) 2480 s.False(tree.Hash.IsZero()) 2481 2482 s.Equal("daniel@lordran.local", commit.Author.Email) 2483} 2484 2485func (s *RepositorySuite) TestCommits() { 2486 r, _ := Init(memory.NewStorage(), nil) 2487 err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) 2488 s.NoError(err) 2489 2490 count := 0 2491 commits, err := r.CommitObjects() 2492 s.NoError(err) 2493 for { 2494 commit, err := commits.Next() 2495 if err != nil { 2496 break 2497 } 2498 2499 count++ 2500 s.False(commit.Hash.IsZero()) 2501 s.Equal(commit.ID(), commit.Hash) 2502 s.Equal(plumbing.CommitObject, commit.Type()) 2503 } 2504 2505 s.Equal(9, count) 2506} 2507 2508func (s *RepositorySuite) TestBlob() { 2509 r, _ := Init(memory.NewStorage(), nil) 2510 err := r.clone(context.Background(), &CloneOptions{ 2511 URL: s.GetBasicLocalRepositoryURL(), 2512 }) 2513 2514 s.NoError(err) 2515 2516 blob, err := r.BlobObject(plumbing.NewHash("b8e471f58bcbca63b07bda20e428190409c2db47")) 2517 s.NotNil(err) 2518 s.Nil(blob) 2519 2520 blobHash := plumbing.NewHash("9a48f23120e880dfbe41f7c9b7b708e9ee62a492") 2521 blob, err = r.BlobObject(blobHash) 2522 s.NoError(err) 2523 2524 s.False(blob.Hash.IsZero()) 2525 s.Equal(blob.ID(), blob.Hash) 2526 s.Equal(blobHash, blob.Hash) 2527 s.Equal(plumbing.BlobObject, blob.Type()) 2528} 2529 2530func (s *RepositorySuite) TestBlobs() { 2531 r, _ := Init(memory.NewStorage(), nil) 2532 err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) 2533 s.NoError(err) 2534 2535 count := 0 2536 blobs, err := r.BlobObjects() 2537 s.NoError(err) 2538 for { 2539 blob, err := blobs.Next() 2540 if err != nil { 2541 break 2542 } 2543 2544 count++ 2545 s.False(blob.Hash.IsZero()) 2546 s.Equal(blob.ID(), blob.Hash) 2547 s.Equal(plumbing.BlobObject, blob.Type()) 2548 } 2549 2550 s.Equal(10, count) 2551} 2552 2553func (s *RepositorySuite) TestTagObject() { 2554 url := s.GetLocalRepositoryURL( 2555 fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), 2556 ) 2557 2558 r, _ := Init(memory.NewStorage(), nil) 2559 err := r.clone(context.Background(), &CloneOptions{URL: url}) 2560 s.NoError(err) 2561 2562 hash := plumbing.NewHash("ad7897c0fb8e7d9a9ba41fa66072cf06095a6cfc") 2563 tag, err := r.TagObject(hash) 2564 s.NoError(err) 2565 2566 s.False(tag.Hash.IsZero()) 2567 s.Equal(hash, tag.Hash) 2568 s.Equal(plumbing.TagObject, tag.Type()) 2569} 2570 2571func (s *RepositorySuite) TestTags() { 2572 url := s.GetLocalRepositoryURL( 2573 fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), 2574 ) 2575 2576 r, _ := Init(memory.NewStorage(), nil) 2577 err := r.clone(context.Background(), &CloneOptions{URL: url}) 2578 s.NoError(err) 2579 2580 count := 0 2581 tags, err := r.Tags() 2582 s.NoError(err) 2583 2584 tags.ForEach(func(tag *plumbing.Reference) error { 2585 count++ 2586 s.False(tag.Hash().IsZero()) 2587 s.True(tag.Name().IsTag()) 2588 return nil 2589 }) 2590 2591 s.Equal(5, count) 2592} 2593 2594func (s *RepositorySuite) TestCreateTagLightweight() { 2595 url := s.GetLocalRepositoryURL( 2596 fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), 2597 ) 2598 2599 r, _ := Init(memory.NewStorage(), nil) 2600 err := r.clone(context.Background(), &CloneOptions{URL: url}) 2601 s.NoError(err) 2602 2603 expected, err := r.Head() 2604 s.NoError(err) 2605 2606 ref, err := r.CreateTag("foobar", expected.Hash(), nil) 2607 s.NoError(err) 2608 s.NotNil(ref) 2609 2610 actual, err := r.Tag("foobar") 2611 s.NoError(err) 2612 2613 s.Equal(actual.Hash(), expected.Hash()) 2614} 2615 2616func (s *RepositorySuite) TestCreateTagLightweightExists() { 2617 url := s.GetLocalRepositoryURL( 2618 fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), 2619 ) 2620 2621 r, _ := Init(memory.NewStorage(), nil) 2622 err := r.clone(context.Background(), &CloneOptions{URL: url}) 2623 s.NoError(err) 2624 2625 expected, err := r.Head() 2626 s.NoError(err) 2627 2628 ref, err := r.CreateTag("lightweight-tag", expected.Hash(), nil) 2629 s.Nil(ref) 2630 s.ErrorIs(err, ErrTagExists) 2631} 2632 2633func (s *RepositorySuite) TestCreateTagAnnotated() { 2634 url := s.GetLocalRepositoryURL( 2635 fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), 2636 ) 2637 2638 r, _ := Init(memory.NewStorage(), nil) 2639 err := r.clone(context.Background(), &CloneOptions{URL: url}) 2640 s.NoError(err) 2641 2642 h, err := r.Head() 2643 s.NoError(err) 2644 2645 expectedHash := h.Hash() 2646 2647 ref, err := r.CreateTag("foobar", expectedHash, &CreateTagOptions{ 2648 Tagger: defaultSignature(), 2649 Message: "foo bar baz qux", 2650 }) 2651 s.NoError(err) 2652 2653 tag, err := r.Tag("foobar") 2654 s.NoError(err) 2655 2656 obj, err := r.TagObject(tag.Hash()) 2657 s.NoError(err) 2658 2659 s.Equal(tag, ref) 2660 s.Equal(ref.Hash(), obj.Hash) 2661 s.Equal(plumbing.TagObject, obj.Type()) 2662 s.Equal(expectedHash, obj.Target) 2663} 2664 2665func (s *RepositorySuite) TestCreateTagAnnotatedBadOpts() { 2666 url := s.GetLocalRepositoryURL( 2667 fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), 2668 ) 2669 2670 r, _ := Init(memory.NewStorage(), nil) 2671 err := r.clone(context.Background(), &CloneOptions{URL: url}) 2672 s.NoError(err) 2673 2674 h, err := r.Head() 2675 s.NoError(err) 2676 2677 expectedHash := h.Hash() 2678 2679 ref, err := r.CreateTag("foobar", expectedHash, &CreateTagOptions{}) 2680 s.Nil(ref) 2681 s.ErrorIs(err, ErrMissingMessage) 2682} 2683 2684func (s *RepositorySuite) TestCreateTagAnnotatedBadHash() { 2685 url := s.GetLocalRepositoryURL( 2686 fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), 2687 ) 2688 2689 r, _ := Init(memory.NewStorage(), nil) 2690 err := r.clone(context.Background(), &CloneOptions{URL: url}) 2691 s.NoError(err) 2692 2693 ref, err := r.CreateTag("foobar", plumbing.ZeroHash, &CreateTagOptions{ 2694 Tagger: defaultSignature(), 2695 Message: "foo bar baz qux", 2696 }) 2697 s.Nil(ref) 2698 s.ErrorIs(err, plumbing.ErrObjectNotFound) 2699} 2700 2701func (s *RepositorySuite) TestCreateTagSigned() { 2702 url := s.GetLocalRepositoryURL( 2703 fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), 2704 ) 2705 2706 r, _ := Init(memory.NewStorage(), nil) 2707 err := r.clone(context.Background(), &CloneOptions{URL: url}) 2708 s.NoError(err) 2709 2710 h, err := r.Head() 2711 s.NoError(err) 2712 2713 key := commitSignKey(s.T(), true) 2714 _, err = r.CreateTag("foobar", h.Hash(), &CreateTagOptions{ 2715 Tagger: defaultSignature(), 2716 Message: "foo bar baz qux", 2717 SignKey: key, 2718 }) 2719 s.NoError(err) 2720 2721 tag, err := r.Tag("foobar") 2722 s.NoError(err) 2723 2724 obj, err := r.TagObject(tag.Hash()) 2725 s.NoError(err) 2726 2727 // Verify the tag. 2728 pks := new(bytes.Buffer) 2729 pkw, err := armor.Encode(pks, openpgp.PublicKeyType, nil) 2730 s.NoError(err) 2731 2732 err = key.Serialize(pkw) 2733 s.NoError(err) 2734 err = pkw.Close() 2735 s.NoError(err) 2736 2737 actual, err := obj.Verify(pks.String()) 2738 s.NoError(err) 2739 s.Equal(key.PrimaryKey, actual.PrimaryKey) 2740} 2741 2742func (s *RepositorySuite) TestCreateTagSignedBadKey() { 2743 url := s.GetLocalRepositoryURL( 2744 fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), 2745 ) 2746 2747 r, _ := Init(memory.NewStorage(), nil) 2748 err := r.clone(context.Background(), &CloneOptions{URL: url}) 2749 s.NoError(err) 2750 2751 h, err := r.Head() 2752 s.NoError(err) 2753 2754 key := commitSignKey(s.T(), false) 2755 _, err = r.CreateTag("foobar", h.Hash(), &CreateTagOptions{ 2756 Tagger: defaultSignature(), 2757 Message: "foo bar baz qux", 2758 SignKey: key, 2759 }) 2760 s.ErrorIs(err, openpgperr.InvalidArgumentError("signing key is encrypted")) 2761} 2762 2763func (s *RepositorySuite) TestCreateTagCanonicalize() { 2764 url := s.GetLocalRepositoryURL( 2765 fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), 2766 ) 2767 2768 r, _ := Init(memory.NewStorage(), nil) 2769 err := r.clone(context.Background(), &CloneOptions{URL: url}) 2770 s.NoError(err) 2771 2772 h, err := r.Head() 2773 s.NoError(err) 2774 2775 key := commitSignKey(s.T(), true) 2776 _, err = r.CreateTag("foobar", h.Hash(), &CreateTagOptions{ 2777 Tagger: defaultSignature(), 2778 Message: "\n\nfoo bar baz qux\n\nsome message here", 2779 SignKey: key, 2780 }) 2781 s.NoError(err) 2782 2783 tag, err := r.Tag("foobar") 2784 s.NoError(err) 2785 2786 obj, err := r.TagObject(tag.Hash()) 2787 s.NoError(err) 2788 2789 // Assert the new canonicalized message. 2790 s.Equal("foo bar baz qux\n\nsome message here\n", obj.Message) 2791 2792 // Verify the tag. 2793 pks := new(bytes.Buffer) 2794 pkw, err := armor.Encode(pks, openpgp.PublicKeyType, nil) 2795 s.NoError(err) 2796 2797 err = key.Serialize(pkw) 2798 s.NoError(err) 2799 err = pkw.Close() 2800 s.NoError(err) 2801 2802 actual, err := obj.Verify(pks.String()) 2803 s.NoError(err) 2804 s.Equal(key.PrimaryKey, actual.PrimaryKey) 2805} 2806 2807func (s *RepositorySuite) TestTagLightweight() { 2808 url := s.GetLocalRepositoryURL( 2809 fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), 2810 ) 2811 2812 r, _ := Init(memory.NewStorage(), nil) 2813 err := r.clone(context.Background(), &CloneOptions{URL: url}) 2814 s.NoError(err) 2815 2816 expected := plumbing.NewHash("f7b877701fbf855b44c0a9e86f3fdce2c298b07f") 2817 2818 tag, err := r.Tag("lightweight-tag") 2819 s.NoError(err) 2820 2821 actual := tag.Hash() 2822 s.Equal(actual, expected) 2823} 2824 2825func (s *RepositorySuite) TestTagLightweightMissingTag() { 2826 url := s.GetLocalRepositoryURL( 2827 fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), 2828 ) 2829 2830 r, _ := Init(memory.NewStorage(), nil) 2831 err := r.clone(context.Background(), &CloneOptions{URL: url}) 2832 s.NoError(err) 2833 2834 tag, err := r.Tag("lightweight-tag-tag") 2835 s.Nil(tag) 2836 s.ErrorIs(err, ErrTagNotFound) 2837} 2838 2839func (s *RepositorySuite) TestDeleteTag() { 2840 url := s.GetLocalRepositoryURL( 2841 fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), 2842 ) 2843 2844 r, _ := Init(memory.NewStorage(), nil) 2845 err := r.clone(context.Background(), &CloneOptions{URL: url}) 2846 s.NoError(err) 2847 2848 err = r.DeleteTag("lightweight-tag") 2849 s.NoError(err) 2850 2851 _, err = r.Tag("lightweight-tag") 2852 s.ErrorIs(err, ErrTagNotFound) 2853} 2854 2855func (s *RepositorySuite) TestDeleteTagMissingTag() { 2856 url := s.GetLocalRepositoryURL( 2857 fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), 2858 ) 2859 2860 r, _ := Init(memory.NewStorage(), nil) 2861 err := r.clone(context.Background(), &CloneOptions{URL: url}) 2862 s.NoError(err) 2863 2864 err = r.DeleteTag("lightweight-tag-tag") 2865 s.ErrorIs(err, ErrTagNotFound) 2866} 2867 2868func (s *RepositorySuite) TestDeleteTagAnnotated() { 2869 url := s.GetLocalRepositoryURL( 2870 fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), 2871 ) 2872 2873 fs := s.TemporalFilesystem() 2874 2875 fss := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) 2876 2877 r, _ := Init(fss, nil) 2878 err := r.clone(context.Background(), &CloneOptions{URL: url}) 2879 s.NoError(err) 2880 2881 ref, err := r.Tag("annotated-tag") 2882 s.NotNil(ref) 2883 s.NoError(err) 2884 2885 obj, err := r.TagObject(ref.Hash()) 2886 s.NotNil(obj) 2887 s.NoError(err) 2888 2889 err = r.DeleteTag("annotated-tag") 2890 s.NoError(err) 2891 2892 _, err = r.Tag("annotated-tag") 2893 s.ErrorIs(err, ErrTagNotFound) 2894 2895 // Run a prune (and repack, to ensure that we are GCing everything regardless 2896 // of the fixture in use) and try to get the tag object again. 2897 // 2898 // The repo needs to be re-opened after the repack. 2899 err = r.Prune(PruneOptions{Handler: r.DeleteObject}) 2900 s.NoError(err) 2901 2902 err = r.RepackObjects(&RepackConfig{}) 2903 s.NoError(err) 2904 2905 r, err = PlainOpen(fs.Root()) 2906 s.NotNil(r) 2907 s.NoError(err) 2908 2909 // Now check to see if the GC was effective in removing the tag object. 2910 obj, err = r.TagObject(ref.Hash()) 2911 s.Nil(obj) 2912 s.ErrorIs(err, plumbing.ErrObjectNotFound) 2913} 2914 2915func (s *RepositorySuite) TestDeleteTagAnnotatedUnpacked() { 2916 url := s.GetLocalRepositoryURL( 2917 fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), 2918 ) 2919 2920 fs := s.TemporalFilesystem() 2921 2922 fss := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) 2923 2924 r, _ := Init(fss, nil) 2925 err := r.clone(context.Background(), &CloneOptions{URL: url}) 2926 s.NoError(err) 2927 2928 // Create a tag for the deletion test. This ensures that the ultimate loose 2929 // object will be unpacked (as we aren't doing anything that should pack it), 2930 // so that we can effectively test that a prune deletes it, without having to 2931 // resort to a repack. 2932 h, err := r.Head() 2933 s.NoError(err) 2934 2935 expectedHash := h.Hash() 2936 2937 ref, err := r.CreateTag("foobar", expectedHash, &CreateTagOptions{ 2938 Tagger: defaultSignature(), 2939 Message: "foo bar baz qux", 2940 }) 2941 s.NoError(err) 2942 2943 tag, err := r.Tag("foobar") 2944 s.NoError(err) 2945 2946 obj, err := r.TagObject(tag.Hash()) 2947 s.NotNil(obj) 2948 s.NoError(err) 2949 2950 err = r.DeleteTag("foobar") 2951 s.NoError(err) 2952 2953 _, err = r.Tag("foobar") 2954 s.ErrorIs(err, ErrTagNotFound) 2955 2956 // As mentioned, only run a prune. We are not testing for packed objects 2957 // here. 2958 err = r.Prune(PruneOptions{Handler: r.DeleteObject}) 2959 s.NoError(err) 2960 2961 // Now check to see if the GC was effective in removing the tag object. 2962 obj, err = r.TagObject(ref.Hash()) 2963 s.Nil(obj) 2964 s.ErrorIs(err, plumbing.ErrObjectNotFound) 2965} 2966 2967func (s *RepositorySuite) TestInvalidTagName() { 2968 r, err := Init(memory.NewStorage(), nil) 2969 s.NoError(err) 2970 for i, name := range []string{ 2971 "", 2972 "foo bar", 2973 "foo\tbar", 2974 "foo\nbar", 2975 } { 2976 _, err = r.CreateTag(name, plumbing.ZeroHash, nil) 2977 s.Error(err, fmt.Sprintf("case %d %q", i, name)) 2978 } 2979} 2980 2981func (s *RepositorySuite) TestBranches() { 2982 f := fixtures.ByURL("https://github.com/git-fixtures/root-references.git").One() 2983 sto := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault()) 2984 r, err := Open(sto, f.DotGit()) 2985 s.NoError(err) 2986 2987 count := 0 2988 branches, err := r.Branches() 2989 s.NoError(err) 2990 2991 branches.ForEach(func(branch *plumbing.Reference) error { 2992 count++ 2993 s.False(branch.Hash().IsZero()) 2994 s.True(branch.Name().IsBranch()) 2995 return nil 2996 }) 2997 2998 s.Equal(8, count) 2999} 3000 3001func (s *RepositorySuite) TestNotes() { 3002 // TODO add fixture with Notes 3003 url := s.GetLocalRepositoryURL( 3004 fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), 3005 ) 3006 3007 r, _ := Init(memory.NewStorage(), nil) 3008 err := r.clone(context.Background(), &CloneOptions{URL: url}) 3009 s.NoError(err) 3010 3011 count := 0 3012 notes, err := r.Notes() 3013 s.NoError(err) 3014 3015 notes.ForEach(func(note *plumbing.Reference) error { 3016 count++ 3017 s.False(note.Hash().IsZero()) 3018 s.True(note.Name().IsNote()) 3019 return nil 3020 }) 3021 3022 s.Equal(0, count) 3023} 3024 3025func (s *RepositorySuite) TestTree() { 3026 r, _ := Init(memory.NewStorage(), nil) 3027 err := r.clone(context.Background(), &CloneOptions{ 3028 URL: s.GetBasicLocalRepositoryURL(), 3029 }) 3030 s.NoError(err) 3031 3032 invalidHash := plumbing.NewHash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") 3033 tree, err := r.TreeObject(invalidHash) 3034 s.Nil(tree) 3035 s.NotNil(err) 3036 3037 hash := plumbing.NewHash("dbd3641b371024f44d0e469a9c8f5457b0660de1") 3038 tree, err = r.TreeObject(hash) 3039 s.NoError(err) 3040 3041 s.False(tree.Hash.IsZero()) 3042 s.Equal(tree.ID(), tree.Hash) 3043 s.Equal(hash, tree.Hash) 3044 s.Equal(plumbing.TreeObject, tree.Type()) 3045 s.NotEqual(0, len(tree.Entries)) 3046} 3047 3048func (s *RepositorySuite) TestTrees() { 3049 r, _ := Init(memory.NewStorage(), nil) 3050 err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) 3051 s.NoError(err) 3052 3053 count := 0 3054 trees, err := r.TreeObjects() 3055 s.NoError(err) 3056 for { 3057 tree, err := trees.Next() 3058 if err != nil { 3059 break 3060 } 3061 3062 count++ 3063 s.False(tree.Hash.IsZero()) 3064 s.Equal(tree.ID(), tree.Hash) 3065 s.Equal(plumbing.TreeObject, tree.Type()) 3066 s.NotEqual(0, len(tree.Entries)) 3067 } 3068 3069 s.Equal(12, count) 3070} 3071 3072func (s *RepositorySuite) TestTagObjects() { 3073 url := s.GetLocalRepositoryURL( 3074 fixtures.ByURL("https://github.com/git-fixtures/tags.git").One(), 3075 ) 3076 3077 r, _ := Init(memory.NewStorage(), nil) 3078 err := r.clone(context.Background(), &CloneOptions{URL: url}) 3079 s.NoError(err) 3080 3081 count := 0 3082 tags, err := r.TagObjects() 3083 s.NoError(err) 3084 3085 tags.ForEach(func(tag *object.Tag) error { 3086 count++ 3087 3088 s.False(tag.Hash.IsZero()) 3089 s.Equal(plumbing.TagObject, tag.Type()) 3090 return nil 3091 }) 3092 3093 refs, _ := r.References() 3094 refs.ForEach(func(ref *plumbing.Reference) error { 3095 return nil 3096 }) 3097 3098 s.Equal(4, count) 3099} 3100 3101func (s *RepositorySuite) TestCommitIterClosePanic() { 3102 r, _ := Init(memory.NewStorage(), nil) 3103 err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) 3104 s.NoError(err) 3105 3106 commits, err := r.CommitObjects() 3107 s.NoError(err) 3108 commits.Close() 3109} 3110 3111func (s *RepositorySuite) TestRef() { 3112 r, _ := Init(memory.NewStorage(), nil) 3113 err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) 3114 s.NoError(err) 3115 3116 ref, err := r.Reference(plumbing.HEAD, false) 3117 s.NoError(err) 3118 s.Equal(plumbing.HEAD, ref.Name()) 3119 3120 ref, err = r.Reference(plumbing.HEAD, true) 3121 s.NoError(err) 3122 s.Equal(plumbing.ReferenceName("refs/heads/master"), ref.Name()) 3123} 3124 3125func (s *RepositorySuite) TestRefs() { 3126 r, _ := Init(memory.NewStorage(), nil) 3127 err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) 3128 s.NoError(err) 3129 3130 s.NoError(err) 3131 3132 iter, err := r.References() 3133 s.NoError(err) 3134 s.NotNil(iter) 3135} 3136 3137func (s *RepositorySuite) TestObject() { 3138 r, _ := Init(memory.NewStorage(), nil) 3139 err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) 3140 s.NoError(err) 3141 3142 hash := plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5") 3143 o, err := r.Object(plumbing.CommitObject, hash) 3144 s.NoError(err) 3145 3146 s.False(o.ID().IsZero()) 3147 s.Equal(plumbing.CommitObject, o.Type()) 3148} 3149 3150func (s *RepositorySuite) TestObjects() { 3151 r, _ := Init(memory.NewStorage(), nil) 3152 err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) 3153 s.NoError(err) 3154 3155 count := 0 3156 objects, err := r.Objects() 3157 s.NoError(err) 3158 for { 3159 o, err := objects.Next() 3160 if err != nil { 3161 break 3162 } 3163 3164 count++ 3165 s.False(o.ID().IsZero()) 3166 s.NotEqual(plumbing.AnyObject, o.Type()) 3167 } 3168 3169 s.Equal(31, count) 3170} 3171 3172func (s *RepositorySuite) TestObjectNotFound() { 3173 r, _ := Init(memory.NewStorage(), nil) 3174 err := r.clone(context.Background(), &CloneOptions{URL: s.GetBasicLocalRepositoryURL()}) 3175 s.NoError(err) 3176 3177 hash := plumbing.NewHash("0a3fb06ff80156fb153bcdcc58b5e16c2d27625c") 3178 tag, err := r.Object(plumbing.TagObject, hash) 3179 s.ErrorIs(err, plumbing.ErrObjectNotFound) 3180 s.Nil(tag) 3181} 3182 3183func (s *RepositorySuite) TestWorktree() { 3184 def := memfs.New() 3185 r, _ := Init(memory.NewStorage(), def) 3186 w, err := r.Worktree() 3187 s.NoError(err) 3188 s.Equal(def, w.Filesystem) 3189} 3190 3191func (s *RepositorySuite) TestWorktreeBare() { 3192 r, _ := Init(memory.NewStorage(), nil) 3193 w, err := r.Worktree() 3194 s.ErrorIs(err, ErrIsBareRepository) 3195 s.Nil(w) 3196} 3197 3198func (s *RepositorySuite) TestResolveRevision() { 3199 f := fixtures.ByURL("https://github.com/git-fixtures/basic.git").One() 3200 sto := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault()) 3201 r, err := Open(sto, f.DotGit()) 3202 s.NoError(err) 3203 3204 datas := map[string]string{ 3205 "HEAD": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 3206 "heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 3207 "heads/master~1": "918c48b83bd081e863dbe1b80f8998f058cd8294", 3208 "refs/heads/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 3209 "refs/heads/master~2^^~": "b029517f6300c2da0f4b651b8642506cd6aaf45d", 3210 "refs/tags/v1.0.0": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 3211 "refs/remotes/origin/master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 3212 "refs/remotes/origin/HEAD": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 3213 "HEAD~2^^~": "b029517f6300c2da0f4b651b8642506cd6aaf45d", 3214 "HEAD~3^2": "a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69", 3215 "HEAD~3^2^0": "a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69", 3216 "HEAD~2^{/binary file}": "35e85108805c84807bc66a02d91535e1e24b38b9", 3217 "HEAD~^{/!-some}": "1669dce138d9b841a518c64b10914d88f5e488ea", 3218 "master": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 3219 "branch": "e8d3ffab552895c19b9fcf7aa264d277cde33881", 3220 "v1.0.0": "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 3221 "branch~1": "918c48b83bd081e863dbe1b80f8998f058cd8294", 3222 "v1.0.0~1": "918c48b83bd081e863dbe1b80f8998f058cd8294", 3223 "master~1": "918c48b83bd081e863dbe1b80f8998f058cd8294", 3224 "918c48b83bd081e863dbe1b80f8998f058cd8294": "918c48b83bd081e863dbe1b80f8998f058cd8294", 3225 "918c48b": "918c48b83bd081e863dbe1b80f8998f058cd8294", // odd number of hex digits 3226 } 3227 3228 for rev, hash := range datas { 3229 h, err := r.ResolveRevision(plumbing.Revision(rev)) 3230 3231 s.NoError(err, fmt.Sprintf("while checking %s", rev)) 3232 s.Equal(hash, h.String(), fmt.Sprintf("while checking %s", rev)) 3233 } 3234} 3235 3236func (s *RepositorySuite) TestResolveRevisionAnnotated() { 3237 f := fixtures.ByURL("https://github.com/git-fixtures/tags.git").One() 3238 sto := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault()) 3239 r, err := Open(sto, f.DotGit()) 3240 s.NoError(err) 3241 3242 datas := map[string]string{ 3243 "refs/tags/annotated-tag": "f7b877701fbf855b44c0a9e86f3fdce2c298b07f", 3244 "b742a2a9fa0afcfa9a6fad080980fbc26b007c69": "f7b877701fbf855b44c0a9e86f3fdce2c298b07f", 3245 } 3246 3247 for rev, hash := range datas { 3248 h, err := r.ResolveRevision(plumbing.Revision(rev)) 3249 3250 s.NoError(err, fmt.Sprintf("while checking %s", rev)) 3251 s.Equal(hash, h.String(), fmt.Sprintf("while checking %s", rev)) 3252 } 3253} 3254 3255func (s *RepositorySuite) TestResolveRevisionWithErrors() { 3256 url := s.GetLocalRepositoryURL( 3257 fixtures.ByURL("https://github.com/git-fixtures/basic.git").One(), 3258 ) 3259 3260 r, _ := Init(memory.NewStorage(), nil) 3261 err := r.clone(context.Background(), &CloneOptions{URL: url}) 3262 s.NoError(err) 3263 3264 headRef, err := r.Head() 3265 s.NoError(err) 3266 3267 ref := plumbing.NewHashReference("refs/heads/918c48b83bd081e863dbe1b80f8998f058cd8294", headRef.Hash()) 3268 err = r.Storer.SetReference(ref) 3269 s.NoError(err) 3270 3271 datas := map[string]string{ 3272 "efs/heads/master~": "reference not found", 3273 "HEAD^3": `Revision invalid : "3" found must be 0, 1 or 2 after "^"`, 3274 "HEAD^{/whatever}": `no commit message match regexp: "whatever"`, 3275 "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83": "reference not found", 3276 } 3277 3278 for rev, rerr := range datas { 3279 _, err := r.ResolveRevision(plumbing.Revision(rev)) 3280 s.NotNil(err) 3281 s.Equal(rerr, err.Error()) 3282 } 3283} 3284 3285func (s *RepositorySuite) testRepackObjects(deleteTime time.Time, expectedPacks int) { 3286 srcFs := fixtures.ByTag("unpacked").One().DotGit() 3287 var sto storage.Storer 3288 var err error 3289 sto = filesystem.NewStorage(srcFs, cache.NewObjectLRUDefault()) 3290 3291 los := sto.(storer.LooseObjectStorer) 3292 s.NotNil(los) 3293 3294 numLooseStart := 0 3295 err = los.ForEachObjectHash(func(_ plumbing.Hash) error { 3296 numLooseStart++ 3297 return nil 3298 }) 3299 s.NoError(err) 3300 s.True(numLooseStart > 0) 3301 3302 pos := sto.(storer.PackedObjectStorer) 3303 s.NotNil(los) 3304 3305 packs, err := pos.ObjectPacks() 3306 s.NoError(err) 3307 numPacksStart := len(packs) 3308 s.True(numPacksStart > 1) 3309 3310 r, err := Open(sto, srcFs) 3311 s.NoError(err) 3312 s.NotNil(r) 3313 3314 err = r.RepackObjects(&RepackConfig{ 3315 OnlyDeletePacksOlderThan: deleteTime, 3316 }) 3317 s.NoError(err) 3318 3319 numLooseEnd := 0 3320 err = los.ForEachObjectHash(func(_ plumbing.Hash) error { 3321 numLooseEnd++ 3322 return nil 3323 }) 3324 s.NoError(err) 3325 s.Equal(0, numLooseEnd) 3326 3327 packs, err = pos.ObjectPacks() 3328 s.NoError(err) 3329 numPacksEnd := len(packs) 3330 s.Equal(expectedPacks, numPacksEnd) 3331} 3332 3333func (s *RepositorySuite) TestRepackObjects() { 3334 if testing.Short() { 3335 s.T().Skip("skipping test in short mode.") 3336 } 3337 3338 s.testRepackObjects(time.Time{}, 1) 3339} 3340 3341func (s *RepositorySuite) TestRepackObjectsWithNoDelete() { 3342 if testing.Short() { 3343 s.T().Skip("skipping test in short mode.") 3344 } 3345 3346 s.testRepackObjects(time.Unix(0, 1), 3) 3347} 3348 3349func ExecuteOnPath(t *testing.T, path string, cmds ...string) error { 3350 for _, cmd := range cmds { 3351 err := executeOnPath(path, cmd) 3352 assert.NoError(t, err) 3353 } 3354 3355 return nil 3356} 3357 3358func executeOnPath(path, cmd string) error { 3359 args := strings.Split(cmd, " ") 3360 c := exec.Command(args[0], args[1:]...) 3361 c.Dir = path 3362 c.Env = os.Environ() 3363 3364 buf := bytes.NewBuffer(nil) 3365 c.Stderr = buf 3366 c.Stdout = buf 3367 3368 return c.Run() 3369} 3370 3371func (s *RepositorySuite) TestBrokenMultipleShallowFetch() { 3372 r, _ := Init(memory.NewStorage(), nil) 3373 _, err := r.CreateRemote(&config.RemoteConfig{ 3374 Name: DefaultRemoteName, 3375 URLs: []string{s.GetBasicLocalRepositoryURL()}, 3376 }) 3377 s.NoError(err) 3378 3379 s.NoError(r.Fetch(&FetchOptions{ 3380 Depth: 2, 3381 RefSpecs: []config.RefSpec{config.RefSpec("refs/heads/master:refs/heads/master")}, 3382 })) 3383 3384 shallows, err := r.Storer.Shallow() 3385 s.NoError(err) 3386 s.Len(shallows, 1) 3387 3388 ref, err := r.Reference("refs/heads/master", true) 3389 s.NoError(err) 3390 cobj, err := r.CommitObject(ref.Hash()) 3391 s.NoError(err) 3392 s.NotNil(cobj) 3393 err = object.NewCommitPreorderIter(cobj, nil, nil).ForEach(func(c *object.Commit) error { 3394 for _, ph := range c.ParentHashes { 3395 for _, h := range shallows { 3396 if ph == h { 3397 return storer.ErrStop 3398 } 3399 } 3400 } 3401 3402 return nil 3403 }) 3404 s.NoError(err) 3405 3406 s.NoError(r.Fetch(&FetchOptions{ 3407 Depth: 5, 3408 RefSpecs: []config.RefSpec{config.RefSpec("refs/heads/*:refs/heads/*")}, 3409 })) 3410 3411 shallows, err = r.Storer.Shallow() 3412 s.NoError(err) 3413 s.Len(shallows, 3) 3414 3415 ref, err = r.Reference("refs/heads/master", true) 3416 s.NoError(err) 3417 cobj, err = r.CommitObject(ref.Hash()) 3418 s.NoError(err) 3419 s.NotNil(cobj) 3420 err = object.NewCommitPreorderIter(cobj, nil, nil).ForEach(func(c *object.Commit) error { 3421 for _, ph := range c.ParentHashes { 3422 for _, h := range shallows { 3423 if ph == h { 3424 return storer.ErrStop 3425 } 3426 } 3427 } 3428 3429 return nil 3430 }) 3431 s.NoError(err) 3432} 3433 3434func (s *RepositorySuite) TestDotGitToOSFilesystemsInvalidPath() { 3435 _, _, err := dotGitToOSFilesystems("\000", false) 3436 s.NotNil(err) 3437} 3438 3439func (s *RepositorySuite) TestIssue674() { 3440 r, _ := Init(memory.NewStorage(), nil) 3441 h, err := r.ResolveRevision(plumbing.Revision("")) 3442 3443 s.NotNil(err) 3444 s.NotNil(h) 3445 s.True(h.IsZero()) 3446} 3447 3448func BenchmarkObjects(b *testing.B) { 3449 defer fixtures.Clean() 3450 3451 for _, f := range fixtures.ByTag("packfile") { 3452 if f.DotGitHash == "" { 3453 continue 3454 } 3455 3456 b.Run(f.URL, func(b *testing.B) { 3457 fs := f.DotGit() 3458 st := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) 3459 3460 worktree, err := fs.Chroot(filepath.Dir(fs.Root())) 3461 if err != nil { 3462 b.Fatal(err) 3463 } 3464 3465 repo, err := Open(st, worktree) 3466 if err != nil { 3467 b.Fatal(err) 3468 } 3469 3470 for i := 0; i < b.N; i++ { 3471 iter, err := repo.Objects() 3472 if err != nil { 3473 b.Fatal(err) 3474 } 3475 3476 for { 3477 _, err := iter.Next() 3478 if err == io.EOF { 3479 break 3480 } 3481 3482 if err != nil { 3483 b.Fatal(err) 3484 } 3485 } 3486 3487 iter.Close() 3488 } 3489 }) 3490 } 3491} 3492 3493func BenchmarkPlainClone(b *testing.B) { 3494 b.StopTimer() 3495 clone := func(b *testing.B) { 3496 _, err := PlainClone(b.TempDir(), true, &CloneOptions{ 3497 URL: "https://github.com/go-git/go-git.git", 3498 Depth: 1, 3499 Tags: plumbing.NoTags, 3500 SingleBranch: true, 3501 }) 3502 if err != nil { 3503 b.Error(err) 3504 } 3505 } 3506 3507 // Warm-up as the initial clone could have a higher cost which 3508 // may skew results. 3509 clone(b) 3510 3511 b.StartTimer() 3512 for i := 0; i < b.N; i++ { 3513 clone(b) 3514 } 3515}