{"id":13471978,"url":"https://github.com/rhysd/go-github-selfupdate","last_synced_at":"2025-05-15T03:07:23.545Z","repository":{"id":27978607,"uuid":"115316912","full_name":"rhysd/go-github-selfupdate","owner":"rhysd","description":"Binary self-update mechanism for Go commands using GitHub","archived":false,"fork":false,"pushed_at":"2023-09-19T12:13:44.000Z","size":118,"stargazers_count":614,"open_issues_count":21,"forks_count":76,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-04-14T03:08:42.111Z","etag":null,"topics":["cli","github","go","golang","selfupdate","update"],"latest_commit_sha":null,"homepage":"https://godoc.org/github.com/rhysd/go-github-selfupdate/selfupdate","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rhysd.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-12-25T07:30:33.000Z","updated_at":"2025-03-15T17:55:22.000Z","dependencies_parsed_at":"2024-01-13T22:58:49.959Z","dependency_job_id":"aeb38a43-36d7-43be-86c8-e2625f30c383","html_url":"https://github.com/rhysd/go-github-selfupdate","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhysd%2Fgo-github-selfupdate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhysd%2Fgo-github-selfupdate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhysd%2Fgo-github-selfupdate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhysd%2Fgo-github-selfupdate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rhysd","download_url":"https://codeload.github.com/rhysd/go-github-selfupdate/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254264766,"owners_count":22041793,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","github","go","golang","selfupdate","update"],"created_at":"2024-07-31T16:00:50.843Z","updated_at":"2025-05-15T03:07:18.461Z","avatar_url":"https://github.com/rhysd.png","language":"Go","readme":"Self-Update Mechanism for Go Commands Using GitHub\n==================================================\n\n[![GoDoc Badge][]][GoDoc]\n[![TravisCI Status][]][TravisCI]\n[![AppVeyor Status][]][AppVeyor]\n[![Codecov Status][]][Codecov]\n\n[go-github-selfupdate][] is a Go library to provide a self-update mechanism to command line tools.\n\nGo does not provide a way to install/update the stable version of tools. By default, Go command line\ntools are updated:\n\n1. using `go get -u`, but it is not stable because HEAD of the repository is built\n2. using system's package manager, but it is harder to release because of depending on the platform\n3. downloading executables from GitHub release page, but it requires users to download and put it in an executable path manually\n\n[go-github-selfupdate][] resolves the problem of 3 by detecting the latest release, downloading it and\nputting it in `$GOPATH/bin` automatically.\n\n[go-github-selfupdate][] detects the information of the latest release via [GitHub Releases API][] and\nchecks the current version. If a newer version than itself is detected, it downloads the released binary from\nGitHub and replaces itself.\n\n- Automatically detect the latest version of released binary on GitHub\n- Retrieve the proper binary for the OS and arch where the binary is running\n- Update the binary with rollback support on failure\n- Tested on Linux, macOS and Windows (using Travis CI and AppVeyor)\n- Many archive and compression formats are supported (zip, tar, gzip, xzip)\n- Support private repositories\n- Support [GitHub Enterprise][]\n- Support hash, signature validation (thanks to [@tobiaskohlbau](https://github.com/tobiaskohlbau))\n\nAnd small wrapper CLIs are provided:\n\n- [detect-latest-release](./cmd/detect-latest-release): Detect the latest release of given GitHub repository from command line\n- [go-get-release](./cmd/go-get-release): Like `go get`, but install a release binary from GitHub instead\n\n[Slide at GoCon 2018 Spring (Japanese)](https://speakerdeck.com/rhysd/go-selfupdate-github-de-turuwozi-ji-atupudetosuru)\n\n[go-github-selfupdate]: https://github.com/rhysd/go-github-selfupdate\n[GitHub Releases API]: https://developer.github.com/v3/repos/releases/\n\n\n\n## Try Out Example\n\nExample to understand what this library does is prepared as [CLI](./cmd/selfupdate-example/main.go).\n\nInstall it at first.\n\n```\n$ go get -u github.com/rhysd/go-github-selfupdate/cmd/selfupdate-example\n```\n\nAnd check the version by `-version`. `-help` flag is also available to know all flags.\n\n```\n$ selfupdate-example -version\n```\n\nIt should show `v1.2.3`.\n\nThen run `-selfupdate`\n\n```\n$ selfupdate-example -selfupdate\n```\n\nIt should replace itself and finally show a message containing release notes.\n\nPlease check the binary version is updated to `v1.2.4` with `-version`. The binary is up-to-date.\nSo running `-selfupdate` again only shows 'Current binary is the latest version'.\n\n### Real World Examples\n\nFollowing tools are using this library.\n\n- [dot-github](https://github.com/rhysd/dot-github)\n- [dotfiles](https://github.com/rhysd/dotfiles)\n- [github-clone-all](https://github.com/rhysd/github-clone-all)\n- [pythonbrew](https://github.com/utahta/pythonbrew)\n- [akashic](https://github.com/cowlick/akashic)\n- [butler](https://github.com/netzkern/butler)\n\n\n\n## Usage\n\n### Code Usage\n\nIt provides `selfupdate` package.\n\n- `selfupdate.UpdateSelf()`: Detect the latest version of itself and run self update.\n- `selfupdate.UpdateCommand()`: Detect the latest version of given repository and update given command.\n- `selfupdate.DetectLatest()`: Detect the latest version of given repository.\n- `selfupdate.DetectVersion()`: Detect the user defined version of given repository.\n- `selfupdate.UpdateTo()`: Update given command to the binary hosted on given URL.\n- `selfupdate.Updater`: Context manager of self-update process. If you want to customize some behavior\n  of self-update (e.g. specify API token, use GitHub Enterprise, ...), please make an instance of\n  `Updater` and use its methods.\n\nFollowing is the easiest way to use this package.\n\n```go\nimport (\n    \"log\"\n    \"github.com/blang/semver\"\n    \"github.com/rhysd/go-github-selfupdate/selfupdate\"\n)\n\nconst version = \"1.2.3\"\n\nfunc doSelfUpdate() {\n    v := semver.MustParse(version)\n    latest, err := selfupdate.UpdateSelf(v, \"myname/myrepo\")\n    if err != nil {\n        log.Println(\"Binary update failed:\", err)\n        return\n    }\n    if latest.Version.Equals(v) {\n        // latest version is the same as current version. It means current binary is up to date.\n        log.Println(\"Current binary is the latest version\", version)\n    } else {\n        log.Println(\"Successfully updated to version\", latest.Version)\n        log.Println(\"Release note:\\n\", latest.ReleaseNotes)\n    }\n}\n```\n\nFollowing asks user to update or not.\n\n```go\nimport (\n    \"bufio\"\n    \"github.com/blang/semver\"\n    \"github.com/rhysd/go-github-selfupdate/selfupdate\"\n    \"log\"\n    \"os\"\n)\n\nconst version = \"1.2.3\"\n\nfunc confirmAndSelfUpdate() {\n    latest, found, err := selfupdate.DetectLatest(\"owner/repo\")\n    if err != nil {\n        log.Println(\"Error occurred while detecting version:\", err)\n        return\n    }\n\n    v := semver.MustParse(version)\n    if !found || latest.Version.LTE(v) {\n        log.Println(\"Current version is the latest\")\n        return\n    }\n\n    fmt.Print(\"Do you want to update to\", latest.Version, \"? (y/n): \")\n    input, err := bufio.NewReader(os.Stdin).ReadString('\\n')\n    if err != nil || (input != \"y\\n\" \u0026\u0026 input != \"n\\n\") {\n        log.Println(\"Invalid input\")\n        return\n    }\n    if input == \"n\\n\" {\n        return\n    }\n\n    exe, err := os.Executable()\n    if err != nil {\n        log.Println(\"Could not locate executable path\")\n        return\n    }\n    if err := selfupdate.UpdateTo(latest.AssetURL, exe); err != nil {\n        log.Println(\"Error occurred while updating binary:\", err)\n        return\n    }\n    log.Println(\"Successfully updated to version\", latest.Version)\n}\n```\n\nIf GitHub API token is set to `[token]` section in `gitconfig` or `$GITHUB_TOKEN` environment variable,\nthis library will use it to call GitHub REST API. It's useful when reaching rate limits or when using\nthis library with private repositories.\n\nNote that `os.Args[0]` is not available since it does not provide a full path to executable. Instead,\nplease use `os.Executable()`.\n\nPlease see [the documentation page][GoDoc] for more detail.\n\nThis library should work with [GitHub Enterprise][]. To configure API base URL, please setup `Updater`\ninstance and use its methods instead (actually all functions above are just a shortcuts of methods of an\n`Updater` instance).\n\nFollowing is an example of usage with GitHub Enterprise.\n\n```go\nimport (\n    \"log\"\n    \"github.com/blang/semver\"\n    \"github.com/rhysd/go-github-selfupdate/selfupdate\"\n)\n\nconst version = \"1.2.3\"\n\nfunc doSelfUpdate(token string) {\n    v := semver.MustParse(version)\n    up, err := selfupdate.NewUpdater(selfupdate.Config{\n        APIToken: token,\n        EnterpriseBaseURL: \"https://github.your.company.com/api/v3\",\n    })\n    latest, err := up.UpdateSelf(v, \"myname/myrepo\")\n    if err != nil {\n        log.Println(\"Binary update failed:\", err)\n        return\n    }\n    if latest.Version.Equals(v) {\n        // latest version is the same as current version. It means current binary is up to date.\n        log.Println(\"Current binary is the latest version\", version)\n    } else {\n        log.Println(\"Successfully updated to version\", latest.Version)\n        log.Println(\"Release note:\\n\", latest.ReleaseNotes)\n    }\n}\n```\n\nIf `APIToken` field is not given, it tries to retrieve API token from `[token]` section of `.gitconfig`\nor `$GITHUB_TOKEN` environment variable. If no token is found, it raises an error because GitHub Enterprise\nAPI does not work without authentication.\n\nIf your GitHub Enterprise instance's upload URL is different from the base URL, please also set the `EnterpriseUploadURL`\nfield.\n\n\n### Naming Rules of Released Binaries\n\ngo-github-selfupdate assumes that released binaries are put for each combination of platforms and archs.\nBinaries for each platform can be easily built using tools like [gox][]\n\nYou need to put the binaries with the following format.\n\n```\n{cmd}_{goos}_{goarch}{.ext}\n```\n\n`{cmd}` is a name of command.\n`{goos}` and `{goarch}` are the platform and the arch type of the binary.\n`{.ext}` is a file extension. go-github-selfupdate supports `.zip`, `.gzip`, `.tar.gz` and `.tar.xz`.\nYou can also use blank and it means binary is not compressed.\n\nIf you compress binary, uncompressed directory or file must contain the executable named `{cmd}`.\n\nAnd you can also use `-` for separator instead of `_` if you like.\n\nFor example, if your command name is `foo-bar`, one of followings is expected to be put in release\npage on GitHub as binary for platform `linux` and arch `amd64`.\n\n- `foo-bar_linux_amd64` (executable)\n- `foo-bar_linux_amd64.zip` (zip file)\n- `foo-bar_linux_amd64.tar.gz` (tar file)\n- `foo-bar_linux_amd64.xz` (xzip file)\n- `foo-bar-linux-amd64.tar.gz` (`-` is also ok for separator)\n\nIf you compress and/or archive your release asset, it must contain an executable named one of followings:\n\n- `foo-bar` (only command name)\n- `foo-bar_linux_amd64` (full name)\n- `foo-bar-linux-amd64` (`-` is also ok for separator)\n\nTo archive the executable directly on Windows, `.exe` can be added before file extension like\n`foo-bar_windows_amd64.exe.zip`.\n\n[gox]: https://github.com/mitchellh/gox\n\n\n### Naming Rules of Versions (=Git Tags)\n\ngo-github-selfupdate searches binaries' versions via Git tag names (not a release title).\nWhen your tool's version is `1.2.3`, you should use the version number for tag of the Git\nrepository (i.e. `1.2.3` or `v1.2.3`).\n\nThis library assumes you adopt [semantic versioning][]. It is necessary for comparing versions\nsystematically.\n\nPrefix before version number `\\d+\\.\\d+\\.\\d+` is automatically omitted. For example, `ver1.2.3` or\n`release-1.2.3` are also ok.\n\nTags which don't contain a version number are ignored (i.e. `nightly`). And releases marked as `pre-release`\nare also ignored.\n\n[semantic versioning]: https://semver.org/\n\n\n### Structure of Releases\n\nIn summary, structure of releases on GitHub looks like:\n\n- `v1.2.0`\n  - `foo-bar-linux-amd64.tar.gz`\n  - `foo-bar-linux-386.tar.gz`\n  - `foo-bar-darwin-amd64.tar.gz`\n  - `foo-bar-windows-amd64.zip`\n  - ... (Other binaries for v1.2.0)\n- `v1.1.3`\n  - `foo-bar-linux-amd64.tar.gz`\n  - `foo-bar-linux-386.tar.gz`\n  - `foo-bar-darwin-amd64.tar.gz`\n  - `foo-bar-windows-amd64.zip`\n  - ... (Other binaries for v1.1.3)\n- ... (older versions)\n\n\n### Hash or Signature Validation\n\ngo-github-selfupdate supports hash or signature validatiom of the downloaded files. It comes\nwith support for sha256 hashes or ECDSA signatures. In addition to internal functions the\nuser can implement the `Validator` interface for own validation mechanisms.\n\n```go\n// Validator represents an interface which enables additional validation of releases.\ntype Validator interface {\n\t// Validate validates release bytes against an additional asset bytes.\n\t// See SHA2Validator or ECDSAValidator for more information.\n\tValidate(release, asset []byte) error\n\t// Suffix describes the additional file ending which is used for finding the\n\t// additional asset.\n\tSuffix() string\n}\n```\n\n#### SHA256\n\nTo verify the integrity by SHA256 generate a hash sum and save it within a file which has the\nsame naming as original file with the suffix `.sha256`.\nFor e.g. use sha256sum, the file `selfupdate/testdata/foo.zip.sha256` is generated with:\n```shell\nsha256sum foo.zip \u003e foo.zip.sha256\n```\n\n#### ECDSA\nTo verify the signature by ECDSA generate a signature and save it within a file which has the\nsame naming as original file with the suffix `.sig`.\nFor e.g. use openssl, the file `selfupdate/testdata/foo.zip.sig` is generated with:\n```shell\nopenssl dgst -sha256 -sign Test.pem -out foo.zip.sig foo.zip\n```\n\ngo-github-selfupdate makes use of go internal crypto package. Therefore the used private key\nhas to be compatbile with FIPS 186-3.\n\n\n\n## Development\n\n### Running tests\n\nAll library sources are put in `/selfupdate` directory. So you can run tests as following\nat the top of the repository:\n\n```\n$ go test -v ./selfupdate\n```\n\nSome tests are not run without setting a GitHub API token because they call GitHub API too many times.\nTo run them, please generate an API token and set it to an environment variable.\n\n```\n$ export GITHUB_TOKEN=\"{token generated by you}\"\n$ go test -v ./selfupdate\n```\n\nThe above command runs almost all tests and it's enough to check the behavior before creating a pull request.\nSome tests are still not tested because they depend on my personal API access token, though; for repositories\non GitHub Enterprise or private repositories on GitHub.\n\n\n### Debugging\n\nThis library can output logs for debugging. By default, logger is disabled.\nYou can enable the logger by the following and can know the details of the self update.\n\n```go\nselfupdate.EnableLog()\n```\n\n\n### CI\n\nTests run on CIs (Travis CI, Appveyor) are run with the token I generated. However, because of security\nreasons, it is not used for the tests for pull requests. In the tests, a GitHub API token is not set and\nAPI rate limit is often exceeding. So please ignore the test failures on creating a pull request.\n\n\n\n## Dependencies\n\nThis library utilizes\n- [go-github][] to retrieve the information of releases\n- [go-update][] to replace current binary\n- [semver][] to compare versions\n- [xz][] to support XZ compress format\n\n\u003e Copyright (c) 2013 The go-github AUTHORS. All rights reserved.\n\n\u003e Copyright 2015 Alan Shreve\n\n\u003e Copyright (c) 2014 Benedikt Lang \u003cgithub at benediktlang.de\u003e\n\n\u003e Copyright (c) 2014-2016  Ulrich Kunitz\n\n[go-github]: https://github.com/google/go-github\n[go-update]: https://github.com/inconshreveable/go-update\n[semver]: https://github.com/blang/semver\n[xz]: https://github.com/ulikunitz/xz\n\n\n\n## What is different from [tj/go-update][]?\n\nThis library's goal is the same as tj/go-update, but it's different in following points.\n\ntj/go-update:\n\n- does not support Windows\n- only allows `v` for version prefix\n- does not ignore pre-release\n- has [only a few tests](https://github.com/tj/go-update/blob/master/update_test.go)\n- supports Apex store for putting releases\n\n[tj/go-update]: https://github.com/tj/go-update\n\n\n\n## License\n\nDistributed under the [MIT License](LICENSE)\n\n[GoDoc Badge]: https://godoc.org/github.com/rhysd/go-github-selfupdate/selfupdate?status.svg\n[GoDoc]: https://godoc.org/github.com/rhysd/go-github-selfupdate/selfupdate\n[TravisCI Status]: https://travis-ci.org/rhysd/go-github-selfupdate.svg?branch=master\n[TravisCI]: https://travis-ci.org/rhysd/go-github-selfupdate\n[AppVeyor Status]: https://ci.appveyor.com/api/projects/status/1tpyd9q9tw3ime5u/branch/master?svg=true\n[AppVeyor]: https://ci.appveyor.com/project/rhysd/go-github-selfupdate/branch/master\n[Codecov Status]: https://codecov.io/gh/rhysd/go-github-selfupdate/branch/master/graph/badge.svg\n[Codecov]: https://codecov.io/gh/rhysd/go-github-selfupdate\n[GitHub Enterprise]: https://enterprise.github.com/home\n","funding_links":[],"categories":["开源类库","Go"],"sub_categories":["优雅升级"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frhysd%2Fgo-github-selfupdate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frhysd%2Fgo-github-selfupdate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frhysd%2Fgo-github-selfupdate/lists"}