@@ -531,6 +531,9 @@ func TestFindOrCreateReleaseIssue(t *testing.T) {
531
531
}
532
532
533
533
func TestGoplsPrereleaseFlow (t * testing.T ) {
534
+ if testing .Short () {
535
+ t .Skip ("skipping an end-to-end workflow test in short mode" )
536
+ }
534
537
mustHaveShell (t )
535
538
536
539
testcases := []struct {
@@ -1019,3 +1022,307 @@ echo -n "foo" > file_b
1019
1022
})
1020
1023
}
1021
1024
}
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