@@ -14,39 +14,7 @@ import (
14
14
"golang.org/x/oauth2"
15
15
)
16
16
17
- func main () {
18
- if err := generate (context .Background ()); err != nil {
19
- log .Fatal (err )
20
- }
21
- }
22
-
23
- func generate (ctx context.Context ) error {
24
- allReleases , err := fetchAllReleases (ctx )
25
- if err != nil {
26
- return fmt .Errorf ("failed to fetch all releases: %w" , err )
27
- }
28
-
29
- cfg , err := buildConfig (allReleases )
30
- if err != nil {
31
- return fmt .Errorf ("failed to build config: %w" , err )
32
- }
33
-
34
- if len (os .Args ) != 2 { //nolint:gomnd
35
- return fmt .Errorf ("usage: go run .../main.go out-path.json" )
36
- }
37
- outFile , err := os .Create (os .Args [1 ])
38
- if err != nil {
39
- return fmt .Errorf ("failed to create output config file: %w" , err )
40
- }
41
- defer outFile .Close ()
42
- enc := json .NewEncoder (outFile )
43
- enc .SetIndent ("" , " " )
44
- if err = enc .Encode (cfg ); err != nil {
45
- return fmt .Errorf ("failed to json encode config: %w" , err )
46
- }
47
-
48
- return nil
49
- }
17
+ const noPatch = - 1
50
18
51
19
type logInfo struct {
52
20
Warning string `json:",omitempty"`
@@ -72,79 +40,142 @@ type version struct {
72
40
73
41
func (v version ) String () string {
74
42
ret := fmt .Sprintf ("v%d.%d" , v .major , v .minor )
43
+
75
44
if v .patch != noPatch {
76
45
ret += fmt .Sprintf (".%d" , v .patch )
77
46
}
47
+
78
48
return ret
79
49
}
80
50
81
- func (v * version ) isAfterOrEq (vv * version ) bool {
51
+ func (v version ) isAfterOrEq (vv * version ) bool {
82
52
if v .major != vv .major {
83
53
return v .major >= vv .major
84
54
}
55
+
85
56
if v .minor != vv .minor {
86
57
return v .minor >= vv .minor
87
58
}
88
59
89
60
return v .patch >= vv .patch
90
61
}
91
62
92
- const noPatch = - 1
63
+ type release struct {
64
+ TagName string
65
+ ReleaseAssets struct {
66
+ Nodes []releaseAsset
67
+ } `graphql:"releaseAssets(first: 50)"`
68
+ }
93
69
94
- func parseVersion (s string ) (* version , error ) {
95
- const vPrefix = "v"
96
- if ! strings .HasPrefix (s , vPrefix ) {
97
- return nil , fmt .Errorf ("version should start with %q" , vPrefix )
70
+ type releaseAsset struct {
71
+ DownloadURL string
72
+ }
73
+
74
+ func main () {
75
+ if err := generate (context .Background ()); err != nil {
76
+ log .Fatal (err )
98
77
}
99
- s = strings . TrimPrefix ( s , vPrefix )
78
+ }
100
79
101
- parts := strings .Split (s , "." )
80
+ func generate (ctx context.Context ) error {
81
+ if len (os .Args ) != 2 {
82
+ return fmt .Errorf ("usage: go run .../main.go out-path.json" )
83
+ }
102
84
103
- var nums []int
104
- for _ , part := range parts {
105
- num , err := strconv .Atoi (part )
106
- if err != nil {
107
- return nil , fmt .Errorf ("failed to parse version part: %w" , err )
108
- }
109
- nums = append (nums , num )
85
+ allReleases , err := fetchAllReleases (ctx )
86
+ if err != nil {
87
+ return fmt .Errorf ("failed to fetch all releases: %w" , err )
110
88
}
111
89
112
- if len (nums ) == 2 { //nolint:gomnd
113
- return & version {major : nums [0 ], minor : nums [1 ], patch : noPatch }, nil
90
+ cfg , err := buildConfig (allReleases )
91
+ if err != nil {
92
+ return fmt .Errorf ("failed to build config: %w" , err )
114
93
}
115
- if len (nums ) == 3 { //nolint:gomnd
116
- return & version {major : nums [0 ], minor : nums [1 ], patch : nums [2 ]}, nil
94
+
95
+ outFile , err := os .Create (os .Args [1 ])
96
+ if err != nil {
97
+ return fmt .Errorf ("failed to create output config file: %w" , err )
117
98
}
118
99
119
- return nil , errors .New ("invalid version format" )
100
+ defer outFile .Close ()
101
+
102
+ enc := json .NewEncoder (outFile )
103
+ enc .SetIndent ("" , " " )
104
+
105
+ if err = enc .Encode (cfg ); err != nil {
106
+ return fmt .Errorf ("failed to json encode config: %w" , err )
107
+ }
108
+
109
+ return nil
120
110
}
121
111
122
- func findLinuxAssetURL (ver * version , releaseAssets []releaseAsset ) (string , error ) {
123
- pattern := fmt .Sprintf ("golangci-lint-%d.%d.%d-linux-amd64.tar.gz" , ver .major , ver .minor , ver .patch )
124
- for _ , relAsset := range releaseAssets {
125
- if strings .HasSuffix (relAsset .DownloadURL , pattern ) {
126
- return relAsset .DownloadURL , nil
112
+ func fetchAllReleases (ctx context.Context ) ([]release , error ) {
113
+ githubToken := os .Getenv ("GITHUB_TOKEN" )
114
+ if githubToken == "" {
115
+ return nil , errors .New ("no GITHUB_TOKEN environment variable" )
116
+ }
117
+
118
+ client := githubv4 .NewClient (oauth2 .NewClient (ctx , oauth2 .StaticTokenSource (& oauth2.Token {AccessToken : githubToken })))
119
+
120
+ var q struct {
121
+ Repository struct {
122
+ Releases struct {
123
+ Nodes []release
124
+ PageInfo struct {
125
+ EndCursor githubv4.String
126
+ HasNextPage bool
127
+ }
128
+ } `graphql:"releases(first: 100, orderBy: { field: CREATED_AT, direction: DESC }, after: $releasesCursor)"`
129
+ } `graphql:"repository(owner: $owner, name: $name)"`
130
+ }
131
+
132
+ vars := map [string ]any {
133
+ "owner" : githubv4 .String ("golangci" ),
134
+ "name" : githubv4 .String ("golangci-lint" ),
135
+ "releasesCursor" : (* githubv4 .String )(nil ),
136
+ }
137
+
138
+ var allReleases []release
139
+ for {
140
+ err := client .Query (ctx , & q , vars )
141
+ if err != nil {
142
+ return nil , fmt .Errorf ("failed to fetch releases page from GitHub: %w" , err )
127
143
}
144
+
145
+ releases := q .Repository .Releases
146
+ allReleases = append (allReleases , releases .Nodes ... )
147
+
148
+ if ! releases .PageInfo .HasNextPage {
149
+ break
150
+ }
151
+
152
+ vars ["releasesCursor" ] = githubv4 .NewString (releases .PageInfo .EndCursor )
128
153
}
129
- return "" , fmt .Errorf ("no matched asset url for pattern %q" , pattern )
154
+
155
+ return allReleases , nil
130
156
}
131
157
132
158
func buildConfig (releases []release ) (* actionConfig , error ) {
133
159
versionToRelease := map [version ]release {}
160
+
134
161
for _ , rel := range releases {
135
162
ver , err := parseVersion (rel .TagName )
136
163
if err != nil {
137
164
return nil , fmt .Errorf ("failed to parse release %s version: %w" , rel .TagName , err )
138
165
}
166
+
139
167
if _ , ok := versionToRelease [* ver ]; ok {
140
168
return nil , fmt .Errorf ("duplicate release %s" , rel .TagName )
141
169
}
170
+
142
171
versionToRelease [* ver ] = rel
143
172
}
144
173
145
174
maxPatchReleases := map [string ]version {}
175
+
146
176
for ver := range versionToRelease {
147
177
key := fmt .Sprintf ("v%d.%d" , ver .major , ver .minor )
178
+
148
179
if mapVer , ok := maxPatchReleases [key ]; ! ok || ver .isAfterOrEq (& mapVer ) {
149
180
maxPatchReleases [key ] = ver
150
181
}
@@ -155,6 +186,7 @@ func buildConfig(releases []release) (*actionConfig, error) {
155
186
156
187
latestVersion := version {}
157
188
latestVersionConfig := versionConfig {}
189
+
158
190
for minorVersionedStr , maxPatchVersion := range maxPatchReleases {
159
191
if ! maxPatchVersion .isAfterOrEq (& minAllowedVersion ) {
160
192
minorVersionToConfig [minorVersionedStr ] = versionConfig {
@@ -163,77 +195,67 @@ func buildConfig(releases []release) (*actionConfig, error) {
163
195
}
164
196
continue
165
197
}
198
+
166
199
maxPatchVersion := maxPatchVersion
200
+
167
201
assetURL , err := findLinuxAssetURL (& maxPatchVersion , versionToRelease [maxPatchVersion ].ReleaseAssets .Nodes )
168
202
if err != nil {
169
203
return nil , fmt .Errorf ("failed to find linux asset url for release %s: %w" , maxPatchVersion , err )
170
204
}
205
+
171
206
minorVersionToConfig [minorVersionedStr ] = versionConfig {
172
207
TargetVersion : maxPatchVersion .String (),
173
208
AssetURL : assetURL ,
174
209
}
210
+
175
211
if maxPatchVersion .isAfterOrEq (& latestVersion ) {
176
212
latestVersion = maxPatchVersion
177
213
latestVersionConfig .TargetVersion = maxPatchVersion .String ()
178
214
latestVersionConfig .AssetURL = assetURL
179
215
}
180
216
}
217
+
181
218
minorVersionToConfig ["latest" ] = latestVersionConfig
182
219
183
220
return & actionConfig {MinorVersionToConfig : minorVersionToConfig }, nil
184
221
}
185
222
186
- type release struct {
187
- TagName string
188
- ReleaseAssets struct {
189
- Nodes []releaseAsset
190
- } `graphql:"releaseAssets(first: 50)"`
191
- }
192
-
193
- type releaseAsset struct {
194
- DownloadURL string
195
- }
223
+ func findLinuxAssetURL (ver * version , releaseAssets []releaseAsset ) (string , error ) {
224
+ pattern := fmt .Sprintf ("golangci-lint-%d.%d.%d-linux-amd64.tar.gz" , ver .major , ver .minor , ver .patch )
196
225
197
- func fetchAllReleases ( ctx context. Context ) ([] release , error ) {
198
- githubToken := os . Getenv ( "GITHUB_TOKEN" )
199
- if githubToken == "" {
200
- return nil , errors . New ( "no GITHUB_TOKEN environment variable" )
226
+ for _ , relAsset := range releaseAssets {
227
+ if strings . HasSuffix ( relAsset . DownloadURL , pattern ) {
228
+ return relAsset . DownloadURL , nil
229
+ }
201
230
}
202
- src := oauth2 .StaticTokenSource (& oauth2.Token {AccessToken : githubToken })
203
- httpClient := oauth2 .NewClient (ctx , src )
204
- client := githubv4 .NewClient (httpClient )
205
231
206
- var q struct {
207
- Repository struct {
208
- Releases struct {
209
- Nodes []release
210
- PageInfo struct {
211
- EndCursor githubv4.String
212
- HasNextPage bool
213
- }
214
- } `graphql:"releases(first: 100, orderBy: { field: CREATED_AT, direction: DESC }, after: $releasesCursor)"`
215
- } `graphql:"repository(owner: $owner, name: $name)"`
216
- }
232
+ return "" , fmt .Errorf ("no matched asset url for pattern %q" , pattern )
233
+ }
217
234
218
- vars := map [ string ] any {
219
- "owner" : githubv4 . String ( "golangci" ),
220
- "name" : githubv4 . String ( "golangci-lint" ),
221
- "releasesCursor" : ( * githubv4 . String )( nil ),
235
+ func parseVersion ( s string ) ( * version , error ) {
236
+ const vPrefix = "v"
237
+ if ! strings . HasPrefix ( s , vPrefix ) {
238
+ return nil , fmt . Errorf ( "version %q should start with %q" , s , vPrefix )
222
239
}
223
240
224
- var allReleases []release
225
- for {
226
- err := client .Query (ctx , & q , vars )
241
+ parts := strings .Split (strings .TrimPrefix (s , vPrefix ), "." )
242
+
243
+ var nums []int
244
+ for _ , part := range parts {
245
+ num , err := strconv .Atoi (part )
227
246
if err != nil {
228
- return nil , fmt .Errorf ("failed to fetch releases page from GitHub : %w" , err )
247
+ return nil , fmt .Errorf ("failed to parse version %q : %w" , s , err )
229
248
}
230
- releases := q .Repository .Releases
231
- allReleases = append (allReleases , releases .Nodes ... )
232
- if ! releases .PageInfo .HasNextPage {
233
- break
234
- }
235
- vars ["releasesCursor" ] = githubv4 .NewString (releases .PageInfo .EndCursor )
249
+
250
+ nums = append (nums , num )
236
251
}
237
252
238
- return allReleases , nil
253
+ switch len (nums ) {
254
+ case 2 :
255
+ return & version {major : nums [0 ], minor : nums [1 ], patch : noPatch }, nil
256
+ case 3 :
257
+ return & version {major : nums [0 ], minor : nums [1 ], patch : nums [2 ]}, nil
258
+ default :
259
+ return nil , fmt .Errorf ("invalid version format: %s" , s )
260
+ }
239
261
}
0 commit comments