forked from
tangled.org/core
Monorepo for Tangled
1package git
2
3import (
4 "fmt"
5 "slices"
6 "strconv"
7 "strings"
8 "time"
9
10 "github.com/go-git/go-git/v5/plumbing"
11 "github.com/go-git/go-git/v5/plumbing/object"
12)
13
14func (g *GitRepo) Tags() ([]object.Tag, error) {
15 fields := []string{
16 "refname:short",
17 "objectname",
18 "objecttype",
19 "*objectname",
20 "*objecttype",
21 "taggername",
22 "taggeremail",
23 "taggerdate:unix",
24 "contents",
25 }
26
27 var outFormat strings.Builder
28 outFormat.WriteString("--format=")
29 for i, f := range fields {
30 if i != 0 {
31 outFormat.WriteString(fieldSeparator)
32 }
33 outFormat.WriteString(fmt.Sprintf("%%(%s)", f))
34 }
35 outFormat.WriteString("")
36 outFormat.WriteString(recordSeparator)
37
38 output, err := g.forEachRef(outFormat.String(), "refs/tags")
39 if err != nil {
40 return nil, fmt.Errorf("failed to get tags: %w", err)
41 }
42
43 records := strings.Split(strings.TrimSpace(string(output)), recordSeparator)
44 if len(records) == 1 && records[0] == "" {
45 return nil, nil
46 }
47
48 tags := make([]object.Tag, 0, len(records))
49
50 for _, line := range records {
51 parts := strings.SplitN(strings.TrimSpace(line), fieldSeparator, len(fields))
52 if len(parts) < 6 {
53 continue
54 }
55
56 tagName := parts[0]
57 objectHash := parts[1]
58 objectType := parts[2]
59 targetHash := parts[3] // dereferenced object hash (empty for lightweight tags)
60 // targetType := parts[4] // dereferenced object type (empty for lightweight tags)
61 taggerName := parts[5]
62 taggerEmail := parts[6]
63 taggerDate := parts[7]
64 message := parts[8]
65
66 // parse creation time
67 var createdAt time.Time
68 if unix, err := strconv.ParseInt(taggerDate, 10, 64); err == nil {
69 createdAt = time.Unix(unix, 0)
70 }
71
72 // parse object type
73 typ, err := plumbing.ParseObjectType(objectType)
74 if err != nil {
75 return nil, err
76 }
77
78 // strip email separators
79 taggerEmail = strings.TrimSuffix(strings.TrimPrefix(taggerEmail, "<"), ">")
80
81 tag := object.Tag{
82 Hash: plumbing.NewHash(objectHash),
83 Name: tagName,
84 Tagger: object.Signature{
85 Name: taggerName,
86 Email: taggerEmail,
87 When: createdAt,
88 },
89 Message: message,
90 TargetType: typ,
91 Target: plumbing.NewHash(targetHash),
92 }
93
94 tags = append(tags, tag)
95 }
96
97 slices.Reverse(tags)
98 return tags, nil
99}