-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathchangelog.go
125 lines (100 loc) · 3.1 KB
/
changelog.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
package main
import (
"bytes"
"fmt"
"log/slog"
"regexp"
"strings"
"time"
"github.com/google/go-github/v66/github"
)
type Config struct {
Level int
Drafts bool
Prerelease bool
Ignore *regexp.Regexp
Extract *regexp.Regexp
}
func (c *Config) filterReleases(rels []*github.RepositoryRelease) []*github.RepositoryRelease {
i := 0
for i < len(rels) {
r := rels[i]
t := r.GetTagName()
if (c.Drafts || !r.GetDraft()) &&
(c.Prerelease || !r.GetPrerelease()) &&
(c.Ignore == nil || !c.Ignore.MatchString(t)) &&
(c.Extract == nil || c.Extract.MatchString(t)) {
i++
} else {
slog.Debug("Filtered release due to configuration", "release", r, "tag", t)
rels = append(rels[:i], rels[i+1:]...)
}
}
return rels
}
// GenerateChangeLog generates changelog text from given project data and configuration.
func GenerateChangeLog(c *Config, p *Project) ([]byte, error) {
type ref struct {
label string
url string
}
var out bytes.Buffer
rels := c.filterReleases(p.Releases)
heading := strings.Repeat("#", c.Level)
url := p.RepoURL()
slog.Debug("Start generating release notes", "url", url, "config", c)
linker := NewReflinker(url)
for _, l := range p.Autolinks {
linker.AddExtRef(*l.KeyPrefix, *l.URLTemplate, *l.IsAlphanumeric)
}
numRels := len(rels)
refs := make([]ref, 0, numRels)
for i, rel := range rels {
prevTag := ""
if i+1 < numRels {
prevTag = rels[i+1].GetTagName()
}
title := strings.TrimSpace(rel.GetName())
tag := rel.GetTagName()
if tag == "" {
return nil, fmt.Errorf(
"release %q created at %s is not associated with any tag name. cannot determine a tag name for the release. did you forget setting tag name in the draft release?",
strings.TrimSpace(rel.GetName()),
rel.CreatedAt.Format(time.RFC3339),
)
}
var created github.Timestamp
if rel.GetDraft() {
created = rel.GetCreatedAt()
} else {
created = rel.GetPublishedAt()
}
slog.Debug("Generating release", "name", title, "tag", tag, "created", created)
var compareURL string
if prevTag == "" {
compareURL = fmt.Sprintf("%s/tree/%s", url, tag)
} else {
compareURL = fmt.Sprintf("%s/compare/%s...%s", url, prevTag, tag)
}
fmt.Fprintf(&out, "<a id=\"%s\"></a>\n", tag)
if title == "" {
title = tag
} else if !strings.Contains(title, tag) {
title = fmt.Sprintf("%s (%s)", title, tag)
}
pageURL := fmt.Sprintf("%s/releases/tag/%s", url, tag)
date := created.Format(time.DateOnly)
fmt.Fprintf(&out, "%s [%s](%s) - %s\n\n", heading, title, pageURL, date)
fmt.Fprint(&out, linker.Link(strings.Replace(rel.GetBody(), "\r", "", -1)))
fmt.Fprintf(&out, "\n\n[Changes][%s]\n\n\n", tag)
refs = append(refs, ref{tag, compareURL})
slog.Debug("Generated release", "title", title, "page", pageURL, "date", date)
}
slog.Debug("Generate release links", "links", len(refs))
for _, r := range refs {
fmt.Fprintf(&out, "[%s]: %s\n", r.label, r.url)
}
fmt.Fprintf(&out, "\n<!-- Generated by https://github.com/rhysd/changelog-from-release %s -->\n", version)
slog.Debug("Finish to generate release notes", "url", url)
return out.Bytes(), nil
}