Skip to content

Commit

Permalink
testutil/genchangelog: ignore rc's, template changes (#2652)
Browse files Browse the repository at this point in the history
This PR:

- filters out pre-releases (i.e. `-rcX`) when automatically gathering tags
- modify changelog template to also output all the PRs that have been merged between two tags

category: refactor
ticket: none
  • Loading branch information
gsora authored Oct 30, 2023
1 parent 10c3ee0 commit 85ea8d1
Show file tree
Hide file tree
Showing 8 changed files with 761 additions and 197 deletions.
5 changes: 5 additions & 0 deletions app/version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ func (v SemVer) String() string {
return fmt.Sprintf("v%d.%d-%s", v.major, v.minor, v.preRelease)
}

// PreRelease returns true if v represents a tag for a pre-release.
func (v SemVer) PreRelease() bool {
return v.semVerType == typePreRelease
}

// Minor returns the minor version of the semantic version.
// It strips the typePatch version and pre-release label if present.
func (v SemVer) Minor() SemVer {
Expand Down
10 changes: 10 additions & 0 deletions app/version/version_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@ func TestSemVerCompare(t *testing.T) {
}
}

func TestIsPrerelease(t *testing.T) {
preRelease, err := version.Parse("v0.17.1-rc1")
require.NoError(t, err)
require.True(t, preRelease.PreRelease())

release, err := version.Parse("v0.17.1")
require.NoError(t, err)
require.False(t, release.PreRelease())
}

func TestCurrentInSupported(t *testing.T) {
require.Equal(t, 0, version.Compare(version.Version, version.Supported()[0]))
}
Expand Down
99 changes: 63 additions & 36 deletions testutil/genchangelog/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@
// It requires the following:
// - Each commit is a squash merged GitHub PR.
// - The commit subject contains the PR number '(#123)'.
// - Each commit contains a 'category: foo' line in the body.
// - Each commit is linked to a Github Issue via a 'ticket: #321' line in the body.
// - Only PRs with supported categories linked to Issues will be included in the changelog.
//
//nolint:forbidigo,gosec
// PRs that don't have a linked ticket or category will be placed in the "What's changed" section of the changelog.
//
//nolint:forbidigo
package main

import (
Expand All @@ -23,6 +22,7 @@ import (
"os"
"os/exec"
"regexp"
"slices"
"sort"
"strconv"
"strings"
Expand All @@ -31,6 +31,7 @@ import (

"github.com/obolnetwork/charon/app/errors"
applog "github.com/obolnetwork/charon/app/log"
"github.com/obolnetwork/charon/app/version"
"github.com/obolnetwork/charon/app/z"
)

Expand Down Expand Up @@ -83,6 +84,7 @@ type tplData struct {
RangeText string
RangeLink string
Categories []tplCategory
ExtraPRs []pullRequest
}

// tplCategory is a category section in the changelog.
Expand Down Expand Up @@ -131,7 +133,7 @@ func run(gitRange string, output string, token string) error {
return err
}

gitRange = fmt.Sprintf("%s..%s", tags[1], tags[0])
gitRange = fmt.Sprintf("%s..%s", tags[0], tags[1])
fmt.Printf("Flag --range empty, defaulting to %s\n", gitRange)
}

Expand Down Expand Up @@ -230,8 +232,16 @@ func execTemplate(data tplData) ([]byte, error) {

// tplDataFromPRs builds the template data from the provides PRs, git range, issue title func.
func tplDataFromPRs(prs []pullRequest, gitRange string, issueData func(int) (string, string, error)) (tplData, error) {
var noIssuePRs []pullRequest
issues := make(map[int]tplIssue)

for _, pr := range prs {
if pr.Issue == 0 {
// zero-indexed element from issues represents all the PRs with no issue associated
noIssuePRs = append(noIssuePRs, pr)
continue
}

issue := issues[pr.Issue]
issue.Number = pr.Issue
issue.Label = fmt.Sprintf("#%d", pr.Issue)
Expand All @@ -240,6 +250,17 @@ func tplDataFromPRs(prs []pullRequest, gitRange string, issueData func(int) (str
issues[pr.Issue] = issue
}

// order PRs with no issue by their number, ascending
slices.SortFunc(noIssuePRs, func(a, b pullRequest) int {
if a.Number < b.Number {
return -1
} else if a.Number > b.Number {
return 1
} else {
return 0
}
})

cats := make(map[string]tplCategory)
for _, issue := range issues {
title, status, err := issueData(issue.Number)
Expand Down Expand Up @@ -282,6 +303,7 @@ func tplDataFromPRs(prs []pullRequest, gitRange string, issueData func(int) (str
RangeText: gitRange,
RangeLink: fmt.Sprintf("https://github.com/obolnetwork/charon/compare/%s", gitRange),
Categories: catSlice,
ExtraPRs: noIssuePRs,
}, nil
}

Expand Down Expand Up @@ -350,51 +372,43 @@ func prFromLog(l log) (pullRequest, bool) {
return pullRequest{}, false
}

var (
category string
issue int
number int
)
var ok bool

number, ok := getNumber(l.Subject)
pr := pullRequest{
Title: l.Subject,
}

pr.Number, ok = getNumber(l.Subject)
if !ok {
fmt.Printf("Failed parsing PR number from git subject (%v): %s\n", l.Commit, l.Subject)
return pullRequest{}, false
}

category, ok = getFirstMatch(categoryRegex, l.Body)
pr.Category, ok = getFirstMatch(categoryRegex, l.Body)
if !ok {
fmt.Printf("Failed parsing category from git body (%v): %s\n", l.Commit, l.Subject)
return pullRequest{}, false
} else if skippedCategories[category] {
fmt.Printf("Skipping PR with '%s' category (%v): %s\n", category, l.Commit, l.Subject)
return pullRequest{}, false
} else if categoryOrder[category] == 0 {
fmt.Printf("Unsupported category %s (%v): %s\n", category, l.Commit, l.Subject)
return pr, true
} else if skippedCategories[pr.Category] {
fmt.Printf("Skipping PR with '%s' category (%v): %s\n", pr.Category, l.Commit, l.Subject)
return pullRequest{}, false
} else if categoryOrder[pr.Category] == 0 {
return pr, true
}

ticket, ok := getFirstMatch(ticketRegex, l.Body)
if !ok {
fmt.Printf("Failed parsing ticket from git body (%v): %s\n", l.Commit, l.Subject)
return pullRequest{}, false
} else if strings.Contains(ticket, "none") {
fmt.Printf("Skipping PR with 'none' ticket (%s): %s\n", l.Commit, l.Subject)
return pullRequest{}, false
return pr, true
} else {
issue, ok = getNumber(ticket)
pr.Issue, ok = getNumber(ticket)
if !ok {
fmt.Printf("Failed parsing issue number from ticket (%v): %s \n", l.Commit, ticket)
return pullRequest{}, false
}
}

return pullRequest{
Number: number,
Title: l.Subject,
Category: category,
Issue: issue,
}, true
return pr, true
}

// getNumber returns a github issue number from the string.
Expand Down Expand Up @@ -429,18 +443,31 @@ func getLatestTags(n int) ([]string, error) {
return nil, errors.Wrap(err, "git fetch", z.Str("out", string(out)))
}

out, err = exec.Command("git", "rev-list", "--tags", "--max-count="+fmt.Sprint(n)).CombinedOutput()
out, err = exec.Command("git", "tag", "--sort=v:refname").CombinedOutput()
if err != nil {
return nil, errors.Wrap(err, "git rev-list", z.Str("out", string(out)))
return nil, errors.Wrap(err, "git tag", z.Str("out", string(out)))
}

args := []string{"describe", "--tags", "--abbrev=0"}
args = append(args, strings.Fields(string(out))...)
var tags []string

out, err = exec.Command("git", args...).CombinedOutput()
if err != nil {
return nil, errors.Wrap(err, "git describe", z.Str("out", string(out)))
// filter out rc releases
for _, tag := range strings.Fields(string(out)) {
versionInfo, err := version.Parse(tag)
if err != nil {
return nil, errors.Wrap(err, "can't parse tag version")
}

if versionInfo.PreRelease() {
continue
}

tags = append(tags, tag)
}

if len(tags) < n {
return nil, errors.New("not enough tags", z.Int("expected", n), z.Int("available", len(tags)))
}

return strings.Fields(string(out)), nil
// return the latest N tags
return tags[len(tags)-n:], nil
}
5 changes: 5 additions & 0 deletions testutil/genchangelog/main_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ func TestPRFromLog(t *testing.T) {
Body: "Body\n\ncategory: feature\nticket: none",
Subject: "(#266)",
},
out: pullRequest{
Title: "(#266)",
Number: 266,
Category: "feature",
},
},
{
in: log{
Expand Down
7 changes: 7 additions & 0 deletions testutil/genchangelog/template.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# {{.Tag}} - {{.Date}}

![Obol Logo](https://obol.tech/obolnetwork.png)

This release introduces general fixes and improvements including progress on great new features.

**Full Changelog**: [{{.RangeText}}]({{.RangeLink}})
Expand All @@ -9,3 +11,8 @@ This release introduces general fixes and improvements including progress on gre
- {{.Title}} {{.Label}} ({{range $i, $v := .PRs}}{{if $i}},{{end}}{{$v.Label}}{{end}})
{{- end}}
{{end}}

## What's Changed
{{range .ExtraPRs}}
- [{{.Title}}](https://github.com/ObolNetwork/charon/pull/{{.Number}})
{{end}}
Loading

0 comments on commit 85ea8d1

Please sign in to comment.