-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
github.go
302 lines (257 loc) · 8.77 KB
/
github.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
package github
// notes:
// looks like the github graphql api needs an auth token, no matter which data you query
// the REST API allows some the tags endpoint to be queried without an auth token
import (
"encoding/json"
"io/ioutil"
"net/http"
"strings"
"time"
log "github.com/sirupsen/logrus"
)
// Commit has basic commit info: url and sha
type Commit struct {
SHA string `json:"sha"`
URL string `json:"url"`
}
// Tags has details of a tag in a repo
type Tags struct {
Name string `json:"name"`
ZipballURL string `json:"zipball_url"`
TarballURL string `json:"tarball_url"`
Commit Commit `json:"commit"`
NodeID string `json:"node_id"`
}
// Asset details a file assosociated with a release
type Asset struct {
URL string `json:"url"`
ID int64 `json:"id"`
NodeID string `json:"node_id"`
Name string `json:"name"`
Label string `json:"label"`
Uploader Author `json:"uploader"`
ContentType string `json:"content_type"`
State string `json:"state"`
Size int64 `json:"size"`
DownloadCount int64 `json:"download_count"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
BrowserDownloadURL string `json:"browser_download_url"`
}
// Author has details about the author of a commit
type Author struct {
Login string `json:"login"`
ID int64 `json:"id"`
NodeID string `json:"node_id"`
AvatarURL string `json:"avatar_url"`
GravatarID string `json:"gravatar_id"`
URL string `json:"url"`
HTMLURL string `json:"html_url"`
FollowersURL string `json:"followers_url"`
FollowingURL string `json:"following_url"`
GistsURL string `json:"gists_url"`
StarredURL string `json:"starred_url"`
SubscriptionsURL string `json:"subscriptions_url"`
OrganizationsURL string `json:"organizations_url"`
ReposURL string `json:"repos_url"`
EventsURL string `json:"events_url"`
ReceivedEventsURL string `json:"received_events_url"`
Type string `json:"type"`
SiteAdmin bool `json:"site_admin"`
}
// Release has details of a release for a repo
type Release struct {
URL string `json:"url"`
AssetsURL string `json:"assets_url"`
UploadURL string `json:"upload_url"`
HTMLURL string `json:"html_url"`
ID int64 `json:"id"`
NodeID string `json:"node_id"`
TagName string `json:"tag_name"`
TargetCommitish string `json:"target_commitish"`
Name string `json:"name"`
Draft bool `json:"draft"`
Author Author `json:"author"`
Prerelease bool `json:"prerelease"`
CreatedAt string `json:"created_at"`
PublishedAt string `json:"published_at"`
Assets []Asset `json:"assets"`
}
// GetRepoReleases will return a list of all the releases for a given repo
func GetRepoReleases(owner string, repo string) (repoReleases []Release, err error) {
// get all releases, 100 at a time
// paginate through results if more than 100
apiURL := "https://api.github.com/repos/" + owner + "/" + repo + "/releases?page=1&per_page=100"
for len(apiURL) > 0 {
data, headers, err := makeRepoReleasesRequest(apiURL)
if err != nil {
return nil, err
}
// following caching headers are available: ETag & Cache-Control
// following rate limiting headers are available: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
// extract the release data
// format: array of 'release' structs
// e.g. v1.17.1-alpha1+k3s1 (note releases before 2020 have different format)
// extract the release data
var releases []Release
err = json.Unmarshal([]byte(data), &releases)
if err != nil {
return repoReleases, err
}
// add each release to array that will be returned
repoReleases = append(repoReleases, releases...)
// reset API URL - will only set again if there are more pages to load
apiURL = ""
// see if there are more releases
linkHeader := headers.Get("Link")
links := strings.Split(linkHeader, ",")
for _, linkInfo := range links {
linkFields := strings.Split(linkInfo, ";")
link := linkFields[0]
linkType := strings.TrimSpace(linkFields[1])
if strings.Compare(linkType, "rel=\"next\"") == 0 {
apiURL = strings.Trim(link, " <>")
}
}
}
return repoReleases, err
}
// GetVersionUsingREST will get the versions of k3s available on github
func GetVersionUsingREST() []string {
var k3sReleases []string
apiURL := "https://api.github.com/repos/rancher/k3s/releases?page=1&per_page=100"
for len(apiURL) > 0 {
data, headers, err := makeRepoReleasesRequest(apiURL)
if err != nil {
return nil
}
// following headers are available if we need them
// header := response.Header.Get("ETag")
// header = response.Header.Get("Cache-Control")
// header = response.Header.Get("Bla")
// header = response.Header.Get("X-Github-Media-Type")
// header = response.Header.Get("X-RateLimit-Limit")
// header = response.Header.Get("X-RateLimit-Remaining")
// header = response.Header.Get("X-RateLimit-Reset")
// extract the release data
// format: v1.17.1-alpha1+k3s1 (note releases before 2020 have different format)
var releases []Release
err = json.Unmarshal([]byte(data), &releases)
if err != nil {
return nil
}
log.Debug(len(releases))
for _, release := range releases {
tagName := release.TagName
// releaseName := release.Name // older releases have this blank
// parse release name
fields := strings.Split(tagName, "+")
// releaseParts[1] should always be 'k3s1'
releaseParts := strings.Split(fields[0], "-")
if len(releaseParts) == 1 {
// only want final releases
// ideally want to sort into streams 1.16, 1.17, etc
// split by major.minor
k3sReleases = append(k3sReleases, releaseParts[0])
// } else {
// ignore non-final releases
// log.Debug("ignoring", releaseParts[0], releaseParts[1])
}
}
apiURL = ""
// see if there are more releases
linkHeader := headers.Get("Link")
links := strings.Split(linkHeader, ",")
for _, linkInfo := range links {
linkFields := strings.Split(linkInfo, ";")
link := linkFields[0]
linkType := strings.TrimSpace(linkFields[1])
if strings.Compare(linkType, "rel=\"next\"") == 0 {
log.Debug(link)
apiURL = strings.Trim(link, "<>")
}
}
}
// return an map with 'major release' as key
return k3sReleases
}
// GetVersions will return a list of k3s versions that can be downloaded
// func getVersionsUsingGraphQL() bool {
// // need to use github api
// // note, we will be unauthenticated and have a rate limit of 60/hour
// jsonData := map[string]string{
// "query": `
// {
// rateLimit {
// limit
// cost
// remaining
// resetAt
// }
// repository(owner:"rancher", name: "k3s") {
// refs(refPrefix: "refs/tags/", last: 1) {
// nodes {
// repository {
// releases(first:1, orderBy: {field: CREATED_AT, direction: DESC}) {
// nodes {
// name
// createdAt
// url
// releaseAssets(last: 4) {
// nodes {
// name
// downloadCount
// downloadUrl
// }
// }
// }
// }
// }
// }
// }
// }
// }
// `,
// }
// jsonValue, _ := json.Marshal(jsonData)
// request, err := http.NewRequest("POST", "https://api.github.com/graphql", bytes.NewBuffer(jsonValue))
// client := &http.Client{Timeout: time.Second * 10}
// response, err := client.Do(request)
// if err != nil {
// msg := fmt.Sprintf("The HTTP request failed with error %s\n", err)
// log.Error(msg)
// }
// defer response.Body.Close()
// data, _ := ioutil.ReadAll(response.Body)
// fmt.Println(string(data))
// // need parse json that came back
// fmt.Println("Please format response")
// return true
// }
// makeRepoReleasesRequest will get release info for the repo
func makeRepoReleasesRequest(apiURL string) (data []byte, headers http.Header, err error) {
// setup api request
request, err := http.NewRequest("GET", apiURL, nil)
if err != nil {
return nil, nil, err
}
request.Header.Add("User-agent", "eezhee")
request.Header.Add("Accept", "application/vnd.github.v3+json")
// make the api request
client := &http.Client{Timeout: time.Second * 10}
response, err := client.Do(request)
if err != nil {
log.Error("The HTTP request failed with error", err)
return data, headers, err
}
defer response.Body.Close()
// get relase data
data, err = ioutil.ReadAll(response.Body)
if err != nil {
return data, headers, err
}
// get headers
headers = response.Header
return data, headers, err
}