go-github-selfupdate

repository·master·Indexed 20 days ago

https://github.com/rhysd/go-github-selfupdate

A Go library that enables command-line tools to automatically update themselves by detecting and downloading the latest releases from GitHub. It supports automatic OS/arch binary selection, rollback, multiple archive formats, private repositories, GitHub Enterprise, and hash or signature validation. The project also includes CLI wrapper tools: detect-latest-release for identifying the latest release version and go-get-release for installing release binaries from GitHub.

Tokens
4.3K
Snippets
16
Records
20
Agent score
71%

What's inside go-github-selfupdate

  1. What is go-github-selfupdate?

    master

    go-github-selfupdate is a Go library designed to provide a self-update mechanism for command-line tools. It automates the process of detecting the latest release on GitHub, downloading the appropriate binary for the current OS and architecture, and replacing the existing binary in $GOPATH/bin.

    Key features include:

    • Automatic detection of the latest GitHub release.
    • Automatic selection of the correct OS/arch binary.
    • Rollback support if the update fails.
    • Support for multiple archive formats (zip, tar, gzip, xzip).
    • Support for private repositories and GitHub Enterprise.
    • Support for hash and signature validation.
  2. Configure versioning and Git tags

    master

    The library identifies versions using Git tag names, not release titles.

    Requirements

    • Semantic Versioning: The library assumes you use semver.
    • Tag Format: Use the version number directly (e.g., 1.2.3) or with a v prefix (e.g., v1.2.3).
    • Prefixes: Common prefixes like ver1.2.3 or release-1.2.3 are automatically handled and stripped.

    Exclusions

    • Tags that do not contain a valid version number (e.g., nightly) are ignored.
    • Releases marked as pre-release on GitHub are ignored.
  3. Format released binaries for go-github-selfupdate

    master

    To ensure the library can find and update your binaries, you must follow specific naming conventions for your GitHub release assets. The library expects binaries to be organized by platform and architecture.

    Binary Naming Pattern

    Use the following format: {cmd}_{goos}_{goarch}{.ext}

    • {cmd}: The name of your command.
    • {goos}: The target operating system (e.g., linux, darwin, windows).
    • {goarch}: The target architecture (e.g., amd64, arm64).
    • {.ext}: Optional extension. Supported formats: .zip, .gzip, .tar.gz, .tar.xz. If omitted, the binary is assumed to be uncompressed.
    • Separator: You may use a hyphen - instead of an underscore _.

    Examples for foo-bar on linux/amd64

    • foo-bar_linux_amd64 (uncompressed)
    • foo-bar_linux_amd64.tar.gz (compressed)
    • foo-bar-linux-amd64.tar.gz (hyphen separator)

    Requirements for Compressed Archives

    If you use an archive (like .zip or .tar.gz), the archive must contain an executable named one of the following:

    1. {cmd} (e.g., foo-bar)
    2. {cmd}_{goos}_{goarch} (e.g., foo-bar_linux_amd64)
    3. {cmd}-{goos}-{goarch} (e.g., foo-bar-linux-amd64)

    On Windows, you can add .exe before the archive extension, e.g., foo-bar_windows_amd64.exe.zip.

  4. Use the detect-latest-release CLI

    master

    The detect-latest-release tool identifies the latest release version of a GitHub repository.

    To use it, provide the repository owner and name as an argument (e.g., owner/repo). If you run the command without arguments, it will display its usage information.

    # To see usage information:
    detect-latest-release
    
    # To find the latest version of a specific repository:
    detect-latest-release rhysd/github-clone-all
  5. Use go-get-release to update GitHub binaries

    master

    The go-get-release command functions similarly to go get, but instead of compiling from source, it downloads and installs the latest release binary from GitHub.

    Requirements:

    • The {package} must be hosted on GitHub (the path must start with github.com/).
    • The package must follow the Git tag naming rules and released binaries naming rules defined in the main repository documentation.
    go-get-release {package}
  6. Example: Update ghr using go-get-release

    master

    To download and install the latest released binary of ghr (hosted at github.com/tcnksm/ghr) to your $GOPATH/bin, run the following command:

    go-get-release github.com/tcnksm/ghr
    # Output example:
    # Command was updated to the latest version 0.5.4: /Users/you/.go/bin/ghr
    
    $ ghr -version
    # ghr version v0.5.4 (a12ff1c)
  7. Try the selfupdate-example CLI

    master

    You can test the library's functionality using the provided selfupdate-example CLI tool. This example demonstrates the full lifecycle: installing the tool, checking the current version, and performing a self-update.

    1. Install the example CLI:

      go get -u github.com/rhysd/go-github-selfupdate/cmd/selfupdate-example
    2. Check the current version: Use the -version flag to see the installed version.

      selfupdate-example -version
    3. Perform a self-update: Use the -selfupdate flag to trigger the update process. If a newer version is available, the tool will replace itself and display the release notes.

      selfupdate-example -selfupdate
    4. Verify the update: Run the -version flag again to confirm the binary has been updated.

    $ go get -u github.com/rhysd/go-github-selfupdate/cmd/selfupdate-example
    $ selfupdate-example -version
    $ selfupdate-example -selfupdate
    $ selfupdate-example -version
  8. Use the selfupdate package for automatic updates

    master

    The selfupdate package provides several high-level functions to manage binary updates via GitHub.

    Core API Functions

    • selfupdate.UpdateSelf(currentVersion, repo): Detects the latest version of the current binary and performs the update.
    • selfupdate.UpdateCommand(repo): Detects the latest version of a given repository and updates the command.
    • selfupdate.DetectLatest(repo): Returns the latest version information for a given repository.
    • selfupdate.DetectVersion(repo): Detects a specific user-defined version of a repository.
    • selfupdate.UpdateTo(assetURL, executablePath): Updates a command to a binary hosted at a specific URL.
    • selfupdate.Updater: A context manager used for advanced customization (e.g., GitHub Enterprise, custom API tokens).

    Implementation Example: Simple Self-Update

    To implement a simple self-update check, use UpdateSelf with the current version and the repository name (e.g., owner/repo).

    import (
        "log"
        "github.com/blang/semver"
        "github.com/rhysd/go-github-selfupdate/selfupdate"
    )
    
    const version = "1.2.3"
    
    func doSelfUpdate() {
        v := semver.MustParse(version)
        latest, err := selfupdate.UpdateSelf(v, "myname/myrepo")
        if err != nil {
            log.Println("Binary update failed:", err)
            return
        }
        if latest.Version.Equals(v) {
            log.Println("Current binary is the latest version", version)
        } else {
            log.Println("Successfully updated to version", latest.Version)
            log.Println("Release note:\n", latest.ReleaseNotes)
        }
    }
  9. Configure Updater for GitHub Enterprise or Custom Tokens

    master

    For advanced configurations like using GitHub Enterprise or providing a specific API token, instantiate an Updater using selfupdate.NewUpdater with a selfupdate.Config object.

    Note: When using GitHub Enterprise, you must provide an APIToken because the Enterprise API typically requires authentication. If APIToken is omitted, the library attempts to find it in the [token] section of .gitconfig or the $GITHUB_TOKEN environment variable.

    Configuration Options

    • APIToken: The GitHub API token.
    • EnterpriseBaseURL: The base URL for the GitHub Enterprise API (e.g., https://github.your.company.com/api/v3).
    • EnterpriseUploadURL: Use this if your Enterprise instance's upload URL differs from the base URL.
    import (
        "log"
        "github.com/blang/semver"
        "github.com/rhysd/go-github-selfupdate/selfupdate"
    )
    
    const version = "1.2.3"
    
    func doSelfUpdate(token string) {
        v := semver.MustParse(version)
        up, err := selfupdate.NewUpdater(selfupdate.Config{
            APIToken: token,
            EnterpriseBaseURL: "https://github.your.company.com/api/v3",
        })
        latest, err := up.UpdateSelf(v, "myname/myrepo")
        // ... handle err and latest ...
    }
  10. Implement Hash or Signature validation

    master

    You can verify the integrity of downloaded assets using SHA256 hashes or ECDSA signatures by implementing the Validator interface.

    The Validator Interface

    type Validator interface {
    	// Validate validates release bytes against an additional asset bytes.
    	Validate(release, asset []byte) error
    	// Suffix describes the additional file ending used for finding the additional asset.
    	Suffix() string
    }

    Supported Validation Methods

    SHA256

    To use SHA256, create a file with the same name as the asset but with a .sha256 suffix. Example command:

    sha256sum foo.zip > foo.zip.sha256

    ECDSA

    To use ECDSA, create a file with the same name as the asset but with a .sig suffix. The private key must be compatible with FIPS 186-3. Example command:

    openssl dgst -sha256 -sign Test.pem -out foo.zip.sig foo.zip
    // Validator represents an interface which enables additional validation of releases.
    type Validator interface {
    	// Validate validates release bytes against an additional asset bytes.
    	// See SHA2Validator or ECDSAValidator for more information.
    	Validate(release, asset []byte) error
    	// Suffix describes the additional file ending which is used for finding the
    	// additional asset.
    	Suffix() string
    }