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".
169 lines
3.4 KiB
Go
169 lines
3.4 KiB
Go
package resource
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/zachgersh/go-github/github"
|
|
)
|
|
|
|
type InCommand struct {
|
|
github GitHub
|
|
writer io.Writer
|
|
}
|
|
|
|
func NewInCommand(github GitHub, writer io.Writer) *InCommand {
|
|
return &InCommand{
|
|
github: github,
|
|
writer: writer,
|
|
}
|
|
}
|
|
|
|
func (c *InCommand) Run(destDir string, request InRequest) (InResponse, error) {
|
|
err := os.MkdirAll(destDir, 0755)
|
|
if err != nil {
|
|
return InResponse{}, err
|
|
}
|
|
|
|
var foundRelease *github.RepositoryRelease
|
|
|
|
foundRelease, err = c.github.GetReleaseByTag(request.Version.Tag)
|
|
if err != nil {
|
|
return InResponse{}, err
|
|
}
|
|
|
|
if foundRelease == nil {
|
|
return InResponse{}, errors.New("no releases")
|
|
}
|
|
|
|
tagPath := filepath.Join(destDir, "tag")
|
|
err = ioutil.WriteFile(tagPath, []byte(*foundRelease.TagName), 0644)
|
|
if err != nil {
|
|
return InResponse{}, err
|
|
}
|
|
|
|
version := determineVersionFromTag(*foundRelease.TagName)
|
|
versionPath := filepath.Join(destDir, "version")
|
|
err = ioutil.WriteFile(versionPath, []byte(version), 0644)
|
|
if err != nil {
|
|
return InResponse{}, err
|
|
}
|
|
|
|
assets, err := c.github.ListReleaseAssets(*foundRelease)
|
|
if err != nil {
|
|
return InResponse{}, err
|
|
}
|
|
|
|
for _, asset := range assets {
|
|
path := filepath.Join(destDir, *asset.Name)
|
|
|
|
var matchFound bool
|
|
if len(request.Params.Globs) == 0 {
|
|
matchFound = true
|
|
} else {
|
|
for _, glob := range request.Params.Globs {
|
|
matches, err := filepath.Match(glob, *asset.Name)
|
|
if err != nil {
|
|
return InResponse{}, err
|
|
}
|
|
|
|
if matches {
|
|
matchFound = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
if !matchFound {
|
|
continue
|
|
}
|
|
|
|
fmt.Fprintf(c.writer, "downloading asset: %s\n", *asset.Name)
|
|
|
|
err := c.downloadAsset(asset, path)
|
|
if err != nil {
|
|
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{
|
|
Version: Version{
|
|
Tag: *foundRelease.TagName,
|
|
},
|
|
Metadata: metadataFromRelease(foundRelease),
|
|
}, nil
|
|
}
|
|
|
|
func (c *InCommand) downloadAsset(asset github.ReleaseAsset, destPath string) error {
|
|
out, err := os.Create(destPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer out.Close()
|
|
|
|
content, err := c.github.DownloadReleaseAsset(asset)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer content.Close()
|
|
|
|
_, err = io.Copy(out, content)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
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
|
|
}
|