github.com/buildpacks/pack@v0.33.3-0.20240516162812-884dd1837311/pkg/project/v02/metadata_test.go (about)

     1  package v02
     2  
     3  import (
     4  	"fmt"
     5  	"math/rand"
     6  	"os"
     7  	"path/filepath"
     8  	"sort"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/buildpacks/lifecycle/platform/files"
    13  	"github.com/go-git/go-git/v5"
    14  	"github.com/go-git/go-git/v5/config"
    15  	"github.com/go-git/go-git/v5/plumbing"
    16  	"github.com/go-git/go-git/v5/plumbing/object"
    17  	"github.com/heroku/color"
    18  	"github.com/sclevine/spec"
    19  	"github.com/sclevine/spec/report"
    20  
    21  	h "github.com/buildpacks/pack/testhelpers"
    22  )
    23  
    24  func TestMetadata(t *testing.T) {
    25  	color.Disable(true)
    26  	defer color.Disable(false)
    27  	spec.Run(t, "Metadata", testMetadata, spec.Sequential(), spec.Report(report.Terminal{}))
    28  }
    29  
    30  func testMetadata(t *testing.T, when spec.G, it spec.S) {
    31  	var (
    32  		repoPath string
    33  		repo     *git.Repository
    34  		commits  []plumbing.Hash
    35  	)
    36  
    37  	it.Before(func() {
    38  		var err error
    39  
    40  		repoPath, err = os.MkdirTemp("", "test-repo")
    41  		h.AssertNil(t, err)
    42  
    43  		repo, err = git.PlainInit(repoPath, false)
    44  		h.AssertNil(t, err)
    45  
    46  		commits = createCommits(t, repo, repoPath, 5)
    47  	})
    48  
    49  	it.After(func() {
    50  		h.AssertNil(t, os.RemoveAll(repoPath))
    51  	})
    52  
    53  	when("#GitMetadata", func() {
    54  		it("returns proper metadata format", func() {
    55  			assert := h.NewAssertionManager(t)
    56  			remoteOpts := &config.RemoteConfig{
    57  				Name: "origin",
    58  				URLs: []string{"git@github.com:testorg/testproj.git", "git@github.com:testorg/testproj.git"},
    59  			}
    60  			repo.CreateRemote(remoteOpts)
    61  			createUnannotatedTag(t, repo, commits[len(commits)-1], "testTag")
    62  
    63  			output := GitMetadata(repoPath)
    64  			expectedOutput := &files.ProjectSource{
    65  				Type: "git",
    66  				Version: map[string]interface{}{
    67  					"commit":   commits[len(commits)-1].String(),
    68  					"describe": "testTag",
    69  				},
    70  				Metadata: map[string]interface{}{
    71  					"refs": []string{"master", "testTag"},
    72  					"url":  "git@github.com:testorg/testproj.git",
    73  				},
    74  			}
    75  			assert.Equal(output, expectedOutput)
    76  		})
    77  
    78  		it("returns nil if error occurs while fetching metadata", func() {
    79  			output := GitMetadata("/git-path-not-found-ok")
    80  			h.AssertNil(t, output)
    81  		})
    82  	})
    83  
    84  	when("#generateTagsMap", func() {
    85  		when("repository has no tags", func() {
    86  			it("returns empty map", func() {
    87  				commitTagsMap := generateTagsMap(repo)
    88  				h.AssertEq(t, len(commitTagsMap), 0)
    89  			})
    90  		})
    91  
    92  		when("repository has only unannotated tags", func() {
    93  			it("returns correct map if commits only have one tag", func() {
    94  				for i := 0; i < 4; i++ {
    95  					createUnannotatedTag(t, repo, commits[i], "")
    96  				}
    97  
    98  				commitTagsMap := generateTagsMap(repo)
    99  				h.AssertEq(t, len(commitTagsMap), 4)
   100  				for i := 0; i < 4; i++ {
   101  					tagsInfo, shouldExist := commitTagsMap[commits[i].String()]
   102  					h.AssertEq(t, shouldExist, true)
   103  					h.AssertNotEq(t, tagsInfo[0].Name, "")
   104  					h.AssertEq(t, tagsInfo[0].Type, "unannotated")
   105  					h.AssertEq(t, tagsInfo[0].Message, "")
   106  				}
   107  				_, shouldNotExist := commitTagsMap[commits[3].String()]
   108  				h.AssertEq(t, shouldNotExist, true)
   109  			})
   110  
   111  			it("returns map sorted by ascending tag name if commits have multiple tags", func() {
   112  				for i := 0; i < 4; i++ {
   113  					for j := 0; j <= rand.Intn(10); j++ {
   114  						createUnannotatedTag(t, repo, commits[i], "")
   115  					}
   116  				}
   117  
   118  				commitTagsMap := generateTagsMap(repo)
   119  				h.AssertEq(t, len(commitTagsMap), 4)
   120  				for i := 0; i < 4; i++ {
   121  					tagsInfo, shouldExist := commitTagsMap[commits[i].String()]
   122  					h.AssertEq(t, shouldExist, true)
   123  
   124  					tagsSortedByName := sort.SliceIsSorted(tagsInfo, func(i, j int) bool {
   125  						return tagsInfo[i].Name < tagsInfo[j].Name
   126  					})
   127  					h.AssertEq(t, tagsSortedByName, true)
   128  				}
   129  			})
   130  		})
   131  
   132  		when("repository has only annotated tags", func() {
   133  			it("returns correct map if commits only have one tag", func() {
   134  				for i := 0; i < 4; i++ {
   135  					createAnnotatedTag(t, repo, commits[i], "")
   136  				}
   137  
   138  				commitTagsMap := generateTagsMap(repo)
   139  				h.AssertEq(t, len(commitTagsMap), 4)
   140  				for i := 0; i < 4; i++ {
   141  					tagsInfo, shouldExist := commitTagsMap[commits[i].String()]
   142  					h.AssertEq(t, shouldExist, true)
   143  					h.AssertNotEq(t, tagsInfo[0].Name, "")
   144  					h.AssertEq(t, tagsInfo[0].Type, "annotated")
   145  					h.AssertNotEq(t, tagsInfo[0].Message, "")
   146  				}
   147  				_, shouldNotExist := commitTagsMap[commits[3].String()]
   148  				h.AssertEq(t, shouldNotExist, true)
   149  			})
   150  
   151  			it("returns map sorted by descending tag creation time if commits have multiple tags", func() {
   152  				for i := 0; i < 4; i++ {
   153  					for j := 0; j <= rand.Intn(10); j++ {
   154  						createAnnotatedTag(t, repo, commits[i], "")
   155  					}
   156  				}
   157  
   158  				commitTagsMap := generateTagsMap(repo)
   159  				h.AssertEq(t, len(commitTagsMap), 4)
   160  				for i := 0; i < 4; i++ {
   161  					tagsInfo, shouldExist := commitTagsMap[commits[i].String()]
   162  					h.AssertEq(t, shouldExist, true)
   163  
   164  					tagsSortedByTime := sort.SliceIsSorted(tagsInfo, func(i, j int) bool {
   165  						return tagsInfo[i].TagTime.After(tagsInfo[j].TagTime)
   166  					})
   167  					h.AssertEq(t, tagsSortedByTime, true)
   168  				}
   169  				_, shouldNotExist := commitTagsMap[commits[3].String()]
   170  				h.AssertEq(t, shouldNotExist, true)
   171  			})
   172  		})
   173  
   174  		when("repository has both annotated and unannotated tags", func() {
   175  			it("returns map where annotated tags exist prior to unnanotated if commits have multiple tags", func() {
   176  				for i := 0; i < 4; i++ {
   177  					for j := 0; j <= rand.Intn(10); j++ {
   178  						createAnnotatedTag(t, repo, commits[i], "")
   179  					}
   180  					for j := 0; j <= rand.Intn(10); j++ {
   181  						createUnannotatedTag(t, repo, commits[i], "")
   182  					}
   183  				}
   184  
   185  				commitTagsMap := generateTagsMap(repo)
   186  				h.AssertEq(t, len(commitTagsMap), 4)
   187  				for i := 0; i < 4; i++ {
   188  					tagsInfo, shouldExist := commitTagsMap[commits[i].String()]
   189  					h.AssertEq(t, shouldExist, true)
   190  
   191  					tagsSortedByType := sort.SliceIsSorted(tagsInfo, func(i, j int) bool {
   192  						if tagsInfo[i].Type == "annotated" && tagsInfo[j].Type == "unannotated" {
   193  							return true
   194  						}
   195  						return false
   196  					})
   197  					h.AssertEq(t, tagsSortedByType, true)
   198  				}
   199  			})
   200  		})
   201  	})
   202  
   203  	when("#generateBranchMap", func() {
   204  		it("returns map with latest commit of the `master` branch", func() {
   205  			branchMap := generateBranchMap(repo)
   206  			h.AssertEq(t, branchMap[commits[len(commits)-1].String()][0], "master")
   207  		})
   208  
   209  		it("returns map with latest commit all the branches", func() {
   210  			checkoutBranch(t, repo, "newbranch-1", true)
   211  			newBranchCommits := createCommits(t, repo, repoPath, 3)
   212  			checkoutBranch(t, repo, "master", false)
   213  			checkoutBranch(t, repo, "newbranch-2", true)
   214  
   215  			branchMap := generateBranchMap(repo)
   216  			h.AssertEq(t, branchMap[commits[len(commits)-1].String()][0], "master")
   217  			h.AssertEq(t, branchMap[commits[len(commits)-1].String()][1], "newbranch-2")
   218  			h.AssertEq(t, branchMap[newBranchCommits[len(newBranchCommits)-1].String()][0], "newbranch-1")
   219  		})
   220  	})
   221  
   222  	when("#parseGitDescribe", func() {
   223  		when("all tags are defined in a single branch", func() {
   224  			when("repository has no tags", func() {
   225  				it("returns latest commit hash", func() {
   226  					commitTagsMap := generateTagsMap(repo)
   227  					headRef, err := repo.Head()
   228  					h.AssertNil(t, err)
   229  
   230  					output := parseGitDescribe(repo, headRef, commitTagsMap)
   231  					h.AssertEq(t, output, commits[len(commits)-1].String())
   232  				})
   233  			})
   234  
   235  			when("repository has only unannotated tags", func() {
   236  				it("returns first tag encountered from HEAD", func() {
   237  					for i := 0; i < 3; i++ {
   238  						tagName := fmt.Sprintf("v0.%d-lw", i+1)
   239  						createUnannotatedTag(t, repo, commits[i], tagName)
   240  					}
   241  
   242  					commitTagsMap := generateTagsMap(repo)
   243  					headRef, err := repo.Head()
   244  					h.AssertNil(t, err)
   245  					output := parseGitDescribe(repo, headRef, commitTagsMap)
   246  					h.AssertEq(t, output, "v0.3-lw")
   247  				})
   248  
   249  				it("returns proper tag name for tags containing `/`", func() {
   250  					tagName := "v0.1/testing"
   251  					t.Logf("Checking output for tag name: %s", tagName)
   252  					createUnannotatedTag(t, repo, commits[0], tagName)
   253  
   254  					commitTagsMap := generateTagsMap(repo)
   255  					headRef, err := repo.Head()
   256  					h.AssertNil(t, err)
   257  					output := parseGitDescribe(repo, headRef, commitTagsMap)
   258  					h.AssertContains(t, output, "v0.1/testing")
   259  				})
   260  			})
   261  
   262  			when("repository has only annotated tags", func() {
   263  				it("returns first tag encountered from HEAD", func() {
   264  					for i := 0; i < 3; i++ {
   265  						tagName := fmt.Sprintf("v0.%d", i+1)
   266  						createAnnotatedTag(t, repo, commits[i], tagName)
   267  					}
   268  
   269  					commitTagsMap := generateTagsMap(repo)
   270  					headRef, err := repo.Head()
   271  					h.AssertNil(t, err)
   272  					output := parseGitDescribe(repo, headRef, commitTagsMap)
   273  					h.AssertEq(t, output, "v0.3")
   274  				})
   275  			})
   276  
   277  			when("repository has both annotated and unannotated tags", func() {
   278  				when("each commit has only one tag", func() {
   279  					it("returns the first tag encountered from HEAD if unannotated tag comes first", func() {
   280  						createAnnotatedTag(t, repo, commits[0], "ann-tag-at-commit-0")
   281  						createUnannotatedTag(t, repo, commits[1], "unann-tag-at-commit-1")
   282  						createAnnotatedTag(t, repo, commits[2], "ann-tag-at-commit-2")
   283  						createUnannotatedTag(t, repo, commits[3], "unann-tag-at-commit-3")
   284  						createUnannotatedTag(t, repo, commits[4], "unann-tag-at-commit-4")
   285  
   286  						commitTagsMap := generateTagsMap(repo)
   287  						headRef, err := repo.Head()
   288  						h.AssertNil(t, err)
   289  						output := parseGitDescribe(repo, headRef, commitTagsMap)
   290  						h.AssertEq(t, output, "unann-tag-at-commit-4")
   291  					})
   292  
   293  					it("returns the first tag encountered from HEAD if annotated tag comes first", func() {
   294  						createAnnotatedTag(t, repo, commits[0], "ann-tag-at-commit-0")
   295  						createUnannotatedTag(t, repo, commits[1], "unann-tag-at-commit-1")
   296  						createAnnotatedTag(t, repo, commits[2], "ann-tag-at-commit-2")
   297  						createAnnotatedTag(t, repo, commits[3], "ann-tag-at-commit-3")
   298  
   299  						commitTagsMap := generateTagsMap(repo)
   300  						headRef, err := repo.Head()
   301  						h.AssertNil(t, err)
   302  						output := parseGitDescribe(repo, headRef, commitTagsMap)
   303  						h.AssertEq(t, output, "ann-tag-at-commit-3")
   304  					})
   305  
   306  					it("returns the tag at HEAD if annotated tag exists at HEAD", func() {
   307  						createAnnotatedTag(t, repo, commits[4], "ann-tag-at-HEAD")
   308  
   309  						commitTagsMap := generateTagsMap(repo)
   310  						headRef, err := repo.Head()
   311  						h.AssertNil(t, err)
   312  						output := parseGitDescribe(repo, headRef, commitTagsMap)
   313  						h.AssertEq(t, output, "ann-tag-at-HEAD")
   314  					})
   315  
   316  					it("returns the tag at HEAD if unannotated tag exists at HEAD", func() {
   317  						createUnannotatedTag(t, repo, commits[4], "unann-tag-at-HEAD")
   318  
   319  						commitTagsMap := generateTagsMap(repo)
   320  						headRef, err := repo.Head()
   321  						h.AssertNil(t, err)
   322  						output := parseGitDescribe(repo, headRef, commitTagsMap)
   323  						h.AssertEq(t, output, "unann-tag-at-HEAD")
   324  					})
   325  				})
   326  
   327  				when("commits have multiple tags", func() {
   328  					it("returns most recently created tag if a commit has multiple annotated tags", func() {
   329  						createAnnotatedTag(t, repo, commits[1], "ann-tag-1-at-commit-1")
   330  						createAnnotatedTag(t, repo, commits[2], "ann-tag-1-at-commit-2")
   331  						createAnnotatedTag(t, repo, commits[2], "ann-tag-2-at-commit-2")
   332  						createAnnotatedTag(t, repo, commits[2], "ann-tag-3-at-commit-2")
   333  
   334  						commitTagsMap := generateTagsMap(repo)
   335  						headRef, err := repo.Head()
   336  						h.AssertNil(t, err)
   337  
   338  						output := parseGitDescribe(repo, headRef, commitTagsMap)
   339  						tagsAtCommit := commitTagsMap[commits[2].String()]
   340  						h.AssertEq(t, output, tagsAtCommit[0].Name)
   341  						for i := 1; i < len(tagsAtCommit); i++ {
   342  							h.AssertEq(t, tagsAtCommit[i].TagTime.Before(tagsAtCommit[0].TagTime), true)
   343  						}
   344  					})
   345  
   346  					it("returns the tag name that comes first when sorted alphabetically if a commit has multiple unannotated tags", func() {
   347  						createUnannotatedTag(t, repo, commits[1], "ann-tag-1-at-commit-1")
   348  						createUnannotatedTag(t, repo, commits[2], "v0.000002-lw")
   349  						createUnannotatedTag(t, repo, commits[2], "v0.0002-lw")
   350  						createUnannotatedTag(t, repo, commits[2], "v1.0002-lw")
   351  
   352  						commitTagsMap := generateTagsMap(repo)
   353  						headRef, err := repo.Head()
   354  						h.AssertNil(t, err)
   355  
   356  						output := parseGitDescribe(repo, headRef, commitTagsMap)
   357  						h.AssertEq(t, output, "v0.000002-lw")
   358  					})
   359  
   360  					it("returns annotated tag is a commit has both annotated and unannotated tags", func() {
   361  						createAnnotatedTag(t, repo, commits[1], "ann-tag-1-at-commit-1")
   362  						createAnnotatedTag(t, repo, commits[2], "ann-tag-1-at-commit-2")
   363  						createUnannotatedTag(t, repo, commits[2], "unann-tag-1-at-commit-2")
   364  
   365  						commitTagsMap := generateTagsMap(repo)
   366  						headRef, err := repo.Head()
   367  						h.AssertNil(t, err)
   368  
   369  						output := parseGitDescribe(repo, headRef, commitTagsMap)
   370  						h.AssertEq(t, output, "ann-tag-1-at-commit-2")
   371  					})
   372  				})
   373  			})
   374  		})
   375  
   376  		when("tags are defined in multiple branches", func() {
   377  			when("tag is defined in the latest commit of `master` branch and HEAD is at a different branch", func() {
   378  				it("returns the tag if HEAD, master and different branch is at tags", func() {
   379  					checkoutBranch(t, repo, "new-branch", true)
   380  					createAnnotatedTag(t, repo, commits[len(commits)-1], "ann-tag-at-HEAD")
   381  
   382  					headRef, err := repo.Head()
   383  					h.AssertNil(t, err)
   384  					commitTagsMap := generateTagsMap(repo)
   385  					output := parseGitDescribe(repo, headRef, commitTagsMap)
   386  					h.AssertEq(t, output, "ann-tag-at-HEAD")
   387  				})
   388  
   389  				when("branch is multiple commits ahead of master", func() {
   390  					it("returns git generated version of annotated tag if branch is 2 commits ahead of `master`", func() {
   391  						createAnnotatedTag(t, repo, commits[len(commits)-1], "testTag")
   392  						checkoutBranch(t, repo, "new-branch", true)
   393  						newCommits := createCommits(t, repo, repoPath, 2)
   394  
   395  						headRef, err := repo.Head()
   396  						h.AssertNil(t, err)
   397  						commitTagsMap := generateTagsMap(repo)
   398  						output := parseGitDescribe(repo, headRef, commitTagsMap)
   399  						expectedOutput := fmt.Sprintf("testTag-2-g%s", newCommits[len(newCommits)-1].String())
   400  						h.AssertEq(t, output, expectedOutput)
   401  					})
   402  
   403  					it("returns git generated version of unannotated tag if branch is 5 commits ahead of `master`", func() {
   404  						createUnannotatedTag(t, repo, commits[len(commits)-1], "testTag")
   405  						checkoutBranch(t, repo, "new-branch", true)
   406  						newCommits := createCommits(t, repo, repoPath, 5)
   407  
   408  						headRef, err := repo.Head()
   409  						h.AssertNil(t, err)
   410  						commitTagsMap := generateTagsMap(repo)
   411  						output := parseGitDescribe(repo, headRef, commitTagsMap)
   412  						expectedOutput := fmt.Sprintf("testTag-5-g%s", newCommits[len(newCommits)-1].String())
   413  						h.AssertEq(t, output, expectedOutput)
   414  					})
   415  
   416  					it("returns the commit hash if only the diverged tree of `master` branch has a tag", func() {
   417  						checkoutBranch(t, repo, "new-branch", true)
   418  						checkoutBranch(t, repo, "master", false)
   419  						newCommits := createCommits(t, repo, repoPath, 3)
   420  						createUnannotatedTag(t, repo, newCommits[len(newCommits)-1], "testTagAtMaster")
   421  						checkoutBranch(t, repo, "new-branch", false)
   422  
   423  						headRef, err := repo.Head()
   424  						h.AssertNil(t, err)
   425  						commitTagsMap := generateTagsMap(repo)
   426  						output := parseGitDescribe(repo, headRef, commitTagsMap)
   427  						expectedOutput := commits[len(commits)-1].String()
   428  						h.AssertEq(t, output, expectedOutput)
   429  					})
   430  				})
   431  			})
   432  		})
   433  	})
   434  
   435  	when("#parseGitRefs", func() {
   436  		when("HEAD is not at a tag", func() {
   437  			it("returns branch name if checked out branch is `master`", func() {
   438  				commitTagsMap := generateTagsMap(repo)
   439  				headRef, err := repo.Head()
   440  				h.AssertNil(t, err)
   441  				output := parseGitRefs(repo, headRef, commitTagsMap)
   442  				expectedOutput := []string{"master"}
   443  				h.AssertEq(t, output, expectedOutput)
   444  			})
   445  
   446  			it("returns branch name if checked out branch is not `master`", func() {
   447  				checkoutBranch(t, repo, "tests/05-05/test-branch", true)
   448  				createCommits(t, repo, repoPath, 1)
   449  
   450  				commitTagsMap := generateTagsMap(repo)
   451  				headRef, err := repo.Head()
   452  				h.AssertNil(t, err)
   453  				output := parseGitRefs(repo, headRef, commitTagsMap)
   454  				expectedOutput := []string{"tests/05-05/test-branch"}
   455  				h.AssertEq(t, output, expectedOutput)
   456  			})
   457  		})
   458  
   459  		when("HEAD is at a commit with single tag", func() {
   460  			it("returns annotated tag and branch name", func() {
   461  				createAnnotatedTag(t, repo, commits[len(commits)-1], "test-tag")
   462  				commitTagsMap := generateTagsMap(repo)
   463  				headRef, err := repo.Head()
   464  				h.AssertNil(t, err)
   465  				output := parseGitRefs(repo, headRef, commitTagsMap)
   466  				expectedOutput := []string{"master", "test-tag"}
   467  				h.AssertEq(t, output, expectedOutput)
   468  			})
   469  
   470  			it("returns unannotated tag and branch name", func() {
   471  				createUnannotatedTag(t, repo, commits[len(commits)-1], "test-tag")
   472  				commitTagsMap := generateTagsMap(repo)
   473  				headRef, err := repo.Head()
   474  				h.AssertNil(t, err)
   475  				output := parseGitRefs(repo, headRef, commitTagsMap)
   476  				expectedOutput := []string{"master", "test-tag"}
   477  				h.AssertEq(t, output, expectedOutput)
   478  			})
   479  		})
   480  
   481  		when("HEAD is at a commit with multiple tags", func() {
   482  			it("returns correct tag names if all tags are unannotated", func() {
   483  				createUnannotatedTag(t, repo, commits[len(commits)-2], "v0.01-testtag-lw")
   484  				createUnannotatedTag(t, repo, commits[len(commits)-1], "v0.02-testtag-lw-1")
   485  				createUnannotatedTag(t, repo, commits[len(commits)-1], "v0.02-testtag-lw-2")
   486  				commitTagsMap := generateTagsMap(repo)
   487  				headRef, err := repo.Head()
   488  				h.AssertNil(t, err)
   489  				output := parseGitRefs(repo, headRef, commitTagsMap)
   490  				expectedOutput := []string{"master", "v0.02-testtag-lw-1", "v0.02-testtag-lw-2"}
   491  				h.AssertEq(t, output, expectedOutput)
   492  			})
   493  
   494  			it("returns correct tag names if all tags are annotated", func() {
   495  				createAnnotatedTag(t, repo, commits[len(commits)-2], "v0.01-testtag")
   496  				createAnnotatedTag(t, repo, commits[len(commits)-1], "v0.02-testtag")
   497  				createAnnotatedTag(t, repo, commits[len(commits)-1], "v0.03-testtag")
   498  				commitTagsMap := generateTagsMap(repo)
   499  				headRef, err := repo.Head()
   500  				h.AssertNil(t, err)
   501  				output := parseGitRefs(repo, headRef, commitTagsMap)
   502  				expectedOutput := []string{"master", "v0.02-testtag", "v0.03-testtag"}
   503  				sort.Strings(output)
   504  				sort.Strings(expectedOutput)
   505  				h.AssertEq(t, output, expectedOutput)
   506  			})
   507  
   508  			it("returns correct tag names for both tag types", func() {
   509  				createUnannotatedTag(t, repo, commits[len(commits)-3], "v0.001-testtag-lw")
   510  				createAnnotatedTag(t, repo, commits[len(commits)-2], "v0.01-testtag")
   511  				createUnannotatedTag(t, repo, commits[len(commits)-1], "v0.02-testtag-lw-1")
   512  				createUnannotatedTag(t, repo, commits[len(commits)-1], "v0.02-testtag-lw-2")
   513  				createAnnotatedTag(t, repo, commits[len(commits)-1], "v0.02-testtag-1")
   514  
   515  				commitTagsMap := generateTagsMap(repo)
   516  				headRef, err := repo.Head()
   517  				h.AssertNil(t, err)
   518  				output := parseGitRefs(repo, headRef, commitTagsMap)
   519  				expectedOutput := []string{"master", "v0.02-testtag-1", "v0.02-testtag-lw-1", "v0.02-testtag-lw-2"}
   520  				h.AssertEq(t, output, expectedOutput)
   521  			})
   522  
   523  			it("returns correct tag names for both tag types when branch is not `master`", func() {
   524  				checkoutBranch(t, repo, "test-branch", true)
   525  				createUnannotatedTag(t, repo, commits[len(commits)-3], "v0.001-testtag-lw")
   526  				createAnnotatedTag(t, repo, commits[len(commits)-2], "v0.01-testtag")
   527  				createUnannotatedTag(t, repo, commits[len(commits)-1], "v0.02-testtag-lw-1")
   528  				createUnannotatedTag(t, repo, commits[len(commits)-1], "v0.02-testtag-lw-2")
   529  				createAnnotatedTag(t, repo, commits[len(commits)-1], "v0.02-testtag-1")
   530  				createAnnotatedTag(t, repo, commits[len(commits)-1], "v0.02-testtag-2")
   531  
   532  				commitTagsMap := generateTagsMap(repo)
   533  				headRef, err := repo.Head()
   534  				h.AssertNil(t, err)
   535  				output := parseGitRefs(repo, headRef, commitTagsMap)
   536  				expectedOutput := []string{"test-branch", "v0.02-testtag-1", "v0.02-testtag-2", "v0.02-testtag-lw-1", "v0.02-testtag-lw-2"}
   537  				sort.Strings(output)
   538  				sort.Strings(expectedOutput)
   539  				h.AssertEq(t, output, expectedOutput)
   540  			})
   541  		})
   542  	})
   543  
   544  	when("#parseGitRemote", func() {
   545  		it("returns fetch url if remote `origin` exists", func() {
   546  			remoteOpts := &config.RemoteConfig{
   547  				Name: "origin",
   548  				URLs: []string{"git@github.com:testorg/testproj.git", "git@github.com:testorg/testproj.git"},
   549  			}
   550  			repo.CreateRemote(remoteOpts)
   551  
   552  			output := parseGitRemote(repo)
   553  			h.AssertEq(t, output, "git@github.com:testorg/testproj.git")
   554  		})
   555  
   556  		it("returns empty string if no remote exists", func() {
   557  			output := parseGitRemote(repo)
   558  			h.AssertEq(t, output, "")
   559  		})
   560  
   561  		it("returns fetch url if fetch and push URLs are different", func() {
   562  			remoteOpts := &config.RemoteConfig{
   563  				Name: "origin",
   564  				URLs: []string{"git@fetch.com:testorg/testproj.git", "git@pushing-p-github.com:testorg/testproj.git"},
   565  			}
   566  			repo.CreateRemote(remoteOpts)
   567  
   568  			output := parseGitRemote(repo)
   569  			h.AssertEq(t, output, "git@fetch.com:testorg/testproj.git")
   570  		})
   571  	})
   572  
   573  	when("#getRefName", func() {
   574  		it("return proper ref for refs with `/`", func() {
   575  			output := getRefName("refs/tags/this/is/a/tag/with/slashes")
   576  			h.AssertEq(t, output, "this/is/a/tag/with/slashes")
   577  		})
   578  	})
   579  }
   580  
   581  func createCommits(t *testing.T, repo *git.Repository, repoPath string, numberOfCommits int) []plumbing.Hash {
   582  	worktree, err := repo.Worktree()
   583  	h.AssertNil(t, err)
   584  
   585  	var commitHashes []plumbing.Hash
   586  	for i := 0; i < numberOfCommits; i++ {
   587  		file, err := os.CreateTemp(repoPath, h.RandString(10))
   588  		h.AssertNil(t, err)
   589  		defer file.Close()
   590  
   591  		_, err = worktree.Add(filepath.Base(file.Name()))
   592  		h.AssertNil(t, err)
   593  
   594  		commitMsg := fmt.Sprintf("%s %d", "test commit number", i)
   595  		commitOpts := git.CommitOptions{
   596  			All: true,
   597  			Author: &object.Signature{
   598  				Name:  "Test Author",
   599  				Email: "testauthor@test.com",
   600  				When:  time.Now(),
   601  			},
   602  			Committer: &object.Signature{
   603  				Name:  "Test Committer",
   604  				Email: "testcommitter@test.com",
   605  				When:  time.Now(),
   606  			},
   607  		}
   608  		commitHash, err := worktree.Commit(commitMsg, &commitOpts)
   609  		h.AssertNil(t, err)
   610  		commitHashes = append(commitHashes, commitHash)
   611  	}
   612  	return commitHashes
   613  }
   614  
   615  func createUnannotatedTag(t *testing.T, repo *git.Repository, commitHash plumbing.Hash, tagName string) {
   616  	if tagName == "" {
   617  		version := rand.Float32()*10 + float32(rand.Intn(20))
   618  		tagName = fmt.Sprintf("v%f-lw", version)
   619  	}
   620  	_, err := repo.CreateTag(tagName, commitHash, nil)
   621  	h.AssertNil(t, err)
   622  }
   623  
   624  func createAnnotatedTag(t *testing.T, repo *git.Repository, commitHash plumbing.Hash, tagName string) {
   625  	if tagName == "" {
   626  		version := rand.Float32()*10 + float32(rand.Intn(20))
   627  		tagName = fmt.Sprintf("v%f-%s", version, h.RandString(5))
   628  	}
   629  	tagMessage := fmt.Sprintf("This is an annotated tag for version - %s", tagName)
   630  	tagOpts := &git.CreateTagOptions{
   631  		Message: tagMessage,
   632  		Tagger: &object.Signature{
   633  			Name:  "Test Tagger",
   634  			Email: "testtagger@test.com",
   635  			When:  time.Now().Add(time.Hour*time.Duration(rand.Intn(100)) + time.Minute*time.Duration(rand.Intn(100))),
   636  		},
   637  	}
   638  	_, err := repo.CreateTag(tagName, commitHash, tagOpts)
   639  	h.AssertNil(t, err)
   640  }
   641  
   642  func checkoutBranch(t *testing.T, repo *git.Repository, branchName string, newBranch bool) {
   643  	worktree, err := repo.Worktree()
   644  	h.AssertNil(t, err)
   645  
   646  	var fullBranchName string
   647  	if branchName == "" {
   648  		fullBranchName = "refs/heads/" + h.RandString(10)
   649  	} else {
   650  		fullBranchName = "refs/heads/" + branchName
   651  	}
   652  
   653  	checkoutOpts := &git.CheckoutOptions{
   654  		Branch: plumbing.ReferenceName(fullBranchName),
   655  		Create: newBranch,
   656  	}
   657  	err = worktree.Checkout(checkoutOpts)
   658  	h.AssertNil(t, err)
   659  }