diff --git a/hack/tools/release/notes/generator.go b/hack/tools/release/notes/generator.go index 9acb60cd6269..11e63f722889 100644 --- a/hack/tools/release/notes/generator.go +++ b/hack/tools/release/notes/generator.go @@ -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. @@ -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 } diff --git a/hack/tools/release/notes/list.go b/hack/tools/release/notes/list.go index fae9c823e5da..4cb5bcf1cbf2 100644 --- a/hack/tools/release/notes/list.go +++ b/hack/tools/release/notes/list.go @@ -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 } diff --git a/hack/tools/release/notes/main.go b/hack/tools/release/notes/main.go index 711336cbc1b5..eb3aecaf6c08 100644 --- a/hack/tools/release/notes/main.go +++ b/hack/tools/release/notes/main.go @@ -51,6 +51,7 @@ type notesCmdConfig struct { toRef string newTag string branch string + previousReleaseVersion string prefixAreaLabel bool preReleaseVersion bool deprecation bool @@ -65,6 +66,7 @@ func readCmdConfig() *notesCmdConfig { flag.StringVar(&config.toRef, "to", "", "The ref (tag, branch or commit to stop at. It must be formatted as heads/ for branches and tags/ 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.preReleaseVersion, "pre-release-version", false, "If enabled, will add a pre-release warning header. (default false)") @@ -102,6 +104,11 @@ 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.isPreRelease = cmd.config.preReleaseVersion printer.printDeprecation = cmd.config.deprecation @@ -114,7 +121,7 @@ func (cmd *notesCmd) run() error { newDependenciesProcessor(cmd.config.repo, from.value, to.value), ) - return generator.run() + return generator.run(previousReleaseRef) } func ensureInstalledDependencies() error { @@ -151,6 +158,12 @@ func validateConfig(config *notesCmdConfig) error { } } + if config.preReleaseVersion { + if config.previousReleaseVersion == "" { + return errors.New("--previous-release-version need to be set with --pre-release-version as true") + } + } + return nil } diff --git a/hack/tools/release/notes/print.go b/hack/tools/release/notes/print.go index 2c0a4affbe83..d73397cbd72a 100644 --- a/hack/tools/release/notes/print.go +++ b/hack/tools/release/notes/print.go @@ -37,6 +37,8 @@ var defaultOutputOrder = []string{ release.Unknown, } +var isExpanderAdded = false + // releaseNotesPrinter outputs the PR entries following // the right format for the release notes. type releaseNotesPrinter struct { @@ -57,7 +59,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: {}, @@ -76,10 +78,14 @@ func (p *releaseNotesPrinter) print(entries []notesEntry, commitsInRelease int, } if p.isPreRelease { - fmt.Printf("🚨 This is a RELEASE CANDIDATE. Use it only for testing purposes. If you find any bugs, file an [issue](https://github.com/%s/issues/new).\n", p.repo) + fmt.Printf("🚨 This is a RELEASE CANDIDATE/BETA RELEASE. Use it only for testing purposes. If you find any bugs, file an [issue](https://github.com/%s/issues/new).\n", p.repo) } - if p.printKubernetesSupport { + if p.printKubernetesSupport && previousReleaseRef.value == "" { + // This will add the release notes expansion functionality for pre-release version + fmt.Print("
\nMore details about the release\n") + isExpanderAdded = true + fmt.Print(`## 👌 Kubernetes version support - Management Cluster: v1.**X**.x -> v1.**X**.x @@ -106,7 +112,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 { @@ -139,18 +149,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) @@ -170,5 +182,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("
\n
\n") + } + if previousReleaseRef.value == "" { + fmt.Println("_Thanks to all our contributors!_ 😊") + } } diff --git a/hack/tools/release/notes/process.go b/hack/tools/release/notes/process.go index 1bc3fed534c6..d5f7c14b1689 100644 --- a/hack/tools/release/notes/process.go +++ b/hack/tools/release/notes/process.go @@ -117,10 +117,18 @@ 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) + + var fromTag string + if previousRelease.value != "" { + fromTag = previousRelease.value + } else { + fromTag = d.fromTag + } + deps, err := notes.NewDependencies().ChangesForURL( - repoURL, d.fromTag, d.toTag, + repoURL, fromTag, d.toTag, ) if err != nil { return "", err