coverage~bigbes/sr-ht-compare9720ccc2gitx/refs.go

Coverage
72.9% 35/48 statements
Δ
Blob
db942cd
1 package gitx
2
3 import (
4 "context"
5 "sort"
6 "time"
7
8 "github.com/go-git/go-git/v5/plumbing"
9 )
10
11 // Ref is a named git reference paired with the object id it points at (the tag
12 // object for annotated tags, matching git for-each-ref's %(objectname)).
13 type Ref struct {
14 Name string
15 SHA string
16 }
17
18 // Refs lists the repository's branches and tags. Branches are returned with the
19 // default (HEAD) branch first and the remainder alphabetical; tags are ordered
20 // newest-first by creator date (tagger date for annotated tags, committer date
21 // for lightweight tags).
22 1 func (r *Repo) Refs(ctx context.Context) (branches, tags []Ref, err error) {
23 1 _, cancel := r.withTimeout(ctx)
24 1 defer cancel()
25 1
26 1 bIter, err := r.repo.Branches()
27 1 if err != nil {
28 0 return nil, nil, err
29 0 }
30 2 err = bIter.ForEach(func(ref *plumbing.Reference) error {
31 2 branches = append(branches, Ref{Name: ref.Name().Short(), SHA: ref.Hash().String()})
32 2 return nil
33 2 })
34 1 if err != nil {
35 0 return nil, nil, err
36 0 }
37 1 def, _ := r.DefaultBranch(ctx)
38 1 sortBranches(branches, def)
39 1
40 1 type tagRef struct {
41 1 ref Ref
42 1 when time.Time
43 1 }
44 1 var trefs []tagRef
45 1 tIter, err := r.repo.Tags()
46 1 if err != nil {
47 0 return nil, nil, err
48 0 }
49 2 err = tIter.ForEach(func(ref *plumbing.Reference) error {
50 2 trefs = append(trefs, tagRef{
51 2 ref: Ref{Name: ref.Name().Short(), SHA: ref.Hash().String()},
52 2 when: r.tagWhen(ref.Hash()),
53 2 })
54 2 return nil
55 2 })
56 1 if err != nil {
57 0 return nil, nil, err
58 0 }
59 1 sort.SliceStable(trefs, func(i, j int) bool {
60 1 if !trefs[i].when.Equal(trefs[j].when) {
61 1 return trefs[i].when.After(trefs[j].when)
62 1 }
63 0 return trefs[i].ref.Name > trefs[j].ref.Name
64 })
65 2 for _, t := range trefs {
66 2 tags = append(tags, t.ref)
67 2 }
68
69 1 return branches, tags, nil
70 }
71
72 // DefaultBranch returns the short name of the branch HEAD points at (e.g.
73 // "main"). It fails if HEAD is detached (not a symbolic reference).
74 2 func (r *Repo) DefaultBranch(ctx context.Context) (string, error) {
75 2 _, cancel := r.withTimeout(ctx)
76 2 defer cancel()
77 2
78 2 ref, err := r.repo.Reference(plumbing.HEAD, false)
79 2 if err != nil {
80 0 return "", err
81 0 }
82 2 if ref.Type() != plumbing.SymbolicReference {
83 0 return "", plumbing.ErrReferenceNotFound
84 0 }
85 2 return ref.Target().Short(), nil
86 }
87
88 // tagWhen returns the creation time of a tag reference: the tagger time for an
89 // annotated tag, else the committer time of the pointed-at commit. A zero time
90 // is returned when neither can be resolved.
91 2 func (r *Repo) tagWhen(h plumbing.Hash) time.Time {
92 2 if t, err := r.repo.TagObject(h); err == nil {
93 2 return t.Tagger.When
94 2 }
95 0 if c, err := r.repo.CommitObject(h); err == nil {
96 0 return c.Committer.When
97 0 }
98 0 return time.Time{}
99 }
100
101 // sortBranches orders refs alphabetically but floats the default branch to the
102 // front.
103 1 func sortBranches(refs []Ref, defaultBranch string) {
104 1 sort.SliceStable(refs, func(i, j int) bool {
105 1 if refs[i].Name == defaultBranch {
106 1 return refs[j].Name != defaultBranch
107 1 }
108 0 if refs[j].Name == defaultBranch {
109 0 return false
110 0 }
111 0 return refs[i].Name < refs[j].Name
112 })
113 }