diff --git a/github/repos_releases.go b/github/repos_releases.go index 629b321..4e4e2ab 100644 --- a/github/repos_releases.go +++ b/github/repos_releases.go @@ -8,6 +8,7 @@ package github import ( "errors" "fmt" + "io" "mime" "os" "path/filepath" @@ -211,6 +212,29 @@ func (s *RepositoriesService) GetReleaseAsset(owner, repo string, id int) (*Rele return asset, resp, err } +// DownloadReleaseAsset downloads a release asset. +// +// DownloadReleaseAsset returns an io.ReadCloser that reads the contents of the +// specified release asset. It is the caller's responsibility to close the ReadCloser. +// +// GitHub API docs : http://developer.github.com/v3/repos/releases/#get-a-single-release-asset +func (s *RepositoriesService) DownloadReleaseAsset(owner, repo string, id int) (io.ReadCloser, error) { + u := fmt.Sprintf("repos/%s/%s/releases/assets/%d", owner, repo, id) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, err + } + req.Header.Set("Accept", defaultMediaType) + + resp, err := s.client.client.Do(req) + if err != nil { + return nil, err + } + + return resp.Body, nil +} + // EditReleaseAsset edits a repository release asset. // // GitHub API docs : http://developer.github.com/v3/repos/releases/#edit-a-release-asset diff --git a/github/repos_releases_test.go b/github/repos_releases_test.go index 21808b7..5b0f094 100644 --- a/github/repos_releases_test.go +++ b/github/repos_releases_test.go @@ -6,8 +6,10 @@ package github import ( + "bytes" "encoding/json" "fmt" + "io/ioutil" "net/http" "os" "reflect" @@ -204,6 +206,64 @@ func TestRepositoriesService_GetReleaseAsset(t *testing.T) { } } +func TestRepositoriesService_DownloadReleaseAsset_Stream(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/releases/assets/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testHeader(t, r, "Accept", defaultMediaType) + w.Header().Set("Content-Type", "application/octet-stream") + w.Header().Set("Content-Disposition", "attachment; filename=hello-world.txt") + fmt.Fprint(w, "Hello World") + }) + + reader, err := client.Repositories.DownloadReleaseAsset("o", "r", 1) + if err != nil { + t.Errorf("Repositories.DownloadReleaseAsset returned error: %v", err) + } + want := []byte("Hello World") + content, err := ioutil.ReadAll(reader) + if err != nil { + t.Errorf("Repositories.DownloadReleaseAsset returned bad reader: %v", err) + } + if !bytes.Equal(want, content) { + t.Errorf("Repositories.DownloadReleaseAsset returned %+v, want %+v", content, want) + } +} + +func TestRepositoriesService_DownloadReleaseAsset_Redirect(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/releases/assets/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testHeader(t, r, "Accept", defaultMediaType) + w.Header().Set("Location", server.URL+"/github-cloud/releases/1/hello-world.txt") + w.WriteHeader(http.StatusFound) + }) + + mux.HandleFunc("/github-cloud/releases/1/hello-world.txt", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + w.Header().Set("Content-Type", "application/octet-stream") + w.Header().Set("Content-Disposition", "attachment; filename=hello-world.txt") + fmt.Fprint(w, "Hello World") + }) + + reader, err := client.Repositories.DownloadReleaseAsset("o", "r", 1) + if err != nil { + t.Errorf("Repositories.DownloadReleaseAsset returned error: %v", err) + } + want := []byte("Hello World") + content, err := ioutil.ReadAll(reader) + if err != nil { + t.Errorf("Repositories.DownloadReleaseAsset returned bad reader: %v", err) + } + if !bytes.Equal(want, content) { + t.Errorf("Repositories.DownloadReleaseAsset returned %+v, want %+v", content, want) + } +} + func TestRepositoriesService_EditReleaseAsset(t *testing.T) { setup() defer teardown()