Skip to content

Commit ad8de1a

Browse files
h9jianggopherbot
authored andcommitted
internal/task: rename version input param and add E2E for release flow
For golang/go#57643 Change-Id: I6ba563b941df4ce703281163f2aaa714f57f3646 Reviewed-on: https://go-review.googlesource.com/c/build/+/610895 Reviewed-by: Robert Findley <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> Auto-Submit: Hongxiang Jiang <[email protected]>
1 parent 929e531 commit ad8de1a

File tree

2 files changed

+308
-1
lines changed

2 files changed

+308
-1
lines changed

internal/task/releasegopls.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@ func (r *ReleaseGoplsTasks) NewReleaseDefinition() *wf.Definition {
633633
// inputVersion allows manual override of the version, bypassing the version
634634
// bump strategy.
635635
// Use with caution.
636-
inputVersion := wf.Param(wd, wf.ParamDef[string]{Name: "explicit pre-release version (optional)"})
636+
inputVersion := wf.Param(wd, wf.ParamDef[string]{Name: "explicit version (optional)"})
637637
reviewers := wf.Param(wd, reviewersParam)
638638

639639
release := wf.Task2(wd, "determine the release version", r.determineReleaseVersion, inputVersion, versionBumpStrategy)

internal/task/releasegopls_test.go

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,9 @@ func TestFindOrCreateReleaseIssue(t *testing.T) {
531531
}
532532

533533
func TestGoplsPrereleaseFlow(t *testing.T) {
534+
if testing.Short() {
535+
t.Skip("skipping an end-to-end workflow test in short mode")
536+
}
534537
mustHaveShell(t)
535538

536539
testcases := []struct {
@@ -1019,3 +1022,307 @@ echo -n "foo" > file_b
10191022
})
10201023
}
10211024
}
1025+
1026+
func TestGoplsReleaseFlow(t *testing.T) {
1027+
if testing.Short() {
1028+
t.Skip("skipping an end-to-end workflow test in short mode")
1029+
}
1030+
mustHaveShell(t)
1031+
1032+
testcases := []struct {
1033+
name string
1034+
// The fields below are the prepared states before running the gopls
1035+
// release flow.
1036+
// commitTags specifies a sequence of (possibly) tagged commits.
1037+
// For each entry, a new commit is created, and if the entry is
1038+
// non empty that commit is tagged with the entry value.
1039+
commitTags []string
1040+
// goplsGoMod specifies the content of gopls/go.mod in x/tools' master
1041+
// branch before the flow execution.
1042+
goplsGoMod string
1043+
semv semversion
1044+
1045+
// The fields below are the desired states.
1046+
// wantPrereleaseTag is the expected prerelease tag in x/tools repo
1047+
// associated with the final release tag.
1048+
wantPrereleaseTag string
1049+
// wantCommit controls whether a commit should be made to a particular
1050+
// branch in a specified repository.
1051+
wantCommit map[string]map[string]bool
1052+
// wantGoplsGoMod specifies the desired content of gopls/go.mod in x/tools'
1053+
// master branch after the flow execution.
1054+
wantGoplsGoMod string
1055+
}{
1056+
{
1057+
name: "release patch v0.16.3-pre.3, update vscode-go release and master branch",
1058+
commitTags: []string{"gopls/v0.16.2", "gopls/v0.16.3-pre.1", "gopls/v0.16.3-pre.2", "gopls/v0.16.3-pre.3"},
1059+
goplsGoMod: "foo",
1060+
semv: semversion{Major: 0, Minor: 16, Patch: 3},
1061+
wantPrereleaseTag: "gopls/v0.16.3-pre.3",
1062+
wantCommit: map[string]map[string]bool{
1063+
"tools": {
1064+
"master": false, "gopls-release-branch.0.16": false,
1065+
},
1066+
"vscode-go": {
1067+
"master": true, "release-v0.44": true,
1068+
},
1069+
},
1070+
wantGoplsGoMod: "foo",
1071+
},
1072+
{
1073+
name: "release minor v0.17.0-pre.2, update vscode-go release and master branch, update tools gopls go.mod",
1074+
commitTags: []string{"gopls/v0.16.0", "gopls/v0.17.0-pre.1", "gopls/v0.17.0-pre.2"},
1075+
goplsGoMod: "foo",
1076+
semv: semversion{Major: 0, Minor: 17, Patch: 0},
1077+
wantPrereleaseTag: "gopls/v0.17.0-pre.2",
1078+
wantCommit: map[string]map[string]bool{
1079+
"tools": {
1080+
"master": true, "gopls-release-branch.0.17": false,
1081+
},
1082+
"vscode-go": {
1083+
"master": true, "release-v0.44": true,
1084+
},
1085+
},
1086+
wantGoplsGoMod: "bar",
1087+
},
1088+
{
1089+
name: "release minor v0.17.0-pre.2, update vscode-go release and master branch, skip update tools gopls go.mod",
1090+
commitTags: []string{"gopls/v0.16.0", "gopls/v0.17.0-pre.1", "gopls/v0.17.0-pre.2"},
1091+
goplsGoMod: "bar",
1092+
semv: semversion{Major: 0, Minor: 17, Patch: 0},
1093+
wantPrereleaseTag: "gopls/v0.17.0-pre.2",
1094+
wantCommit: map[string]map[string]bool{
1095+
"tools": {
1096+
"master": false, "gopls-release-branch.0.17": false,
1097+
},
1098+
"vscode-go": {
1099+
"master": true, "release-v0.44": true,
1100+
},
1101+
},
1102+
wantGoplsGoMod: "bar",
1103+
},
1104+
}
1105+
1106+
for _, tc := range testcases {
1107+
runTestWithInput := func(input map[string]any) {
1108+
ctx, cancel := context.WithCancel(context.Background())
1109+
defer cancel()
1110+
releaseBranch := goplsReleaseBranchName(tc.semv)
1111+
1112+
vscodego := NewFakeRepo(t, "vscode-go")
1113+
initial := vscodego.Commit(map[string]string{
1114+
"extension/src/goToolsInformation.ts": "foo", // arbitrary initial contents, to be mutated by the fakeGo script below
1115+
})
1116+
vscodego.Branch("release-v0.44", initial)
1117+
1118+
tools := NewFakeRepo(t, "tools")
1119+
initial = tools.Commit(map[string]string{
1120+
"gopls/go.mod": tc.goplsGoMod,
1121+
"gopls/go.sum": "\n",
1122+
})
1123+
tools.Branch(releaseBranch, initial)
1124+
for i, tag := range tc.commitTags {
1125+
commit := tools.CommitOnBranch(releaseBranch, map[string]string{
1126+
"README.md": fmt.Sprintf("THIS IS READ ME FOR %v.", i),
1127+
})
1128+
if tag != "" {
1129+
tools.Tag(tag, commit)
1130+
}
1131+
}
1132+
1133+
gerrit := NewFakeGerrit(t, tools, vscodego)
1134+
1135+
// Var before records the initial state of the branch head prior to
1136+
// executing the release flow.
1137+
before := map[string]map[string]string{}
1138+
for repo := range tc.wantCommit {
1139+
if _, ok := before[repo]; !ok {
1140+
before[repo] = map[string]string{}
1141+
}
1142+
for branch := range tc.wantCommit[repo] {
1143+
commit, err := gerrit.ReadBranchHead(ctx, repo, branch)
1144+
if err != nil {
1145+
t.Fatal(err)
1146+
}
1147+
before[repo][branch] = commit
1148+
}
1149+
}
1150+
1151+
// fakeGo handles multiple arguments in gopls release flow:
1152+
// - go get will write "bar" content to gopls/go.mod in x/tools master
1153+
// branch to simulate the dependency upgrade.
1154+
// - go mod will exit without error.
1155+
// - go run will write "bar" content to file in vscode-go project
1156+
// containing gopls versions.
1157+
var fakeGo = fmt.Sprintf(`#!/bin/bash -exu
1158+
1159+
case "$1" in
1160+
"get")
1161+
echo -n "bar" > go.mod
1162+
exit 0
1163+
;;
1164+
"mod")
1165+
exit 0
1166+
;;
1167+
"run")
1168+
# Only update the goToolsInformation.ts if runs generate.go.
1169+
for param in "$@:2"; do
1170+
if [[ $param == *"generate.go"* ]]; then
1171+
echo -n "bar" > extension/src/goToolsInformation.ts
1172+
fi
1173+
done
1174+
exit 0
1175+
;;
1176+
*)
1177+
echo unexpected command $@
1178+
exit 1
1179+
;;
1180+
esac
1181+
`)
1182+
1183+
tasks := &ReleaseGoplsTasks{
1184+
Gerrit: gerrit,
1185+
CloudBuild: NewFakeCloudBuild(t, gerrit, "", nil, fakeGo),
1186+
Github: &FakeGitHub{
1187+
Milestones: map[int]string{
1188+
1: fmt.Sprintf("gopls/v%v.%v.%v", tc.semv.Major, tc.semv.Minor, tc.semv.Patch),
1189+
},
1190+
Issues: map[int]*github.Issue{
1191+
1: {
1192+
Number: github.Int(1),
1193+
Title: github.String(fmt.Sprintf("x/tools/gopls: release version v%v.%v.%v", tc.semv.Major, tc.semv.Minor, tc.semv.Patch)),
1194+
Milestone: &github.Milestone{ID: github.Int64(1)},
1195+
},
1196+
},
1197+
},
1198+
ApproveAction: func(tc *workflow.TaskContext) error { return nil },
1199+
}
1200+
1201+
wd := tasks.NewReleaseDefinition()
1202+
w, err := workflow.Start(wd, input)
1203+
if err != nil {
1204+
t.Fatal(err)
1205+
}
1206+
1207+
_, err = w.Run(ctx, &verboseListener{t: t})
1208+
if err != nil {
1209+
t.Fatal(err)
1210+
}
1211+
1212+
// Verify that the expected commits were made to each repository's branches.
1213+
// Ensure no unexpected commits were merged.
1214+
for repo := range tc.wantCommit {
1215+
for branch, wantCommit := range tc.wantCommit[repo] {
1216+
afterHead, err := gerrit.ReadBranchHead(ctx, repo, branch)
1217+
if err != nil {
1218+
t.Fatal(err)
1219+
}
1220+
beforeHead := before[repo][branch]
1221+
1222+
// The branch head commit should not change after the process runs.
1223+
if !wantCommit {
1224+
if afterHead != beforeHead {
1225+
t.Errorf("repo %s branch %s should not have any commit, before head %s, after head %s", repo, branch, beforeHead, afterHead)
1226+
}
1227+
continue
1228+
}
1229+
1230+
// The branch head should advance to the next commit.
1231+
var gitHistory []string
1232+
switch repo {
1233+
case "tools":
1234+
gitHistory = tools.History()
1235+
case "vscode-go":
1236+
gitHistory = vscodego.History()
1237+
default:
1238+
t.Fatal(fmt.Errorf("unexpected repo name %q", repo))
1239+
}
1240+
var beforeIndex, afterIndex int
1241+
for i, commit := range gitHistory {
1242+
if commit == beforeHead {
1243+
beforeIndex = i
1244+
}
1245+
if commit == afterHead {
1246+
afterIndex = i
1247+
}
1248+
}
1249+
1250+
if beforeIndex-afterIndex != 1 {
1251+
t.Errorf("the repo %s branch %s should have exactly one commit merged, before head %s, after head %s, history %v", repo, branch, beforeHead, afterHead, gitHistory)
1252+
}
1253+
}
1254+
}
1255+
1256+
// Verify the release tag exists and matches the expected prerelease tag.
1257+
wantCommit, err := gerrit.GetTag(ctx, "tools", tc.wantPrereleaseTag)
1258+
if err != nil {
1259+
t.Fatalf("can not get the commit for tag %s", tc.wantPrereleaseTag)
1260+
}
1261+
gotCommit, err := gerrit.GetTag(ctx, "tools", fmt.Sprintf("gopls/v%v.%v.%v", tc.semv.Major, tc.semv.Minor, tc.semv.Patch))
1262+
if err != nil {
1263+
t.Errorf("can not get the commit for tag %s", fmt.Sprintf("gopls/v%v.%v.%v", tc.semv.Major, tc.semv.Minor, tc.semv.Patch))
1264+
}
1265+
if wantCommit.Revision != gotCommit.Revision {
1266+
t.Errorf("the flow create release tag upon commit %s, but should tag on commit %s which have tag %s", gotCommit.Revision, wantCommit.Revision, tc.wantPrereleaseTag)
1267+
}
1268+
1269+
// Verify the content of following files are expected.
1270+
contentChecks := []struct {
1271+
repo string
1272+
branch string
1273+
path string
1274+
want string
1275+
}{
1276+
{
1277+
repo: "tools",
1278+
branch: "master",
1279+
path: "gopls/go.mod",
1280+
want: tc.wantGoplsGoMod,
1281+
},
1282+
{
1283+
repo: "vscode-go",
1284+
branch: "master",
1285+
path: "extension/src/goToolsInformation.ts",
1286+
want: "bar",
1287+
},
1288+
{
1289+
repo: "vscode-go",
1290+
branch: "release-v0.44",
1291+
path: "extension/src/goToolsInformation.ts",
1292+
want: "bar",
1293+
},
1294+
}
1295+
for _, check := range contentChecks {
1296+
commit, err := gerrit.ReadBranchHead(ctx, check.repo, check.branch)
1297+
if err != nil {
1298+
t.Fatal(err)
1299+
}
1300+
got, err := gerrit.ReadFile(ctx, check.repo, commit, check.path)
1301+
if err != nil {
1302+
t.Fatal(err)
1303+
}
1304+
if string(got) != check.want {
1305+
t.Errorf("Content of %q = %q, want %q", check.path, got, check.want)
1306+
}
1307+
}
1308+
}
1309+
t.Run("manual input version: "+tc.name, func(t *testing.T) {
1310+
runTestWithInput(map[string]any{
1311+
reviewersParam.Name: []string(nil),
1312+
"explicit version (optional)": fmt.Sprintf("v%v.%v.%v", tc.semv.Major, tc.semv.Minor, tc.semv.Patch),
1313+
"next version": "use explicit version",
1314+
})
1315+
})
1316+
versionBump := "next patch"
1317+
if tc.semv.Patch == 0 {
1318+
versionBump = "next minor"
1319+
}
1320+
t.Run("interpret version "+versionBump+": "+tc.name, func(t *testing.T) {
1321+
runTestWithInput(map[string]any{
1322+
reviewersParam.Name: []string(nil),
1323+
"explicit version (optional)": "",
1324+
"next version": versionBump,
1325+
})
1326+
})
1327+
}
1328+
}

0 commit comments

Comments
 (0)