releaser-pleaser/internal/releasepr/releasepr.go

185 lines
4.3 KiB
Go
Raw Normal View History

package releasepr
2024-07-30 20:24:58 +02:00
import (
"bytes"
_ "embed"
2024-07-30 20:24:58 +02:00
"fmt"
"log"
2024-08-04 21:22:22 +02:00
"regexp"
"text/template"
2024-07-30 20:24:58 +02:00
"github.com/apricote/releaser-pleaser/internal/git"
"github.com/apricote/releaser-pleaser/internal/markdown"
"github.com/apricote/releaser-pleaser/internal/versioning"
)
var (
releasePRTemplate *template.Template
2024-07-30 20:24:58 +02:00
)
//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)
}
}
2024-07-30 20:24:58 +02:00
type ReleasePullRequest struct {
git.PullRequest
Labels []Label
2024-08-03 03:00:36 +02:00
2024-08-04 21:22:22 +02:00
Head string
ReleaseCommit *git.Commit
2024-07-30 20:24:58 +02:00
}
// Label is the string identifier of a pull/merge request label on the forge.
type Label string
func NewReleasePullRequest(head, branch, version, changelogEntry string) (*ReleasePullRequest, error) {
rp := &ReleasePullRequest{
Head: head,
2024-08-17 15:45:36 +02:00
Labels: []Label{LabelReleasePending},
}
rp.SetTitle(branch, version)
if err := rp.SetDescription(changelogEntry, ReleaseOverrides{}); err != nil {
return nil, err
}
return rp, nil
}
2024-07-30 20:24:58 +02:00
type ReleaseOverrides struct {
Prefix string
Suffix string
NextVersionType versioning.NextVersionType
}
2024-07-30 20:24:58 +02:00
const (
2024-08-17 15:45:36 +02:00
LabelNextVersionTypeNormal Label = "rp-next-version::normal"
LabelNextVersionTypeRC Label = "rp-next-version::rc"
LabelNextVersionTypeBeta Label = "rp-next-version::beta"
LabelNextVersionTypeAlpha Label = "rp-next-version::alpha"
2024-08-17 15:45:36 +02:00
LabelReleasePending Label = "rp-release::pending"
LabelReleaseTagged Label = "rp-release::tagged"
2024-07-30 20:24:58 +02:00
)
2024-08-17 15:45:36 +02:00
var KnownLabels = []Label{
2024-08-05 01:00:34 +02:00
LabelNextVersionTypeNormal,
LabelNextVersionTypeRC,
LabelNextVersionTypeBeta,
LabelNextVersionTypeAlpha,
LabelReleasePending,
LabelReleaseTagged,
}
2024-07-30 20:24:58 +02:00
const (
DescriptionLanguagePrefix = "rp-prefix"
DescriptionLanguageSuffix = "rp-suffix"
)
const (
2024-08-04 21:22:22 +02:00
MarkdownSectionChangelog = "changelog"
)
const (
TitleFormat = "chore(%s): release %s"
)
var (
TitleRegex = regexp.MustCompile("chore(.*): release (.*)")
)
2024-07-30 20:24:58 +02:00
func (pr *ReleasePullRequest) GetOverrides() (ReleaseOverrides, error) {
overrides := ReleaseOverrides{}
overrides = pr.parseVersioningFlags(overrides)
overrides, err := pr.parseDescription(overrides)
if err != nil {
return ReleaseOverrides{}, err
}
return overrides, nil
}
func (pr *ReleasePullRequest) parseVersioningFlags(overrides ReleaseOverrides) ReleaseOverrides {
for _, label := range pr.Labels {
switch label {
// Versioning
case LabelNextVersionTypeNormal:
overrides.NextVersionType = versioning.NextVersionTypeNormal
2024-07-30 20:24:58 +02:00
case LabelNextVersionTypeRC:
overrides.NextVersionType = versioning.NextVersionTypeRC
2024-07-30 20:24:58 +02:00
case LabelNextVersionTypeBeta:
overrides.NextVersionType = versioning.NextVersionTypeBeta
2024-07-30 20:24:58 +02:00
case LabelNextVersionTypeAlpha:
overrides.NextVersionType = versioning.NextVersionTypeAlpha
2024-08-23 22:35:06 +02:00
case LabelReleasePending, LabelReleaseTagged:
// These labels have no effect on the versioning.
break
2024-07-30 20:24:58 +02:00
}
}
return overrides
}
func (pr *ReleasePullRequest) parseDescription(overrides ReleaseOverrides) (ReleaseOverrides, error) {
source := []byte(pr.Description)
err := markdown.WalkAST(source,
markdown.GetCodeBlockText(source, DescriptionLanguagePrefix, &overrides.Prefix, nil),
markdown.GetCodeBlockText(source, DescriptionLanguageSuffix, &overrides.Suffix, nil),
)
2024-07-30 20:24:58 +02:00
if err != nil {
return ReleaseOverrides{}, err
}
return overrides, nil
}
2024-08-04 21:22:22 +02:00
func (pr *ReleasePullRequest) ChangelogText() (string, error) {
source := []byte(pr.Description)
var sectionText string
err := markdown.WalkAST(source, markdown.GetSectionText(source, MarkdownSectionChangelog, &sectionText))
2024-08-04 21:22:22 +02:00
if err != nil {
return "", err
}
return sectionText, nil
2024-07-30 20:24:58 +02:00
}
func (pr *ReleasePullRequest) SetTitle(branch, version string) {
pr.Title = fmt.Sprintf(TitleFormat, branch, version)
}
2024-08-04 21:22:22 +02:00
func (pr *ReleasePullRequest) Version() (string, error) {
matches := TitleRegex.FindStringSubmatch(pr.Title)
if len(matches) != 3 {
return "", fmt.Errorf("title has unexpected format")
}
return matches[2], nil
}
func (pr *ReleasePullRequest) SetDescription(changelogEntry string, overrides ReleaseOverrides) error {
var description bytes.Buffer
err := releasePRTemplate.Execute(&description, map[string]any{
"Changelog": changelogEntry,
"Overrides": overrides,
})
if err != nil {
return err
}
pr.Description = description.String()
2024-07-30 20:24:58 +02:00
return nil
2024-07-30 20:24:58 +02:00
}