From e6967d58149ec7f4231e11b9ba47eba5b6821262 Mon Sep 17 00:00:00 2001 From: Chance Zibolski Date: Wed, 24 Jul 2024 12:36:16 -0700 Subject: [PATCH] Differentiate between label-filter and release labels Partially reverts the behavior change introduced by https://github.com/cilium/release/pull/238. Filtering is still done in the changelog generation, but now we store all of the PR labels in the release-state and return to filtering against all the PR labels using --label-filter. The newly introduced behavior in #238 is now part of the new --release-labels flag, which configures the release-labels to use when generating release notes. Signed-off-by: Chance Zibolski --- cmd/changelog/changelog.go | 4 +++- cmd/changelog/generate.go | 33 ++++++++++++++++++++++++++++----- cmd/changelog/labels.go | 15 +++++++++++++++ cmd/changelog/labels_test.go | 15 +++++++++++++++ cmd/main.go | 3 ++- pkg/github/release.go | 2 ++ pkg/types/pull_request.go | 1 + 7 files changed, 66 insertions(+), 7 deletions(-) create mode 100644 cmd/changelog/labels.go create mode 100644 cmd/changelog/labels_test.go diff --git a/cmd/changelog/changelog.go b/cmd/changelog/changelog.go index 3a23e25..afcb7b5 100644 --- a/cmd/changelog/changelog.go +++ b/cmd/changelog/changelog.go @@ -22,6 +22,7 @@ type ChangeLogConfig struct { LastStable string StateFile string LabelFilters []string + ReleaseLabels []string ExcludePRReferences bool SkipHeader bool } @@ -66,7 +67,8 @@ func Command(ctx context.Context, logger *log.Logger) *cobra.Command { cmd.Flags().StringVar(&cfg.LastStable, "last-stable", "", "When last stable version is set, it will be used to detect if a bug was already backported or not to that particular branch (e.g.: '1.5', '1.6')") cmd.Flags().StringVar(&cfg.StateFile, "state-file", "release-state.json", "When set, it will use the already fetched information from a previous run") cmd.Flags().StringVar(&cfg.RepoName, "repo", "cilium/cilium", "GitHub organization and repository names separated by a slash") - cmd.Flags().StringArrayVar(&cfg.LabelFilters, "label-filter", []string{}, "Filter pull requests by labels. This also defines the order of the release notes.") + cmd.Flags().StringArrayVar(&cfg.LabelFilters, "label-filter", []string{}, "Filter pull requests by labels.") + cmd.Flags().StringArrayVar(&cfg.ReleaseLabels, "release-labels", []string{}, "Specify release labels to consider when generating the changelog. This also defines the order of the release notes.") cmd.Flags().BoolVar(&cfg.ExcludePRReferences, "exclude-pr-references", false, "If true, do not include references to the PR or PR author") cmd.Flags().BoolVar(&cfg.SkipHeader, "skip-header", false, "If true, do not print 'Summary of of changes' header") diff --git a/cmd/changelog/generate.go b/cmd/changelog/generate.go index 87397c4..60a833f 100644 --- a/cmd/changelog/generate.go +++ b/cmd/changelog/generate.go @@ -159,18 +159,41 @@ func GenerateReleaseNotes(globalCtx context.Context, ghClient *gh.Client, logger } func (cl *ChangeLog) PrintReleaseNotesForWriter(w io.Writer) { + var ( + listOfPRs = make(types.PullRequests) + prsWithUpstream = make(types.BackportPRs) + ) + + // Filter the PRs by --label-filter + for id, pr := range cl.listOfPrs.DeepCopy() { + if !filterByLabels(pr.Labels, cl.LabelFilters) { + continue + } + listOfPRs[id] = pr + } + + // Filter the Backport PRs by --label-filter + for prNumber, upstreamedPRs := range cl.prsWithUpstream.DeepCopy() { + for upstreamPRNumber, upstreamPR := range upstreamedPRs { + if !filterByLabels(upstreamPR.Labels, cl.LabelFilters) { + continue + } + prsWithUpstream[prNumber][upstreamPRNumber] = upstreamPR + } + } + + cl.Logger.Printf("Found %d PRs and %d backport PRs in %s based on --label-filter\n\n", len(listOfPRs), len(prsWithUpstream), cl.StateFile) + if !cl.SkipHeader { fmt.Fprintln(w, "Summary of Changes") fmt.Fprintln(w, "------------------") } - listOfPRs := cl.listOfPrs.DeepCopy() - prsWithUpstream := cl.prsWithUpstream.DeepCopy() - var releaseNotesOrder []string - if len(cl.LabelFilters) != 0 { + if len(cl.ReleaseLabels) != 0 { + // Only add release notes for release labels specified by --release-labels for _, label := range defaultReleaseNotesOrder { - if !slices.Contains(cl.LabelFilters, label) { + if !slices.Contains(cl.ReleaseLabels, label) { continue } releaseNotesOrder = append(releaseNotesOrder, label) diff --git a/cmd/changelog/labels.go b/cmd/changelog/labels.go new file mode 100644 index 0000000..7e2826e --- /dev/null +++ b/cmd/changelog/labels.go @@ -0,0 +1,15 @@ +package changelog + +import "slices" + +func filterByLabels(labels []string, filters []string) bool { + if len(filters) == 0 { + return true + } + for _, label := range labels { + if slices.Contains(filters, label) { + return true + } + } + return false +} diff --git a/cmd/changelog/labels_test.go b/cmd/changelog/labels_test.go new file mode 100644 index 0000000..99f30fd --- /dev/null +++ b/cmd/changelog/labels_test.go @@ -0,0 +1,15 @@ +package changelog + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_filterByLabels(t *testing.T) { + assert.True(t, filterByLabels([]string{"label-a", "label-b", "label-c"}, []string{})) + assert.True(t, filterByLabels([]string{"label-a", "label-b", "label-c"}, []string{"label-a"})) + assert.True(t, filterByLabels([]string{"label-a", "label-b", "label-c"}, []string{"label-b"})) + assert.True(t, filterByLabels([]string{"label-a", "label-b", "label-c"}, []string{"label-c"})) + assert.False(t, filterByLabels([]string{"label-a", "label-b", "label-c"}, []string{"label-d"})) +} diff --git a/cmd/main.go b/cmd/main.go index 00ab556..e5ad7f5 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -98,7 +98,8 @@ func addFlags(cmd *cobra.Command) { cmd.Flags().StringVar(&cfg.StateFile, "state-file", "release-state.json", "When set, it will use the already fetched information from a previous run") cmd.Flags().StringVar(&cfg.RepoName, "repo", "cilium/cilium", "GitHub organization and repository names separated by a slash") cmd.Flags().BoolVar(&cfg.ForceMovePending, "force-move-pending-backports", false, "Force move pending backports to the next version's project") - cmd.Flags().StringArrayVar(&cfg.LabelFilters, "label-filter", []string{}, "Filter pull requests by labels") + cmd.Flags().StringArrayVar(&cfg.LabelFilters, "label-filter", []string{}, "Filter pull requests by labels.") + cmd.Flags().StringArrayVar(&cfg.ReleaseLabels, "release-labels", []string{}, "Specify release labels to consider when generating the changelog. This also defines the order of the release notes.") cmd.Flags().BoolVar(&cfg.ExcludePRReferences, "exclude-pr-references", false, "If true, do not include references to the PR or PR author") cmd.Flags().BoolVar(&cfg.SkipHeader, "skip-header", false, "If true, do not print 'Summary of of changes' header") } diff --git a/pkg/github/release.go b/pkg/github/release.go index 5cbf3ce..fc09bf7 100644 --- a/pkg/github/release.go +++ b/pkg/github/release.go @@ -83,6 +83,7 @@ func GeneratePatchRelease( ReleaseLabel: getReleaseLabel(lbls), AuthorName: pr.GetUser().GetLogin(), BackportBranches: getBackportBranches(lbls), + Labels: lbls, } nodeIDs[pr.GetNumber()] = pr.GetNodeID() continue @@ -110,6 +111,7 @@ func GeneratePatchRelease( ReleaseNote: getReleaseNote(upstreamPR.GetTitle(), upstreamPR.GetBody()), ReleaseLabel: getReleaseLabel(lbls), AuthorName: upstreamPR.GetUser().GetLogin(), + Labels: lbls, } nodeIDs[pr.GetNumber()] = pr.GetNodeID() nodeIDs[upstreamPR.GetNumber()] = upstreamPR.GetNodeID() diff --git a/pkg/types/pull_request.go b/pkg/types/pull_request.go index 73fde4f..d5bd00b 100644 --- a/pkg/types/pull_request.go +++ b/pkg/types/pull_request.go @@ -21,6 +21,7 @@ type PullRequest struct { // BackportBranches contains all the backport-done labels present in the // PullRequest. BackportBranches []string + Labels []string } // NodeIDs maps a Pull Request number to its graphql node_id