From 55997ccbdce39affa4333d85a037ca6020da7fe8 Mon Sep 17 00:00:00 2001 From: Florent Poinsard Date: Wed, 22 May 2024 17:38:19 -0600 Subject: [PATCH 01/12] Only do code freeze when in patch release or RC-1 Signed-off-by: Florent Poinsard --- go/interactive/pre_release/code_freeze.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/go/interactive/pre_release/code_freeze.go b/go/interactive/pre_release/code_freeze.go index 66c0fd2..9e99e5d 100644 --- a/go/interactive/pre_release/code_freeze.go +++ b/go/interactive/pre_release/code_freeze.go @@ -40,6 +40,10 @@ func CodeFreezeMenuItem(ctx context.Context) *ui.MenuItem { Update: codeFreezeUpdate, Info: state.Issue.CodeFreeze.URL, IsDone: state.Issue.CodeFreeze.Done, + + // We only want to do code freeze if we are doing a patch release or RC-1. + // See RFC https://github.com/vitessio/vitess/issues/15586 which document this process. + Ignore: state.VitessRelease.GA || state.Issue.RC > 1, } } From 290db6a43c6bc7adeee536ec6e6fb5e71fceb533 Mon Sep 17 00:00:00 2001 From: Florent Poinsard Date: Wed, 22 May 2024 17:56:41 -0600 Subject: [PATCH 02/12] Create two branches when doing code freeze on RC1 Signed-off-by: Florent Poinsard --- go/cmd/cmd.go | 9 ++++++++- go/releaser/git/git.go | 11 +++++++++++ go/releaser/pre_release/code_freeze.go | 10 +++++++++- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/go/cmd/cmd.go b/go/cmd/cmd.go index 676bedd..c13f584 100644 --- a/go/cmd/cmd.go +++ b/go/cmd/cmd.go @@ -123,6 +123,13 @@ func setUpVitessReleaseInformation(s *releaser.State, repo string, rc int) (rele release, releaseBranch, isLatestRelease, isFromMain, ga := releaser.FindNextRelease(remote, releaseVersion, false, rc) issueNb, issueLink, releaseFromIssue := github.GetReleaseIssueInfo(repo, releaseVersion, rcIncrement) + // If we are doing an RC or a GA release we always want to use the rc release branch ("release-20.0-rc") instead of + // the normal release branch ("release-20.0") + // See RFC https://github.com/vitessio/vitess/issues/15586 for more information about this process. + if rc > 0 || ga { + releaseBranch = fmt.Sprintf("%s-rc", releaseBranch) + } + // if we want to do an RC-1 release and the branch is different from `main`, something is wrong // and if we want to do an >= RC-2 release, the release as to be the latest AKA on the latest release branch if rcIncrement >= 1 && !isLatestRelease { @@ -136,7 +143,7 @@ func setUpVitessReleaseInformation(s *releaser.State, repo string, rc int) (rele MajorRelease: releaseVersion, IsLatestRelease: isLatestRelease, Release: releaseFromIssue, - GA: ga, + GA: ga, } if vitessRelease.Release == "" { vitessRelease.Release = releaser.AddRCToReleaseTitle(release, rcIncrement) diff --git a/go/releaser/git/git.go b/go/releaser/git/git.go index 6ac4354..7899e17 100644 --- a/go/releaser/git/git.go +++ b/go/releaser/git/git.go @@ -48,6 +48,17 @@ func ResetHard(remote, branch string) { utils.Exec("git", "reset", "--hard", remote+"/"+branch) } +func CreateBranch(branch, base string) error { + out, err := utils.ExecWithError("git", "checkout", branch, base) + if err != nil { + if strings.Contains(out, fmt.Sprintf("a branch named '%s' already exists", branch)) { + return errBranchExists + } + utils.LogPanic(err, "got: %s", out) + } + return nil +} + func CreateBranchAndCheckout(branch, base string) error { out, err := utils.ExecWithError("git", "checkout", "-b", branch, base) if err != nil { diff --git a/go/releaser/pre_release/code_freeze.go b/go/releaser/pre_release/code_freeze.go index 17a6568..f15cbd4 100644 --- a/go/releaser/pre_release/code_freeze.go +++ b/go/releaser/pre_release/code_freeze.go @@ -82,9 +82,17 @@ func CodeFreeze(state *releaser.State) (*logging.ProgressLogging, func() string) git.CorrectCleanRepo(state.VitessRelease.Repo) + // For RC-1 we need to create two branches, the new release branch ("release-20.0") + // and the rc release branch ("release-20.0-rc") if state.Issue.RC == 1 { git.ResetHard(state.VitessRelease.Remote, "main") - if err := git.CreateBranchAndCheckout(state.VitessRelease.ReleaseBranch, fmt.Sprintf("%s/main", state.VitessRelease.Remote)); err != nil { + + // create the release branch ("release-20.0") + baseReleaseBranch := state.VitessRelease.ReleaseBranch[:len(state.VitessRelease.ReleaseBranch)-len("-rc")] + _ = git.CreateBranch(state.VitessRelease.ReleaseBranch, fmt.Sprintf("%s/main", state.VitessRelease.Remote)) + + // create the rc release branch ("release-20.0-rc") + if err := git.CreateBranchAndCheckout(state.VitessRelease.ReleaseBranch, fmt.Sprintf("%s/%s", state.VitessRelease.Remote, baseReleaseBranch)); err != nil { git.Checkout(state.VitessRelease.ReleaseBranch) } else { git.Push(state.VitessRelease.Remote, state.VitessRelease.ReleaseBranch) From 661ed034db7e39b56e6d28b12f008b05d81a072d Mon Sep 17 00:00:00 2001 From: Florent Poinsard Date: Wed, 22 May 2024 18:03:10 -0600 Subject: [PATCH 03/12] Copy branch protection rules of the new rc release branch Signed-off-by: Florent Poinsard --- go/cmd/cmd.go | 17 ++++++++++------- .../pre_release/copy_branch_protection_rules.go | 7 +++++-- go/releaser/state.go | 11 ++++++++--- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/go/cmd/cmd.go b/go/cmd/cmd.go index c13f584..b8ca8fd 100644 --- a/go/cmd/cmd.go +++ b/go/cmd/cmd.go @@ -126,7 +126,9 @@ func setUpVitessReleaseInformation(s *releaser.State, repo string, rc int) (rele // If we are doing an RC or a GA release we always want to use the rc release branch ("release-20.0-rc") instead of // the normal release branch ("release-20.0") // See RFC https://github.com/vitessio/vitess/issues/15586 for more information about this process. + var baseReleaseBranch string if rc > 0 || ga { + baseReleaseBranch = releaseBranch releaseBranch = fmt.Sprintf("%s-rc", releaseBranch) } @@ -137,13 +139,14 @@ func setUpVitessReleaseInformation(s *releaser.State, repo string, rc int) (rele } vitessRelease := releaser.ReleaseInformation{ - Repo: repo, - Remote: remote, - ReleaseBranch: releaseBranch, - MajorRelease: releaseVersion, - IsLatestRelease: isLatestRelease, - Release: releaseFromIssue, - GA: ga, + Repo: repo, + Remote: remote, + ReleaseBranch: releaseBranch, + BaseReleaseBranch: baseReleaseBranch, + MajorRelease: releaseVersion, + IsLatestRelease: isLatestRelease, + Release: releaseFromIssue, + GA: ga, } if vitessRelease.Release == "" { vitessRelease.Release = releaser.AddRCToReleaseTitle(release, rcIncrement) diff --git a/go/releaser/pre_release/copy_branch_protection_rules.go b/go/releaser/pre_release/copy_branch_protection_rules.go index 06a17e8..3417d62 100644 --- a/go/releaser/pre_release/copy_branch_protection_rules.go +++ b/go/releaser/pre_release/copy_branch_protection_rules.go @@ -24,7 +24,7 @@ import ( func CopyBranchProtectionRules(state *releaser.State) (*logging.ProgressLogging, func() string) { pl := &logging.ProgressLogging{ - TotalSteps: 3, + TotalSteps: 4, } return pl, func() string { @@ -40,8 +40,11 @@ func CopyBranchProtectionRules(state *releaser.State) (*logging.ProgressLogging, pl.NewStepf("Skipping as we are not running on vitessio/vitess.") return "" } - pl.NewStepf("Duplicating the branch protection rules") + pl.NewStepf("Duplicating the branch protection rules for %s", state.VitessRelease.ReleaseBranch) github.CopyBranchProtectionRules(state.VitessRelease.Repo, state.VitessRelease.ReleaseBranch) + + pl.NewStepf("Duplicating the branch protection rules for %s", state.VitessRelease.BaseReleaseBranch) + github.CopyBranchProtectionRules(state.VitessRelease.Repo, state.VitessRelease.BaseReleaseBranch) return "" } } diff --git a/go/releaser/state.go b/go/releaser/state.go index 41c0932..50bbe21 100644 --- a/go/releaser/state.go +++ b/go/releaser/state.go @@ -42,9 +42,14 @@ func WrapState(ctx context.Context, s *State) context.Context { } type ReleaseInformation struct { - Repo string - Remote string - ReleaseBranch string + Repo string + Remote string + + // BaseReleaseBranch is used to refer to the root release branch (i.e. "release-20.0") when doing + // an RC release or a GA. In this situation the ReleaseBranch will be set to something like "release-20.0-rc". + // For patch releases, the ReleaseBranch remains as usual i.e. "release-20.0" and BaseReleaseBranch will be empty. + ReleaseBranch string + BaseReleaseBranch string MajorRelease string Release string From a9844178d5a44ebe11244cf59286346a21943a30 Mon Sep 17 00:00:00 2001 From: Florent Poinsard Date: Wed, 22 May 2024 18:07:22 -0600 Subject: [PATCH 04/12] Create backport to labels for both branches Signed-off-by: Florent Poinsard --- .../pre_release/create_backport_to_label.go | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/go/releaser/pre_release/create_backport_to_label.go b/go/releaser/pre_release/create_backport_to_label.go index 04fba28..0cd8697 100644 --- a/go/releaser/pre_release/create_backport_to_label.go +++ b/go/releaser/pre_release/create_backport_to_label.go @@ -32,13 +32,22 @@ const ( func CreateBackportToLabel(state *releaser.State) (*logging.ProgressLogging, func() string) { pl := &logging.ProgressLogging{ - TotalSteps: 4, + TotalSteps: 5, } return pl, func() string { - pl.NewStepf("Duplicating the branch protection rules") - github.CreateLabel(state.VitessRelease.Repo, backportToLabelName+state.VitessRelease.ReleaseBranch, backportToLabelColor, backportToLabelDesc+state.VitessRelease.ReleaseBranch) - labelURL := fmt.Sprintf("https://github.com/%s/labels?q=Backport+to%%3A+%s", state.VitessRelease.Repo, state.VitessRelease.ReleaseBranch) + // Create the label for the rc release branch i.e. "Backport to: release-20.0-rc" + labelRcBranch := backportToLabelName + state.VitessRelease.ReleaseBranch + pl.NewStepf("Creating '%s' label", labelRcBranch) + github.CreateLabel(state.VitessRelease.Repo, labelRcBranch, backportToLabelColor, backportToLabelDesc+state.VitessRelease.ReleaseBranch) + + // Create the label for the base release branch i.e. "Backport to: release-20.0" + labelBaseBranch := backportToLabelName + state.VitessRelease.BaseReleaseBranch + pl.NewStepf("Creating '%s' label", labelBaseBranch) + github.CreateLabel(state.VitessRelease.Repo, labelBaseBranch, backportToLabelColor, backportToLabelDesc+state.VitessRelease.BaseReleaseBranch) + + // Let's use the base branch for the link as that label will also match the label of the rc branch + labelURL := fmt.Sprintf("https://github.com/%s/labels?q=Backport+to%%3A+%s", state.VitessRelease.Repo, state.VitessRelease.BaseReleaseBranch) pl.NewStepf("Label created, see: %s", labelURL) pl.NewStepf("Update Issue %s on GitHub", state.IssueLink) From 040d4f54cd6d5023a34670f700c86c0e0f792588 Mon Sep 17 00:00:00 2001 From: Florent Poinsard Date: Wed, 22 May 2024 18:11:16 -0600 Subject: [PATCH 05/12] Unfreeze the release branch only if we are doing a patch or GA Signed-off-by: Florent Poinsard --- go/releaser/pre_release/create_release_pr.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/go/releaser/pre_release/create_release_pr.go b/go/releaser/pre_release/create_release_pr.go index eca8220..b74796d 100644 --- a/go/releaser/pre_release/create_release_pr.go +++ b/go/releaser/pre_release/create_release_pr.go @@ -65,7 +65,14 @@ const versionName = "%s" func CreateReleasePR(state *releaser.State) (*logging.ProgressLogging, func() string) { pl := &logging.ProgressLogging{ - TotalSteps: 15, + TotalSteps: 14, + } + + // If we are doing a patch release or doing a GA we have one more step to take: unfreeze the branch + // RFC https://github.com/vitessio/vitess/issues/15586 defines this new process. + unfreezeBranch := state.Issue.RC == 0 + if unfreezeBranch { + pl.TotalSteps++ } var done bool @@ -103,8 +110,10 @@ func CreateReleasePR(state *releaser.State) (*logging.ProgressLogging, func() st newBranchName := git.FindNewGeneratedBranch(state.VitessRelease.Remote, state.VitessRelease.ReleaseBranch, "create-release") // deactivate code freeze - pl.NewStepf("Deactivate code freeze on %s", state.VitessRelease.ReleaseBranch) - deactivateCodeFreeze() + if unfreezeBranch { + pl.NewStepf("Deactivate code freeze on %s", state.VitessRelease.ReleaseBranch) + deactivateCodeFreeze() + } pl.NewStepf("Commit unfreezing the branch %s", state.VitessRelease.ReleaseBranch) if !git.CommitAll(fmt.Sprintf("Unfreeze branch %s", state.VitessRelease.ReleaseBranch)) { From 792b01427993ab0032d31e1d11570411477fa654 Mon Sep 17 00:00:00 2001 From: Florent Poinsard Date: Wed, 22 May 2024 18:43:18 -0600 Subject: [PATCH 06/12] Add general pre-req guide in GH issue Signed-off-by: Florent Poinsard --- go/releaser/issue.go | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/go/releaser/issue.go b/go/releaser/issue.go index 151a807..3495d93 100644 --- a/go/releaser/issue.go +++ b/go/releaser/issue.go @@ -32,6 +32,7 @@ import ( const ( stateReadingItem = iota + stateReadingGeneral stateReadingBackport stateReadingReleaseBlockerIssue stateReadingCodeFreezeItem @@ -56,6 +57,7 @@ const ( dateItem = "This release is scheduled for" // Prerequisites + generalPrerequisitesItem = "General prerequisites." preSlackAnnouncementItem = "Notify the community on Slack." checkSummaryItem = "Make sure the release notes summary is prepared and clean." backportItem = "Make sure backport Pull Requests are merged, list below." @@ -123,6 +125,7 @@ type ( GA bool // Prerequisites + General ParentOfItems SlackPreRequisite bool CheckSummary bool DraftBlogPost bool @@ -175,8 +178,12 @@ The release of vitess-operator v{{.VtopRelease}} is also planned -### Prerequisites for Release +### Prerequisites +- [{{fmtStatus .General.Done}}] General prerequisites. +{{- range $item := .General.Items }} + - [{{fmtStatus $item.Done}}] {{$item.URL}} +{{- end }} - [{{fmtStatus .SlackPreRequisite}}] Notify the community on Slack. - [{{fmtStatus .CheckSummary}}] Make sure the release notes summary is prepared and clean. {{- if eq .RC 0 }} @@ -355,6 +362,8 @@ func (s *State) LoadIssue() { } switch { + case strings.Contains(line, generalPrerequisitesItem) && isNextLineAList(lines, i): + st = stateReadingGeneral case strings.Contains(line, draftBlogPostItem): newIssue.DraftBlogPost = strings.HasPrefix(line, markdownItemDone) case strings.Contains(line, crossBlogPostItem): @@ -459,6 +468,8 @@ func (s *State) LoadIssue() { case strings.Contains(line, javaRelease): newIssue.JavaRelease = strings.HasPrefix(line, markdownItemDone) } + case stateReadingGeneral: + newIssue.General.Items = append(newIssue.General.Items, handleNewListItem(lines, i, &st)) case stateReadingBackport: newIssue.CheckBackport.Items = append(newIssue.CheckBackport.Items, handleNewListItem(lines, i, &st)) case stateReadingReleaseBlockerIssue: @@ -554,6 +565,13 @@ func CreateReleaseIssue(state *State) (*logging.ProgressLogging, func() (int, st } return pl, func() (int, string) { + state.Issue.General.Items = append(state.Issue.General.Items, + ItemWithLink{URL: "Be part of the `Release` team in the `vitessio` GitHub organization, [here](https://github.com/orgs/vitessio/teams/release)."}, + ItemWithLink{URL: "Be an admin of the `planetscale/vitess-operator` repository."}, + ItemWithLink{URL: "Have access to Vitess' Java repository and have it working locally, [guide here](https://github.com/vitessio/vitess/blob/main/doc/internal/release/java-packages.md)."}, + ItemWithLink{URL: "Have `vitessio/vitess` and `planetscale/vitess-operator` cloned in the same parent directory."}, + ) + pl.NewStepf("Create Release Issue on GitHub") issueTitle := fmt.Sprintf("Release of `v%s`", state.VitessRelease.Release) newIssue := github.Issue{ From 2f3ffb30f55724a2a8a8bb49ca00b0229febe8a5 Mon Sep 17 00:00:00 2001 From: Florent Poinsard Date: Thu, 23 May 2024 08:51:23 -0600 Subject: [PATCH 07/12] Add general pre-req guide in the UI Signed-off-by: Florent Poinsard --- go/interactive/general_prereq.go | 72 +++++++++++++++++++++++++++++ go/interactive/main_menu.go | 1 + go/releaser/issue.go | 10 +++- go/releaser/prerequisite/general.go | 27 +++++++++++ go/releaser/steps/steps.go | 11 +++-- 5 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 go/interactive/general_prereq.go create mode 100644 go/releaser/prerequisite/general.go diff --git a/go/interactive/general_prereq.go b/go/interactive/general_prereq.go new file mode 100644 index 0000000..adb86b9 --- /dev/null +++ b/go/interactive/general_prereq.go @@ -0,0 +1,72 @@ +/* +Copyright 2024 The Vitess Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package interactive + +import ( + "context" + + tea "github.com/charmbracelet/bubbletea" + "vitess.io/vitess-releaser/go/interactive/ui" + "vitess.io/vitess-releaser/go/releaser" + "vitess.io/vitess-releaser/go/releaser/prerequisite" + "vitess.io/vitess-releaser/go/releaser/steps" +) + +type ( + generalPrerequisiteMessage []string +) + +func generalPrerequisiteMenuItem(ctx context.Context) *ui.MenuItem { + state := releaser.UnwrapState(ctx) + return &ui.MenuItem{ + State: state, + Name: steps.GeneralPrerequisite, + Act: generalPrerequisiteAct, + Update: generalPrerequisiteUpdate, + IsDone: state.Issue.General.Done(), + } +} + +func generalPrerequisiteAct(mi *ui.MenuItem) (*ui.MenuItem, tea.Cmd) { + return mi, func() tea.Msg { + return generalPrerequisiteMessage(prerequisite.General()) + } +} + +func generalPrerequisiteUpdate(mi *ui.MenuItem, msg tea.Msg) (*ui.MenuItem, tea.Cmd) { + switch msg := msg.(type) { + case generalPrerequisiteMessage: + return mi, ui.PushDialog(&ui.DoneDialog{ + StepName: mi.Name, + Title: "Please respect all these requirements before proceeding with the release.", + Message: msg, + IsDone: mi.IsDone, + }) + case ui.DoneDialogAction: + if string(msg) != mi.Name { + return mi, nil + } + mi.State.Issue.General.InverseItemStatus() + mi.IsDone = !mi.IsDone + pl, fn := mi.State.UploadIssue() + return mi, tea.Batch(func() tea.Msg { + fn() + return tea.Msg("") + }, ui.PushDialog(ui.NewProgressDialog("Updating the Release Issue", pl))) + } + return mi, nil +} diff --git a/go/interactive/main_menu.go b/go/interactive/main_menu.go index 8940002..c81cdc8 100644 --- a/go/interactive/main_menu.go +++ b/go/interactive/main_menu.go @@ -37,6 +37,7 @@ func MainScreen(ctx context.Context) { prereqMenu := ui.NewMenu( ctx, "Prerequisites", + generalPrerequisiteMenuItem(ctx), slackAnnouncementMenuItem(ctx, slackAnnouncementPreRequisite), checkSummaryMenuItem(ctx), draftBlogPostMenuItem(ctx), diff --git a/go/releaser/issue.go b/go/releaser/issue.go index 3495d93..6fd72b3 100644 --- a/go/releaser/issue.go +++ b/go/releaser/issue.go @@ -300,7 +300,7 @@ The release of vitess-operator v{{.VtopRelease}} is also planned ` ) -func (pi ParentOfItems) ItemsLeft() int { +func (pi *ParentOfItems) ItemsLeft() int { nb := 0 for _, item := range pi.Items { if !item.Done { @@ -310,7 +310,13 @@ func (pi ParentOfItems) ItemsLeft() int { return nb } -func (pi ParentOfItems) Done() bool { +func (pi *ParentOfItems) InverseItemStatus() { + for i, _ := range pi.Items { + pi.Items[i].Done = !pi.Items[i].Done + } +} + +func (pi *ParentOfItems) Done() bool { for _, item := range pi.Items { if !item.Done { return false diff --git a/go/releaser/prerequisite/general.go b/go/releaser/prerequisite/general.go new file mode 100644 index 0000000..9e596ce --- /dev/null +++ b/go/releaser/prerequisite/general.go @@ -0,0 +1,27 @@ +/* +Copyright 2024 The Vitess Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package prerequisite + +func General() []string { + return []string{ + "Please make sure you respect all the following items:", + "\t- Be part of the vitessio \"Release\" team: https://github.com/orgs/vitessio/teams/release", + "\t- Be an admin of the \"planetscale/vitess-operator\" repository", + "\t- Have access to Vitess' Java repository and have it working locally: https://github.com/vitessio/vitess/blob/main/doc/internal/release/java-packages.md", + "\t- Have \"vitessio/vitess\" and \"planetscale/vitess-operator\" cloned in the same parent directory", + } +} diff --git a/go/releaser/steps/steps.go b/go/releaser/steps/steps.go index a9c019c..341847c 100644 --- a/go/releaser/steps/steps.go +++ b/go/releaser/steps/steps.go @@ -21,11 +21,12 @@ const ( ReleaseIssue = "Release Issue" // Prerequisite - SlackAnnouncement = "Slack Announcement" - CheckAndAdd = "Pending PRs/Issues" - CheckSummary = "Check Release Summary" - DraftBlogPost = "Draft Blog Post" - CrossPostBlogPost = "Cross-post Blog Post" + GeneralPrerequisite = "General" + SlackAnnouncement = "Slack Announcement" + CheckAndAdd = "Pending PRs/Issues" + CheckSummary = "Check Release Summary" + DraftBlogPost = "Draft Blog Post" + CrossPostBlogPost = "Cross-post Blog Post" // Pre-Release CodeFreeze = "Code Freeze" From ef73121f7f6963a07eb71c0b03eff97fb18ca42c Mon Sep 17 00:00:00 2001 From: Florent Poinsard Date: Thu, 23 May 2024 11:16:36 -0600 Subject: [PATCH 08/12] Fix verious bugs found when doing RC1 and RC2 Signed-off-by: Florent Poinsard --- go/interactive/general_prereq.go | 2 +- .../pre_release/create_backport_to_label.go | 2 +- go/interactive/release/release_notes_to_main.go | 4 ++-- go/interactive/ui/menu.go | 2 +- go/releaser/git/git.go | 11 ----------- go/releaser/github/label.go | 1 + go/releaser/issue.go | 6 ++++-- go/releaser/pre_release/code_freeze.go | 4 +++- .../pre_release/copy_branch_protection_rules.go | 1 + go/releaser/pre_release/create_release_pr.go | 16 ++++++++-------- go/releaser/vitess.go | 15 ++++++++++++--- 11 files changed, 34 insertions(+), 30 deletions(-) diff --git a/go/interactive/general_prereq.go b/go/interactive/general_prereq.go index adb86b9..e0850c5 100644 --- a/go/interactive/general_prereq.go +++ b/go/interactive/general_prereq.go @@ -37,7 +37,7 @@ func generalPrerequisiteMenuItem(ctx context.Context) *ui.MenuItem { Name: steps.GeneralPrerequisite, Act: generalPrerequisiteAct, Update: generalPrerequisiteUpdate, - IsDone: state.Issue.General.Done(), + IsDone: state.Issue.General.Done() && len(state.Issue.General.Items) > 0, } } diff --git a/go/interactive/pre_release/create_backport_to_label.go b/go/interactive/pre_release/create_backport_to_label.go index 201119f..e91f665 100644 --- a/go/interactive/pre_release/create_backport_to_label.go +++ b/go/interactive/pre_release/create_backport_to_label.go @@ -62,6 +62,6 @@ func createBackportToLabelUpdate(mi *ui.MenuItem, msg tea.Msg) (*ui.MenuItem, te func createBackportToLabelAct(mi *ui.MenuItem) (*ui.MenuItem, tea.Cmd) { pl, create := pre_release.CreateBackportToLabel(mi.State) return mi, tea.Batch(func() tea.Msg { - return copyBranchProtectionUrl(create()) + return createBackportToLabelUrl(create()) }, ui.PushDialog(ui.NewProgressDialog("Create Backport To label", pl))) } diff --git a/go/interactive/release/release_notes_to_main.go b/go/interactive/release/release_notes_to_main.go index 8d0ee7b..6f0388c 100644 --- a/go/interactive/release/release_notes_to_main.go +++ b/go/interactive/release/release_notes_to_main.go @@ -50,8 +50,8 @@ func releaseNotesOnMainUpdate(mi *ui.MenuItem, msg tea.Msg) (*ui.MenuItem, tea.C return mi, nil } - mi.Info = mi.State.Issue.CodeFreeze.URL - mi.IsDone = mi.State.Issue.CodeFreeze.Done + mi.Info = mi.State.Issue.ReleaseNotesOnMain.URL + mi.IsDone = mi.State.Issue.ReleaseNotesOnMain.Done return mi, nil } diff --git a/go/interactive/ui/menu.go b/go/interactive/ui/menu.go index bc9120b..ce059b5 100644 --- a/go/interactive/ui/menu.go +++ b/go/interactive/ui/menu.go @@ -66,7 +66,7 @@ func NewMenu(ctx context.Context, title string, items ...*MenuItem) *Menu { if item.Ignore { continue } - if i > 0 { + if i > 0 && len(mi) > 0 { item.previous = mi[len(mi)-1] } mi = append(mi, item) diff --git a/go/releaser/git/git.go b/go/releaser/git/git.go index 7899e17..6ac4354 100644 --- a/go/releaser/git/git.go +++ b/go/releaser/git/git.go @@ -48,17 +48,6 @@ func ResetHard(remote, branch string) { utils.Exec("git", "reset", "--hard", remote+"/"+branch) } -func CreateBranch(branch, base string) error { - out, err := utils.ExecWithError("git", "checkout", branch, base) - if err != nil { - if strings.Contains(out, fmt.Sprintf("a branch named '%s' already exists", branch)) { - return errBranchExists - } - utils.LogPanic(err, "got: %s", out) - } - return nil -} - func CreateBranchAndCheckout(branch, base string) error { out, err := utils.ExecWithError("git", "checkout", "-b", branch, base) if err != nil { diff --git a/go/releaser/github/label.go b/go/releaser/github/label.go index e44eae9..26a05e7 100644 --- a/go/releaser/github/label.go +++ b/go/releaser/github/label.go @@ -24,5 +24,6 @@ func CreateLabel(repo, label, color, desc string) { "--repo", repo, "--color", color, "--description", desc, + "--force", ) } diff --git a/go/releaser/issue.go b/go/releaser/issue.go index 6fd72b3..b0c6de0 100644 --- a/go/releaser/issue.go +++ b/go/releaser/issue.go @@ -68,7 +68,7 @@ const ( // Pre-Release codeFreezeItem = "Code Freeze." copyBranchProtectionRulesItem = "Copy branch protection rules." - createBackportToLabelItem = "Create the Backport to label.." + createBackportToLabelItem = "Create the Backport to labels." updateSnapshotOnMainItem = "Update the SNAPSHOT version on main." createReleasePRItem = "Create Release PR." newMilestoneItem = "Create new GitHub Milestone." @@ -206,13 +206,15 @@ The release of vitess-operator v{{.VtopRelease}} is also planned ### Pre-Release +{{- if not (or (gt .RC 1) (.GA)) }} - [{{fmtStatus .CodeFreeze.Done}}] Code Freeze. {{- if .CodeFreeze.URL }} - {{ .CodeFreeze.URL }} {{- end }} +{{- end }} {{- if eq .RC 1 }} - [{{fmtStatus .CopyBranchProtectionRules}}] Copy branch protection rules. -- [{{fmtStatus .CreateBackportToLabel.Done}}] Create the Backport to label. +- [{{fmtStatus .CreateBackportToLabel.Done}}] Create the Backport to labels. {{- if .CreateBackportToLabel.URL }} - {{ .CreateBackportToLabel.URL }} {{- end }} diff --git a/go/releaser/pre_release/code_freeze.go b/go/releaser/pre_release/code_freeze.go index f15cbd4..f757898 100644 --- a/go/releaser/pre_release/code_freeze.go +++ b/go/releaser/pre_release/code_freeze.go @@ -89,7 +89,9 @@ func CodeFreeze(state *releaser.State) (*logging.ProgressLogging, func() string) // create the release branch ("release-20.0") baseReleaseBranch := state.VitessRelease.ReleaseBranch[:len(state.VitessRelease.ReleaseBranch)-len("-rc")] - _ = git.CreateBranch(state.VitessRelease.ReleaseBranch, fmt.Sprintf("%s/main", state.VitessRelease.Remote)) + if err := git.CreateBranchAndCheckout(baseReleaseBranch, fmt.Sprintf("%s/main", state.VitessRelease.Remote)); err == nil { + git.Push(state.VitessRelease.Remote, baseReleaseBranch) + } // create the rc release branch ("release-20.0-rc") if err := git.CreateBranchAndCheckout(state.VitessRelease.ReleaseBranch, fmt.Sprintf("%s/%s", state.VitessRelease.Remote, baseReleaseBranch)); err != nil { diff --git a/go/releaser/pre_release/copy_branch_protection_rules.go b/go/releaser/pre_release/copy_branch_protection_rules.go index 3417d62..28078b4 100644 --- a/go/releaser/pre_release/copy_branch_protection_rules.go +++ b/go/releaser/pre_release/copy_branch_protection_rules.go @@ -37,6 +37,7 @@ func CopyBranchProtectionRules(state *releaser.State) (*logging.ProgressLogging, }() if state.VitessRelease.Repo != "vitessio/vitess" { + pl.TotalSteps-- pl.NewStepf("Skipping as we are not running on vitessio/vitess.") return "" } diff --git a/go/releaser/pre_release/create_release_pr.go b/go/releaser/pre_release/create_release_pr.go index b74796d..fc5e57c 100644 --- a/go/releaser/pre_release/create_release_pr.go +++ b/go/releaser/pre_release/create_release_pr.go @@ -65,14 +65,14 @@ const versionName = "%s" func CreateReleasePR(state *releaser.State) (*logging.ProgressLogging, func() string) { pl := &logging.ProgressLogging{ - TotalSteps: 14, + TotalSteps: 13, } - // If we are doing a patch release or doing a GA we have one more step to take: unfreeze the branch + // If we are doing a patch release or doing a GA we have two more steps to take: unfreeze the branch and commit // RFC https://github.com/vitessio/vitess/issues/15586 defines this new process. unfreezeBranch := state.Issue.RC == 0 if unfreezeBranch { - pl.TotalSteps++ + pl.TotalSteps += 2 } var done bool @@ -113,12 +113,12 @@ func CreateReleasePR(state *releaser.State) (*logging.ProgressLogging, func() st if unfreezeBranch { pl.NewStepf("Deactivate code freeze on %s", state.VitessRelease.ReleaseBranch) deactivateCodeFreeze() - } - pl.NewStepf("Commit unfreezing the branch %s", state.VitessRelease.ReleaseBranch) - if !git.CommitAll(fmt.Sprintf("Unfreeze branch %s", state.VitessRelease.ReleaseBranch)) { - commitCount++ - git.Push(state.VitessRelease.Remote, newBranchName) + pl.NewStepf("Commit unfreezing the branch %s", state.VitessRelease.ReleaseBranch) + if !git.CommitAll(fmt.Sprintf("Unfreeze branch %s", state.VitessRelease.ReleaseBranch)) { + commitCount++ + git.Push(state.VitessRelease.Remote, newBranchName) + } } pl.NewStepf("Generate the release notes") diff --git a/go/releaser/vitess.go b/go/releaser/vitess.go index 514ac4e..a691474 100644 --- a/go/releaser/vitess.go +++ b/go/releaser/vitess.go @@ -97,10 +97,10 @@ func FindNextRelease(remote, majorRelease string, isVtOp bool, rc int) (currentR utils.LogPanic(nil, "could not parse the found release: %s", currentRelease) } isLatest := mainMajorNb-1 == majorNb - ga = releaseParts[1] == "0" && releaseParts[2] == "0" + ga = rc == 0 && releaseParts[1] == "0" && releaseParts[2] == "0" if isVtOp { isLatest = mainMajorNb == majorNb - ga = releaseParts[2] == "0" + ga = rc == 0 && releaseParts[2] == "0" } return currentRelease, releaseBranchName, isLatest, false, ga } @@ -116,7 +116,16 @@ func FindPreviousRelease(remote, currentMajor string) string { git.Checkout(previousReleaseBranch) git.ResetHard(remote, previousReleaseBranch) - return getCurrentReleaseVitess() + currentRelease := getCurrentReleaseVitess() + currentReleaseSlice := strings.Split(currentRelease, ".") + if len(currentReleaseSlice) != 3 { + utils.LogPanic(nil, "could not parse the version.go in vitessio/vitess, output: %s", currentRelease) + } + patchRelease, err := strconv.Atoi(currentReleaseSlice[2]) + if err != nil { + utils.LogPanic(err, "could not parse the version.go in vitessio/vitess, output: %s", currentRelease) + } + return fmt.Sprintf("%s.%s.%d", currentReleaseSlice[0], currentReleaseSlice[1], patchRelease-1) } func getCurrentReleaseVitess() string { From 64eab5e6a0368e076a7ab583c20464145246d515 Mon Sep 17 00:00:00 2001 From: Florent Poinsard Date: Thu, 23 May 2024 12:57:59 -0600 Subject: [PATCH 09/12] Copy release notes to base release branch after each RC/GA Signed-off-by: Florent Poinsard --- go/interactive/main_menu.go | 1 + .../release/release_notes_to_main.go | 2 +- .../release_notes_to_release_branch.go | 66 +++++++++++++++++++ go/releaser/issue.go | 60 ++++++++++------- ...notes_on_main.go => copy_release_notes.go} | 20 +++--- go/releaser/steps/steps.go | 25 +++---- 6 files changed, 129 insertions(+), 45 deletions(-) create mode 100644 go/interactive/release/release_notes_to_release_branch.go rename go/releaser/release/{release_notes_on_main.go => copy_release_notes.go} (83%) diff --git a/go/interactive/main_menu.go b/go/interactive/main_menu.go index c81cdc8..6ea191a 100644 --- a/go/interactive/main_menu.go +++ b/go/interactive/main_menu.go @@ -69,6 +69,7 @@ func MainScreen(ctx context.Context) { release.VtopCreateReleasePRMenuItem(ctx), release.VtopManualUpdateItem(ctx), release.ReleaseNotesOnMainItem(ctx), + release.ReleaseNotesOnReleaseBranchItem(ctx), release.BackToDevModeItem(ctx), mergeBlogPostPRMenuItem(ctx), websiteDocumentationItem(ctx), diff --git a/go/interactive/release/release_notes_to_main.go b/go/interactive/release/release_notes_to_main.go index 6f0388c..e4b62fa 100644 --- a/go/interactive/release/release_notes_to_main.go +++ b/go/interactive/release/release_notes_to_main.go @@ -56,7 +56,7 @@ func releaseNotesOnMainUpdate(mi *ui.MenuItem, msg tea.Msg) (*ui.MenuItem, tea.C } func releaseNotesOnMainAct(mi *ui.MenuItem) (*ui.MenuItem, tea.Cmd) { - pl, fn := release.ReleaseNotesOnMain(mi.State) + pl, fn := release.CopyReleaseNotesToBranch(mi.State, &mi.State.Issue.ReleaseNotesOnMain, "main") return mi, tea.Batch(func() tea.Msg { return releaseNotesOnMainUrl(fn()) }, ui.PushDialog(ui.NewProgressDialog("Release Notes on Main", pl))) diff --git a/go/interactive/release/release_notes_to_release_branch.go b/go/interactive/release/release_notes_to_release_branch.go new file mode 100644 index 0000000..45b2825 --- /dev/null +++ b/go/interactive/release/release_notes_to_release_branch.go @@ -0,0 +1,66 @@ +/* +Copyright 2024 The Vitess Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package release + +import ( + "context" + + tea "github.com/charmbracelet/bubbletea" + "vitess.io/vitess-releaser/go/interactive/ui" + "vitess.io/vitess-releaser/go/releaser" + "vitess.io/vitess-releaser/go/releaser/release" + "vitess.io/vitess-releaser/go/releaser/steps" +) + +func ReleaseNotesOnReleaseBranchItem(ctx context.Context) *ui.MenuItem { + state := releaser.UnwrapState(ctx) + act := releaseNotesOnReleaseBranchAct + if state.Issue.ReleaseNotesOnReleaseBranch.Done { + act = nil + } + return &ui.MenuItem{ + State: state, + Name: steps.ReleaseNotesOnReleaseBranch, + Act: act, + Update: releaseNotesOnReleaseBranchUpdate, + Info: state.Issue.ReleaseNotesOnReleaseBranch.URL, + IsDone: state.Issue.ReleaseNotesOnReleaseBranch.Done, + + // We want to ignore this step if we are doing a patch release. + Ignore: !state.Issue.GA && state.Issue.RC == 0, + } +} + +type releaseNotesOnReleaseBranchUrl string + +func releaseNotesOnReleaseBranchUpdate(mi *ui.MenuItem, msg tea.Msg) (*ui.MenuItem, tea.Cmd) { + _, ok := msg.(releaseNotesOnReleaseBranchUrl) + if !ok { + return mi, nil + } + + mi.Info = mi.State.Issue.ReleaseNotesOnReleaseBranch.URL + mi.IsDone = mi.State.Issue.ReleaseNotesOnReleaseBranch.Done + return mi, nil +} + +func releaseNotesOnReleaseBranchAct(mi *ui.MenuItem) (*ui.MenuItem, tea.Cmd) { + pl, fn := release.CopyReleaseNotesToBranch(mi.State, &mi.State.Issue.ReleaseNotesOnReleaseBranch, mi.State.VitessRelease.BaseReleaseBranch) + return mi, tea.Batch(func() tea.Msg { + return releaseNotesOnMainUrl(fn()) + }, ui.PushDialog(ui.NewProgressDialog("Release Notes on Main", pl))) +} diff --git a/go/releaser/issue.go b/go/releaser/issue.go index b0c6de0..09bc05e 100644 --- a/go/releaser/issue.go +++ b/go/releaser/issue.go @@ -43,6 +43,7 @@ const ( stateReadingMergedReleasePRItem stateReadingTagReleaseItem stateReadingReleaseNotesMainItem + stateReadingReleaseNotesReleaseBranchItem stateReadingBackToDevModeItem stateReadingCloseMilestoneItem stateReadingVtopUpdateGo @@ -79,18 +80,19 @@ const ( createBlogPostPRItem = "Open a Pull Request on the website repository for the blog post." // Release - mergeReleasePRItem = "Merge the Release PR." - tagReleaseItem = "Tag the release." - javaRelease = "Java release." - vtopCreateReleasePRItem = "Create vitess-operator Release PR." - vtopManualUpdateItem = "Manual update of vitess-operator test code." - releaseNotesMainItem = "Update release notes on main." - backToDevItem = "Go back to dev mode on the release branch." - websiteDocItem = "Update the website documentation." - benchmarkedItem = "Make sure the release is benchmarked by arewefastyet." - dockerImagesItem = "Docker Images available on DockerHub." - closeMilestoneItem = "Close current GitHub Milestone." - mergeBlogPostItem = "Merge the blog post Pull Request on the website repository." + mergeReleasePRItem = "Merge the Release PR." + tagReleaseItem = "Tag the release." + javaRelease = "Java release." + vtopCreateReleasePRItem = "Create vitess-operator Release PR." + vtopManualUpdateItem = "Manual update of vitess-operator test code." + releaseNotesMainItem = "Update release notes on main." + releaseNotesReleaseBranchItem = "Update release notes on the release branch." + backToDevItem = "Go back to dev mode on the release branch." + websiteDocItem = "Update the website documentation." + benchmarkedItem = "Make sure the release is benchmarked by arewefastyet." + dockerImagesItem = "Docker Images available on DockerHub." + closeMilestoneItem = "Close current GitHub Milestone." + mergeBlogPostItem = "Merge the blog post Pull Request on the website repository." // Post-Release postSlackAnnouncementItem = "Notify the community on Slack for the new release." @@ -149,16 +151,17 @@ type ( CreateBlogPostPR bool // Release - MergeReleasePR ItemWithLink - TagRelease ItemWithLink - JavaRelease bool - ReleaseNotesOnMain ItemWithLink - BackToDevMode ItemWithLink - MergeBlogPostPR bool - WebsiteDocumentation bool - Benchmarked bool - DockerImages bool - CloseMilestone ItemWithLink + MergeReleasePR ItemWithLink + TagRelease ItemWithLink + JavaRelease bool + ReleaseNotesOnMain ItemWithLink + ReleaseNotesOnReleaseBranch ItemWithLink + BackToDevMode ItemWithLink + MergeBlogPostPR bool + WebsiteDocumentation bool + Benchmarked bool + DockerImages bool + CloseMilestone ItemWithLink // Post-Release SlackPostRelease bool @@ -277,6 +280,12 @@ The release of vitess-operator v{{.VtopRelease}} is also planned {{- if .ReleaseNotesOnMain.URL }} - {{ .ReleaseNotesOnMain.URL }} {{- end }} +{{- if or (gt .RC 0) (.GA) }} +- [{{fmtStatus .ReleaseNotesOnReleaseBranch.Done}}] Update release notes on the release branch. +{{- if .ReleaseNotesOnReleaseBranch.URL }} + - {{ .ReleaseNotesOnReleaseBranch.URL }} +{{- end }} +{{- end }} - [{{fmtStatus .BackToDevMode.Done}}] Go back to dev mode on the release branch. {{- if .BackToDevMode.URL }} - {{ .BackToDevMode.URL }} @@ -447,6 +456,11 @@ func (s *State) LoadIssue() { if isNextLineAList(lines, i) { st = stateReadingReleaseNotesMainItem } + case strings.Contains(line, releaseNotesReleaseBranchItem): + newIssue.ReleaseNotesOnReleaseBranch.Done = strings.HasPrefix(line, markdownItemDone) + if isNextLineAList(lines, i) { + st = stateReadingReleaseNotesReleaseBranchItem + } case strings.Contains(line, backToDevItem): newIssue.BackToDevMode.Done = strings.HasPrefix(line, markdownItemDone) if isNextLineAList(lines, i) { @@ -498,6 +512,8 @@ func (s *State) LoadIssue() { newIssue.TagRelease.URL = handleSingleTextItem(line, &st) case stateReadingReleaseNotesMainItem: newIssue.ReleaseNotesOnMain.URL = handleSingleTextItem(line, &st) + case stateReadingReleaseNotesReleaseBranchItem: + newIssue.ReleaseNotesOnReleaseBranch.URL = handleSingleTextItem(line, &st) case stateReadingBackToDevModeItem: newIssue.BackToDevMode.URL = handleSingleTextItem(line, &st) case stateReadingCloseMilestoneItem: diff --git a/go/releaser/release/release_notes_on_main.go b/go/releaser/release/copy_release_notes.go similarity index 83% rename from go/releaser/release/release_notes_on_main.go rename to go/releaser/release/copy_release_notes.go index aee9ff9..c292a09 100644 --- a/go/releaser/release/release_notes_on_main.go +++ b/go/releaser/release/copy_release_notes.go @@ -26,7 +26,7 @@ import ( "vitess.io/vitess-releaser/go/releaser/pre_release" ) -func ReleaseNotesOnMain(state *releaser.State) (*logging.ProgressLogging, func() string) { +func CopyReleaseNotesToBranch(state *releaser.State, itemToUpdate *releaser.ItemWithLink, branch string) (*logging.ProgressLogging, func() string) { pl := &logging.ProgressLogging{ TotalSteps: 9, } @@ -35,8 +35,8 @@ func ReleaseNotesOnMain(state *releaser.State) (*logging.ProgressLogging, func() var url string return pl, func() string { defer func() { - state.Issue.ReleaseNotesOnMain.Done = done - state.Issue.ReleaseNotesOnMain.URL = url + itemToUpdate.Done = done + itemToUpdate.URL = url pl.NewStepf("Update Issue %s on GitHub", state.IssueLink) _, fn := state.UploadIssue() issueLink := fn() @@ -48,10 +48,10 @@ func ReleaseNotesOnMain(state *releaser.State) (*logging.ProgressLogging, func() git.CorrectCleanRepo(state.VitessRelease.Repo) git.ResetHard(state.VitessRelease.Remote, state.VitessRelease.ReleaseBranch) - git.Checkout("main") - git.ResetHard(state.VitessRelease.Remote, "main") + git.Checkout(branch) + git.ResetHard(state.VitessRelease.Remote, branch) - prName := fmt.Sprintf("Copy `v%s` release notes on `main`", state.VitessRelease.Release) + prName := fmt.Sprintf("[%s] Copy `v%s` release notes", branch, state.VitessRelease.Release) pl.NewStepf("Look for an existing Pull Request named '%s'", prName) if _, url = github.FindPR(state.VitessRelease.Repo, prName); url != "" { @@ -61,15 +61,15 @@ func ReleaseNotesOnMain(state *releaser.State) (*logging.ProgressLogging, func() return url } - pl.NewStepf("Create new branch based on %s/main", state.VitessRelease.Remote) - newBranchName := git.FindNewGeneratedBranch(state.VitessRelease.Remote, "main", "release-notes-main") + pl.NewStepf("Create new branch based on %s/%s", state.VitessRelease.Remote, branch) + newBranchName := git.FindNewGeneratedBranch(state.VitessRelease.Remote, branch, "release-notes-main") pl.NewStepf("Copy release notes from %s/%s", state.VitessRelease.Remote, state.VitessRelease.ReleaseBranch) releaseNotesPath := pre_release.GetReleaseNotesDirPathForMajor(releaser.RemoveRCFromReleaseTitle(state.VitessRelease.Release)) git.CheckoutPath(state.VitessRelease.Remote, state.VitessRelease.ReleaseBranch, releaseNotesPath) pl.NewStepf("Commit and push to branch %s", newBranchName) - if git.CommitAll(fmt.Sprintf("Copy release notes from %s into main", state.VitessRelease.ReleaseBranch)) { + if git.CommitAll(fmt.Sprintf("Copy release notes from %s into %s", state.VitessRelease.ReleaseBranch, branch)) { pl.TotalSteps = 8 // only 8 total steps in this situation pl.NewStepf("Nothing to commit, seems like the release notes have already been copied") done = true @@ -82,7 +82,7 @@ func ReleaseNotesOnMain(state *releaser.State) (*logging.ProgressLogging, func() Title: prName, Body: fmt.Sprintf("This Pull Request copies the release notes found on `%s` to keep release notes up-to-date after the `v%s` release.", state.VitessRelease.ReleaseBranch, state.VitessRelease.Release), Branch: newBranchName, - Base: "main", + Base: branch, Labels: []github.Label{{Name: "Component: General"}, {Name: "Type: Release"}}, } _, url = pr.Create(state.VitessRelease.Repo) diff --git a/go/releaser/steps/steps.go b/go/releaser/steps/steps.go index 341847c..f60f8d9 100644 --- a/go/releaser/steps/steps.go +++ b/go/releaser/steps/steps.go @@ -41,18 +41,19 @@ const ( VtopUpdateCompatibilityTable = "Update compatibility table in vitess-operator" // Release - MergeReleasePR = "Merge Release PR" - TagRelease = "Tag Release" - VtopCreateReleasePR = "Create vitess-operator release PR" - VtopManualUpdate = "Manual update of vitess-operator tests" - JavaRelease = "Java Release" - ReleaseNotesOnMain = "Release Notes on Main" - BackToDev = "Back To Dev Mode" - MergeBlogPost = "Merge Blog Post" - WebsiteDocumentation = "Website Documentation" - Benchmarked = "Benchmarks" - DockerImages = "Docker Images" - CloseMilestone = "Close Milestone" + MergeReleasePR = "Merge Release PR" + TagRelease = "Tag Release" + VtopCreateReleasePR = "Create vitess-operator release PR" + VtopManualUpdate = "Manual update of vitess-operator tests" + JavaRelease = "Java Release" + ReleaseNotesOnMain = "Release Notes on main" + ReleaseNotesOnReleaseBranch = "Release Notes on release branch" + BackToDev = "Back To Dev Mode" + MergeBlogPost = "Merge Blog Post" + WebsiteDocumentation = "Website Documentation" + Benchmarked = "Benchmarks" + DockerImages = "Docker Images" + CloseMilestone = "Close Milestone" // Post-Release SlackAnnouncementPost = "Slack Announcement Post-Release" From 72f3fdf85cc2542b4dd8544a3b979c6cce10d617 Mon Sep 17 00:00:00 2001 From: Florent Poinsard Date: Thu, 23 May 2024 13:10:35 -0600 Subject: [PATCH 10/12] Go back to dev mode during GA on the base branch Signed-off-by: Florent Poinsard --- go/interactive/main_menu.go | 1 + go/interactive/release/back_to_dev.go | 2 +- .../release/back_to_dev_base_branch.go | 66 +++++++++++++++++++ go/releaser/issue.go | 14 ++++ go/releaser/release/back_to_dev.go | 16 ++--- go/releaser/steps/steps.go | 1 + 6 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 go/interactive/release/back_to_dev_base_branch.go diff --git a/go/interactive/main_menu.go b/go/interactive/main_menu.go index 6ea191a..68f9de9 100644 --- a/go/interactive/main_menu.go +++ b/go/interactive/main_menu.go @@ -71,6 +71,7 @@ func MainScreen(ctx context.Context) { release.ReleaseNotesOnMainItem(ctx), release.ReleaseNotesOnReleaseBranchItem(ctx), release.BackToDevModeItem(ctx), + release.BackToDevModeBaseBranchItem(ctx), mergeBlogPostPRMenuItem(ctx), websiteDocumentationItem(ctx), benchmarkedItem(ctx), diff --git a/go/interactive/release/back_to_dev.go b/go/interactive/release/back_to_dev.go index 901888d..64d63e8 100644 --- a/go/interactive/release/back_to_dev.go +++ b/go/interactive/release/back_to_dev.go @@ -56,7 +56,7 @@ func backToDevModeUpdate(mi *ui.MenuItem, msg tea.Msg) (*ui.MenuItem, tea.Cmd) { } func backToDevModeAct(mi *ui.MenuItem) (*ui.MenuItem, tea.Cmd) { - pl, back := release.BackToDevMode(mi.State) + pl, back := release.BackToDevModeOnBranch(mi.State, &mi.State.Issue.BackToDevMode, mi.State.VitessRelease.ReleaseBranch) return mi, tea.Batch(func() tea.Msg { return backToDevModeUrl(back()) }, ui.PushDialog(ui.NewProgressDialog("Back To Dev Mode", pl))) diff --git a/go/interactive/release/back_to_dev_base_branch.go b/go/interactive/release/back_to_dev_base_branch.go new file mode 100644 index 0000000..d971478 --- /dev/null +++ b/go/interactive/release/back_to_dev_base_branch.go @@ -0,0 +1,66 @@ +/* +Copyright 2024 The Vitess Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package release + +import ( + "context" + + tea "github.com/charmbracelet/bubbletea" + "vitess.io/vitess-releaser/go/interactive/ui" + "vitess.io/vitess-releaser/go/releaser" + "vitess.io/vitess-releaser/go/releaser/release" + "vitess.io/vitess-releaser/go/releaser/steps" +) + +func BackToDevModeBaseBranchItem(ctx context.Context) *ui.MenuItem { + state := releaser.UnwrapState(ctx) + act := backToDevModeBaseBranchAct + if state.Issue.BackToDevModeBaseBranch.Done { + act = nil + } + return &ui.MenuItem{ + State: state, + Name: steps.BackToDevOnBaseBranch, + Act: act, + Update: backToDevModeBaseBranchUpdate, + Info: state.Issue.BackToDevModeBaseBranch.URL, + IsDone: state.Issue.BackToDevModeBaseBranch.Done, + + // We only want to do this during the GA release + Ignore: !state.Issue.GA, + } +} + +type backToDevModeBaseBranchUrl string + +func backToDevModeBaseBranchUpdate(mi *ui.MenuItem, msg tea.Msg) (*ui.MenuItem, tea.Cmd) { + _, ok := msg.(backToDevModeBaseBranchUrl) + if !ok { + return mi, nil + } + + mi.Info = mi.State.Issue.BackToDevModeBaseBranch.URL + mi.IsDone = mi.State.Issue.BackToDevModeBaseBranch.Done + return mi, nil +} + +func backToDevModeBaseBranchAct(mi *ui.MenuItem) (*ui.MenuItem, tea.Cmd) { + pl, back := release.BackToDevModeOnBranch(mi.State, &mi.State.Issue.BackToDevModeBaseBranch, mi.State.VitessRelease.BaseReleaseBranch) + return mi, tea.Batch(func() tea.Msg { + return backToDevModeBaseBranchUrl(back()) + }, ui.PushDialog(ui.NewProgressDialog("Back To Dev Mode on Base Branch", pl))) +} diff --git a/go/releaser/issue.go b/go/releaser/issue.go index 09bc05e..03d354b 100644 --- a/go/releaser/issue.go +++ b/go/releaser/issue.go @@ -45,6 +45,7 @@ const ( stateReadingReleaseNotesMainItem stateReadingReleaseNotesReleaseBranchItem stateReadingBackToDevModeItem + stateReadingBackToDevModeBaseBranchItem stateReadingCloseMilestoneItem stateReadingVtopUpdateGo stateReadingVtopCreateReleasePR @@ -88,6 +89,7 @@ const ( releaseNotesMainItem = "Update release notes on main." releaseNotesReleaseBranchItem = "Update release notes on the release branch." backToDevItem = "Go back to dev mode on the release branch." + backToDevBaseBranchItem = "Go back to dev mode on the base of the release branch." websiteDocItem = "Update the website documentation." benchmarkedItem = "Make sure the release is benchmarked by arewefastyet." dockerImagesItem = "Docker Images available on DockerHub." @@ -157,6 +159,7 @@ type ( ReleaseNotesOnMain ItemWithLink ReleaseNotesOnReleaseBranch ItemWithLink BackToDevMode ItemWithLink + BackToDevModeBaseBranch ItemWithLink MergeBlogPostPR bool WebsiteDocumentation bool Benchmarked bool @@ -291,6 +294,10 @@ The release of vitess-operator v{{.VtopRelease}} is also planned - {{ .BackToDevMode.URL }} {{- end }} {{- if .GA }} +- [{{fmtStatus .BackToDevModeBaseBranch.Done}}] Go back to dev mode on the base of the release branch. +{{- if .BackToDevModeBaseBranch.URL }} + - {{ .BackToDevModeBaseBranch.URL }} +{{- end }} - [{{fmtStatus .MergeBlogPostPR}}] Merge the blog post Pull Request on the website repository. {{- end }} - [{{fmtStatus .WebsiteDocumentation}}] Update the website documentation. @@ -466,6 +473,11 @@ func (s *State) LoadIssue() { if isNextLineAList(lines, i) { st = stateReadingBackToDevModeItem } + case strings.Contains(line, backToDevBaseBranchItem): + newIssue.BackToDevModeBaseBranch.Done = strings.HasPrefix(line, markdownItemDone) + if isNextLineAList(lines, i) { + st = stateReadingBackToDevModeBaseBranchItem + } case strings.Contains(line, websiteDocItem): newIssue.WebsiteDocumentation = strings.HasPrefix(line, markdownItemDone) case strings.Contains(line, benchmarkedItem): @@ -516,6 +528,8 @@ func (s *State) LoadIssue() { newIssue.ReleaseNotesOnReleaseBranch.URL = handleSingleTextItem(line, &st) case stateReadingBackToDevModeItem: newIssue.BackToDevMode.URL = handleSingleTextItem(line, &st) + case stateReadingBackToDevModeBaseBranchItem: + newIssue.BackToDevModeBaseBranch.URL = handleSingleTextItem(line, &st) case stateReadingCloseMilestoneItem: newIssue.CloseMilestone.URL = handleSingleTextItem(line, &st) case stateReadingVtopUpdateGo: diff --git a/go/releaser/release/back_to_dev.go b/go/releaser/release/back_to_dev.go index 90f6443..c43e814 100644 --- a/go/releaser/release/back_to_dev.go +++ b/go/releaser/release/back_to_dev.go @@ -26,7 +26,7 @@ import ( "vitess.io/vitess-releaser/go/releaser/pre_release" ) -func BackToDevMode(state *releaser.State) (*logging.ProgressLogging, func() string) { +func BackToDevModeOnBranch(state *releaser.State, itemToUpdate *releaser.ItemWithLink, branch string) (*logging.ProgressLogging, func() string) { pl := &logging.ProgressLogging{ TotalSteps: 10, } @@ -35,8 +35,8 @@ func BackToDevMode(state *releaser.State) (*logging.ProgressLogging, func() stri var url string return pl, func() string { defer func() { - state.Issue.BackToDevMode.Done = done - state.Issue.BackToDevMode.URL = url + itemToUpdate.Done = done + itemToUpdate.URL = url pl.NewStepf("Update Issue %s on GitHub", state.IssueLink) _, fn := state.UploadIssue() issueLink := fn() @@ -46,7 +46,7 @@ func BackToDevMode(state *releaser.State) (*logging.ProgressLogging, func() stri pl.NewStepf("Fetch from git remote") git.CorrectCleanRepo(state.VitessRelease.Repo) - git.ResetHard(state.VitessRelease.Remote, state.VitessRelease.ReleaseBranch) + git.ResetHard(state.VitessRelease.Remote, branch) // If we are releasing an RC release, the next SNAPSHOT version on the release branch // will be the same release as the RC but without the RC tag. @@ -59,7 +59,7 @@ func BackToDevMode(state *releaser.State) (*logging.ProgressLogging, func() stri devModeRelease := fmt.Sprintf("%s-SNAPSHOT", nextNextRelease) - backToDevModePRName := fmt.Sprintf("[%s] Bump to `v%s` after the `v%s` release", state.VitessRelease.ReleaseBranch, devModeRelease, state.VitessRelease.Release) + backToDevModePRName := fmt.Sprintf("[%s] Bump to `v%s` after the `v%s` release", branch, devModeRelease, state.VitessRelease.Release) // look for existing PRs pl.NewStepf("Look for an existing Pull Request named '%s'", backToDevModePRName) @@ -70,8 +70,8 @@ func BackToDevMode(state *releaser.State) (*logging.ProgressLogging, func() stri return url } - pl.NewStepf("Create new branch based on %s/%s", state.VitessRelease.Remote, state.VitessRelease.ReleaseBranch) - newBranchName := git.FindNewGeneratedBranch(state.VitessRelease.Remote, state.VitessRelease.ReleaseBranch, "back-to-dev-mode") + pl.NewStepf("Create new branch based on %s/%s", state.VitessRelease.Remote, branch) + newBranchName := git.FindNewGeneratedBranch(state.VitessRelease.Remote, branch, "back-to-dev-mode") pl.NewStepf("Update version.go") pre_release.UpdateVersionGoFile(devModeRelease) @@ -93,7 +93,7 @@ func BackToDevMode(state *releaser.State) (*logging.ProgressLogging, func() stri Title: backToDevModePRName, Body: fmt.Sprintf("Includes the changes required to go back into dev mode (v%s) after the release of v%s.", devModeRelease, state.VitessRelease.Release), Branch: newBranchName, - Base: state.VitessRelease.ReleaseBranch, + Base: branch, Labels: []github.Label{{Name: "Component: General"}, {Name: "Type: Release"}}, } _, url = pr.Create(state.VitessRelease.Repo) diff --git a/go/releaser/steps/steps.go b/go/releaser/steps/steps.go index f60f8d9..3a1bc96 100644 --- a/go/releaser/steps/steps.go +++ b/go/releaser/steps/steps.go @@ -49,6 +49,7 @@ const ( ReleaseNotesOnMain = "Release Notes on main" ReleaseNotesOnReleaseBranch = "Release Notes on release branch" BackToDev = "Back To Dev Mode" + BackToDevOnBaseBranch = "Back To Dev Mode on the base branch" MergeBlogPost = "Merge Blog Post" WebsiteDocumentation = "Website Documentation" Benchmarked = "Benchmarks" From 29dedc0056b3f1ed712e3f854fd9b74ef2107880 Mon Sep 17 00:00:00 2001 From: Florent Poinsard Date: Thu, 23 May 2024 13:44:44 -0600 Subject: [PATCH 11/12] Fix bugs found while doing the GA release Signed-off-by: Florent Poinsard --- .../release/release_notes_to_release_branch.go | 4 ++-- go/releaser/github/pr.go | 11 ++++++----- go/releaser/github/release.go | 4 +++- go/releaser/release/copy_release_notes.go | 2 +- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/go/interactive/release/release_notes_to_release_branch.go b/go/interactive/release/release_notes_to_release_branch.go index 45b2825..217b597 100644 --- a/go/interactive/release/release_notes_to_release_branch.go +++ b/go/interactive/release/release_notes_to_release_branch.go @@ -61,6 +61,6 @@ func releaseNotesOnReleaseBranchUpdate(mi *ui.MenuItem, msg tea.Msg) (*ui.MenuIt func releaseNotesOnReleaseBranchAct(mi *ui.MenuItem) (*ui.MenuItem, tea.Cmd) { pl, fn := release.CopyReleaseNotesToBranch(mi.State, &mi.State.Issue.ReleaseNotesOnReleaseBranch, mi.State.VitessRelease.BaseReleaseBranch) return mi, tea.Batch(func() tea.Msg { - return releaseNotesOnMainUrl(fn()) - }, ui.PushDialog(ui.NewProgressDialog("Release Notes on Main", pl))) + return releaseNotesOnReleaseBranchUrl(fn()) + }, ui.PushDialog(ui.NewProgressDialog("Release Notes on release branch", pl))) } diff --git a/go/releaser/github/pr.go b/go/releaser/github/pr.go index 71e5ee4..da0b282 100644 --- a/go/releaser/github/pr.go +++ b/go/releaser/github/pr.go @@ -117,7 +117,7 @@ func CheckBackportToPRs(repo, majorRelease string) map[string]any { func FindPR(repo, prTitle string) (nb int, url string) { stdOut := execGh( "pr", "list", - "--json", "url", + "--json", "url,title", "--repo", repo, "--search", prTitle, "--state", "open", @@ -127,11 +127,12 @@ func FindPR(repo, prTitle string) (nb int, url string) { if err != nil { utils.LogPanic(err, "failed to parse PRs, got: %s", stdOut) } - if len(prs) != 1 { - return 0, "" + for _, pr := range prs { + if pr.Title == prTitle { + return URLToNb(pr.URL), pr.URL + } } - url = prs[0].URL - return URLToNb(url), url + return 0, "" } func GetMergedPRsAndAuthorsByMilestone(repo, milestone string) (prs []PR, authors []string) { diff --git a/go/releaser/github/release.go b/go/releaser/github/release.go index ba45ac3..55364d8 100644 --- a/go/releaser/github/release.go +++ b/go/releaser/github/release.go @@ -42,7 +42,9 @@ func CreateRelease(repo, tag, notesFilePath string, latest, prerelease bool) (ur } if latest { - args = append(args, "--latest") + args = append(args, "--latest=true") + } else { + args = append(args, "--latest=false") } if prerelease { diff --git a/go/releaser/release/copy_release_notes.go b/go/releaser/release/copy_release_notes.go index c292a09..6221664 100644 --- a/go/releaser/release/copy_release_notes.go +++ b/go/releaser/release/copy_release_notes.go @@ -62,7 +62,7 @@ func CopyReleaseNotesToBranch(state *releaser.State, itemToUpdate *releaser.Item } pl.NewStepf("Create new branch based on %s/%s", state.VitessRelease.Remote, branch) - newBranchName := git.FindNewGeneratedBranch(state.VitessRelease.Remote, branch, "release-notes-main") + newBranchName := git.FindNewGeneratedBranch(state.VitessRelease.Remote, branch, fmt.Sprintf("release-notes-%s", branch)) pl.NewStepf("Copy release notes from %s/%s", state.VitessRelease.Remote, state.VitessRelease.ReleaseBranch) releaseNotesPath := pre_release.GetReleaseNotesDirPathForMajor(releaser.RemoveRCFromReleaseTitle(state.VitessRelease.Release)) From c272049a225d1e29c1d045bc1b58350d5faa42c0 Mon Sep 17 00:00:00 2001 From: Florent Poinsard Date: Thu, 23 May 2024 13:55:38 -0600 Subject: [PATCH 12/12] Enhance the format of the release issue Signed-off-by: Florent Poinsard --- go/releaser/issue.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/go/releaser/issue.go b/go/releaser/issue.go index 03d354b..ae6daa5 100644 --- a/go/releaser/issue.go +++ b/go/releaser/issue.go @@ -56,7 +56,7 @@ const ( markdownItemDone = "- [x]" // Divers - dateItem = "This release is scheduled for" + dateItem = "> This release is scheduled for" // Prerequisites generalPrerequisitesItem = "General prerequisites." @@ -174,15 +174,16 @@ type ( ) const ( - releaseIssueTemplate = `This release is scheduled for {{fmtDate .Date }} - + releaseIssueTemplate = `> [!NOTE] +> This release is scheduled for {{fmtDate .Date }}. {{- if .DoVtOp }} -The release of vitess-operator v{{.VtopRelease}} is also planned +> The release of vitess-operator **v{{.VtopRelease}}** is also planned. {{- end }} - - - +> [!IMPORTANT] +> Please **do not** edit the content of the Issue's body manually. +> The **vitess-releaser** tool is managing and handling this issue. +> You can however click on the check boxes to mark them as done/not done, and write comments. ### Prerequisites @@ -377,7 +378,7 @@ func (s *State) LoadIssue() { case stateReadingItem: // divers if strings.HasPrefix(line, dateItem) { - nline := strings.TrimSpace(line[len(dateItem):]) + nline := strings.TrimSpace(line[len(dateItem) : len(line)-1]) parsedDate, err := time.Parse("Mon _2 Jan 2006", nline) if err != nil { utils.LogPanic(err, "failed to parse the date from the release issue body (%s)", nline)