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

Implement new release process #89

Merged
merged 12 commits into from
May 23, 2024
24 changes: 17 additions & 7 deletions go/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,20 +123,30 @@ 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.
var baseReleaseBranch string
if rc > 0 || ga {
baseReleaseBranch = releaseBranch
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 {
utils.LogPanic(nil, "wanted: RC %d but release branch was %s, latest release was %v and is from main is %v", rcIncrement, releaseBranch, isLatestRelease, isFromMain)
}

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)
Expand Down
72 changes: 72 additions & 0 deletions go/interactive/general_prereq.go
Original file line number Diff line number Diff line change
@@ -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() && len(state.Issue.General.Items) > 0,
}
}

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
}
3 changes: 3 additions & 0 deletions go/interactive/main_menu.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func MainScreen(ctx context.Context) {
prereqMenu := ui.NewMenu(
ctx,
"Prerequisites",
generalPrerequisiteMenuItem(ctx),
slackAnnouncementMenuItem(ctx, slackAnnouncementPreRequisite),
checkSummaryMenuItem(ctx),
draftBlogPostMenuItem(ctx),
Expand Down Expand Up @@ -68,7 +69,9 @@ func MainScreen(ctx context.Context) {
release.VtopCreateReleasePRMenuItem(ctx),
release.VtopManualUpdateItem(ctx),
release.ReleaseNotesOnMainItem(ctx),
release.ReleaseNotesOnReleaseBranchItem(ctx),
release.BackToDevModeItem(ctx),
release.BackToDevModeBaseBranchItem(ctx),
mergeBlogPostPRMenuItem(ctx),
websiteDocumentationItem(ctx),
benchmarkedItem(ctx),
Expand Down
4 changes: 4 additions & 0 deletions go/interactive/pre_release/code_freeze.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}

Expand Down
2 changes: 1 addition & 1 deletion go/interactive/pre_release/create_backport_to_label.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
}
2 changes: 1 addition & 1 deletion go/interactive/release/back_to_dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
Expand Down
66 changes: 66 additions & 0 deletions go/interactive/release/back_to_dev_base_branch.go
Original file line number Diff line number Diff line change
@@ -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)))
}
6 changes: 3 additions & 3 deletions go/interactive/release/release_notes_to_main.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ 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
}

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)))
Expand Down
66 changes: 66 additions & 0 deletions go/interactive/release/release_notes_to_release_branch.go
Original file line number Diff line number Diff line change
@@ -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 releaseNotesOnReleaseBranchUrl(fn())
}, ui.PushDialog(ui.NewProgressDialog("Release Notes on release branch", pl)))
}
2 changes: 1 addition & 1 deletion go/interactive/ui/menu.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions go/releaser/github/label.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ func CreateLabel(repo, label, color, desc string) {
"--repo", repo,
"--color", color,
"--description", desc,
"--force",
)
}
11 changes: 6 additions & 5 deletions go/releaser/github/pr.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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) {
Expand Down
4 changes: 3 additions & 1 deletion go/releaser/github/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Loading