Skip to content

Commit 6c380a7

Browse files
update templates
1 parent 4222b92 commit 6c380a7

File tree

11 files changed

+187
-44
lines changed

11 files changed

+187
-44
lines changed

cmd/render.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ func RenderCmd(fs afero.Fs) *cobra.Command {
3535
RunE: func(cmd *cobra.Command, args []string) error {
3636
dest := viper.GetString("changelog_destination")
3737
renderedDest := viper.GetString("rendered_changelog_destination")
38+
repo := viper.GetString("repo")
3839

3940
version, err := cmd.Flags().GetString("version")
4041
if err != nil {
@@ -51,7 +52,7 @@ func RenderCmd(fs afero.Fs) *cobra.Command {
5152
return fmt.Errorf("error loading changelog from file: %w", err)
5253
}
5354

54-
r := changelog.NewRenderer(fs, c, renderedDest, template)
55+
r := changelog.NewRenderer(fs, c, renderedDest, template, repo)
5556

5657
if err := r.Render(); err != nil {
5758
return fmt.Errorf("cannot build asciidoc file: %w", err)

config.yaml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
owner: elastic
22
repo: elastic-agent-changelog-tool
3-
template: asciidoc-embedded
4-
components: [elastic-agent-changelog-tool]
3+
template:
4+
- asciidoc-embedded
5+
- markdown-breaking-template
6+
- markdown-deprecations-template
7+
- markdown-index-template
8+
- markdown-known-issues-template
9+
components:
10+
- beats
11+
- elastic-agent
12+
- fleet-server

internal/assets/assets.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,29 @@ import (
1414
// These strings can be used in the config template field or renderer template flag
1515
func GetEmbeddedTemplates() embeddedTemplates {
1616
return map[string]string{
17-
"asciidoc-embedded": "asciidoc-template.asciidoc",
17+
"asciidoc-embedded": "asciidoc-template.asciidoc",
18+
"markdown-index": "markdown-index-template.md",
19+
"markdown-breaking": "markdown-breaking-template.md",
20+
"markdown-deprecations": "markdown-deprecations-template.md",
21+
"markdown-known-issues": "markdown-known-issues-template.md",
1822
}
1923
}
2024

2125
//go:embed asciidoc-template.asciidoc
2226
var AsciidocTemplate embed.FS
2327

28+
//go:embed markdown-index-template.md
29+
var MarkdownIndexTemplate embed.FS
30+
31+
//go:embed markdown-breaking-template.md
32+
var MarkdownBreakingTemplate embed.FS
33+
34+
//go:embed markdown-deprecations-template.md
35+
var MarkdownDeprecationsTemplate embed.FS
36+
37+
//go:embed markdown-known-issues-template.md
38+
var MarkdownKnownIssuesTemplate embed.FS
39+
2440
type embeddedTemplates map[string]string
2541

2642
func (t embeddedTemplates) String() string {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
## {{.Version}} [{{.Repo}}-{{.Version}}-breaking-changes]
2+
3+
{{ if .BreakingChange -}}{{ range $k, $v := .BreakingChange }}{{ range $item := $v }}
4+
::::{dropdown} {{ $item.Summary | beautify }}
5+
{{ if $item.Description }}{{ $item.Description }}{{ end }}
6+
7+
For more information, check {{ linkPRSource $item.Component $item.LinkedPR }}{{ linkIssueSource $item.Component $item.LinkedIssue }}.
8+
9+
{{ if not $item.Impact }}% {{ end }}**Impact**<br>{{ if $item.Impact }}{{ $item.Impact }}{{ else }}_Add a description of the impact_{{ end }}
10+
11+
{{ if not $item.Action }}% {{ end }}**Action**<br>{{ if $item.Action }}{{ $item.Action }}{{ else }}_Add a description of the what action to take_{{ end }}
12+
::::
13+
{{- end }}{{- end }}{{- end }}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
## {{.Version}} [{{.Repo}}-{{.Version}}-deprecations]
2+
{{ if .Deprecation -}}{{ range $k, $v := .Deprecation }}{{ range $item := $v }}
3+
4+
::::{dropdown} {{ $item.Summary | beautify }}
5+
{{ if $item.Description }}{{ $item.Description }}{{ end }}
6+
7+
For more information, check {{ linkPRSource $item.Component $item.LinkedPR }}{{ linkIssueSource $item.Component $item.LinkedIssue }}.
8+
9+
{{ if not $item.Impact }}% {{ end }}**Impact**<br>{{ if $item.Impact }}{{ $item.Impact }}{{ else }}_Add a description of the impact_{{ end }}
10+
11+
{{ if not $item.Action }}% {{ end }}**Action**<br>{{ if $item.Action }}{{ $item.Action }}{{ else }}_Add a description of the what action to take_{{ end }}
12+
::::
13+
{{- end }}{{- end }}
14+
{{ else }}_No deprecations._
15+
{{- end }}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
## {{.Version}} [{{.Repo}}-release-notes-{{.Version}}]
2+
3+
{{ if or .Feature .Enhancement }}
4+
### Features and enhancements [{{.Repo}}-{{.Version}}-features-enhancements]
5+
{{ if .Feature }}{{ range $k, $v := .Feature }}{{ range $item := $v }}
6+
* {{ $item.Summary | beautify }} {{ linkPRSource $item.Component $item.LinkedPR }} {{ linkIssueSource $item.Component $item.LinkedIssue }}
7+
{{- end }}{{- end }}{{- end }}{{ if .Enhancement }}{{ range $k, $v := .Enhancement }}{{ range $item := $v }}
8+
* {{ $item.Summary | beautify }} {{ linkPRSource $item.Component $item.LinkedPR }} {{ linkIssueSource $item.Component $item.LinkedIssue }}
9+
{{- end }}{{- end }}{{- end }}
10+
{{- end }}
11+
12+
{{ if or .Security .BugFix }}
13+
### Fixes [{{.Repo}}-{{.Version}}-fixes]
14+
{{ if .Security }}{{ range $k, $v := .Security }}{{ range $item := $v }}
15+
* {{ $item.Summary | beautify }} {{ linkPRSource $item.Component $item.LinkedPR }} {{ linkIssueSource $item.Component $item.LinkedIssue }}
16+
{{- end }}{{- end }}{{- end }}{{ if .BugFix }}{{ range $k, $v := .BugFix }}{{ range $item := $v }}
17+
* {{ $item.Summary | beautify }} {{ linkPRSource $item.Component $item.LinkedPR }} {{ linkIssueSource $item.Component $item.LinkedIssue }}
18+
{{- end }}{{- end }}{{- end }}
19+
{{- end }}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{{ if .KnownIssue -}}{{ range $k, $v := .KnownIssue }}{{ range $item := $v }}
2+
3+
::::{dropdown} {{ $item.Summary | beautify }}
4+
**Applies to**: {{.Version}}
5+
6+
{{ if $item.Description }}{{ $item.Description }}{{ end }}
7+
8+
For more information, check {{ linkPRSource $item.Component $item.LinkedPR }}{{ linkIssueSource $item.Component $item.LinkedIssue }}.
9+
10+
{{ if not $item.Impact }}% {{ end }}**Impact**<br>{{ if $item.Impact }}{{ $item.Impact }}{{ else }}_Add a description of the impact_{{ end }}
11+
12+
{{ if not $item.Action }}% {{ end }}**Action**<br>{{ if $item.Action }}{{ $item.Action }}{{ else }}_Add a description of the what action to take_{{ end }}
13+
::::
14+
{{- end }}{{- end }}{{- end }}

internal/changelog/entry.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ type Entry struct {
2020
Component string `yaml:"component"`
2121
LinkedPR []string `yaml:"pr"`
2222
LinkedIssue []string `yaml:"issue"`
23+
Impact string `yaml:"impact"`
24+
Action string `yaml:"action"`
25+
Workaround string `yaml:"workaround"`
2326

2427
Timestamp int64 `yaml:"timestamp"`
2528
File FragmentFileInfo `yaml:"file"`
@@ -35,6 +38,9 @@ func EntryFromFragment(f fragment.File) Entry {
3538
Component: f.Fragment.Component,
3639
LinkedPR: []string{},
3740
LinkedIssue: []string{},
41+
Impact: f.Fragment.Impact,
42+
Action: f.Fragment.Action,
43+
Workaround: f.Fragment.Workaround,
3844
Timestamp: f.Timestamp,
3945
File: FragmentFileInfo{
4046
Name: f.Name,
Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# REQUIRED
12
# Kind can be one of:
23
# - breaking-change: a change to previously-documented behavior
34
# - deprecation: functionality that is being removed in a later release
@@ -10,23 +11,35 @@
1011
# - other: does not fit into any of the other categories
1112
kind: feature
1213

14+
# REQUIRED for all kinds
1315
# Change summary; a 80ish characters long description of the change.
1416
summary: {{.Summary}}
1517

18+
# REQUIRED for breaking-change, deprecation, known-issue
1619
# Long description; in case the summary is not enough to describe the change
1720
# this field accommodate a description without length limits.
18-
# NOTE: This field will be rendered only for breaking-change and known-issue kinds at the moment.
19-
#description:
21+
# description:
2022

23+
# REQUIRED for breaking-change, deprecation, known-issue
24+
# impact:
25+
26+
# REQUIRED for breaking-change, deprecation, known-issue
27+
# action:
28+
29+
# REQUIRED for all kinds
2130
# Affected component; usually one of "elastic-agent", "fleet-server", "filebeat", "metricbeat", "auditbeat", "all", etc.
2231
component:
2332

24-
# PR URL; optional; the PR number that added the changeset.
33+
# AUTOMATED
34+
# OPTIONAL to manually add other PR URLs
35+
# PR URL: A link the PR that added the changeset.
2536
# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added.
2637
# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number.
2738
# Please provide it if you are adding a fragment for a different PR.
28-
#pr: https://github.com/owner/repo/1234
39+
# pr: https://github.com/owner/repo/1234
2940

41+
# AUTOMATED
42+
# OPTIONAL to manually add other issue URLs
3043
# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of).
3144
# If not present is automatically filled by the tooling with the issue linked to the PR number.
32-
#issue: https://github.com/owner/repo/1234
45+
# issue: https://github.com/owner/repo/1234

internal/changelog/renderer.go

Lines changed: 72 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ import (
99
"fmt"
1010
"html/template"
1111
"log"
12+
"os"
1213
"path"
14+
"regexp"
1315
"strings"
1416

1517
"github.com/elastic/elastic-agent-changelog-tool/internal/assets"
1618
"github.com/spf13/afero"
1719
"github.com/spf13/viper"
18-
"golang.org/x/text/cases"
19-
"golang.org/x/text/language"
2020
)
2121

2222
type Renderer struct {
@@ -25,14 +25,16 @@ type Renderer struct {
2525
// dest is the destination location where the changelog is written to
2626
dest string
2727
templ string
28+
repo string
2829
}
2930

30-
func NewRenderer(fs afero.Fs, c Changelog, dest string, templ string) *Renderer {
31+
func NewRenderer(fs afero.Fs, c Changelog, dest string, templ string, repo string) *Renderer {
3132
return &Renderer{
3233
changelog: c,
3334
fs: fs,
3435
dest: dest,
3536
templ: templ,
37+
repo: repo,
3638
}
3739
}
3840

@@ -47,6 +49,7 @@ func (r Renderer) Render() error {
4749
type TemplateData struct {
4850
Component string
4951
Version string
52+
Repo string
5053
Changelog Changelog
5154
Kinds map[Kind]bool
5255

@@ -62,15 +65,20 @@ func (r Renderer) Render() error {
6265
}
6366

6467
td := TemplateData{
65-
buildTitleByComponents(r.changelog.Entries), r.changelog.Version, r.changelog,
68+
buildTitleByComponents(r.changelog.Entries), r.changelog.Version, r.repo, r.changelog,
6669
collectKinds(r.changelog.Entries),
67-
collectByKindMap(r.changelog.Entries, BreakingChange),
68-
collectByKindMap(r.changelog.Entries, Deprecation),
69-
collectByKindMap(r.changelog.Entries, BugFix),
70+
// In Markdown, this goes to release notes
7071
collectByKindMap(r.changelog.Entries, Enhancement),
7172
collectByKindMap(r.changelog.Entries, Feature),
72-
collectByKindMap(r.changelog.Entries, KnownIssue),
7373
collectByKindMap(r.changelog.Entries, Security),
74+
collectByKindMap(r.changelog.Entries, BugFix),
75+
// In Markdown, this goes to breaking changes
76+
collectByKindMap(r.changelog.Entries, BreakingChange),
77+
// In Markdown, this goes to deprecations
78+
collectByKindMap(r.changelog.Entries, Deprecation),
79+
// In Markdown, this goes to known issues
80+
collectByKindMap(r.changelog.Entries, KnownIssue),
81+
// In Markdown... TBD
7482
collectByKindMap(r.changelog.Entries, Upgrade),
7583
collectByKindMap(r.changelog.Entries, Other),
7684
}
@@ -81,42 +89,35 @@ func (r Renderer) Render() error {
8189
return strings.Join(ids, "-")
8290
},
8391
// nolint:staticcheck // ignoring for now, supports for multiple component is not implemented
84-
"linkPRSource": func(component string, ids []string) string {
92+
"linkPRSource": func(repo string, ids []string) string {
8593
res := make([]string, len(ids))
86-
8794
for i, id := range ids {
88-
res[i] = fmt.Sprintf("{%s-pull}%v[#%v]", component, id, id)
95+
res[i] = getLink(id, r.repo, "pull", r.templ)
8996
}
90-
9197
return strings.Join(res, " ")
9298
},
9399
// nolint:staticcheck // ignoring for now, supports for multiple component is not implemented
94-
"linkIssueSource": func(component string, ids []string) string {
100+
"linkIssueSource": func(repo string, ids []string) string {
95101
res := make([]string, len(ids))
96-
97102
for i, id := range ids {
98-
res[i] = fmt.Sprintf("{%s-issue}%v[#%v]", component, id, id)
103+
res[i] = getLink(id, r.repo, "issues", r.templ)
99104
}
100-
101105
return strings.Join(res, " ")
102106
},
103107
// Capitalize sentence and ensure ends with .
104-
"beautify": func(s1 string) string {
105-
s2 := strings.Builder{}
106-
s2.WriteString(cases.Title(language.English).String(s1))
107-
if !strings.HasSuffix(s1, ".") {
108-
s2.WriteString(".")
108+
"beautify": func(s string) string {
109+
if s == "" {
110+
return ""
109111
}
110-
return s2.String()
112+
s = strings.ToUpper(string(s[0])) + s[1:]
113+
if !strings.HasSuffix(s, ".") {
114+
s += "."
115+
}
116+
return s
111117
},
112118
// Ensure components have section styling
113119
"header2": func(s1 string) string {
114-
s2 := strings.Builder{}
115-
s2.WriteString(s1)
116-
if !strings.HasSuffix(s1, "::") && s1 != "" {
117-
s2.WriteString("::")
118-
}
119-
return s2.String()
120+
return fmt.Sprintf("**%s**", s1)
120121
},
121122
}).
122123
Parse(string(tpl))
@@ -131,22 +132,44 @@ func (r Renderer) Render() error {
131132
panic(err)
132133
}
133134

134-
outFile := path.Join(r.dest, fmt.Sprintf("%s.asciidoc", r.changelog.Version))
135-
log.Printf("saving changelog in %s\n", outFile)
136-
137-
return afero.WriteFile(r.fs, outFile, data.Bytes(), changelogFilePerm)
135+
outFile := func(template string) string {
136+
if template == "markdown-index" {
137+
return path.Join(r.dest, r.changelog.Version, "index.md")
138+
} else if template == "markdown-breaking" {
139+
return path.Join(r.dest, r.changelog.Version, "breaking.md")
140+
} else if template == "markdown-deprecations" {
141+
return path.Join(r.dest, r.changelog.Version, "deprecations.md")
142+
} else if template == "markdown-known-issues" {
143+
return path.Join(r.dest, r.changelog.Version, "known-issues.md")
144+
} else {
145+
return path.Join(r.dest, fmt.Sprintf("%s.asciidoc", r.changelog.Version))
146+
}
147+
}
148+
if r.templ != "asciidoc-embedded" {
149+
os.MkdirAll(path.Join(r.dest, r.changelog.Version), os.ModePerm)
150+
}
151+
return afero.WriteFile(r.fs, outFile(r.templ), data.Bytes(), changelogFilePerm)
138152
}
139153

140154
func (r Renderer) Template() ([]byte, error) {
141155
var data []byte
142156
var err error
143157

144158
if embeddedFileName, ok := assets.GetEmbeddedTemplates()[r.templ]; ok {
145-
data, err = assets.AsciidocTemplate.ReadFile(embeddedFileName)
159+
if r.templ == "markdown-index" {
160+
data, err = assets.MarkdownIndexTemplate.ReadFile(embeddedFileName)
161+
} else if r.templ == "markdown-breaking" {
162+
data, err = assets.MarkdownBreakingTemplate.ReadFile(embeddedFileName)
163+
} else if r.templ == "markdown-deprecations" {
164+
data, err = assets.MarkdownDeprecationsTemplate.ReadFile(embeddedFileName)
165+
} else if r.templ == "markdown-known-issues" {
166+
data, err = assets.MarkdownKnownIssuesTemplate.ReadFile(embeddedFileName)
167+
} else if r.templ == "asciidoc-embedded" {
168+
data, err = assets.AsciidocTemplate.ReadFile(embeddedFileName)
169+
}
146170
if err != nil {
147171
return []byte{}, fmt.Errorf("cannot read embedded template: %s %w", embeddedFileName, err)
148172
}
149-
150173
return data, nil
151174
}
152175

@@ -158,6 +181,21 @@ func (r Renderer) Template() ([]byte, error) {
158181
return data, nil
159182
}
160183

184+
func getLink(id string, repo string, ghType string, templ string) string {
185+
re := regexp.MustCompile(`\d+$`)
186+
number := re.FindString(id)
187+
if id == number {
188+
id = fmt.Sprintf("https://github.com/elastic/%s/%s/%s", repo, ghType, id)
189+
}
190+
if templ == "asciidoc-embedded" {
191+
// Format as AsciiDoc links
192+
return fmt.Sprintf("%s[#%s]", id, number)
193+
} else {
194+
// Format as Markdown links
195+
return fmt.Sprintf("[#%s](%s)", number, id)
196+
}
197+
}
198+
161199
func collectKinds(items []Entry) map[Kind]bool {
162200
// NOTE: collect kinds in a set-like map to avoid duplicates
163201
kinds := map[Kind]bool{}

0 commit comments

Comments
 (0)