Skip to content

Commit

Permalink
internal/task: reuse or create release milestone and issue
Browse files Browse the repository at this point in the history
If there are open release milestone and release issue in
golang/vscode-go, the flow will reuse them.

A local relui screenshot is at golang/vscode-go#3500 (comment)

For golang/vscode-go#3500

Change-Id: I7ba69a670bd66618bdb294761901af0fb7fd0dd1
Reviewed-on: https://go-review.googlesource.com/c/build/+/608417
Reviewed-by: Hyang-Ah Hana Kim <[email protected]>
LUCI-TryBot-Result: Go LUCI <[email protected]>
  • Loading branch information
h9jiang committed Aug 28, 2024
1 parent 3a2d61c commit 8ac64cc
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 2 deletions.
4 changes: 4 additions & 0 deletions cmd/relui/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,10 @@ func main() {
dh.RegisterDefinition("Update x/crypto NSS root bundle", bundleTasks.NewDefinition())

releaseVSCodeGoTasks := task.ReleaseVSCodeGoTasks{
GitHub: &task.GitHubClient{
V3: github.NewClient(githubHTTPClient),
V4: githubv4.NewClient(githubHTTPClient),
},
Gerrit: gerritClient,
ApproveAction: relui.ApproveActionDep(dbPool),
}
Expand Down
3 changes: 3 additions & 0 deletions internal/task/fakes.go
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,9 @@ func (f *FakeGitHub) FetchMilestone(_ context.Context, owner, repo, name string,

if create {
newID := f.nextMilestoneID()
if f.Milestones == nil {
f.Milestones = map[int]string{}
}
f.Milestones[newID] = name
return newID, nil
}
Expand Down
51 changes: 49 additions & 2 deletions internal/task/releasevscodego.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
package task

import (
_ "embed"
"fmt"

"github.com/google/go-github/v48/github"
"golang.org/x/build/internal/relui/groups"
"golang.org/x/build/internal/workflow"
wf "golang.org/x/build/internal/workflow"
Expand Down Expand Up @@ -43,6 +45,7 @@ import (
// insider versions.
type ReleaseVSCodeGoTasks struct {
Gerrit GerritClient
GitHub GitHubClientInterface
ApproveAction func(*wf.TaskContext) error
}

Expand All @@ -57,18 +60,62 @@ var nextVersionParam = wf.ParamDef[string]{
},
}

//go:embed template/vscode-go-release-issue.md
var vscodeGOReleaseIssueTmplStr string

// NewPrereleaseDefinition create a new workflow definition for vscode-go pre-release.
func (r *ReleaseVSCodeGoTasks) NewPrereleaseDefinition() *wf.Definition {
wd := wf.New(wf.ACL{Groups: []string{groups.ToolsTeam}})

versionBumpStrategy := wf.Param(wd, nextVersionParam)

version := wf.Task1(wd, "find the next pre-release version", r.nextPrereleaseVersion, versionBumpStrategy)
_ = wf.Action1(wd, "await release coordinator's approval", r.approveVersion, version)
semv := wf.Task1(wd, "find the next pre-release version", r.nextPrereleaseVersion, versionBumpStrategy)
approved := wf.Action1(wd, "await release coordinator's approval", r.approveVersion, semv)

_ = wf.Task1(wd, "create release milestone and issue", r.createReleaseMilestoneAndIssue, semv, wf.After(approved))

return wd
}

func (r *ReleaseVSCodeGoTasks) createReleaseMilestoneAndIssue(ctx *wf.TaskContext, semv semversion) (int, error) {
version := fmt.Sprintf("v%v.%v.%v", semv.Major, semv.Minor, semv.Patch)

// The vscode-go release milestone name matches the release version.
milestoneID, err := r.GitHub.FetchMilestone(ctx, "golang", "vscode-go", version, true)
if err != nil {
return 0, err
}

title := fmt.Sprintf("Release %s", version)
issues, err := r.GitHub.FetchMilestoneIssues(ctx, "golang", "vscode-go", milestoneID)
if err != nil {
return 0, err
}
for id := range issues {
issue, _, err := r.GitHub.GetIssue(ctx, "golang", "vscode-go", id)
if err != nil {
return 0, err
}
if title == issue.GetTitle() {
ctx.Printf("found existing releasing issue %v", id)
return id, nil
}
}

content := fmt.Sprintf(vscodeGOReleaseIssueTmplStr, version)
issue, _, err := r.GitHub.CreateIssue(ctx, "golang", "vscode-go", &github.IssueRequest{
Title: &title,
Body: &content,
Assignee: github.String("h9jiang"),
Milestone: &milestoneID,
})
if err != nil {
return 0, fmt.Errorf("failed to create release tracking issue for %q: %w", version, err)
}
ctx.Printf("created releasing issue %v", *issue.Number)
return *issue.Number, nil
}

// nextPrereleaseVersion determines the next pre-release version for the
// upcoming stable release of vscode-go by examining all existing tags in the
// repository.
Expand Down
68 changes: 68 additions & 0 deletions internal/task/releasevscodego_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,77 @@ import (
"context"
"testing"

"github.com/google/go-github/v48/github"
"golang.org/x/build/internal/workflow"
)

func TestCreateReleaseMilestoneAndIssue(t *testing.T) {
testcases := []struct {
name string
version string
fakeGithub FakeGitHub
wantIssue int
wantMilestone int
}{
{
name: "flow should create a milestone and create an issue under the milestone",
version: "v0.45.0-rc.1",
fakeGithub: FakeGitHub{}, // no issues and no milestones.
wantIssue: 1,
wantMilestone: 1,
},
{
name: "flow should create an issue under the existing milestone",
version: "v0.48.0-rc.1",
fakeGithub: FakeGitHub{
Milestones: map[int]string{999: "v0.48.0", 998: "v0.46.0"},
},
wantIssue: 1,
wantMilestone: 999,
},
{
name: "flow should reuse the existing release issue",
version: "v0.48.0-rc.1",
fakeGithub: FakeGitHub{
Milestones: map[int]string{999: "v0.48.0", 998: "Release v0.46.0"},
Issues: map[int]*github.Issue{1000: {Number: github.Int(1000), Title: github.String("Release v0.48.0"), Milestone: &github.Milestone{ID: github.Int64(999)}}},
},
wantIssue: 1000,
wantMilestone: 999,
},
}

for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
tasks := &ReleaseVSCodeGoTasks{
GitHub: &tc.fakeGithub,
}

semv, ok := parseSemver(tc.version)
if !ok {
t.Fatalf("parseSemver(%q) should success", tc.version)
}
issueNumber, err := tasks.createReleaseMilestoneAndIssue(&workflow.TaskContext{Context: context.Background(), Logger: &testLogger{t, ""}}, semv)
if err != nil {
t.Fatal(err)
}

issue, ok := tc.fakeGithub.Issues[issueNumber]
if !ok {
t.Errorf("release issue with number %v does not exist", issueNumber)
}

if *issue.Number != tc.wantIssue {
t.Errorf("createReleaseMilestoneAndIssue() create an issue with number %v, but should create issue with number %v", issue.Number, tc.wantIssue)
}

if int(*issue.Milestone.ID) != tc.wantMilestone {
t.Errorf("release issue is created under milestone %v should under milestone %v", *issue.Milestone.ID, tc.wantMilestone)
}
})
}
}

func TestNextPrereleaseVersion(t *testing.T) {
tests := []struct {
name string
Expand Down
31 changes: 31 additions & 0 deletions internal/task/template/vscode-go-release-issue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Release candidate (TODO: DATE)
- [x] Announce the release, leave enough time for teams to surface any last minute issues that need to get in before freeze. Make sure debugger and gopls teams are looped in as well.
- [ ] Check [the milestone](https://github.com/golang/vscode-go/issues?q=milestone%%3A%[1]s) and resolve/move unresolved issues.
- [ ] Update master for the release
- [ ] Update hardcoded latest version for gopls.
- [ ] Update [CHANGELOG.md](https://github.com/golang/vscode-go/blob/master/extension/CHANGELOG.md).
- [ ] Make sure the "Thanks" section is up-to-date.
- [ ] Check the Markdown rendering to make sure everything looks good.
- [ ] Update release for the release
- [ ] Create a branch against release for a pull request.
- [ ] Merge changes from master to prepare for the release.
- [ ] Change the version in [package.json](https://github.com/golang/vscode-go/blob/master/extension/package.json) from a -dev suffix
- [ ] Run npm install to make sure [package-lock.json](https://github.com/golang/vscode-go/blob/master/extension/package.json) is up-to-date
- [ ] Update the license file ($ tools/license.sh; mv LICENSE.prod LICENSE)
- [ ] Check the [Long Tests status](https://github.com/golang/vscode-go/actions?query=workflow%%3A%%22Long+Tests%%22) is green. Otherwise, fix the tests, send cls for review, submit them, and repeat.
- [ ] Perform manual [smoke tests](https://github.com/golang/vscode-go/blob/master/docs/smoke-test.md)
- [ ] Create new RC version tag for %[1]s-rc.1 at gerrit’s vscode-go [repo management page](https://go-review.googlesource.com/admin/repos/vscode-go,tags)
- [ ] Go to the release page https://github.com/golang/vscode-go/releases and check if the new release candidate is up. If necessary, you can manually edit the comment by clicking the “Edit” button. Don’t mutate uploaded vsix.
- [ ] Ask @golang/tools-team and contributors to this release to test the release candidate

# Final (TODO: DATE)
- [ ] Tag the new release for %[1]s
- [ ] Monitor the [cloud build status](https://pantheon.corp.google.com/cloud-build/dashboard?project=go-vscode-go)
- [ ] Update the release description with CHANGELOG contents
- [ ] Close the milestone

# Prepare for the Next Release
- [ ] Update master post-release
- [ ] Bump the version number to the next monthly release in the master branch
- [ ] Update package.json
- [ ] Update package-lock.json

0 comments on commit 8ac64cc

Please sign in to comment.