Files
goreleaser-action/README.md
T
73cd4ffe39 feat: reuse the goreleaser binary from the runner tool cache (#577)
* feat: cache the goreleaser binary

Look for GoReleaser in the runner tool cache before a download. This
makes a second use of the action in the same job, or any job on a
self-hosted runner, install immediately.

Add an opt-in `cache-binary` input that also stores the binary in the
GitHub Actions cache. When it hits, the action does not download the
release archive, the checksums and the signature bundle again. Cache
errors are not fatal and fall back to a download.

The runner tool cache entry is now keyed by distribution, so a Pro
binary is no longer returned for an OSS install of the same version.

Closes #476

Co-authored-by: timbretimber <105982513+timbretimber@users.noreply.github.com>
Co-authored-by: Akkuman <akkumans@qq.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* refactor: collapse the duplicated zip extract branches

Both branches called extractZip with the same destination after the
install rewrite, so only the source path differs now.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4eaf86fa-a85b-41f6-8763-612acc1ccc39
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: drop the GitHub Actions cache layer, keep the tool cache lookup

Review found that the GitHub Actions cache layer cost more than it
saved. Measured on ubuntu-latest, same job, same version:

  cold: download + checksum + cosign + extract   0.93 s
  cache hit: restore the 24 MB entry             1.28 s
  first run also pays a save                    +2.26 s

It is slower than a download in every configuration measured, because a
GitHub-hosted runner reaches the release CDN in about 0.4 s for a 15 MB
archive, and the cached entry is the larger extracted directory.

It also skipped the sha256 and cosign verification on a hit, which is
the control it was supposed to protect, and the only case where it wins
on time is when cosign is installed, which is exactly the case where
skipping is wrong. It cost 875 KB (+120%) of dist/index.js for every
user and 24 MB of repository cache quota per version and platform.

The restore and save wrappers were also dead code: @actions/cache
catches everything except ValidationError internally, so the try/catch
and the ReserveCacheError classification could never run.

What remains is the runner tool cache lookup, which is what #476 asked
for, and the distribution-keyed tool name that stops a Pro binary being
returned for an OSS install.

The tool cache test asserted that two installs return the same path, but
that path is a pure function of the tool, version and architecture: it
passed even with the tool cache wiped between the calls. It now asserts
that the second install reports a tool cache hit and does not download,
and it was verified to fail when the lookup is removed.

Co-authored-by: timbretimber <105982513+timbretimber@users.noreply.github.com>
Co-authored-by: Akkuman <akkumans@qq.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4eaf86fa-a85b-41f6-8763-612acc1ccc39
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* docs: drop the GitHub Actions cache rationale from the README

Review feedback: the paragraph explaining why the action does not use the
GitHub Actions cache is not needed. The measurements stay in the pull
request for anyone who asks again.

Also rebuilds dist for js-yaml 5.4.1, merged from master in #578.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4eaf86fa-a85b-41f6-8763-612acc1ccc39
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix(cache): preserve verification guarantees

Keep checksum-skipped downloads out of the persistent tool cache and separate checksum-only entries from cosign-verified entries.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 5abc512e-338c-4459-98ea-d3606438d56a
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

---------

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
Co-authored-by: timbretimber <105982513+timbretimber@users.noreply.github.com>
Co-authored-by: Akkuman <akkumans@qq.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4eaf86fa-a85b-41f6-8763-612acc1ccc39
Copilot-Session: 5abc512e-338c-4459-98ea-d3606438d56a
2026-09-03 00:31:48 -03:00

12 KiB

GoReleaser Logo

GoReleaser Action

GitHub Action for GoReleaser

GitHub release GitHub marketplace Test workflow Codecov


GoRelease Action

Usage

GoReleaser Action runs goreleaser, please follow its docs for more information about how to customize what GoReleaser does.

Workflow

name: goreleaser

on:
  pull_request:
  push:

permissions:
  contents: write

jobs:
  goreleaser:
    runs-on: ubuntu-latest
    steps:
      -
        name: Checkout
        uses: actions/checkout@v6
        with:
          fetch-depth: 0
      -
        name: Set up Go
        uses: actions/setup-go@v6
      -
        name: Run GoReleaser
        uses: goreleaser/goreleaser-action@v7
        with:
          # either 'goreleaser' (default) or 'goreleaser-pro'
          distribution: goreleaser
          # 'latest', 'nightly', or a semver
          version: '~> v2'
          args: release --clean
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          # Your GoReleaser Pro key, if you are using the 'goreleaser-pro' distribution
          # GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}

Important

: note the fetch-depth: 0 input in Checkout step. It is required for the changelog to work correctly.

Verification

The action verifies the integrity of the downloaded GoReleaser archive against the published checksums.txt automatically — no configuration required.

If cosign is available on PATH, the action will additionally verify the cosign sigstore signature of the checksums file against the GoReleaser release workflow's OIDC identity. If cosign isn't installed, this step is silently skipped.

Note

: cosign signature verification requires GoReleaser v2.13.0 or newer (and the matching nightly). Earlier releases ship a .sig detached signature signed with cosign v2, which is not compatible with the cosign v3 sigstore-bundle format the action verifies. For older versions the cosign step is silently skipped — only the checksums.txt SHA-256 verification runs.

Note

: when version: nightly is used, the action resolves the latest immutable vX.Y.Z-<sha>-nightly release from the GitHub Releases API. Pass GITHUB_TOKEN to the action step (as in the example above) to avoid unauthenticated API rate limits.

To enable signature verification, install cosign before running the action:

      -
        name: Install cosign
        uses: sigstore/cosign-installer@v3
      -
        name: Run GoReleaser
        uses: goreleaser/goreleaser-action@v7
        with:
          distribution: goreleaser
          version: '~> v2'
          args: release --clean
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Both checksum and signature verification work for tagged releases (≥ v2.13.0) and the nightly channel.

Run on new tag

If you want to run GoReleaser only on new tag, you can use this event:

on:
  push:
    tags:
      - '*'

Or with a condition on GoReleaser step:

      -
        name: Run GoReleaser
        uses: goreleaser/goreleaser-action@v7
        if: startsWith(github.ref, 'refs/tags/')
        with:
          version: '~> v2'
          args: release --clean
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

For detailed instructions please follow GitHub Actions workflow syntax.

Signing

If signing is enabled in your GoReleaser configuration, you can use the Import GPG GitHub Action along with this one:

      -
        name: Import GPG key
        id: import_gpg
        uses: crazy-max/ghaction-import-gpg@v7
        with:
          gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
          passphrase: ${{ secrets.PASSPHRASE }}
      -
        name: Run GoReleaser
        uses: goreleaser/goreleaser-action@v7
        with:
          version: '~> v2'
          args: release --clean
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}

And reference the fingerprint in your signing configuration using the GPG_FINGERPRINT environment variable:

signs:
  - artifacts: checksum
    args: ["--batch", "-u", "{{ .Env.GPG_FINGERPRINT }}", "--output", "${signature}", "--detach-sign", "${artifact}"]

Upload artifacts

For some events like pull request or schedule you might want to store the artifacts somewhere for testing purposes. You can do that with the actions/upload-artifact action:

      -
        name: Run GoReleaser
        uses: goreleaser/goreleaser-action@v7
        with:
          version: '~> v2'
          args: release --clean
          workdir: myfolder
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      -
        name: Upload assets
        uses: actions/upload-artifact@v6
        with:
          name: myapp
          path: myfolder/dist/*

Install Only

steps:
  -
    name: Install GoReleaser
    uses: goreleaser/goreleaser-action@v7
    with:
      install-only: true
  -
    name: Show GoReleaser version
    run: goreleaser -v

Cache the binary

The action looks for GoReleaser in the runner tool cache before it downloads. A second use of the action in the same job, or any job on a self-hosted runner that already has the version, installs immediately.

A binary taken from the tool cache is not verified again. The cache records whether checksum or checksum and cosign verification completed. When cosign is available, the action only reuses a signature-verified entry. A binary whose checksum could not be verified is used for that invocation but is not cached.

On a self-hosted runner the tool cache is kept between jobs, so it must be trusted like the runner itself. GitHub-hosted runners start with an empty tool cache in every job, so they always download and verify.

Customizing

inputs

Following inputs can be used as step.with keys

Name Type Default Description
distribution String goreleaser GoReleaser distribution, either goreleaser or goreleaser-pro
version¹ String ~> v2 GoReleaser version
version-file² String Read the GoReleaser version from a file (see below)
args String Arguments to pass to GoReleaser
workdir String . Working directory (below repository root)
install-only Bool false Just install GoReleaser

¹ Can be a fixed version like v0.117.0 or a max satisfying semver one like ~> 0.132. In this case this will return v0.132.1.

² Path to a file containing the GoReleaser version. Resolved relative to workdir. Currently only .tool-versions (asdf/mise) format is supported. When set, this takes precedence over version.

# .tool-versions
goreleaser 2.13.0
- uses: goreleaser/goreleaser-action@v7
  with:
    version-file: .tool-versions
    args: release --clean

outputs

Following outputs are available

Name Type Description
artifacts JSON Build result artifacts
metadata JSON Build result metadata

environment variables

Following environment variables can be used as step.env keys

Name Description
GITHUB_TOKEN GITHUB_TOKEN as provided by secrets and requires contents:write
GORELEASER_KEY Your GoReleaser Pro License Key, in case you are using the goreleaser-pro distribution

Limitation

GITHUB_TOKEN permissions are limited to the repository that contains your workflow.

If you need to push the homebrew tap to another repository, you must therefore create a custom Personal Access Token with repo permissions and add it as a secret in the repository. If you create a secret named GH_PAT, the step will look like this:

      -
        name: Run GoReleaser
        uses: goreleaser/goreleaser-action@v7
        with:
          version: '~> v2'
          args: release --clean
        env:
          GITHUB_TOKEN: ${{ secrets.GH_PAT }}

Migrating from v3

If you need the auto-snapshot feature, take a look at this example repository: it's a minimal working example with all you need.

Development

See CONTRIBUTING.md for the full development workflow.

Quick reference:

# install dependencies
npm ci

# format, build dist/, and run tests
npm run pre-checkin

License

MIT. See LICENSE for more details.