mirror of
https://github.com/MedzikUser/go-github-selfupdate.git
synced 2024-08-15 03:25:29 +00:00
download an asset via GitHub Releases API by default
This commit is contained in:
parent
fd492d6b01
commit
6b4eeadeb7
5 changed files with 63 additions and 14 deletions
|
@ -92,10 +92,13 @@ func (up *Updater) DetectLatest(slug string) (release *Release, found bool, err
|
||||||
release = &Release{
|
release = &Release{
|
||||||
AssetURL: url,
|
AssetURL: url,
|
||||||
AssetByteSize: asset.GetSize(),
|
AssetByteSize: asset.GetSize(),
|
||||||
|
AssetID: asset.GetID(),
|
||||||
URL: rel.GetHTMLURL(),
|
URL: rel.GetHTMLURL(),
|
||||||
ReleaseNotes: rel.GetBody(),
|
ReleaseNotes: rel.GetBody(),
|
||||||
Name: rel.GetName(),
|
Name: rel.GetName(),
|
||||||
PublishedAt: &publishedAt,
|
PublishedAt: &publishedAt,
|
||||||
|
RepoOwner: repo[0],
|
||||||
|
RepoName: repo[1],
|
||||||
}
|
}
|
||||||
|
|
||||||
release.Version, err = semver.Make(tag)
|
release.Version, err = semver.Make(tag)
|
||||||
|
|
|
@ -36,9 +36,18 @@ func TestDetectReleaseWithVersionPrefix(t *testing.T) {
|
||||||
if r.AssetByteSize == 0 {
|
if r.AssetByteSize == 0 {
|
||||||
t.Error("Asset's size is unexpectedly zero")
|
t.Error("Asset's size is unexpectedly zero")
|
||||||
}
|
}
|
||||||
|
if r.AssetID == 0 {
|
||||||
|
t.Error("Asset's ID is unexpectedly zero")
|
||||||
|
}
|
||||||
if r.PublishedAt.IsZero() {
|
if r.PublishedAt.IsZero() {
|
||||||
t.Error("Release time is unexpectedly zero")
|
t.Error("Release time is unexpectedly zero")
|
||||||
}
|
}
|
||||||
|
if r.RepoOwner != "rhysd" {
|
||||||
|
t.Error("Repo owner is not correct:", r.RepoOwner)
|
||||||
|
}
|
||||||
|
if r.RepoName != "github-clone-all" {
|
||||||
|
t.Error("Repo name was not properly detectd:", r.RepoName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDetectReleasesForVariousArchives(t *testing.T) {
|
func TestDetectReleasesForVariousArchives(t *testing.T) {
|
||||||
|
@ -82,9 +91,18 @@ func TestDetectReleasesForVariousArchives(t *testing.T) {
|
||||||
if r.AssetByteSize == 0 {
|
if r.AssetByteSize == 0 {
|
||||||
t.Error("Asset's size is unexpectedly zero")
|
t.Error("Asset's size is unexpectedly zero")
|
||||||
}
|
}
|
||||||
|
if r.AssetID == 0 {
|
||||||
|
t.Error("Asset's ID is unexpectedly zero")
|
||||||
|
}
|
||||||
if r.PublishedAt.IsZero() {
|
if r.PublishedAt.IsZero() {
|
||||||
t.Error("Release time is unexpectedly zero")
|
t.Error("Release time is unexpectedly zero")
|
||||||
}
|
}
|
||||||
|
if r.RepoOwner != "rhysd-test" {
|
||||||
|
t.Error("Repo owner should be rhysd-test:", r.RepoOwner)
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(r.RepoName, "test-release-") {
|
||||||
|
t.Error("Repo name was not properly detectd:", r.RepoName)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ type Release struct {
|
||||||
AssetURL string
|
AssetURL string
|
||||||
// AssetSize represents the size of asset in bytes
|
// AssetSize represents the size of asset in bytes
|
||||||
AssetByteSize int
|
AssetByteSize int
|
||||||
|
// AssetID is the ID of the asset on GitHub
|
||||||
|
AssetID int
|
||||||
// URL is a URL to release page for browsing
|
// URL is a URL to release page for browsing
|
||||||
URL string
|
URL string
|
||||||
// ReleaseNotes is a release notes of the release
|
// ReleaseNotes is a release notes of the release
|
||||||
|
@ -21,4 +23,8 @@ type Release struct {
|
||||||
Name string
|
Name string
|
||||||
// PublishedAt is the time when the release was published
|
// PublishedAt is the time when the release was published
|
||||||
PublishedAt *time.Time
|
PublishedAt *time.Time
|
||||||
|
// RepoOwner is the owner of the repository of the release
|
||||||
|
RepoOwner string
|
||||||
|
// RepoName is the name of the repository of the release
|
||||||
|
RepoName string
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package selfupdate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -12,10 +13,26 @@ import (
|
||||||
"github.com/inconshreveable/go-update"
|
"github.com/inconshreveable/go-update"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UpdateTo download an executable from assetURL and replace the current binary with the downloaded one. cmdPath is a file path to command executable.
|
func readAndUpdate(src io.ReadCloser, assetURL, cmdPath string) error {
|
||||||
func (up *Updater) UpdateTo(assetURL, cmdPath string) error {
|
defer src.Close()
|
||||||
// TODO: Use GitHub API client to download assets
|
|
||||||
|
|
||||||
|
_, cmd := filepath.Split(cmdPath)
|
||||||
|
asset, err := UncompressCommand(src, assetURL, cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Will update", cmdPath, "to the latest downloaded from", assetURL)
|
||||||
|
return update.Apply(asset, update.Options{
|
||||||
|
TargetPath: cmdPath,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateTo downloads an executable from assetURL and replace the current binary with the downloaded one.
|
||||||
|
// This function is low-level API to update the binary. Because it does not use GitHub API and downloads asset directly from the URL via HTTP,
|
||||||
|
// this function is not available to update a release for private repositories.
|
||||||
|
// cmdPath is a file path to command executable.
|
||||||
|
func UpdateTo(assetURL, cmdPath string) error {
|
||||||
res, err := http.Get(assetURL)
|
res, err := http.Get(assetURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to download a release file from %s: %s", assetURL, err)
|
return fmt.Errorf("Failed to download a release file from %s: %s", assetURL, err)
|
||||||
|
@ -25,17 +42,22 @@ func (up *Updater) UpdateTo(assetURL, cmdPath string) error {
|
||||||
return fmt.Errorf("Failed to download a release file from %s", assetURL)
|
return fmt.Errorf("Failed to download a release file from %s", assetURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer res.Body.Close()
|
return readAndUpdate(res.Body, assetURL, cmdPath)
|
||||||
_, cmd := filepath.Split(cmdPath)
|
}
|
||||||
asset, err := UncompressCommand(res.Body, assetURL, cmd)
|
|
||||||
|
// UpdateTo downloads an executable from GitHub Releases API and replace current binary with the downloaded one.
|
||||||
|
// It downloads a release asset via GitHub Releases API so this function is available for update releases on private repository.
|
||||||
|
// If a redirect occurs, it fallbacks into directly downloading from the redirect URL.
|
||||||
|
func (up *Updater) UpdateTo(rel *Release, cmdPath string) error {
|
||||||
|
src, redirectURL, err := up.api.Repositories.DownloadReleaseAsset(up.apiCtx, rel.RepoOwner, rel.RepoName, rel.AssetID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if redirectURL != "" {
|
||||||
log.Println("Will update", cmdPath, "to the latest downloaded from", assetURL)
|
log.Println("Redirect URL was returned while trying to download a release asset from GitHub API. Falling back to downloading from asset URL directly:", redirectURL)
|
||||||
return update.Apply(asset, update.Options{
|
return UpdateTo(redirectURL, cmdPath)
|
||||||
TargetPath: cmdPath,
|
}
|
||||||
})
|
return readAndUpdate(src, rel.AssetURL, cmdPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateCommand updates a given command binary to the latest version.
|
// UpdateCommand updates a given command binary to the latest version.
|
||||||
|
@ -71,7 +93,7 @@ func (up *Updater) UpdateCommand(cmdPath string, current semver.Version, slug st
|
||||||
return rel, nil
|
return rel, nil
|
||||||
}
|
}
|
||||||
log.Println("Will update", cmdPath, "to the latest version", rel.Version)
|
log.Println("Will update", cmdPath, "to the latest version", rel.Version)
|
||||||
if err := up.UpdateTo(rel.AssetURL, cmdPath); err != nil {
|
if err := up.UpdateTo(rel, cmdPath); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return rel, nil
|
return rel, nil
|
||||||
|
|
|
@ -237,7 +237,7 @@ func TestInvalidSlugForUpdate(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInvalidAssetURL(t *testing.T) {
|
func TestInvalidAssetURL(t *testing.T) {
|
||||||
err := NewUpdater(Config{}).UpdateTo("https://github.com/rhysd/non-existing-repo/releases/download/v1.2.3/foo.zip", "foo")
|
err := UpdateTo("https://github.com/rhysd/non-existing-repo/releases/download/v1.2.3/foo.zip", "foo")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("Error should occur for URL not found")
|
t.Fatal("Error should occur for URL not found")
|
||||||
}
|
}
|
||||||
|
@ -248,7 +248,7 @@ func TestInvalidAssetURL(t *testing.T) {
|
||||||
|
|
||||||
func TestBrokenAsset(t *testing.T) {
|
func TestBrokenAsset(t *testing.T) {
|
||||||
asset := "https://github.com/rhysd-test/test-incorrect-release/releases/download/invalid/broken-zip.zip"
|
asset := "https://github.com/rhysd-test/test-incorrect-release/releases/download/invalid/broken-zip.zip"
|
||||||
err := NewUpdater(Config{}).UpdateTo(asset, "foo")
|
err := UpdateTo(asset, "foo")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("Error should occur for URL not found")
|
t.Fatal("Error should occur for URL not found")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue