9
9
"slices"
10
10
"strings"
11
11
12
+ "golang.org/x/build/gerrit"
12
13
wf "golang.org/x/build/internal/workflow"
13
14
"golang.org/x/mod/semver"
14
15
)
@@ -26,36 +27,71 @@ func (r *ReleaseGoplsTasks) NewDefinition() *wf.Definition {
26
27
// TODO(hxjiang): provide potential release versions in the relui where the
27
28
// coordinator can choose which version to release instead of manual input.
28
29
version := wf .Param (wd , wf.ParamDef [string ]{Name : "version" })
29
- isValid := wf .Task1 (wd , "validating input version" , r .isValidVersion , version )
30
- wf .Output (wd , "valid " , isValid )
30
+ semversion := wf .Task1 (wd , "validating input version" , r .isValidVersion , version )
31
+ _ = wf .Action1 (wd , "creating new branch if minor release " , r . createBranchIfMinor , semversion )
31
32
return wd
32
33
}
33
34
34
- func (r * ReleaseGoplsTasks ) isValidVersion (ctx * wf.TaskContext , ver string ) (bool , error ) {
35
+ // createBranchIfMinor create the release branch if the input version is a minor
36
+ // release.
37
+ // All patch releases under the same minor version share the same release branch.
38
+ func (r * ReleaseGoplsTasks ) createBranchIfMinor (ctx * wf.TaskContext , semv semversion ) error {
39
+ branch := fmt .Sprintf ("gopls-release-branch.%v.%v" , semv .Major , semv .Minor )
40
+
41
+ // Require gopls release branch existence if this is a non-minor release.
42
+ if semv .Patch != 0 {
43
+ _ , err := r .Gerrit .ReadBranchHead (ctx , "tools" , branch )
44
+ return err
45
+ }
46
+
47
+ // Return early if the branch already exist.
48
+ // This scenario should only occur if the initial minor release flow failed
49
+ // or was interrupted and subsequently re-triggered.
50
+ if _ , err := r .Gerrit .ReadBranchHead (ctx , "tools" , branch ); err == nil {
51
+ return nil
52
+ }
53
+
54
+ // Create the release branch using the revision from the head of master branch.
55
+ head , err := r .Gerrit .ReadBranchHead (ctx , "tools" , "master" )
56
+ if err != nil {
57
+ return err
58
+ }
59
+
60
+ ctx .Printf ("Creating branch %s at revision %s.\n " , branch , head )
61
+ _ , err = r .Gerrit .CreateBranch (ctx , "tools" , branch , gerrit.BranchInput {Revision : head })
62
+ return err
63
+ }
64
+
65
+ func (r * ReleaseGoplsTasks ) isValidVersion (ctx * wf.TaskContext , ver string ) (semversion , error ) {
35
66
if ! semver .IsValid (ver ) {
36
- return false , nil
67
+ return semversion {}, fmt . Errorf ( "the input %q version does not follow semantic version schema" , ver )
37
68
}
38
69
39
70
versions , err := r .possibleGoplsVersions (ctx )
40
71
if err != nil {
41
- return false , fmt .Errorf ("failed to get latest Gopls version tags from x/tool: %w" , err )
72
+ return semversion {}, fmt .Errorf ("failed to get latest Gopls version tags from x/tool: %w" , err )
73
+ }
74
+
75
+ if ! slices .Contains (versions , ver ) {
76
+ return semversion {}, fmt .Errorf ("the input %q is not next version of any existing versions" , ver )
42
77
}
43
78
44
- return slices .Contains (versions , ver ), nil
79
+ semver , _ := parseSemver (ver )
80
+ return semver , nil
45
81
}
46
82
47
83
// semversion is a parsed semantic version.
48
84
type semversion struct {
49
- major , minor , patch int
50
- pre string
85
+ Major , Minor , Patch int
86
+ Pre string
51
87
}
52
88
53
89
// parseSemver attempts to parse semver components out of the provided semver
54
90
// v. If v is not valid semver in canonical form, parseSemver returns false.
55
91
func parseSemver (v string ) (_ semversion , ok bool ) {
56
92
var parsed semversion
57
- v , parsed .pre , _ = strings .Cut (v , "-" )
58
- if _ , err := fmt .Sscanf (v , "v%d.%d.%d" , & parsed .major , & parsed .minor , & parsed .patch ); err == nil {
93
+ v , parsed .Pre , _ = strings .Cut (v , "-" )
94
+ if _ , err := fmt .Sscanf (v , "v%d.%d.%d" , & parsed .Major , & parsed .Minor , & parsed .Patch ); err == nil {
59
95
ok = true
60
96
}
61
97
return parsed , ok
@@ -89,32 +125,32 @@ func (r *ReleaseGoplsTasks) possibleGoplsVersions(ctx *wf.TaskContext) ([]string
89
125
semv , ok := parseSemver (v )
90
126
semVersions = append (semVersions , semv )
91
127
92
- if majorMinorPatch [semv .major ] == nil {
93
- majorMinorPatch [semv .major ] = map [int ]map [int ]bool {}
128
+ if majorMinorPatch [semv .Major ] == nil {
129
+ majorMinorPatch [semv .Major ] = map [int ]map [int ]bool {}
94
130
}
95
- if majorMinorPatch [semv.major ][semv.minor ] == nil {
96
- majorMinorPatch [semv.major ][semv.minor ] = map [int ]bool {}
131
+ if majorMinorPatch [semv.Major ][semv.Minor ] == nil {
132
+ majorMinorPatch [semv.Major ][semv.Minor ] = map [int ]bool {}
97
133
}
98
- majorMinorPatch [semv.major ][semv.minor ][semv .patch ] = true
134
+ majorMinorPatch [semv.Major ][semv.Minor ][semv .Patch ] = true
99
135
}
100
136
101
137
var possible []string
102
138
seen := map [string ]bool {}
103
139
for _ , v := range semVersions {
104
- nextMajor := fmt .Sprintf ("v%d.%d.%d" , v .major + 1 , 0 , 0 )
105
- if _ , ok := majorMinorPatch [v .major + 1 ]; ! ok && ! seen [nextMajor ] {
140
+ nextMajor := fmt .Sprintf ("v%d.%d.%d" , v .Major + 1 , 0 , 0 )
141
+ if _ , ok := majorMinorPatch [v .Major + 1 ]; ! ok && ! seen [nextMajor ] {
106
142
seen [nextMajor ] = true
107
143
possible = append (possible , nextMajor )
108
144
}
109
145
110
- nextMinor := fmt .Sprintf ("v%d.%d.%d" , v .major , v .minor + 1 , 0 )
111
- if _ , ok := majorMinorPatch [v .major ][v .minor + 1 ]; ! ok && ! seen [nextMinor ] {
146
+ nextMinor := fmt .Sprintf ("v%d.%d.%d" , v .Major , v .Minor + 1 , 0 )
147
+ if _ , ok := majorMinorPatch [v .Major ][v .Minor + 1 ]; ! ok && ! seen [nextMinor ] {
112
148
seen [nextMinor ] = true
113
149
possible = append (possible , nextMinor )
114
150
}
115
151
116
- nextPatch := fmt .Sprintf ("v%d.%d.%d" , v .major , v .minor , v .patch + 1 )
117
- if _ , ok := majorMinorPatch [v.major ][v.minor ][v .patch + 1 ]; ! ok && ! seen [nextPatch ] {
152
+ nextPatch := fmt .Sprintf ("v%d.%d.%d" , v .Major , v .Minor , v .Patch + 1 )
153
+ if _ , ok := majorMinorPatch [v.Major ][v.Minor ][v .Patch + 1 ]; ! ok && ! seen [nextPatch ] {
118
154
seen [nextPatch ] = true
119
155
possible = append (possible , nextPatch )
120
156
}
0 commit comments