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

✨ Add release notes expander functionality #10091

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
30 changes: 22 additions & 8 deletions hack/tools/release/notes/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ type pr struct {

// prLister returns a list of PRs.
type prLister interface {
listPRs() ([]pr, error)
listPRs(previousRelease ref) ([]pr, error)
}

// notesEntry represents a line item for the release notes.
Expand All @@ -67,25 +67,39 @@ type prProcessor interface {
// entriesPrinter formats and outputs to stdout the notes
// based on a list of entries.
type entriesPrinter interface {
print([]notesEntry, int, string)
print([]notesEntry, int, string, ref)
}

// run generates and prints the notes.
func (g *notesGenerator) run() error {
prs, err := g.lister.listPRs()
// run generating and prints the notes.
func (g *notesGenerator) run(previousReleaseRef ref) error {
if previousReleaseRef.value != "" {
previousReleasePRs, err := g.lister.listPRs(previousReleaseRef)
if err != nil {
return err
}
previousEntries := g.processor.process(previousReleasePRs)

dependencies, err := g.dependenciesProcessor.generateDependencies(previousReleaseRef)
if err != nil {
return err
}

g.printer.print(previousEntries, len(previousReleasePRs), dependencies, previousReleaseRef)
}

prs, err := g.lister.listPRs(ref{})
if err != nil {
return err
}

entries := g.processor.process(prs)

dependencies, err := g.dependenciesProcessor.generateDependencies()
dependencies, err := g.dependenciesProcessor.generateDependencies(ref{})
if err != nil {
return err
}

// Pass in length of PRs to printer as some PRs are excluded from the entries list
g.printer.print(entries, len(prs), dependencies)
g.printer.print(entries, len(prs), dependencies, ref{})

return nil
}
15 changes: 12 additions & 3 deletions hack/tools/release/notes/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,18 @@ func newGithubFromToPRLister(repo string, fromRef, toRef ref, branch string) *gi
// between fromRef and toRef, discarding any PR not seeing in the commits list.
// This ensures we don't include any PR merged in the same date range that
// doesn't belong to our git timeline.
func (l *githubFromToPRLister) listPRs() ([]pr, error) {
log.Printf("Computing diff between %s and %s", l.fromRef, l.toRef)
diff, err := l.client.getDiffAllCommits(l.fromRef.value, l.toRef.value)
func (l *githubFromToPRLister) listPRs(previousReleaseRef ref) ([]pr, error) {
var (
diff *githubDiff
err error
)
if previousReleaseRef.value != "" {
log.Printf("Computing diff between %s and %s", previousReleaseRef.value, l.toRef)
diff, err = l.client.getDiffAllCommits(previousReleaseRef.value, l.toRef.value)
} else {
log.Printf("Computing diff between %s and %s", l.fromRef, l.toRef)
diff, err = l.client.getDiffAllCommits(l.fromRef.value, l.toRef.value)
}
if err != nil {
return nil, err
}
Expand Down
31 changes: 25 additions & 6 deletions hack/tools/release/notes/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ This tool prints all the titles of all PRs in between to references.
Use these as the base of your release notes.
*/

const (
betaRelease = "BETA RELEASE"
releaseCandidate = "RELEASE CANDIDATE"
)

func main() {
cmd := newNotesCmd()
if err := cmd.run(); err != nil {
Expand All @@ -51,6 +56,7 @@ type notesCmdConfig struct {
toRef string
newTag string
branch string
previousReleaseVersion string
prefixAreaLabel bool
deprecation bool
addKubernetesVersionSupport bool
Expand All @@ -64,6 +70,7 @@ func readCmdConfig() *notesCmdConfig {
flag.StringVar(&config.toRef, "to", "", "The ref (tag, branch or commit to stop at. It must be formatted as heads/<branch name> for branches and tags/<tag name> for tags. If not set, it will default to branch.")
flag.StringVar(&config.branch, "branch", "", "The branch to generate the notes from. If not set, it will be calculated from release.")
flag.StringVar(&config.newTag, "release", "", "The tag for the new release.")
flag.StringVar(&config.previousReleaseVersion, "previous-release-version", "", "The tag for the previous beta release.")

flag.BoolVar(&config.prefixAreaLabel, "prefix-area-label", true, "If enabled, will prefix the area label.")
flag.BoolVar(&config.deprecation, "deprecation", true, "If enabled, will add a templated deprecation warning header.")
Expand All @@ -86,7 +93,8 @@ func newNotesCmd() *notesCmd {
}

func (cmd *notesCmd) run() error {
if err := validateConfig(cmd.config); err != nil {
releaseType := releaseTypeFromNewTag(cmd.config.newTag)
if err := validateConfig(cmd.config, releaseType); err != nil {
return err
}

Expand All @@ -100,8 +108,13 @@ func (cmd *notesCmd) run() error {

from, to := parseRef(cmd.config.fromRef), parseRef(cmd.config.toRef)

var previousReleaseRef ref
if cmd.config.previousReleaseVersion != "" {
previousReleaseRef = parseRef(cmd.config.previousReleaseVersion)
}

printer := newReleaseNotesPrinter(cmd.config.repo, from.value)
printer.releaseType = releaseTypeFromNewTag(cmd.config.newTag)
printer.releaseType = releaseType
printer.printDeprecation = cmd.config.deprecation
printer.printKubernetesSupport = cmd.config.addKubernetesVersionSupport

Expand All @@ -112,7 +125,7 @@ func (cmd *notesCmd) run() error {
newDependenciesProcessor(cmd.config.repo, from.value, to.value),
)

return generator.run()
return generator.run(previousReleaseRef)
}

func releaseTypeFromNewTag(newTagConfig string) string {
Expand All @@ -130,9 +143,9 @@ func releaseTypeFromNewTag(newTagConfig string) string {
// If a new type is not defined, no warning banner will be printed.
switch newTag.Pre[0].VersionStr {
case "rc":
return "RELEASE CANDIDATE"
return releaseCandidate
case "beta":
return "BETA RELEASE"
return betaRelease
}
return ""
}
Expand All @@ -150,7 +163,7 @@ func commandExists(cmd string) bool {
return err == nil
}

func validateConfig(config *notesCmdConfig) error {
func validateConfig(config *notesCmdConfig, releaseType string) error {
if config.fromRef == "" && config.newTag == "" {
return errors.New("at least one of --from or --release need to be set")
}
Expand All @@ -171,6 +184,12 @@ func validateConfig(config *notesCmdConfig) error {
}
}

if releaseType != "" {
if config.previousReleaseVersion == "" {
return errors.New("--previous-release-version need to be set with RELEASE CANDIDATE/BETA RELEASE tag")
}
}

return nil
}

Expand Down
59 changes: 42 additions & 17 deletions hack/tools/release/notes/print.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ var defaultOutputOrder = []string{
release.Unknown,
}

var isExpanderAdded = false
var isPreReleasePrinted = false

// releaseNotesPrinter outputs the PR entries following
// the right format for the release notes.
type releaseNotesPrinter struct {
Expand All @@ -57,7 +60,7 @@ func newReleaseNotesPrinter(repo, fromTag string) *releaseNotesPrinter {
}

// print outputs to stdout the release notes.
func (p *releaseNotesPrinter) print(entries []notesEntry, commitsInRelease int, dependencies string) {
func (p *releaseNotesPrinter) print(entries []notesEntry, commitsInRelease int, dependencies string, previousReleaseRef ref) {
merges := map[string][]string{
release.Features: {},
release.Bugs: {},
Expand All @@ -75,11 +78,22 @@ func (p *releaseNotesPrinter) print(entries []notesEntry, commitsInRelease int,
}
}

if p.releaseType != "" {
if p.releaseType != "" && !isPreReleasePrinted {
fmt.Printf("🚨 This is a %s. Use it only for testing purposes. If you find any bugs, file an [issue](https://github.com/%s/issues/new).\n", p.releaseType, p.repo)
isPreReleasePrinted = true
}

if p.releaseType != "" && previousReleaseRef.value == "" {
// This will add the release notes expansion functionality for a pre-release version
fmt.Print(`<details>
<summary>More details about the release</summary>
`)
fmt.Printf("\n:warning: **%s NOTES** :warning:\n", p.releaseType)

isExpanderAdded = true
}

if p.printKubernetesSupport {
if p.printKubernetesSupport && previousReleaseRef.value == "" {
fmt.Print(`## πŸ‘Œ Kubernetes version support

- Management Cluster: v1.**X**.x -> v1.**X**.x
Expand All @@ -106,7 +120,11 @@ REPLACE ME: A couple sentences describing the deprecation, including links to do
`)
}

fmt.Printf("## Changes since %s\n", p.fromTag)
if previousReleaseRef.value != "" {
fmt.Printf("## Changes since %s\n", previousReleaseRef.value)
} else {
fmt.Printf("## Changes since %s\n", p.fromTag)
}

fmt.Printf("## :chart_with_upwards_trend: Overview\n")
if commitsInRelease == 1 {
Expand Down Expand Up @@ -139,18 +157,20 @@ REPLACE ME: A couple sentences describing the deprecation, including links to do

switch key {
case release.Documentation:
sort.Strings(mergeslice)
if len(mergeslice) == 1 {
fmt.Printf(
":book: Additionally, there has been 1 contribution to our documentation and book. (%s) \n\n",
mergeslice[0],
)
} else {
fmt.Printf(
":book: Additionally, there have been %d contributions to our documentation and book. (%s) \n\n",
len(mergeslice),
strings.Join(mergeslice, ", "),
)
if previousReleaseRef.value == "" {
sort.Strings(mergeslice)
if len(mergeslice) == 1 {
fmt.Printf(
":book: Additionally, there has been 1 contribution to our documentation and book. (%s) \n\n",
mergeslice[0],
)
} else {
fmt.Printf(
":book: Additionally, there have been %d contributions to our documentation and book. (%s) \n\n",
len(mergeslice),
strings.Join(mergeslice, ", "),
)
}
}
default:
fmt.Println("## " + key)
Expand All @@ -170,5 +190,10 @@ REPLACE ME: A couple sentences describing the deprecation, including links to do
fmt.Print(dependencies)

fmt.Println("")
fmt.Println("_Thanks to all our contributors!_ 😊")
if isExpanderAdded {
fmt.Print("</details>\n<br/>\n")
}
if previousReleaseRef.value == "" {
fmt.Println("_Thanks to all our contributors!_ 😊")
}
}
10 changes: 8 additions & 2 deletions hack/tools/release/notes/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,16 @@ func (g prEntriesProcessor) process(prs []pr) []notesEntry {
return entries
}

func (d dependenciesProcessor) generateDependencies() (string, error) {
func (d dependenciesProcessor) generateDependencies(previousRelease ref) (string, error) {
repoURL := fmt.Sprintf("https://github.com/%s", d.repo)

fromTag := d.fromTag
if previousRelease.value != "" {
fromTag = previousRelease.value
}

deps, err := notes.NewDependencies().ChangesForURL(
repoURL, d.fromTag, d.toTag,
repoURL, fromTag, d.toTag,
)
if err != nil {
return "", err
Expand Down
Loading