Skip to content

Commit a15ffe2

Browse files
h9jianggopherbot
authored andcommitted
internal/task: create the branch for the first rc in minor release
A local relui screenshot is at golang/vscode-go#3500 (comment) For golang/vscode-go#3500 Change-Id: Ie6b5650eef8f84d1fe7264e35894f80043cad109 Reviewed-on: https://go-review.googlesource.com/c/build/+/608817 Reviewed-by: Dmitri Shuralyov <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> Auto-Submit: Hongxiang Jiang <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent e049c5c commit a15ffe2

File tree

4 files changed

+135
-1
lines changed

4 files changed

+135
-1
lines changed

internal/task/fakes.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,9 +220,14 @@ func (g *FakeGerrit) ReadBranchHead(ctx context.Context, project, branch string)
220220
if err != nil {
221221
return "", err
222222
}
223-
// TODO: If the branch doesn't exist, return an error matching gerrit.ErrResourceNotExist.
224223
out, err := repo.dir.RunCommand(ctx, "rev-parse", "refs/heads/"+branch)
225224
if err != nil {
225+
// TODO(hxjiang): switch to git show-ref --exists refs/heads/branch after
226+
// upgrade git to 2.43.0.
227+
// https://git-scm.com/docs/git-show-ref/2.43.0#Documentation/git-show-ref.txt---exists
228+
if strings.Contains(err.Error(), "unknown revision or path not in the working tree") {
229+
return "", gerrit.ErrResourceNotExist
230+
}
226231
// Returns empty string if the error is nil to align the same behavior with
227232
// the real Gerrit client.
228233
return "", err

internal/task/releasegopls.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,8 @@ func parseSemver(v string) (_ semversion, ok bool) {
551551
return parsed, ok
552552
}
553553

554+
// prereleaseVersion extracts the integer component from a pre-release version
555+
// string in the format "${STRING}.${INT}".
554556
func (s *semversion) prereleaseVersion() (int, error) {
555557
parts := strings.Split(s.Pre, ".")
556558
if len(parts) == 1 {

internal/task/releasevscodego.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ package task
66

77
import (
88
_ "embed"
9+
"errors"
910
"fmt"
1011
"strconv"
1112
"strings"
1213

1314
"github.com/google/go-github/v48/github"
15+
"golang.org/x/build/gerrit"
1416
"golang.org/x/build/internal/relui/groups"
1517
"golang.org/x/build/internal/workflow"
1618
wf "golang.org/x/build/internal/workflow"
@@ -130,6 +132,7 @@ func (r *ReleaseVSCodeGoTasks) NewPrereleaseDefinition() *wf.Definition {
130132
approved := wf.Action1(wd, "await release coordinator's approval", r.approveVersion, semv)
131133

132134
_ = wf.Task1(wd, "create release milestone and issue", r.createReleaseMilestoneAndIssue, semv, wf.After(approved))
135+
_ = wf.Action1(wd, "create release branch", r.createReleaseBranch, semv, wf.After(approved))
133136

134137
return wd
135138
}
@@ -173,6 +176,52 @@ func (r *ReleaseVSCodeGoTasks) createReleaseMilestoneAndIssue(ctx *wf.TaskContex
173176
return *issue.Number, nil
174177
}
175178

179+
// createReleaseBranch creates corresponding release branch only for the initial
180+
// release candidate of a minor version.
181+
func (r *ReleaseVSCodeGoTasks) createReleaseBranch(ctx *wf.TaskContext, semv semversion) error {
182+
branch := fmt.Sprintf("release-v%v.%v", semv.Major, semv.Minor)
183+
releaseHead, err := r.Gerrit.ReadBranchHead(ctx, "vscode-go", branch)
184+
185+
if err == nil {
186+
ctx.Printf("Found the release branch %q with head pointing to %s\n", branch, releaseHead)
187+
return nil
188+
}
189+
190+
if !errors.Is(err, gerrit.ErrResourceNotExist) {
191+
return fmt.Errorf("failed to read the release branch: %w", err)
192+
}
193+
194+
// Require vscode release branch existence if this is a non-minor release.
195+
if semv.Patch != 0 {
196+
return fmt.Errorf("release branch is required for patch releases: %w", err)
197+
}
198+
199+
rc, err := semv.prereleaseVersion()
200+
if err != nil {
201+
return err
202+
}
203+
204+
// Require vscode release branch existence if this is not the first rc in
205+
// a minor release.
206+
if rc != 1 {
207+
return fmt.Errorf("release branch is required for non-initial release candidates: %w", err)
208+
}
209+
210+
// Create the release branch using the revision from the head of master branch.
211+
head, err := r.Gerrit.ReadBranchHead(ctx, "vscode-go", "master")
212+
if err != nil {
213+
return err
214+
}
215+
216+
ctx.DisableRetries() // Beyond this point we want retries to be done manually, not automatically.
217+
_, err = r.Gerrit.CreateBranch(ctx, "vscode-go", branch, gerrit.BranchInput{Revision: head})
218+
if err != nil {
219+
return err
220+
}
221+
ctx.Printf("Created branch %q at revision %s.\n", branch, head)
222+
return nil
223+
}
224+
176225
// nextPrereleaseVersion determines the next pre-release version for the
177226
// upcoming stable release of vscode-go by examining all existing tags in the
178227
// repository.

internal/task/releasevscodego_test.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package task
66

77
import (
88
"context"
9+
"fmt"
910
"testing"
1011

1112
"github.com/google/go-github/v48/github"
@@ -79,6 +80,83 @@ func TestCreateReleaseMilestoneAndIssue(t *testing.T) {
7980
}
8081
}
8182

83+
func TestCreateReleaseBranch(t *testing.T) {
84+
ctx := context.Background()
85+
testcases := []struct {
86+
name string
87+
version string
88+
existingBranch bool
89+
wantErr bool
90+
}{
91+
{
92+
name: "nil if the release branch does not exist for first rc in a minor release",
93+
version: "v0.44.0-rc.1",
94+
existingBranch: false,
95+
wantErr: false,
96+
},
97+
{
98+
name: "nil if the release branch already exist for non-initial rc in a minor release",
99+
version: "v0.44.0-rc.4",
100+
existingBranch: true,
101+
wantErr: false,
102+
},
103+
{
104+
name: "fail if the release branch does not exist for non-initial rc in a minor release",
105+
version: "v0.44.0-rc.4",
106+
existingBranch: false,
107+
wantErr: true,
108+
},
109+
{
110+
name: "nil if the release branch already exist for a patch version",
111+
version: "v0.44.3-rc.3",
112+
existingBranch: true,
113+
wantErr: false,
114+
},
115+
{
116+
name: "fail if the release branch does not exist for a patch version",
117+
version: "v0.44.3-rc.3",
118+
existingBranch: false,
119+
wantErr: true,
120+
},
121+
}
122+
123+
for _, tc := range testcases {
124+
t.Run(tc.name, func(t *testing.T) {
125+
semv, ok := parseSemver(tc.version)
126+
if !ok {
127+
t.Fatalf("failed to parse the want version: %q", tc.version)
128+
}
129+
130+
vscodego := NewFakeRepo(t, "vscode-go")
131+
commit := vscodego.Commit(map[string]string{
132+
"go.mod": "module github.com/golang/vscode-go\n",
133+
"go.sum": "\n",
134+
})
135+
if tc.existingBranch {
136+
vscodego.Branch(fmt.Sprintf("release-v%v.%v", semv.Major, semv.Minor), commit)
137+
}
138+
139+
gerrit := NewFakeGerrit(t, vscodego)
140+
tasks := &ReleaseVSCodeGoTasks{
141+
Gerrit: gerrit,
142+
}
143+
144+
err := tasks.createReleaseBranch(&workflow.TaskContext{Context: ctx, Logger: &testLogger{t, ""}}, semv)
145+
if tc.wantErr && err == nil {
146+
t.Errorf("createReleaseBranch(%q) should return error but return nil", tc.version)
147+
} else if !tc.wantErr && err != nil {
148+
t.Errorf("createReleaseBranch(%q) should return nil but return err: %v", tc.version, err)
149+
}
150+
151+
if !tc.wantErr {
152+
if _, err := gerrit.ReadBranchHead(ctx, "vscode-go", fmt.Sprintf("release-v%v.%v", semv.Major, semv.Minor)); err != nil {
153+
t.Errorf("createReleaseBranch(%q) should ensure the release branch creation: %v", tc.version, err)
154+
}
155+
}
156+
})
157+
}
158+
}
159+
82160
func TestNextPrereleaseVersion(t *testing.T) {
83161
tests := []struct {
84162
name string

0 commit comments

Comments
 (0)