From a3573534f92cd1f78b851c5494b5a8716fb8446f Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Farez Date: Fri, 2 Feb 2018 12:24:01 +0100 Subject: [PATCH] Add support to pass custom version to fetch from Github --- README.md | 3 ++- selfupdate/detect.go | 34 +++++++++++++++++++++++++--------- selfupdate/detect_test.go | 30 +++++++++++++++++++++++++++++- 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index c6d7ca6..d91ceba 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,7 @@ It provides `selfupdate` package. - `selfupdate.UpdateSelf()`: Detect the latest version of itself and run self update. - `selfupdate.UpdateCommand()`: Detect the latest version of given repository and update given command. - `selfupdate.DetectLatest()`: Detect the latest version of given repository. +- `selfupdate.DetectVersion()`: Detect the user defined version of given repository. - `selfupdate.UpdateTo()`: Update given command to the binary hosted on given URL. - `selfupdate.Updater`: Context manager of self-upadte process. If you want to customize some behavior of self-update (e.g. specify API token, use GitHub Enterprise, ...), please make an instance of @@ -231,7 +232,7 @@ You need to put the binaries with the following format. `{.ext}` is a file extension. go-github-selfupdate supports `.zip`, `.gzip`, `.tar.gz` and `.tar.xz`. You can also use blank and it means binary is not compressed. -If you compress binary, uncompressed directory or file must contain the executable named `{cmd}`. +If you compress binary, uncompressed directory or file must contain the executable named `{cmd}`. And you can also use `-` for separator instead of `_` if you like. diff --git a/selfupdate/detect.go b/selfupdate/detect.go index 0ffe5de..5ab4b9e 100644 --- a/selfupdate/detect.go +++ b/selfupdate/detect.go @@ -12,12 +12,17 @@ import ( var reVersion = regexp.MustCompile(`\d+\.\d+\.\d+`) -func findAssetFromReleasse(rel *github.RepositoryRelease, suffixes []string) (*github.ReleaseAsset, semver.Version, bool) { - if rel.GetDraft() { +func findAssetFromReleasse(rel *github.RepositoryRelease, suffixes []string, targetVersion string) (*github.ReleaseAsset, semver.Version, bool) { + if targetVersion != "" && targetVersion != rel.GetTagName() { + log.Println("Skip", rel.GetTagName(), "not matching to specified version", targetVersion) + return nil, semver.Version{}, false + } + + if targetVersion == "" && rel.GetDraft() { log.Println("Skip draft version", rel.GetTagName()) return nil, semver.Version{}, false } - if rel.GetPrerelease() { + if targetVersion == "" && rel.GetPrerelease() { log.Println("Skip pre-release version", rel.GetTagName()) return nil, semver.Version{}, false } @@ -54,8 +59,8 @@ func findAssetFromReleasse(rel *github.RepositoryRelease, suffixes []string) (*g return nil, semver.Version{}, false } -func findReleaseAndAsset(rels []*github.RepositoryRelease) (*github.RepositoryRelease, *github.ReleaseAsset, semver.Version, bool) { - // Generate valid suffix candidates to match +func findReleaseAndAsset(rels []*github.RepositoryRelease, targetVersion string) (*github.RepositoryRelease, *github.ReleaseAsset, semver.Version, bool) { + // Generate candidates suffixes := make([]string, 0, 2*7*2) for _, sep := range []rune{'_', '-'} { for _, ext := range []string{".zip", ".tar.gz", ".gzip", ".gz", ".tar.xz", ".xz", ""} { @@ -76,7 +81,7 @@ func findReleaseAndAsset(rels []*github.RepositoryRelease) (*github.RepositoryRe // Returned list from GitHub API is in the order of the date when created. // ref: https://github.com/rhysd/go-github-selfupdate/issues/11 for _, rel := range rels { - if a, v, ok := findAssetFromReleasse(rel, suffixes); ok { + if a, v, ok := findAssetFromReleasse(rel, suffixes, targetVersion); ok { // Note: any version with suffix is less than any version without suffix. // e.g. 0.0.1 > 0.0.1-beta if release == nil || v.GTE(ver) { @@ -101,7 +106,13 @@ func findReleaseAndAsset(rels []*github.RepositoryRelease) (*github.RepositoryRe // where 'foo' is a command name. '-' can also be used as a separator. File can be compressed with zip, gzip, zxip, tar&zip or tar&zxip. // So the asset can have a file extension for the corresponding compression format such as '.zip'. // On Windows, '.exe' also can be contained such as 'foo_windows_amd64.exe.zip'. -func (up *Updater) DetectLatest(slug string) (*Release, bool, error) { +func (up *Updater) DetectLatest(slug string) (release *Release, found bool, err error) { + return up.DetectVersion(slug, "") +} + +// DetectVersion tries to get the give nversion of the repository on Github. `slug` means `owner/name` formatted string. +// And version indicates the required version. +func (up *Updater) DetectVersion(slug string, version string) (release *Release, found bool, err error) { repo := strings.Split(slug, "/") if len(repo) != 2 || repo[0] == "" || repo[1] == "" { return nil, false, fmt.Errorf("Invalid slug format. It should be 'owner/name': %s", slug) @@ -118,7 +129,7 @@ func (up *Updater) DetectLatest(slug string) (*Release, bool, error) { return nil, false, err } - rel, asset, ver, found := findReleaseAndAsset(rels) + rel, asset, ver, found := findReleaseAndAsset(rels, version) if !found { return nil, false, nil } @@ -127,7 +138,7 @@ func (up *Updater) DetectLatest(slug string) (*Release, bool, error) { log.Println("Successfully fetched the latest release. tag:", rel.GetTagName(), ", name:", rel.GetName(), ", URL:", rel.GetURL(), ", Asset:", url) publishedAt := rel.GetPublishedAt().Time - release := &Release{ + release = &Release{ ver, url, asset.GetSize(), @@ -147,3 +158,8 @@ func (up *Updater) DetectLatest(slug string) (*Release, bool, error) { func DetectLatest(slug string) (*Release, bool, error) { return DefaultUpdater().DetectLatest(slug) } + +// DetectVersion detects the given release of the slug (owner/repo) from its version. +func DetectVersion(slug string, version string) (*Release, bool, error) { + return DefaultUpdater().DetectVersion(slug, version) +} diff --git a/selfupdate/detect_test.go b/selfupdate/detect_test.go index 2bce039..6f1a8f2 100644 --- a/selfupdate/detect_test.go +++ b/selfupdate/detect_test.go @@ -2,10 +2,11 @@ package selfupdate import ( "fmt" - "github.com/blang/semver" "os" "strings" "testing" + + "github.com/blang/semver" ) func TestDetectReleaseWithVersionPrefix(t *testing.T) { @@ -51,6 +52,33 @@ func TestDetectReleaseWithVersionPrefix(t *testing.T) { } } +func TestDetectVersionExisting(t *testing.T) { + testVersion := "v2.2.0" + r, ok, err := DetectVersion("rhysd/github-clone-all", testVersion) + if err != nil { + t.Fatal("Fetch failed:", err) + } + if !ok { + t.Fatalf("Failed to detect %s", testVersion) + } + if r == nil { + t.Fatal("Release detected but nil returned for it") + } +} + +func TestDetectVersionNotExisting(t *testing.T) { + r, ok, err := DetectVersion("rhysd/github-clone-all", "foobar") + if err != nil { + t.Fatal("Fetch failed:", err) + } + if ok { + t.Fatal("Failed to correctly detect foobar") + } + if r != nil { + t.Fatal("Release not detected but got a returned value for it") + } +} + func TestDetectReleasesForVariousArchives(t *testing.T) { for _, tc := range []struct { slug string