Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tailor output to look better on a GitHub releases page #104

Merged
merged 4 commits into from
Sep 18, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .chronicle.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
log:
level: trace

title: ''
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

[TestMarkdownPresenter_Present - 1]
# v0.19.1

### Bug Fixes

- Redirect cursor hide/show to stderr. _([#456](https://github.com/anchore/syft/pull/456))

### Added Features

- added feature. _([#457](https://github.com/anchore/syft/pull/457) @wagoodman)
- another added feature.

### Breaking Changes

- breaking change. _([#458](https://github.com/anchore/syft/pull/458) [#450](https://github.com/anchore/syft/issues/450) @wagoodman)

**[(Full Changelog)](https://github.com/anchore/syft/compare/v0.19.0...v0.19.1)**

---

[TestMarkdownPresenter_Present_NoTitle - 1]
### Bug Fixes

- Redirect cursor hide/show to stderr. _([#456](https://github.com/anchore/syft/pull/456))

**[(Full Changelog)](https://github.com/anchore/syft/compare/v0.19.0...v0.19.1)**

---

[TestMarkdownPresenter_Present_NoChanges - 1]
# Changelog

**[(Full Changelog)](https://github.com/anchore/syft/compare/v0.19.0...v0.19.1)**

---
60 changes: 49 additions & 11 deletions chronicle/release/format/markdown/presenter.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package markdown

import (
"bytes"
"fmt"
"io"
"strings"
"text/template"

"github.com/wagoodman/go-presenter"
Expand All @@ -12,13 +14,11 @@ import (
)

const (
markdownHeaderTemplate = `# {{.Title}}
markdownHeaderTemplate = `{{if .Title }}# {{.Title}}

## [{{.Version}}]({{.VCSReferenceURL}}) ({{ .Date.Format "2006-01-02" }})
{{ end }}{{if .Changes }}{{ formatChangeSections .Changes }}

[Full Changelog]({{.VCSChangesURL}})

{{ formatChangeSections .Changes }}
{{ end }}**[(Full Changelog)]({{.VCSChangesURL}})**
`
)

Expand Down Expand Up @@ -54,6 +54,17 @@ func NewMarkdownPresenter(config Config) (*Presenter, error) {
return nil, fmt.Errorf("unable to parse markdown presenter template: %w", err)
}

titleTemplater, err := template.New("title").Funcs(funcMap).Parse(config.Title)
if err != nil {
return nil, fmt.Errorf("unable to parse markdown presenter title template: %w", err)
}

buf := bytes.Buffer{}
if err := titleTemplater.Execute(&buf, config); err != nil {
return nil, fmt.Errorf("unable to template title: %w", err)
}
p.config.Title = buf.String()

p.templater = templater

return &p, nil
Expand All @@ -71,7 +82,7 @@ func (m Presenter) formatChangeSections(changes change.Changes) string {
result += formatChangeSection(section.Title, summaries) + "\n"
}
}
return result
return strings.TrimRight(result, "\n")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we now need to remove trailing newlines?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now there is a footer and it became noticeable that we have a large amount of whitespace before the footer -- this makes the whitespace between the content and footer smaller

}

func formatChangeSection(title string, summaries []change.Change) string {
Expand All @@ -83,14 +94,41 @@ func formatChangeSection(title string, summaries []change.Change) string {
}

func formatSummary(summary change.Change) string {
result := fmt.Sprintf("- %s", summary.Text)
result := fmt.Sprintf("- %s", strings.TrimSpace(summary.Text))
if !endsWithPunctuation(result) {
switch result[len(result)-1:] {
case "!", ".", "?":
wagoodman marked this conversation as resolved.
Show resolved Hide resolved
// pass
default:
result += "."
}
}

var refs string
for _, ref := range summary.References {
if ref.URL == "" {
result += fmt.Sprintf(" [%s]", ref.Text)
} else {
result += fmt.Sprintf(" [[%s](%s)]", ref.Text, ref.URL)
switch {
case ref.URL == "":
refs += fmt.Sprintf(" %s", ref.Text)
case strings.HasPrefix(ref.Text, "@") && strings.HasPrefix(ref.URL, "https://github.com/"):
// the github release page will automatically show all contributors as a footer. However, if you
// embed the contributor's github handle in a link, then this feature will not work.
refs += fmt.Sprintf(" %s", ref.Text)
default:
refs += fmt.Sprintf(" [%s](%s)", ref.Text, ref.URL)
}
}

refs = strings.TrimSpace(refs)
if refs != "" {
result += fmt.Sprintf(" _(%s)", refs)
}

return result + "\n"
}

func endsWithPunctuation(s string) bool {
if len(s) == 0 {
return false
}
return strings.Contains("!.?", s[len(s)-1:]) //nolint:gocritic
}
125 changes: 100 additions & 25 deletions chronicle/release/format/markdown/presenter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,29 @@ package markdown

import (
"bytes"
"flag"
"testing"
"time"

"github.com/sergi/go-diff/diffmatchpatch"
"github.com/gkampitakis/go-snaps/snaps"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/wagoodman/go-presenter"

"github.com/anchore/chronicle/chronicle/release"
"github.com/anchore/chronicle/chronicle/release/change"
"github.com/anchore/go-testutils"
)

var updateMarkdownPresenterGoldenFiles = flag.Bool("update-markdown", false, "update the *.golden files for markdown presenters")

func TestMarkdownPresenter_Present(t *testing.T) {
must := func(m *Presenter, err error) *Presenter {
if err != nil {
t.Fatalf(err.Error())
}
require.NoError(t, err)
return m
}
assertPresenterAgainstGoldenSnapshot(
t,
must(
NewMarkdownPresenter(Config{
Title: "Changelog",
// this is the default configuration from the CLI
Title: `{{ .Version }}`,
Description: release.Description{
SupportedChanges: []change.TypeTitle{
{
Expand Down Expand Up @@ -60,14 +56,24 @@ func TestMarkdownPresenter_Present(t *testing.T) {
Text: "Redirect cursor hide/show to stderr",
References: []change.Reference{
{
Text: "456",
Text: "#456",
URL: "https://github.com/anchore/syft/pull/456",
},
},
},
{
ChangeTypes: []change.Type{change.NewType("added", change.SemVerMinor)},
Text: "added feature",
References: []change.Reference{
{
Text: "#457",
URL: "https://github.com/anchore/syft/pull/457",
},
{
Text: "@wagoodman",
URL: "https://github.com/wagoodman",
},
},
},
{
ChangeTypes: []change.Type{change.NewType("added", change.SemVerMinor)},
Expand All @@ -76,42 +82,111 @@ func TestMarkdownPresenter_Present(t *testing.T) {
{
ChangeTypes: []change.Type{change.NewType("breaking", change.SemVerMajor)},
Text: "breaking change",
References: []change.Reference{
{
Text: "#458",
URL: "https://github.com/anchore/syft/pull/458",
},
{
Text: "#450",
URL: "https://github.com/anchore/syft/issues/450",
},
{
Text: "@wagoodman",
URL: "https://github.com/wagoodman",
},
},
},
},
Notice: "notice!",
},
}),
),
*updateMarkdownPresenterGoldenFiles,
)
}

func TestMarkdownPresenter_Present_NoTitle(t *testing.T) {
must := func(m *Presenter, err error) *Presenter {
require.NoError(t, err)
return m
}
assertPresenterAgainstGoldenSnapshot(
t,
must(
NewMarkdownPresenter(Config{
Title: "",
Description: release.Description{
SupportedChanges: []change.TypeTitle{
{
ChangeType: change.NewType("bug", change.SemVerPatch),
Title: "Bug Fixes",
},
},
Release: release.Release{
Version: "v0.19.1",
Date: time.Date(2021, time.September, 16, 19, 34, 0, 0, time.UTC),
},
VCSReferenceURL: "https://github.com/anchore/syft/tree/v0.19.1",
VCSChangesURL: "https://github.com/anchore/syft/compare/v0.19.0...v0.19.1",
Changes: []change.Change{
{
ChangeTypes: []change.Type{change.NewType("bug", change.SemVerPatch)},
Text: "Redirect cursor hide/show to stderr",
References: []change.Reference{
{
Text: "#456",
URL: "https://github.com/anchore/syft/pull/456",
},
},
},
},
Notice: "notice!",
},
}),
),
)
}

func TestMarkdownPresenter_Present_NoChanges(t *testing.T) {
must := func(m *Presenter, err error) *Presenter {
require.NoError(t, err)
return m
}
assertPresenterAgainstGoldenSnapshot(
t,
must(
NewMarkdownPresenter(Config{
Title: "Changelog",
Description: release.Description{
SupportedChanges: []change.TypeTitle{},
Release: release.Release{
Version: "v0.19.1",
Date: time.Date(2021, time.September, 16, 19, 34, 0, 0, time.UTC),
},
VCSReferenceURL: "https://github.com/anchore/syft/tree/v0.19.1",
VCSChangesURL: "https://github.com/anchore/syft/compare/v0.19.0...v0.19.1",
Changes: []change.Change{},
Notice: "notice!",
},
}),
),
)
}

type redactor func(s []byte) []byte

func assertPresenterAgainstGoldenSnapshot(t *testing.T, pres presenter.Presenter, updateSnapshot bool, redactors ...redactor) {
func assertPresenterAgainstGoldenSnapshot(t *testing.T, pres presenter.Presenter, redactors ...redactor) {
t.Helper()

var buffer bytes.Buffer
err := pres.Present(&buffer)
assert.NoError(t, err)
actual := buffer.Bytes()

// replace the expected snapshot contents with the current presenter contents
if updateSnapshot {
testutils.UpdateGoldenFileContents(t, actual)
}

var expected = testutils.GetGoldenFileContents(t)

// remove dynamic values, which should be tested independently
for _, r := range redactors {
actual = r(actual)
expected = r(expected)
}

if !bytes.Equal(expected, actual) {
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(string(expected), string(actual), true)
t.Errorf("mismatched output:\n%s", dmp.DiffPrettyText(diffs))
}
snaps.MatchSnapshot(t, string(actual))
}

This file was deleted.

10 changes: 5 additions & 5 deletions chronicle/release/releasers/github/summarizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,11 +282,11 @@ func createChangesFromPRs(config Config, prs []ghPullRequest) []change.Change {
Timestamp: pr.MergedAt,
References: []change.Reference{
{
Text: fmt.Sprintf("PR #%d", pr.Number),
Text: fmt.Sprintf("#%d", pr.Number),
URL: pr.URL,
},
{
Text: pr.Author,
Text: fmt.Sprintf("@%s", pr.Author),
URL: fmt.Sprintf("https://%s/%s", config.Host, pr.Author),
},
},
Expand Down Expand Up @@ -380,7 +380,7 @@ func createChangesFromIssues(config Config, allMergedPRs []ghPullRequest, issues

references := []change.Reference{
{
Text: fmt.Sprintf("Issue #%d", issue.Number),
Text: fmt.Sprintf("#%d", issue.Number),
URL: issue.URL,
},
}
Expand All @@ -389,13 +389,13 @@ func createChangesFromIssues(config Config, allMergedPRs []ghPullRequest, issues
for _, pr := range getLinkedPRs(allMergedPRs, issue) {
if config.IncludeIssuePRs {
references = append(references, change.Reference{
Text: fmt.Sprintf("PR #%d", pr.Number),
Text: fmt.Sprintf("#%d", pr.Number),
URL: pr.URL,
})
}
if config.IncludeIssuePRAuthors && pr.Author != "" {
references = append(references, change.Reference{
Text: pr.Author,
Text: fmt.Sprintf("@%s", pr.Author),
URL: fmt.Sprintf("https://%s/%s", config.Host, pr.Author),
})
}
Expand Down
Loading