Add support for downloading source artifacts from Github release

This adds support for retrieving the tarball or zip source artifact from a
Github release. This is done through defining a
"params.include_source_tarball" or "params.include_source_zip" boolean setting.

With this, the resource will download the respective source artfact into the
target directory as either "source.tar.gz" or "source.zip".
This commit is contained in:
Ken Robertson
2015-09-23 11:11:05 -07:00
parent 8508409f8a
commit d563c2714c
5 changed files with 168 additions and 4 deletions

View File

@@ -67,6 +67,12 @@ Also creates the following files:
* `globs`: *Optional.* A list of globs for files that will be downloaded from * `globs`: *Optional.* A list of globs for files that will be downloaded from
the release. If not specified, all assets will be fetched. the release. If not specified, all assets will be fetched.
* `include_source_tarball`: *Optional.* Enables downloading of the source
artifact tarball for the release as `source.tar.gz`. Defaults to `false`.
* `include_source_zip`: *Optional.* Enables downloading of the source
artifact zip for the release as `source.zip`. Defaults to `false`.
### `out`: Publish a release. ### `out`: Publish a release.
Given a name specified in `name`, a body specified in `body`, and the tag to use Given a name specified in `name`, a body specified in `body`, and the tag to use

View File

@@ -3,6 +3,7 @@ package fakes
import ( import (
"io" "io"
"net/url"
"os" "os"
"sync" "sync"
@@ -81,6 +82,24 @@ type FakeGitHub struct {
result1 io.ReadCloser result1 io.ReadCloser
result2 error result2 error
} }
GetTarballLinkStub func(tag string) (*url.URL, error)
getTarballLinkMutex sync.RWMutex
getTarballLinkArgsForCall []struct {
tag string
}
getTarballLinkReturns struct {
result1 *url.URL
result2 error
}
GetZipballLinkStub func(tag string) (*url.URL, error)
getZipballLinkMutex sync.RWMutex
getZipballLinkArgsForCall []struct {
tag string
}
getZipballLinkReturns struct {
result1 *url.URL
result2 error
}
} }
func (fake *FakeGitHub) ListReleases() ([]github.RepositoryRelease, error) { func (fake *FakeGitHub) ListReleases() ([]github.RepositoryRelease, error) {
@@ -339,4 +358,70 @@ func (fake *FakeGitHub) DownloadReleaseAssetReturns(result1 io.ReadCloser, resul
}{result1, result2} }{result1, result2}
} }
func (fake *FakeGitHub) GetTarballLink(tag string) (*url.URL, error) {
fake.getTarballLinkMutex.Lock()
fake.getTarballLinkArgsForCall = append(fake.getTarballLinkArgsForCall, struct {
tag string
}{tag})
fake.getTarballLinkMutex.Unlock()
if fake.GetReleaseByTagStub != nil {
return fake.GetTarballLinkStub(tag)
} else {
return fake.getTarballLinkReturns.result1, fake.getTarballLinkReturns.result2
}
}
func (fake *FakeGitHub) GetTarballLinkCallCount() int {
fake.getTarballLinkMutex.RLock()
defer fake.getTarballLinkMutex.RUnlock()
return len(fake.getTarballLinkArgsForCall)
}
func (fake *FakeGitHub) GetTarballLinkArgsForCall(i int) string {
fake.getTarballLinkMutex.RLock()
defer fake.getTarballLinkMutex.RUnlock()
return fake.getTarballLinkArgsForCall[i].tag
}
func (fake *FakeGitHub) GetTarballLinkReturns(result1 *url.URL, result2 error) {
fake.GetTarballLinkStub = nil
fake.getTarballLinkReturns = struct {
result1 *url.URL
result2 error
}{result1, result2}
}
func (fake *FakeGitHub) GetZipballLink(tag string) (*url.URL, error) {
fake.getZipballLinkMutex.Lock()
fake.getZipballLinkArgsForCall = append(fake.getZipballLinkArgsForCall, struct {
tag string
}{tag})
fake.getZipballLinkMutex.Unlock()
if fake.GetReleaseByTagStub != nil {
return fake.GetZipballLinkStub(tag)
} else {
return fake.getZipballLinkReturns.result1, fake.getZipballLinkReturns.result2
}
}
func (fake *FakeGitHub) GetZipballLinkCallCount() int {
fake.getZipballLinkMutex.RLock()
defer fake.getZipballLinkMutex.RUnlock()
return len(fake.getZipballLinkArgsForCall)
}
func (fake *FakeGitHub) GetZipballLinkArgsForCall(i int) string {
fake.getZipballLinkMutex.RLock()
defer fake.getZipballLinkMutex.RUnlock()
return fake.getZipballLinkArgsForCall[i].tag
}
func (fake *FakeGitHub) GetZipballLinkReturns(result1 *url.URL, result2 error) {
fake.GetZipballLinkStub = nil
fake.getZipballLinkReturns = struct {
result1 *url.URL
result2 error
}{result1, result2}
}
var _ resource.GitHub = new(FakeGitHub) var _ resource.GitHub = new(FakeGitHub)

View File

@@ -23,6 +23,9 @@ type GitHub interface {
UploadReleaseAsset(release github.RepositoryRelease, name string, file *os.File) error UploadReleaseAsset(release github.RepositoryRelease, name string, file *os.File) error
DeleteReleaseAsset(asset github.ReleaseAsset) error DeleteReleaseAsset(asset github.ReleaseAsset) error
DownloadReleaseAsset(asset github.ReleaseAsset) (io.ReadCloser, error) DownloadReleaseAsset(asset github.ReleaseAsset) (io.ReadCloser, error)
GetTarballLink(tag string) (*url.URL, error)
GetZipballLink(tag string) (*url.URL, error)
} }
type GitHubClient struct { type GitHubClient struct {
@@ -170,3 +173,23 @@ func (g *GitHubClient) DownloadReleaseAsset(asset github.ReleaseAsset) (io.ReadC
return res, err return res, err
} }
func (g *GitHubClient) GetTarballLink(tag string) (*url.URL, error) {
opt := &github.RepositoryContentGetOptions{Ref: tag}
u, res, err := g.client.Repositories.GetArchiveLink(g.user, g.repository, github.Tarball, opt)
if err != nil {
return nil, err
}
res.Body.Close()
return u, nil
}
func (g *GitHubClient) GetZipballLink(tag string) (*url.URL, error) {
opt := &github.RepositoryContentGetOptions{Ref: tag}
u, res, err := g.client.Repositories.GetArchiveLink(g.user, g.repository, github.Zipball, opt)
if err != nil {
return nil, err
}
res.Body.Close()
return u, nil
}

View File

@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net/http"
"os" "os"
"path/filepath" "path/filepath"
@@ -84,12 +85,34 @@ func (c *InCommand) Run(destDir string, request InRequest) (InResponse, error) {
fmt.Fprintf(c.writer, "downloading asset: %s\n", *asset.Name) fmt.Fprintf(c.writer, "downloading asset: %s\n", *asset.Name)
err := c.downloadFile(asset, path) err := c.downloadAsset(asset, path)
if err != nil { if err != nil {
return InResponse{}, err return InResponse{}, err
} }
} }
if request.Params.IncludeSourceTarball {
u, err := c.github.GetTarballLink(request.Version.Tag)
if err != nil {
return InResponse{}, err
}
fmt.Fprintln(c.writer, "downloading source tarball to source.tar.gz")
if err := c.downloadFile(u.String(), filepath.Join(destDir, "source.tar.gz")); err != nil {
return InResponse{}, err
}
}
if request.Params.IncludeSourceZip {
u, err := c.github.GetZipballLink(request.Version.Tag)
if err != nil {
return InResponse{}, err
}
fmt.Fprintln(c.writer, "downloading source zip to source.zip")
if err := c.downloadFile(u.String(), filepath.Join(destDir, "source.zip")); err != nil {
return InResponse{}, err
}
}
return InResponse{ return InResponse{
Version: Version{ Version: Version{
Tag: *foundRelease.TagName, Tag: *foundRelease.TagName,
@@ -98,7 +121,7 @@ func (c *InCommand) Run(destDir string, request InRequest) (InResponse, error) {
}, nil }, nil
} }
func (c *InCommand) downloadFile(asset github.ReleaseAsset, destPath string) error { func (c *InCommand) downloadAsset(asset github.ReleaseAsset, destPath string) error {
out, err := os.Create(destPath) out, err := os.Create(destPath)
if err != nil { if err != nil {
return err return err
@@ -118,3 +141,28 @@ func (c *InCommand) downloadFile(asset github.ReleaseAsset, destPath string) err
return nil return nil
} }
func (c *InCommand) downloadFile(url, destPath string) error {
out, err := os.Create(destPath)
if err != nil {
return err
}
defer out.Close()
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("failed to download file: HTTP status %d: %s", resp.StatusCode, resp.Status)
}
_, err = io.Copy(out, resp.Body)
if err != nil {
return err
}
return nil
}

View File

@@ -21,6 +21,8 @@ type InRequest struct {
type InParams struct { type InParams struct {
Globs []string `json:"globs"` Globs []string `json:"globs"`
IncludeSourceTarball bool `json:"include_source_tarball"`
IncludeSourceZip bool `json:"include_source_zip"`
} }
type InResponse struct { type InResponse struct {