feat(releasepr): release PRs can be updated

- PR Description
- Read prefix+suffix from PR description and put into changelog
- Keep those overrides on PR description changes
- Add pending level to new PRs
This commit is contained in:
Julian Tölle 2024-08-03 09:26:51 +02:00
parent cb529f4760
commit fe871a0213
17 changed files with 1442 additions and 22 deletions

View file

@ -1,13 +1,34 @@
package rp
import (
"bytes"
_ "embed"
"fmt"
"log"
"text/template"
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/text"
"github.com/apricote/releaser-pleaser/internal/markdown"
east "github.com/apricote/releaser-pleaser/internal/markdown/extensions/ast"
)
var (
releasePRTemplate *template.Template
)
//go:embed releasepr.md.tpl
var rawReleasePRTemplate string
func init() {
var err error
releasePRTemplate, err = template.New("releasepr").Parse(rawReleasePRTemplate)
if err != nil {
log.Fatalf("failed to parse release pr template: %v", err)
}
}
type ReleasePullRequest struct {
ID int
Title string
@ -17,6 +38,20 @@ type ReleasePullRequest struct {
Head string
}
func NewReleasePullRequest(head, branch, version, changelogEntry string) (*ReleasePullRequest, error) {
rp := &ReleasePullRequest{
Head: head,
Labels: []string{LabelReleasePending},
}
rp.SetTitle(branch, version)
if err := rp.SetDescription(changelogEntry); err != nil {
return nil, err
}
return rp, nil
}
type ReleaseOverrides struct {
Prefix string
Suffix string
@ -57,6 +92,9 @@ const (
LabelNextVersionTypeRC = "rp-next-version::rc"
LabelNextVersionTypeBeta = "rp-next-version::beta"
LabelNextVersionTypeAlpha = "rp-next-version::alpha"
LabelReleasePending = "rp-release::pending"
LabelReleaseTagged = "rp-release::tagged"
)
const (
@ -64,6 +102,10 @@ const (
DescriptionLanguageSuffix = "rp-suffix"
)
const (
MarkdownSectionOverrides = "overrides"
)
func (pr *ReleasePullRequest) GetOverrides() (ReleaseOverrides, error) {
overrides := ReleaseOverrides{}
overrides = pr.parseVersioningFlags(overrides)
@ -95,7 +137,7 @@ func (pr *ReleasePullRequest) parseVersioningFlags(overrides ReleaseOverrides) R
func (pr *ReleasePullRequest) parseDescription(overrides ReleaseOverrides) (ReleaseOverrides, error) {
source := []byte(pr.Description)
descriptionAST := parser.NewParser().Parse(text.NewReader(source))
descriptionAST := markdown.New().Parser().Parse(text.NewReader(source))
err := ast.Walk(descriptionAST, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
@ -127,6 +169,51 @@ func (pr *ReleasePullRequest) parseDescription(overrides ReleaseOverrides) (Rele
return overrides, nil
}
func (pr *ReleasePullRequest) getCurrentOverridesText() (string, error) {
source := []byte(pr.Description)
gm := markdown.New()
descriptionAST := gm.Parser().Parse(text.NewReader(source))
var section *east.Section
err := ast.Walk(descriptionAST, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}
if n.Type() != ast.TypeBlock || n.Kind() != east.KindSection {
return ast.WalkContinue, nil
}
anySection, ok := n.(*east.Section)
if !ok {
return ast.WalkStop, fmt.Errorf("node has unexpected type: %T", n)
}
if anySection.Name != MarkdownSectionOverrides {
return ast.WalkContinue, nil
}
section = anySection
return ast.WalkStop, nil
})
if err != nil {
return "", err
}
if section == nil {
return "", nil
}
outputBuffer := new(bytes.Buffer)
err = gm.Renderer().Render(outputBuffer, source, section)
if err != nil {
return "", err
}
return outputBuffer.String(), nil
}
func textFromLines(source []byte, n ast.Node) string {
content := make([]byte, 0)
@ -137,5 +224,28 @@ func textFromLines(source []byte, n ast.Node) string {
}
return string(content)
}
func (pr *ReleasePullRequest) SetTitle(branch, version string) {
pr.Title = fmt.Sprintf("chore(%s): release %s", branch, version)
}
func (pr *ReleasePullRequest) SetDescription(changelogEntry string) error {
overrides, err := pr.getCurrentOverridesText()
if err != nil {
return err
}
var description bytes.Buffer
err = releasePRTemplate.Execute(&description, map[string]any{
"Changelog": changelogEntry,
"Overrides": overrides,
})
if err != nil {
return err
}
pr.Description = description.String()
return nil
}