diff --git a/features/release.feature b/features/release.feature index b26632231e7ec5fc0b9fc8d1fe5ed6075f53a20e..aaee08301c149b22908943a506e76f6ed9665c39 100644 --- a/features/release.feature +++ b/features/release.feature @@ -456,6 +456,33 @@ MARKDOWN Attaching 1 asset...\n """ + Scenario: Retry attaching assets on 5xx errors + Given the GitHub API server: + """ + attempt = 0 + post('/repos/mislav/will_paginate/releases') { + status 201 + json :html_url => "https://github.com/mislav/will_paginate/releases/v1.2.0", + :upload_url => "https://uploads.github.com/uploads/assets{?name,label}" + } + post('/uploads/assets', :host_name => 'uploads.github.com') { + attempt += 1 + halt 400 unless request.body.read.to_s == "TARBALL" + halt 502 if attempt == 1 + status 201 + } + """ + And a file named "hello-1.2.0.tar.gz" with: + """ + TARBALL + """ + When I successfully run `hub release create -m "hello" v1.2.0 -a hello-1.2.0.tar.gz` + Then the output should contain exactly: + """ + https://github.com/mislav/will_paginate/releases/v1.2.0 + Attaching 1 asset...\n + """ + Scenario: Create a release with some assets failing Given the GitHub API server: """ diff --git a/github/client.go b/github/client.go index 9e6b599b833cd9fa797c9dcf0a739cf91939a19e..45394435b310310528dc2bbff367f64f4f378679 100644 --- a/github/client.go +++ b/github/client.go @@ -412,11 +412,28 @@ func (client *Client) UploadReleaseAssets(release *Release, assets []LocalAsset) } uploadPath := addQuery(uploadURL, params) - // TODO: retry failed assets var res *simpleResponse - res, err = api.PostFile(uploadPath, asset.Contents, asset.Size) - if err = checkStatus(201, "uploading release asset", res, err); err != nil { - return + attempts := 0 + maxAttempts := 3 + body := asset.Contents + for { + res, err = api.PostFile(uploadPath, body, asset.Size) + if err == nil && res.StatusCode >= 500 && res.StatusCode < 600 && attempts < maxAttempts { + attempts++ + time.Sleep(time.Second * time.Duration(attempts)) + var f *os.File + f, err = os.Open(asset.Name) + if err != nil { + return + } + defer f.Close() + body = f + continue + } + if err = checkStatus(201, "uploading release asset", res, err); err != nil { + return + } + break } newAsset := ReleaseAsset{}