mirror of
https://github.com/apricote/releaser-pleaser.git
synced 2026-02-08 10:47:02 +00:00
feat: format markdown in changelog entry
This commit is contained in:
parent
4cb22eae10
commit
929e335a29
6 changed files with 72 additions and 8 deletions
|
|
@ -5,8 +5,10 @@ import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
"html/template"
|
"html/template"
|
||||||
"log"
|
"log"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/apricote/releaser-pleaser/internal/commitparser"
|
"github.com/apricote/releaser-pleaser/internal/commitparser"
|
||||||
|
"github.com/apricote/releaser-pleaser/internal/markdown"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -24,7 +26,7 @@ func init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewChangelogEntry(commits []commitparser.AnalyzedCommit, version, link, prefix, suffix string) (string, error) {
|
func NewChangelogEntry(logger *slog.Logger, commits []commitparser.AnalyzedCommit, version, link, prefix, suffix string) (string, error) {
|
||||||
features := make([]commitparser.AnalyzedCommit, 0)
|
features := make([]commitparser.AnalyzedCommit, 0)
|
||||||
fixes := make([]commitparser.AnalyzedCommit, 0)
|
fixes := make([]commitparser.AnalyzedCommit, 0)
|
||||||
|
|
||||||
|
|
@ -50,5 +52,11 @@ func NewChangelogEntry(commits []commitparser.AnalyzedCommit, version, link, pre
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
formatted, err := markdown.Format(changelog.String())
|
||||||
|
if err != nil {
|
||||||
|
logger.Warn("failed to format changelog entry, using unformatted", "error", err)
|
||||||
return changelog.String(), nil
|
return changelog.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return formatted, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,4 +19,4 @@
|
||||||
|
|
||||||
{{- if .Suffix }}
|
{{- if .Suffix }}
|
||||||
{{ .Suffix }}
|
{{ .Suffix }}
|
||||||
{{ end -}}
|
{{ end }}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package changelog
|
package changelog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log/slog"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
@ -34,7 +35,7 @@ func Test_NewChangelogEntry(t *testing.T) {
|
||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
link: "https://example.com/1.0.0",
|
link: "https://example.com/1.0.0",
|
||||||
},
|
},
|
||||||
want: "## [1.0.0](https://example.com/1.0.0)",
|
want: "## [1.0.0](https://example.com/1.0.0)\n",
|
||||||
wantErr: assert.NoError,
|
wantErr: assert.NoError,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -50,7 +51,7 @@ func Test_NewChangelogEntry(t *testing.T) {
|
||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
link: "https://example.com/1.0.0",
|
link: "https://example.com/1.0.0",
|
||||||
},
|
},
|
||||||
want: "## [1.0.0](https://example.com/1.0.0)\n### Features\n\n- Foobar!\n",
|
want: "## [1.0.0](https://example.com/1.0.0)\n\n### Features\n\n- Foobar!\n",
|
||||||
wantErr: assert.NoError,
|
wantErr: assert.NoError,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -66,7 +67,7 @@ func Test_NewChangelogEntry(t *testing.T) {
|
||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
link: "https://example.com/1.0.0",
|
link: "https://example.com/1.0.0",
|
||||||
},
|
},
|
||||||
want: "## [1.0.0](https://example.com/1.0.0)\n### Bug Fixes\n\n- Foobar!\n",
|
want: "## [1.0.0](https://example.com/1.0.0)\n\n### Bug Fixes\n\n- Foobar!\n",
|
||||||
wantErr: assert.NoError,
|
wantErr: assert.NoError,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -100,6 +101,7 @@ func Test_NewChangelogEntry(t *testing.T) {
|
||||||
link: "https://example.com/1.0.0",
|
link: "https://example.com/1.0.0",
|
||||||
},
|
},
|
||||||
want: `## [1.0.0](https://example.com/1.0.0)
|
want: `## [1.0.0](https://example.com/1.0.0)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
- Blabla!
|
- Blabla!
|
||||||
|
|
@ -127,6 +129,7 @@ func Test_NewChangelogEntry(t *testing.T) {
|
||||||
prefix: "### Breaking Changes",
|
prefix: "### Breaking Changes",
|
||||||
},
|
},
|
||||||
want: `## [1.0.0](https://example.com/1.0.0)
|
want: `## [1.0.0](https://example.com/1.0.0)
|
||||||
|
|
||||||
### Breaking Changes
|
### Breaking Changes
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
@ -150,6 +153,7 @@ func Test_NewChangelogEntry(t *testing.T) {
|
||||||
suffix: "### Compatibility\n\nThis version is compatible with flux-compensator v2.2 - v2.9.",
|
suffix: "### Compatibility\n\nThis version is compatible with flux-compensator v2.2 - v2.9.",
|
||||||
},
|
},
|
||||||
want: `## [1.0.0](https://example.com/1.0.0)
|
want: `## [1.0.0](https://example.com/1.0.0)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
- Foobar!
|
- Foobar!
|
||||||
|
|
@ -164,7 +168,7 @@ This version is compatible with flux-compensator v2.2 - v2.9.
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got, err := NewChangelogEntry(tt.args.analyzedCommits, tt.args.version, tt.args.link, tt.args.prefix, tt.args.suffix)
|
got, err := NewChangelogEntry(slog.Default(), tt.args.analyzedCommits, tt.args.version, tt.args.link, tt.args.prefix, tt.args.suffix)
|
||||||
if !tt.wantErr(t, err) {
|
if !tt.wantErr(t, err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
package markdown
|
package markdown
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
|
||||||
markdown "github.com/teekennedy/goldmark-markdown"
|
markdown "github.com/teekennedy/goldmark-markdown"
|
||||||
"github.com/yuin/goldmark"
|
"github.com/yuin/goldmark"
|
||||||
|
"github.com/yuin/goldmark/parser"
|
||||||
|
"github.com/yuin/goldmark/util"
|
||||||
|
|
||||||
"github.com/apricote/releaser-pleaser/internal/markdown/extensions"
|
"github.com/apricote/releaser-pleaser/internal/markdown/extensions"
|
||||||
)
|
)
|
||||||
|
|
@ -10,6 +14,23 @@ import (
|
||||||
func New() goldmark.Markdown {
|
func New() goldmark.Markdown {
|
||||||
return goldmark.New(
|
return goldmark.New(
|
||||||
goldmark.WithExtensions(extensions.Section),
|
goldmark.WithExtensions(extensions.Section),
|
||||||
|
goldmark.WithParserOptions(parser.WithASTTransformers(
|
||||||
|
util.Prioritized(&newLineTransformer{}, 1),
|
||||||
|
)),
|
||||||
goldmark.WithRenderer(markdown.NewRenderer()),
|
goldmark.WithRenderer(markdown.NewRenderer()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Format the Markdown document in a style mimicking Prettier. This is done for compatibility with other tools
|
||||||
|
// users might have installed in their IDE. This does not guarantee that the output matches Prettier exactly.
|
||||||
|
func Format(input string) (string, error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
buf.Grow(len(input))
|
||||||
|
|
||||||
|
err := New().Convert([]byte(input), &buf)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
|
|
|
||||||
31
internal/markdown/prettier.go
Normal file
31
internal/markdown/prettier.go
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
package markdown
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/yuin/goldmark/ast"
|
||||||
|
"github.com/yuin/goldmark/parser"
|
||||||
|
"github.com/yuin/goldmark/text"
|
||||||
|
)
|
||||||
|
|
||||||
|
type newLineTransformer struct{}
|
||||||
|
|
||||||
|
var _ parser.ASTTransformer = (*newLineTransformer)(nil) // interface compliance
|
||||||
|
|
||||||
|
func (t *newLineTransformer) Transform(doc *ast.Document, _ text.Reader, _ parser.Context) {
|
||||||
|
// No error can happen as they can only come from the walker function
|
||||||
|
_ = ast.Walk(doc, func(node ast.Node, entering bool) (ast.WalkStatus, error) {
|
||||||
|
if !entering || node.Type() != ast.TypeBlock {
|
||||||
|
return ast.WalkContinue, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch node.Kind() {
|
||||||
|
case ast.KindListItem:
|
||||||
|
// Do not add empty lines between every list item
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
// Add empty lines between every other block
|
||||||
|
node.SetBlankPreviousLines(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ast.WalkContinue, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -239,7 +239,7 @@ func (rp *ReleaserPleaser) runReconcileReleasePR(ctx context.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
changelogEntry, err := changelog.NewChangelogEntry(analyzedCommits, nextVersion, rp.forge.ReleaseURL(nextVersion), releaseOverrides.Prefix, releaseOverrides.Suffix)
|
changelogEntry, err := changelog.NewChangelogEntry(logger, analyzedCommits, nextVersion, rp.forge.ReleaseURL(nextVersion), releaseOverrides.Prefix, releaseOverrides.Suffix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to build changelog entry: %w", err)
|
return fmt.Errorf("failed to build changelog entry: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue