-
-
Notifications
You must be signed in to change notification settings - Fork 16
/
init.go
135 lines (103 loc) · 3.18 KB
/
init.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package chglog
import (
"fmt"
"os"
"sort"
"github.com/Masterminds/semver/v3"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
)
func versionsInRepo(gitRepo *git.Repository) (map[plumbing.Hash]*semver.Version, error) {
tagRefs, err := gitRepo.Tags()
if err != nil {
return nil, err
}
defer tagRefs.Close()
tags := make(map[plumbing.Hash]*semver.Version)
err = tagRefs.ForEach(func(t *plumbing.Reference) error {
var (
version *semver.Version
tag *object.Tag
)
tagName := t.Name().Short()
hash := t.Hash()
if version, err = semver.NewVersion(tagName); err != nil || version == nil {
fmt.Fprintf(os.Stderr, "Warning: unable to parse version from tag: %s : %v\n", tagName, err)
return nil
}
// If this is an annotated tag look up the hash of the commit and use that.
if tag, err = gitRepo.TagObject(t.Hash()); err == nil {
var c *object.Commit
if c, err = tag.Commit(); err != nil {
return fmt.Errorf("cannot dereference annotated tag: %s : %w", tagName, err)
}
hash = c.Hash
}
tags[hash] = version
return nil
})
if err != nil {
return nil, err
}
return tags, nil
}
func versionsOnBranch(gitRepo *git.Repository) (map[*semver.Version]plumbing.Hash, error) {
repoVersions, err := versionsInRepo(gitRepo)
if err != nil {
return nil, err
}
refs, err := gitRepo.Log(&git.LogOptions{})
if err != nil {
return nil, err
}
defer refs.Close()
versions := make(map[*semver.Version]plumbing.Hash)
err = refs.ForEach(func(c *object.Commit) error {
if v, ok := repoVersions[c.Hash]; ok {
versions[v] = c.Hash
}
return nil
})
return versions, err
}
// InitChangelog create a new ChangeLogEntries from a git repo.
func InitChangelog(gitRepo *git.Repository, owner string, notes *ChangeLogNotes, deb *ChangelogDeb, useConventionalCommits bool, excludeMergeCommits bool) (cle ChangeLogEntries, err error) {
var start, end plumbing.Hash
cle = make(ChangeLogEntries, 0)
end = plumbing.ZeroHash
versions, err := versionsOnBranch(gitRepo)
if err != nil {
return nil, err
}
tags := make([]*semver.Version, 0, len(versions))
for v := range versions {
tags = append(tags, v)
}
sort.Slice(tags, func(i, j int) bool { return tags[i].LessThan(tags[j]) })
for _, version := range tags {
var (
commits []*object.Commit
commitObject *object.Commit
)
if version.Prerelease() != "" {
// Do not need change logs for pre-release entries
continue
}
start = versions[version]
if commitObject, err = gitRepo.CommitObject(start); err != nil {
return nil, fmt.Errorf("unable to fetch commit from tag %v: %w", version.Original(), err)
}
if owner == "" {
owner = fmt.Sprintf("%s <%s>", commitObject.Committer.Name, commitObject.Committer.Email)
}
if commits, err = CommitsBetween(gitRepo, start, end, excludeMergeCommits); err != nil {
return nil, fmt.Errorf("unable to find commits between %s & %s: %w", end, start, err)
}
changelog := CreateEntry(commitObject.Committer.When, version, owner, notes, deb, commits, useConventionalCommits)
cle = append(cle, changelog)
end = start
}
sort.Sort(sort.Reverse(cle))
return cle, nil
}