1
2
3
4
5
6 package github
7
8 import (
9 "context"
10 "errors"
11 "fmt"
12 "io"
13 "mime"
14 "net/http"
15 "os"
16 "path/filepath"
17 "strings"
18 )
19
20
21 type RepositoryRelease struct {
22 TagName *string `json:"tag_name,omitempty"`
23 TargetCommitish *string `json:"target_commitish,omitempty"`
24 Name *string `json:"name,omitempty"`
25 Body *string `json:"body,omitempty"`
26 Draft *bool `json:"draft,omitempty"`
27 Prerelease *bool `json:"prerelease,omitempty"`
28
29
30 ID *int64 `json:"id,omitempty"`
31 CreatedAt *Timestamp `json:"created_at,omitempty"`
32 PublishedAt *Timestamp `json:"published_at,omitempty"`
33 URL *string `json:"url,omitempty"`
34 HTMLURL *string `json:"html_url,omitempty"`
35 AssetsURL *string `json:"assets_url,omitempty"`
36 Assets []*ReleaseAsset `json:"assets,omitempty"`
37 UploadURL *string `json:"upload_url,omitempty"`
38 ZipballURL *string `json:"zipball_url,omitempty"`
39 TarballURL *string `json:"tarball_url,omitempty"`
40 Author *User `json:"author,omitempty"`
41 NodeID *string `json:"node_id,omitempty"`
42 }
43
44 func (r RepositoryRelease) String() string {
45 return Stringify(r)
46 }
47
48
49 type ReleaseAsset struct {
50 ID *int64 `json:"id,omitempty"`
51 URL *string `json:"url,omitempty"`
52 Name *string `json:"name,omitempty"`
53 Label *string `json:"label,omitempty"`
54 State *string `json:"state,omitempty"`
55 ContentType *string `json:"content_type,omitempty"`
56 Size *int `json:"size,omitempty"`
57 DownloadCount *int `json:"download_count,omitempty"`
58 CreatedAt *Timestamp `json:"created_at,omitempty"`
59 UpdatedAt *Timestamp `json:"updated_at,omitempty"`
60 BrowserDownloadURL *string `json:"browser_download_url,omitempty"`
61 Uploader *User `json:"uploader,omitempty"`
62 NodeID *string `json:"node_id,omitempty"`
63 }
64
65 func (r ReleaseAsset) String() string {
66 return Stringify(r)
67 }
68
69
70
71
72 func (s *RepositoriesService) ListReleases(ctx context.Context, owner, repo string, opts *ListOptions) ([]*RepositoryRelease, *Response, error) {
73 u := fmt.Sprintf("repos/%s/%s/releases", owner, repo)
74 u, err := addOptions(u, opts)
75 if err != nil {
76 return nil, nil, err
77 }
78
79 req, err := s.client.NewRequest("GET", u, nil)
80 if err != nil {
81 return nil, nil, err
82 }
83
84 var releases []*RepositoryRelease
85 resp, err := s.client.Do(ctx, req, &releases)
86 if err != nil {
87 return nil, resp, err
88 }
89 return releases, resp, nil
90 }
91
92
93
94
95 func (s *RepositoriesService) GetRelease(ctx context.Context, owner, repo string, id int64) (*RepositoryRelease, *Response, error) {
96 u := fmt.Sprintf("repos/%s/%s/releases/%d", owner, repo, id)
97 return s.getSingleRelease(ctx, u)
98 }
99
100
101
102
103 func (s *RepositoriesService) GetLatestRelease(ctx context.Context, owner, repo string) (*RepositoryRelease, *Response, error) {
104 u := fmt.Sprintf("repos/%s/%s/releases/latest", owner, repo)
105 return s.getSingleRelease(ctx, u)
106 }
107
108
109
110
111 func (s *RepositoriesService) GetReleaseByTag(ctx context.Context, owner, repo, tag string) (*RepositoryRelease, *Response, error) {
112 u := fmt.Sprintf("repos/%s/%s/releases/tags/%s", owner, repo, tag)
113 return s.getSingleRelease(ctx, u)
114 }
115
116 func (s *RepositoriesService) getSingleRelease(ctx context.Context, url string) (*RepositoryRelease, *Response, error) {
117 req, err := s.client.NewRequest("GET", url, nil)
118 if err != nil {
119 return nil, nil, err
120 }
121
122 release := new(RepositoryRelease)
123 resp, err := s.client.Do(ctx, req, release)
124 if err != nil {
125 return nil, resp, err
126 }
127 return release, resp, nil
128 }
129
130
131
132
133
134
135
136 type repositoryReleaseRequest struct {
137 TagName *string `json:"tag_name,omitempty"`
138 TargetCommitish *string `json:"target_commitish,omitempty"`
139 Name *string `json:"name,omitempty"`
140 Body *string `json:"body,omitempty"`
141 Draft *bool `json:"draft,omitempty"`
142 Prerelease *bool `json:"prerelease,omitempty"`
143 }
144
145
146
147
148
149
150
151 func (s *RepositoriesService) CreateRelease(ctx context.Context, owner, repo string, release *RepositoryRelease) (*RepositoryRelease, *Response, error) {
152 u := fmt.Sprintf("repos/%s/%s/releases", owner, repo)
153
154 releaseReq := &repositoryReleaseRequest{
155 TagName: release.TagName,
156 TargetCommitish: release.TargetCommitish,
157 Name: release.Name,
158 Body: release.Body,
159 Draft: release.Draft,
160 Prerelease: release.Prerelease,
161 }
162
163 req, err := s.client.NewRequest("POST", u, releaseReq)
164 if err != nil {
165 return nil, nil, err
166 }
167
168 r := new(RepositoryRelease)
169 resp, err := s.client.Do(ctx, req, r)
170 if err != nil {
171 return nil, resp, err
172 }
173 return r, resp, nil
174 }
175
176
177
178
179
180
181
182 func (s *RepositoriesService) EditRelease(ctx context.Context, owner, repo string, id int64, release *RepositoryRelease) (*RepositoryRelease, *Response, error) {
183 u := fmt.Sprintf("repos/%s/%s/releases/%d", owner, repo, id)
184
185 releaseReq := &repositoryReleaseRequest{
186 TagName: release.TagName,
187 TargetCommitish: release.TargetCommitish,
188 Name: release.Name,
189 Body: release.Body,
190 Draft: release.Draft,
191 Prerelease: release.Prerelease,
192 }
193
194 req, err := s.client.NewRequest("PATCH", u, releaseReq)
195 if err != nil {
196 return nil, nil, err
197 }
198
199 r := new(RepositoryRelease)
200 resp, err := s.client.Do(ctx, req, r)
201 if err != nil {
202 return nil, resp, err
203 }
204 return r, resp, nil
205 }
206
207
208
209
210 func (s *RepositoriesService) DeleteRelease(ctx context.Context, owner, repo string, id int64) (*Response, error) {
211 u := fmt.Sprintf("repos/%s/%s/releases/%d", owner, repo, id)
212
213 req, err := s.client.NewRequest("DELETE", u, nil)
214 if err != nil {
215 return nil, err
216 }
217 return s.client.Do(ctx, req, nil)
218 }
219
220
221
222
223 func (s *RepositoriesService) ListReleaseAssets(ctx context.Context, owner, repo string, id int64, opts *ListOptions) ([]*ReleaseAsset, *Response, error) {
224 u := fmt.Sprintf("repos/%s/%s/releases/%d/assets", owner, repo, id)
225 u, err := addOptions(u, opts)
226 if err != nil {
227 return nil, nil, err
228 }
229
230 req, err := s.client.NewRequest("GET", u, nil)
231 if err != nil {
232 return nil, nil, err
233 }
234
235 var assets []*ReleaseAsset
236 resp, err := s.client.Do(ctx, req, &assets)
237 if err != nil {
238 return nil, resp, err
239 }
240 return assets, resp, nil
241 }
242
243
244
245
246 func (s *RepositoriesService) GetReleaseAsset(ctx context.Context, owner, repo string, id int64) (*ReleaseAsset, *Response, error) {
247 u := fmt.Sprintf("repos/%s/%s/releases/assets/%d", owner, repo, id)
248
249 req, err := s.client.NewRequest("GET", u, nil)
250 if err != nil {
251 return nil, nil, err
252 }
253
254 asset := new(ReleaseAsset)
255 resp, err := s.client.Do(ctx, req, asset)
256 if err != nil {
257 return nil, resp, err
258 }
259 return asset, resp, nil
260 }
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275 func (s *RepositoriesService) DownloadReleaseAsset(ctx context.Context, owner, repo string, id int64, followRedirectsClient *http.Client) (rc io.ReadCloser, redirectURL string, err error) {
276 u := fmt.Sprintf("repos/%s/%s/releases/assets/%d", owner, repo, id)
277
278 req, err := s.client.NewRequest("GET", u, nil)
279 if err != nil {
280 return nil, "", err
281 }
282 req.Header.Set("Accept", defaultMediaType)
283
284 s.client.clientMu.Lock()
285 defer s.client.clientMu.Unlock()
286
287 var loc string
288 saveRedirect := s.client.client.CheckRedirect
289 s.client.client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
290 loc = req.URL.String()
291 return errors.New("disable redirect")
292 }
293 defer func() { s.client.client.CheckRedirect = saveRedirect }()
294
295 req = withContext(ctx, req)
296 resp, err := s.client.client.Do(req)
297 if err != nil {
298 if !strings.Contains(err.Error(), "disable redirect") {
299 return nil, "", err
300 }
301 if followRedirectsClient != nil {
302 rc, err := s.downloadReleaseAssetFromURL(ctx, followRedirectsClient, loc)
303 return rc, "", err
304 }
305 return nil, loc, nil
306 }
307
308 if err := CheckResponse(resp); err != nil {
309 resp.Body.Close()
310 return nil, "", err
311 }
312
313 return resp.Body, "", nil
314 }
315
316 func (s *RepositoriesService) downloadReleaseAssetFromURL(ctx context.Context, followRedirectsClient *http.Client, url string) (rc io.ReadCloser, err error) {
317 req, err := http.NewRequest("GET", url, nil)
318 if err != nil {
319 return nil, err
320 }
321 req = withContext(ctx, req)
322 req.Header.Set("Accept", "*/*")
323 resp, err := followRedirectsClient.Do(req)
324 if err != nil {
325 return nil, err
326 }
327 if err := CheckResponse(resp); err != nil {
328 resp.Body.Close()
329 return nil, err
330 }
331 return resp.Body, nil
332 }
333
334
335
336
337 func (s *RepositoriesService) EditReleaseAsset(ctx context.Context, owner, repo string, id int64, release *ReleaseAsset) (*ReleaseAsset, *Response, error) {
338 u := fmt.Sprintf("repos/%s/%s/releases/assets/%d", owner, repo, id)
339
340 req, err := s.client.NewRequest("PATCH", u, release)
341 if err != nil {
342 return nil, nil, err
343 }
344
345 asset := new(ReleaseAsset)
346 resp, err := s.client.Do(ctx, req, asset)
347 if err != nil {
348 return nil, resp, err
349 }
350 return asset, resp, nil
351 }
352
353
354
355
356 func (s *RepositoriesService) DeleteReleaseAsset(ctx context.Context, owner, repo string, id int64) (*Response, error) {
357 u := fmt.Sprintf("repos/%s/%s/releases/assets/%d", owner, repo, id)
358
359 req, err := s.client.NewRequest("DELETE", u, nil)
360 if err != nil {
361 return nil, err
362 }
363 return s.client.Do(ctx, req, nil)
364 }
365
366
367
368
369
370 func (s *RepositoriesService) UploadReleaseAsset(ctx context.Context, owner, repo string, id int64, opts *UploadOptions, file *os.File) (*ReleaseAsset, *Response, error) {
371 u := fmt.Sprintf("repos/%s/%s/releases/%d/assets", owner, repo, id)
372 u, err := addOptions(u, opts)
373 if err != nil {
374 return nil, nil, err
375 }
376
377 stat, err := file.Stat()
378 if err != nil {
379 return nil, nil, err
380 }
381 if stat.IsDir() {
382 return nil, nil, errors.New("the asset to upload can't be a directory")
383 }
384
385 mediaType := mime.TypeByExtension(filepath.Ext(file.Name()))
386 if opts.MediaType != "" {
387 mediaType = opts.MediaType
388 }
389
390 req, err := s.client.NewUploadRequest(u, file, stat.Size(), mediaType)
391 if err != nil {
392 return nil, nil, err
393 }
394
395 asset := new(ReleaseAsset)
396 resp, err := s.client.Do(ctx, req, asset)
397 if err != nil {
398 return nil, resp, err
399 }
400 return asset, resp, nil
401 }
402
View as plain text