diff --git a/Makefile b/Makefile index f664e70..79d2ce8 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. +# build local vitess-releaser for development purposes build: go build -o vitess-releaser ./main.go ./vitess-releaser -v + +# install the released vitess-releaser package, for production use +install: + go install github.com/vitessio/vitess-releaser@latest + +# serves for local testing with mods, as well as quick documentation on how to use the tool +test: build + ./vitess-releaser --date 2024-10-23 --rc 2 -r 21 # --live --vtop-release 2.14 diff --git a/go/cmd/cmd.go b/go/cmd/cmd.go index 7ab5a41..376c253 100644 --- a/go/cmd/cmd.go +++ b/go/cmd/cmd.go @@ -34,7 +34,7 @@ import ( "github.com/vitessio/vitess-releaser/go/releaser/utils" ) -const VERSION = "v1.0.2" +const VERSION = "v1.0.3" var ( releaseVersion string @@ -223,7 +223,9 @@ func getGitRepos() (vitessRepo, vtopRepo string) { } func printVersionAndExit() { - fmt.Printf("Version: %s\n", VERSION) + fmt.Printf("\nvitess-releaser Version: %s\n", VERSION) + msg, _ := getGitCommit() + fmt.Printf("\nLast Commit: %s\n", msg) os.Exit(0) } diff --git a/go/interactive/main_menu.go b/go/interactive/main_menu.go index 20dd2a8..a8b4e5f 100644 --- a/go/interactive/main_menu.go +++ b/go/interactive/main_menu.go @@ -29,6 +29,10 @@ import ( "github.com/vitessio/vitess-releaser/go/interactive/ui" "github.com/vitessio/vitess-releaser/go/releaser" "github.com/vitessio/vitess-releaser/go/releaser/github" + postreleaselogic "github.com/vitessio/vitess-releaser/go/releaser/post_release" + prereleaselogic "github.com/vitessio/vitess-releaser/go/releaser/pre_release" + releaselogic "github.com/vitessio/vitess-releaser/go/releaser/release" + "github.com/vitessio/vitess-releaser/go/releaser/steps" ) func blankLineMenu() *ui.MenuItem { @@ -66,6 +70,7 @@ func MainScreen(ctx context.Context, state *releaser.State) { pre_release.CreateReleasePRMenuItem(ctx), pre_release.VtopUpdateGolangMenuItem(ctx), createBlogPostPRMenuItem(ctx), + simpleMenuItem(ctx, "UpdateCobraDocs", prereleaselogic.CobraDocs(state), steps.UpdateCobraDocs, false), ) releaseMenu := ui.NewMenu( @@ -83,6 +88,7 @@ func MainScreen(ctx context.Context, state *releaser.State) { benchmarkedItem(ctx), dockerImagesItem(ctx), release.CloseMilestoneItem(ctx), + simpleMenuItem(ctx, "ReleaseArtifacts", releaselogic.CheckArtifacts(state), steps.ReleaseArtifacts, false), ) releaseMenu.Sequential = true @@ -91,6 +97,7 @@ func MainScreen(ctx context.Context, state *releaser.State) { "Post Release", slackAnnouncementMenuItem(ctx, slackAnnouncementPostRelease), twitterMenuItem(ctx), + simpleMenuItem(ctx, "RemoveBypassProtection", postreleaselogic.RemoveByPassProtectionRules(), steps.RemoveBypassProtection, false), post_release.CloseIssueItem(ctx), ) diff --git a/go/interactive/menu_item_constructors.go b/go/interactive/menu_item_constructors.go index e693e73..35c6554 100644 --- a/go/interactive/menu_item_constructors.go +++ b/go/interactive/menu_item_constructors.go @@ -18,7 +18,7 @@ package interactive import ( "context" - + "fmt" "github.com/vitessio/vitess-releaser/go/interactive/ui" "github.com/vitessio/vitess-releaser/go/releaser" "github.com/vitessio/vitess-releaser/go/releaser/code_freeze" @@ -26,6 +26,8 @@ import ( "github.com/vitessio/vitess-releaser/go/releaser/prerequisite" "github.com/vitessio/vitess-releaser/go/releaser/release" "github.com/vitessio/vitess-releaser/go/releaser/steps" + "github.com/vitessio/vitess-releaser/go/releaser/utils" + "reflect" ) func checkSummaryMenuItem(ctx context.Context) *ui.MenuItem { @@ -98,7 +100,7 @@ func dockerImagesItem(ctx context.Context) *ui.MenuItem { state := releaser.UnwrapState(ctx) return newBooleanMenu( ctx, - release.CheckDockerMessage(state.VitessRelease.MajorReleaseNb, state.VitessRelease.Repo, state.VtOpRelease.Repo), + release.CheckDockerMessage(state), steps.DockerImages, func() { state.Issue.DockerImages = !state.Issue.DockerImages }, state.Issue.DockerImages, @@ -137,3 +139,42 @@ func mergeBlogPostPRMenuItem(ctx context.Context) *ui.MenuItem { state.Issue.MergeBlogPostPR, !state.Issue.GA) } + +func simpleMenuItem(ctx context.Context, issueFieldName string, msgs []string, stepName string, onlyGA bool) *ui.MenuItem { + state := releaser.UnwrapState(ctx) + logMsg := fmt.Sprintf("Menu item %s", stepName) + + fieldVal := getFieldVal(&state.Issue, issueFieldName, logMsg) + + ignore := false + if onlyGA { + ignore = !state.Issue.GA + } + + return newBooleanMenu( + ctx, + msgs, + stepName, + func() { + fieldVal.SetBool(!fieldVal.Bool()) + }, + fieldVal.Bool(), + ignore, + ) +} + +func getFieldVal(issue *releaser.Issue, issueFieldName string, logMsg string) reflect.Value { + v := reflect.ValueOf(issue).Elem() + fieldVal := v.FieldByName(issueFieldName) + if !fieldVal.IsValid() { + utils.BailOut(fmt.Errorf("no such field: %s", issueFieldName), logMsg) + } + if fieldVal.Kind() != reflect.Bool { + utils.BailOut(fmt.Errorf("field %s is not of type bool", issueFieldName), logMsg) + } + + if !fieldVal.CanSet() { + utils.BailOut(fmt.Errorf("cannot set field: %s", issueFieldName), logMsg) + } + return fieldVal +} diff --git a/go/releaser/issue.go b/go/releaser/issue.go index 416d30e..5ce45a7 100644 --- a/go/releaser/issue.go +++ b/go/releaser/issue.go @@ -79,6 +79,7 @@ const ( vtopUpdateGoItem = "Update vitess-operator Golang version." vtopUpdateCompTableItem = "Update vitess-operator compatibility table." createBlogPostPRItem = "Open a Pull Request on the website repository for the blog post." + UpdateCobraDocs = "Update Cobra Docs." // Release mergeReleasePRItem = "Merge the Release PR." @@ -95,10 +96,12 @@ const ( dockerImagesItem = "Docker Images available on DockerHub." closeMilestoneItem = "Close current GitHub Milestone." mergeBlogPostItem = "Merge the blog post Pull Request on the website repository." + ReleaseArtifactsItem = "Check that release artifacts were generated." // Post-Release postSlackAnnouncementItem = "Notify the community on Slack for the new release." twitterItem = "Twitter announcement." + RemoveBypassProtection = "Remove bypass branch protection rules, if required." closeReleaseItem = "Close this Issue." ) @@ -151,6 +154,7 @@ type ( VtopCreateReleasePR ItemWithLinks VtopManualUpdate bool CreateBlogPostPR bool + UpdateCobraDocs bool // Release MergeReleasePR ItemWithLink @@ -165,11 +169,13 @@ type ( Benchmarked bool DockerImages bool CloseMilestone ItemWithLink + ReleaseArtifacts bool // Post-Release - SlackPostRelease bool - Twitter bool - CloseIssue bool + SlackPostRelease bool + Twitter bool + CloseIssue bool + RemoveBypassProtection bool } ) @@ -257,6 +263,7 @@ const ( {{- if .GA }} - [{{fmtStatus .CreateBlogPostPR}}] Open a Pull Request on the website repository for the blog post. {{- end }} +- [{{fmtStatus .UpdateCobraDocs}}] Update Cobra Docs. ### Release _({{fmtShortDate .Date }})_ @@ -298,12 +305,14 @@ const ( - {{ .CloseMilestone.URL }} {{- end }} {{- end }} - +- [{{fmtStatus .ReleaseArtifacts}}] Check that release artifacts were generated. ### Post-Release _({{fmtShortDate .Date }})_ - [{{fmtStatus .SlackPostRelease}}] Notify the community on Slack for the new release. - [{{fmtStatus .Twitter}}] Twitter announcement. +- [{{fmtStatus .RemoveBypassProtection}}] Remove bypass branch protection rules, if required. - [{{fmtStatus .CloseIssue}}] Close this Issue. + ` ) @@ -497,6 +506,12 @@ func (s *State) LoadIssue() { newIssue.MergeBlogPostPR = strings.HasPrefix(line, markdownItemDone) case strings.Contains(line, javaRelease): newIssue.JavaRelease = strings.HasPrefix(line, markdownItemDone) + case strings.Contains(line, UpdateCobraDocs): + newIssue.UpdateCobraDocs = strings.HasPrefix(line, markdownItemDone) + case strings.Contains(line, ReleaseArtifactsItem): + newIssue.ReleaseArtifacts = strings.HasPrefix(line, markdownItemDone) + case strings.Contains(line, RemoveBypassProtection): + newIssue.RemoveBypassProtection = strings.HasPrefix(line, markdownItemDone) } case stateReadingGeneral: newIssue.General.Items = append(newIssue.General.Items, handleNewListItem(lines, i, &st)) diff --git a/go/releaser/post_release/protection_rules.go b/go/releaser/post_release/protection_rules.go new file mode 100644 index 0000000..d0dc171 --- /dev/null +++ b/go/releaser/post_release/protection_rules.go @@ -0,0 +1,24 @@ +/* +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 post_release + +func RemoveByPassProtectionRules() []string { + return []string{ + "In branch protection for current branch, confirm 'Do not allow bypassing the above settings' is checked.", + "", + } +} diff --git a/go/releaser/pre_release/cobra_docs.go b/go/releaser/pre_release/cobra_docs.go new file mode 100644 index 0000000..5bdd00c --- /dev/null +++ b/go/releaser/pre_release/cobra_docs.go @@ -0,0 +1,33 @@ +/* +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 pre_release + +import ( + "fmt" + + "github.com/vitessio/vitess-releaser/go/releaser" +) + +func CobraDocs(state *releaser.State) []string { + return []string{ + "Regenerate cobra cli docs by running the following in the root of the website repo:\n", + fmt.Sprintf("\t$> export COBRADOC_VERSION_PAIRS=\"v%s:%s.0\"", + releaser.RemoveRCFromReleaseTitle(state.VitessRelease.Release), state.VitessRelease.MajorRelease), + fmt.Sprintf("\t$> make generated-docs"), + "", + } +} diff --git a/go/releaser/release/artifacts.go b/go/releaser/release/artifacts.go new file mode 100644 index 0000000..cd93ad6 --- /dev/null +++ b/go/releaser/release/artifacts.go @@ -0,0 +1,30 @@ +/* +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 ( + "fmt" + + "github.com/vitessio/vitess-releaser/go/releaser" +) + +func CheckArtifacts(state *releaser.State) []string { + return []string{ + fmt.Sprintf("Check that release artifacts were generated: at bottom of https://github.com/vitessio/vitess/releases/tag/%s.", state.GetTag()), + "", + } +} diff --git a/go/releaser/release/docker.go b/go/releaser/release/docker.go index 98bb305..db3536b 100644 --- a/go/releaser/release/docker.go +++ b/go/releaser/release/docker.go @@ -16,9 +16,17 @@ limitations under the License. package release -import "fmt" +import ( + "fmt" + "github.com/vitessio/vitess-releaser/go/releaser" + "strings" +) -func CheckDockerMessage(majorRelease int, repo string, vtopRepo string) []string { +func CheckDockerMessage(state *releaser.State) []string { + majorRelease := state.VitessRelease.MajorReleaseNb + repo := state.VitessRelease.Repo + vtopRepo := state.VtOpRelease.Repo + release := strings.ToLower(state.VitessRelease.Release) msg := []string{ "Make sure the Docker Images are being built by GitHub Actions.", "This can be done by visiting the following links, our new release should appear in either green (done) or yellow (building / pending build):", @@ -38,6 +46,7 @@ func CheckDockerMessage(majorRelease int, repo string, vtopRepo string) []string } else { // this links to the newer GitHub Actions workflow that was introduced in v21 by https://github.com/vitessio/vitess/pull/16339 msg = append(msg, fmt.Sprintf("\t- https://github.com/%s/vitess/actions/workflows/build_docker_images.yml", repo)) + msg = append(msg, fmt.Sprintf("\nCheck that the vttestserver image is pushed at https://hub.docker.com/r/vitess/vttestserver/tags?name=%s.", release)) } if vtopRepo != "" { diff --git a/go/releaser/state.go b/go/releaser/state.go index fac050d..ffe2032 100644 --- a/go/releaser/state.go +++ b/go/releaser/state.go @@ -18,7 +18,9 @@ package releaser import ( "context" + "fmt" "path" + "strings" "syscall" "github.com/vitessio/vitess-releaser/go/releaser/utils" @@ -87,6 +89,10 @@ func (s *State) GoToVtOp() { changeDir(p) } +func (s *State) GetTag() string { + return fmt.Sprintf("v%s", strings.ToLower(s.VitessRelease.Release)) +} + func changeDir(p string) { cwd, err := syscall.Getwd() if err != nil { diff --git a/go/releaser/steps/steps.go b/go/releaser/steps/steps.go index 24dfffd..24efa21 100644 --- a/go/releaser/steps/steps.go +++ b/go/releaser/steps/steps.go @@ -39,6 +39,7 @@ const ( CreateReleasePR = "Create Release PR" CreateMilestone = "Create Milestone" VtopUpdateGolang = "Update Go version in vitess-operator" + UpdateCobraDocs = "Update Cobra Docs" // Release MergeReleasePR = "Merge Release PR" @@ -55,9 +56,11 @@ const ( Benchmarked = "Benchmarks" DockerImages = "Docker Images" CloseMilestone = "Close Milestone" + ReleaseArtifacts = "Release Artifacts" // Post-Release - SlackAnnouncementPost = "Slack Announcement Post-Release" - Twitter = "Twitter" - CloseIssue = "Close Issue" + SlackAnnouncementPost = "Slack Announcement Post-Release" + Twitter = "Twitter" + CloseIssue = "Close Issue" + RemoveBypassProtection = "Remove Bypass Protection" )