feat: add a verifiable configuration file with GoReleaser#22
Merged
Conversation
Owner
tmknom
commented
Jan 3, 2025
- feat: copy from goreleaser/default.yml to goreleaser/verifiable.yml
- feat: enhancing software integrity using Cosign with GoReleaser
- feat: secure container images using Cosign with GoReleaser
- feat: generating SBOMs with GoReleaser
- feat: build native Linux packages with GoReleaser
- feat: generate a Homebrew formula with GoReleaser
The `signs` section in GoReleaser enables binary signing using **Cosign**, ensuring the authenticity and integrity of your software artifacts. By signing binaries, you strengthen supply chain security, providing users with a verifiable way to trust your software's source and integrity.
---
### Example Configuration
```yaml
signs:
- cmd: cosign
artifacts: all
signature: ${artifact}.sig
certificate: ${artifact}.pem
output: true
args:
- sign-blob
- --output-signature=${signature}
- --output-certificate=${certificate}
- --oidc-issuer=https://token.actions.githubusercontent.com
- --oidc-provider=github-actions
- --yes
- ${artifact}
```
**Key Features**:
1. Signs all generated binaries.
2. Produces signature (`.sig`) and certificate (`.pem`) files for verification.
3. Integrates with CI environments like GitHub Actions, adhering to best practices for supply chain security.
---
### Key Benefits
1. **Authenticity**
Ensures binaries originate from the intended source, helping users verify their origin.
2. **Integrity**
Guarantees that artifacts haven't been tampered with during distribution.
3. **Supply Chain Security**
Critical for modern software pipelines, enabling traceability and trust.
4. **User Confidence**
Builds trust among end users, fostering confidence in adopting your software.
---
### Why Use Cosign?
Cosign offers a robust, open-source solution for signing and verifying artifacts:
- **Authenticity**: Verifies the source of the binaries.
- **Integrity**: Confirms the binaries remain unchanged.
- **Supply Chain Security**: Aligns with modern standards like SLSA (Supply Chain Levels for Software Artifacts).
- **Ease of Verification**: Simplifies validation with signatures and certificates.
---
### Configuration Options
#### **`artifacts`**
The `artifacts` option specifies which artifacts to sign:
```yaml
artifacts: all
```
- **`all`**: Signs all generated artifacts during the release process, ensuring comprehensive security coverage.
---
#### **`signature`**
The `signature` option defines the name and location of the signature file:
```yaml
signature: ${artifact}.sig
```
**Example**:
For an artifact named `mybinary_1.0.0_linux_amd64`, the signature file will be `mybinary_1.0.0_linux_amd64.sig`.
---
#### **`certificate`**
The `certificate` option defines the name and location of the certificate file:
```yaml
certificate: ${artifact}.pem
```
**Example**:
For the same artifact above, the certificate file will be `mybinary_1.0.0_linux_amd64.pem`.
---
#### **`args`**
The `args` option customizes arguments for the `cosign` command:
```yaml
args:
- sign-blob
- --output-signature=${signature}
- --output-certificate=${certificate}
- --oidc-issuer=https://token.actions.githubusercontent.com
- --oidc-provider=github-actions
- --yes
- ${artifact}
```
**Breakdown of Key Arguments**:
- **`sign-blob`**: Signs a blob (binary or artifact).
- **`--output-signature`**: Specifies where to save the signature file.
- **`--output-certificate`**: Specifies where to save the certificate file.
- **`--oidc-issuer`**: Configures the OpenID Connect (OIDC) issuer (e.g., `token.actions.githubusercontent.com`).
- **`--oidc-provider`**: Sets the OIDC provider (e.g., `github-actions`).
- **`--yes`**: Automates the signing process, bypassing interactive prompts.
- **`${artifact}`**: Processes all artifacts generated during the build.
---
# Quoting the GoReleaser documentation:
- https://goreleaser.com/customization/sign/
## Signing archives, packages, checksums
Signing ensures that the artifacts have been generated by yourself, and your
users can verify that by comparing the generated signature with your public
signing key.
GoReleaser provides means to sign both executables and archives.
### Usage
Signing works in combination with checksum files, and it is generally enough
to sign the checksum files only.
The default is configured to create a detached signature for the checksum files
with [GnuPG](https://www.gnupg.org/), and your default key.
To enable signing just add this to your configuration:
```yaml title=".goreleaser.yaml"
signs:
- artifacts: checksum
```
To customize the signing pipeline you can use the following options:
```yaml title=".goreleaser.yaml"
signs:
- #
# ID of the sign config, must be unique.
#
# Default: 'default'.
id: foo
# Name of the signature file.
#
# Default: '${artifact}.sig'.
# Templates: allowed.
signature: "${artifact}_sig"
# Path to the signature command
#
# Default: 'gpg'.
cmd: gpg2
# Command line arguments for the command
#
# to sign with a specific key use
# args: ["-u", "<key id, fingerprint, email, ...>", "--output", "${signature}", "--detach-sign", "${artifact}"]
#
# Default: ["--output", "${signature}", "--detach-sign", "${artifact}"].
# Templates: allowed.
args: ["--output", "${signature}", "${artifact}", "{{ .ProjectName }}"]
# Which artifacts to sign
#
# Valid options are:
# - none no signing
# - all: all artifacts
# - checksum: checksum files
# - source: source archive
# - package: Linux packages (deb, rpm, apk, etc)
# - installer: Windows MSI installers (Pro only)
# - diskimage: macOS DMG disk images (Pro only)
# - archive: archives from archive pipe
# - sbom: any SBOMs generated for other artifacts
# - binary: binaries (only when `archives.format` is 'binary', use binaries_sign otherwise)
#
# Default: 'none'.
artifacts: all
# IDs of the artifacts to sign.
#
# If `artifacts` is checksum or source, this fields has no effect.
ids:
- foo
- bar
# Allows to further filter the artifacts.
#
# Artifacts that do not match this expression will be ignored.
#
# <!-- md:inline_pro -->.
# <!-- md:inline_version v2.2 -->.
# Templates: allowed.
if: '{{ eq .Os "linux" }}'
# Stdin data to be given to the signature command as stdin.
#
# Templates: allowed.
stdin: "{{ .Env.GPG_PASSWORD }}"
# StdinFile file to be given to the signature command as stdin.
stdin_file: ./.password
# Sets a certificate that your signing command should write to.
#
# You can later use `${certificate}` or `.Env.certificate` in the `args` section.
#
# This is particularly useful for keyless signing with cosign, and should
# not usually be used otherwise.
#
# Note that this should be a name, not a path.
#
# Templates: allowed.
certificate: '{{ trimsuffix .Env.artifact ".tar.gz" }}.pem'
# List of environment variables that will be passed to the signing command
# as well as the templates.
env:
- FOO=bar
- HONK=honkhonk
# By default, the stdout and stderr of the signing cmd are discarded unless
# GoReleaser is running with `--verbose` set.
# You can set this to true if you want them to be displayed regardless.
output: true
```
#### Available variable names
These environment variables might be available in the fields that accept
templates:
- `${artifact}`: the path to the artifact that will be signed
- `${artifactID}`: the ID of the artifact that will be signed
- `${certificate}`: the certificate filename, if provided
- `${signature}`: the signature filename
### Signing with cosign
You can sign your artifacts with [cosign][] as well.
Assuming you have a `cosign.key` in the repository root and a `COSIGN_PWD`
environment variable set, a simple usage example would look like this:
```yaml title=".goreleaser.yaml"
signs:
- cmd: cosign
stdin: "{{ .Env.COSIGN_PWD }}"
args:
- "sign-blob"
- "--key=cosign.key"
- "--output-signature=${signature}"
- "${artifact}"
- "--yes" # needed on cosign 2.0.0+
artifacts: all
```
Your users can then verify the signature with:
```sh
cosign verify-blob -key cosign.pub -signature file.tar.gz.sig file.tar.gz
```
<!-- TODO: keyless signing with cosign example -->
### Signing executables
Executables can be signed after build using post hooks.
#### With gon
!!! notice
[gon][] was discontinued by its maintainer, but it lives on in a
[fork][gon-fork], which we'll use here.
For example, you can use [gon][gon-fork] to create notarized macOS apps:
```yaml title=".goreleaser.yaml"
builds:
- binary: foo
id: foo
goos:
- linux
- windows
goarch:
- amd64
# notice that we need a separated build for the MacOS binary only:
- binary: foo
id: foo-macos
goos:
- darwin
goarch:
- amd64
hooks:
post: gon gon.hcl
```
And:
```terraform
# gon.hcl
#
# The path follows a pattern
# ./dist/BUILD-ID_TARGET/BINARY-NAME
source = ["./dist/foo-macos_darwin_amd64/foo"]
bundle_id = "com.mitchellh.example.terraform"
apple_id {
username = "mitchell@example.com"
password = "@env:AC_PASSWORD"
}
sign {
application_identity = "Developer ID Application: Mitchell Hashimoto"
}
```
Note that notarizing may take some time, and will need to be run from a macOS
machine.
If you generate ZIP or DMG as part of your signing via gon you may need to
ensure their file names align with desired pattern of other artifacts as
GoReleaser doesn't control how these get generated beyond just executing `gon`
with given arguments. Relatedly you may need to list these additional artifacts
as `extra_files` in the `release` section to make sure they also get uploaded.
You can also check
[this issue](goreleaser/goreleaser#1227) for more
details.
#### With cosign
You can also use [cosign][] to sign the binaries directly, but you'll need to
manually add the `.sig` files to the release and/or archive:
```yaml title=".goreleaser.yaml"
builds:
- hooks:
post:
- sh -c "COSIGN_PASSWORD=$COSIGN_PWD cosign sign-blob --key cosign.key --output-signature dist/{{ .ProjectName }}_{{ .Version }}_{{ .Target }}.sig {{ .Path }}"
# add to the release directly:
release:
extra_files:
- glob: dist/*.sig
# or just to the archives:
archives:
- files:
- dist/*.sig
```
While this works, I would recommend using the signing pipe directly.
### Signing Docker images and manifests
Please refer to [Docker Images Signing](docker_sign.md).
### Limitations
You can sign with any command that either outputs a file or modify the file
being signed.
If you want to sign with something that writes to `STDOUT` instead of a file,
you can wrap the command inside a `sh -c` execution, for instance:
```yaml title=".goreleaser.yaml"
signs:
- cmd: sh
args:
- "-c"
- 'echo "${artifact} is signed and I can prove it" | tee ${signature}'
artifacts: all
```
And it will work just fine. Just make sure to always use the `${signature}`
template variable as the result file name and `${artifact}` as the origin file.
[gon]: https://github.com/mitchellh/gon
[gon-fork]: https://github.com/Bearer/gon
[cosign]: https://github.com/sigstore/cosign
The `docker_signs` section in GoReleaser enables signing container images using **Cosign**, ensuring their **authenticity** and **integrity**. This is a crucial step for securing containerized software, particularly in supply chains where trust and verification are essential.
---
### Example Configuration
```yaml
docker_signs:
- cmd: cosign
artifacts: all
output: true
args:
- sign
- --oidc-issuer=https://token.actions.githubusercontent.com
- --oidc-provider=github-actions
- --yes
- ${artifact}@${digest}
```
---
### Key Benefits of Signing Container Images
1. **Authenticity**
Verifies that the container image comes from the intended source.
2. **Integrity**
Ensures the image content has not been tampered with after it was built.
3. **Supply Chain Security**
Aligns with modern best practices by providing trust and traceability for container images.
4. **Automation-Friendly**
Seamlessly integrates with CI/CD pipelines, automating the signing process for consistent security.
---
### Configuration Options
#### **`artifacts`**
The `artifacts` option specifies which container images should be signed:
```yaml
artifacts: all
```
- **`all`**: Signs every container image produced during the build process, ensuring comprehensive security coverage.
- **Importance**: This ensures no image is left unsigned, mitigating risks of compromised or tampered images.
---
#### **`output`**
The `output` option controls whether to save the signing process's output:
```yaml
output: true
```
- **`true`**: Ensures signed container images and related data are stored, making them available for further processes like deployment or verification.
- **Use Case**: Ideal for maintaining records of signed images for auditing or downstream usage.
---
#### **`args`**
The `args` option customizes the arguments passed to the `cosign` command:
```yaml
args:
- sign
- --oidc-issuer=https://token.actions.githubusercontent.com
- --oidc-provider=github-actions
- --yes
- ${artifact}@${digest}
```
**Breakdown of Arguments**:
- **`sign`**: The primary command to sign container images.
- **`--oidc-issuer`**: Specifies the OpenID Connect (OIDC) issuer URL (e.g., `https://token.actions.githubusercontent.com`) to authenticate the signing process.
- **`--oidc-provider`**: Defines the OIDC provider (e.g., GitHub Actions) responsible for identity verification.
- **`--yes`**: Automates confirmation of the signing process, making it ideal for non-interactive CI/CD workflows.
- **`${artifact}@${digest}`**: Refers to the container image and its digest:
- **`${artifact}`**: The name of the container image (e.g., `myapp:1.0.0`).
- **`${digest}`**: The unique hash of the image, ensuring precise identification and matching of content during signing.
---
# Quoting the GoReleaser documentation:
- https://goreleaser.com/customization/docker_sign/
## Signing Docker Images and Manifests
Signing Docker Images and Manifests is also possible with GoReleaser.
This pipe was designed based on the common [sign](sign.md) pipe
having [cosign](https://github.com/sigstore/cosign) in mind.
!!! info
Note that this pipe will run only at the end of the GoReleaser execution (in
its publishing phase), as cosign will change the image in the registry.
To customize the signing pipeline you can use the following options:
```yaml title=".goreleaser.yaml"
docker_signs:
- # ID of the sign config, must be unique.
# Only relevant if you want to produce some sort of signature file.
#
# Default: 'default'.
id: foo
# Path to the signature command.
#
# Default: 'cosign'.
cmd: cosign
# Command line arguments for the command.
#
# Default: ["sign", "--key=cosign.key", "${artifact}", "--yes"].
# Templates: allowed.
args:
- "sign"
- "--key=cosign.key"
- "--upload=false"
- "${artifact}"
- "--yes" # needed on cosign 2.0.0+
# Which artifacts to sign.
#
# all: all artifacts
# none: no signing
# images: only docker images
# manifests: only docker manifests
#
# Default: 'none'.
artifacts: all
# IDs of the artifacts to sign.
ids:
- foo
- bar
# Allows to further filter the artifacts.
#
# Artifacts that do not match this expression will be ignored.
#
# <!-- md:inline_pro -->.
# <!-- md:inline_version v2.2 -->.
# Templates: allowed.
if: '{{ eq .Os "linux" }}'
# Stdin data to be given to the signature command as stdin.
#
# Templates: allowed.
stdin: "{{ .Env.COSIGN_PWD }}"
# StdinFile file to be given to the signature command as stdin.
stdin_file: ./.password
# List of environment variables that will be passed to the signing command
# as well as the templates.
env:
- FOO=bar
- HONK=honkhonk
# By default, the stdout and stderr of the signing cmd are discarded unless
# GoReleaser is running with `--verbose` set.
# You can set this to true if you want them to be displayed regardless.
output: true
```
#### Available variable names
These environment variables might be available in the fields that are templateable:
- `${artifact}`[^1]: the path to the artifact that will be signed (including the
digest[^2])
- `${digest}`[^2]: the digest of the image/manifest that will be signed
- `${artifactID}`: the ID of the artifact that will be signed
- `${certificate}`: the certificate file name, if provided
[^1]:
notice that this might contain `/` characters, which depending on how
you use it might evaluate to actual paths within the file system. Use with
care.
[^2]:
those are extracted automatically when running Docker push from within
GoReleaser. Using the digest helps making sure you're signing the right image
and avoid concurrency issues.
### Common usage example
Assuming you have a `cosign.key` in the repository root and a `COSIGN_PWD`
environment variable, the simplest configuration to sign both Docker images
and manifests would look like this:
```yaml title=".goreleaser.yaml"
docker_signs:
- artifacts: all
stdin: "{{ .Env.COSIGN_PWD }}"
```
Later on you (and anyone else) can verify the image with:
```bash
cosign verify --key cosign.pub your/image
```
The `sboms` section in GoReleaser is designed to generate **Software Bill of Materials (SBOMs)** for your project. An SBOM provides detailed insights into the components and dependencies used in your software, which is essential for improving **security**, **compliance**, and **transparency**.
---
### Example Configuration
```yaml
sboms:
- id: binary
artifacts: binary
documents:
- "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}.sbom.json"
- id: package
artifacts: package
```
---
### Why Generate SBOMs?
1. **Transparency**
SBOMs provide a complete list of components and dependencies in your software, helping stakeholders assess its content.
2. **Vulnerability Management**
By listing all dependencies, SBOMs enable you to quickly identify and mitigate vulnerabilities.
3. **Compliance**
SBOMs help align with industry regulations and standards, such as **Executive Order 14028** in the U.S., which mandates secure software practices.
4. **Supply Chain Security**
SBOMs improve visibility and trust in your software supply chain, ensuring accountability at every stage.
---
### Configuration Options
#### **`artifacts`**
The `artifacts` option specifies the types of artifacts for which SBOMs should be generated:
```yaml
artifacts: binary
```
**Available Options**:
- **`binary`**: Generates SBOMs for binary artifacts.
- **`package`**: Generates SBOMs for package-based artifacts.
**Use Case**: Select the relevant artifact type(s) based on your project’s distribution strategy to ensure complete SBOM coverage.
---
#### **`documents`**
The `documents` option defines the naming convention for SBOM files using GoReleaser's templating system:
```yaml
documents:
- "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}.sbom.json"
```
**Example Output**:
For a project named `example`, version `1.0.0`, targeting `linux` and `amd64`, the resulting SBOM file would be named:
`example_1.0.0_linux_amd64.sbom.json`
**Key Variables**:
- **`{{ .ProjectName }}`**: The name of the project.
- **`{{ .Version }}`**: The current version of the project.
- **`{{ .Os }}`**: The target operating system (e.g., `linux`, `windows`).
- **`{{ .Arch }}`**: The target CPU architecture (e.g., `amd64`, `arm64`).
---
# Quoting the GoReleaser documentation:
- https://goreleaser.com/customization/sbom/
## Cataloging artifacts
A Software Bill of Materials (SBOM) is a description of the components that make
up a software artifact.
GoReleaser can create one or more SBOMs for any artifacts generated by
GoReleaser.
### Usage
The artifact cataloging step can analyze one or more artifacts generated by
GoReleaser and output one or more SBOM files into the dist directory.
The default is configured to create an SBOM for each binary produced with
[Syft](https://github.com/anchore/syft). To enable artifact cataloging just add:
```yaml title=".goreleaser.yaml"
sboms:
- artifacts: archive
```
To customize the artifact cataloging pipeline you can use the following options:
```yaml title=".goreleaser.yaml"
sboms:
- # ID of the sbom config, must be unique.
#
# Default: 'default'.
id: foo
# List of names of the SBOM documents created at this step
# (relative to the dist dir).
#
# Each element configured is made available as variables. For example:
# documents: ["foo", "bar"]
#
# would make the following variables that can be referenced as template keys:
# document0: "foo"
# document1: "bar"
#
# Note that multiple sbom values are only allowed if the value of
# "artifacts" is "any".
#
# Default:
# When "binary": ["{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}.sbom.json"]
# When "any": []
# Otherwise: ["{{ .ArtifactName }}.sbom.json"]
# Templates: allowed.
documents:
- "${artifact}.spdx.sbom.json"
# Path to the SBOM generator command
#
# Note: the process CWD will be set to the same location as "dist"
#
# Default: 'syft'.
cmd: syft
# Command line arguments for the command
#
# Default: ["$artifact", "--output", "spdx-json=$document"].
# Templates: allowed.
args: ["$artifact", "--output", "cyclonedx-json=$document"]
# List of environment variables that will be passed to the SBOM command as
# well as the templates.
#
# Default: [ "SYFT_FILE_METADATA_CATALOGER_ENABLED=true" ].
env:
- FOO=bar
- HONK=honkhonk
# Which artifacts to catalog.
#
# Valid options are:
# - any: let the SBOM tool decide which artifacts available in
# the cwd should be cataloged
# - source: source archive
# - package: Linux packages (deb, rpm, apk, etc)
# - installer: Windows MSI installers (Pro only)
# - diskimage: macOS DMG disk images (Pro only)
# - archive: archives from archive pipe
# - binary: binaries output from the build stage
#
# Default: 'archive'.
artifacts: archive
# IDs of the artifacts to catalog.
#
# If `artifacts` is "source" or "any" then this fields has no effect.
ids:
- foo
- bar
```
#### Available variable names
These environment variables might be available in the fields that are accept
templates:
- `${artifact}`: the path to the artifact that will be cataloged (unless
"artifacts" config item is "any")
- `${artifactID}`: the ID of the artifact that will be cataloged (unless
"artifacts" config item is "any")
- `${document}`: the SBOM filename generated (corresponds to `${document0}` if
the "artifacts" config item is "any")
- `${document#}`: the SBOM filenames generated, where `#` corresponds to the
list index under the "documents" config item (e.g. `${document0}`)
### Limitations
Container images generated by GoReleaser are not available to be cataloged by
the SBOM tool.
The `nfpms` section is used to build native Linux packages like `.deb`, `.rpm`, and `.apk`.
These packages simplify distribution for Linux users by embedding essential metadata and making the application installable via native package managers.
---
#### Example Configuration
```yaml
nfpms:
- package_name: "{{ .ProjectName }}"
file_name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Arch }}"
homepage: "{{ .GitURL }}"
maintainer: "{{ .Env.GITHUB_REPOSITORY_OWNER }} <{{ .Env.GITHUB_REPOSITORY_OWNER_ID }}+{{ .Env.GITHUB_REPOSITORY_OWNER }}@users.noreply.github.com>"
description: "{{ .ProjectName }} {{ .Version }}"
license: "Apache License 2.0"
formats:
- deb
- rpm
- apk
```
---
#### Key Benefits
- **Seamless Installation**: Packages enable Linux users to install your application via native package managers like `apt`, `yum`, or `apk`.
- **Metadata-Rich Packaging**: Includes critical information such as description, license, and homepage for professionalism and trust.
- **Wide Compatibility**: Supports multiple formats to reach users across various Linux distributions.
Configuring the `nfpms` section allows you to deliver your application in a polished, user-friendly format aligned with Linux standards.
---
### Configuration Options
#### `file_name_template`
Defines the naming convention for package files:
```yaml
file_name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Arch }}"
```
**Template Variables**:
- `{{ .ProjectName }}`: The name of your project.
- `{{ .Version }}`: The version being packaged.
- `{{ .Arch }}`: The target architecture (e.g., `amd64`, `arm64`).
**Example**:
For `example` version `1.0.0` targeting `amd64`, the `.deb` package will be named:
```plaintext
example_1.0.0_amd64.deb
```
---
#### `formats`
Specifies the package types to generate:
```yaml
formats:
- deb
- rpm
- apk
```
**Supported Formats**:
- `deb`: For Debian-based systems like Ubuntu.
- `rpm`: For Red Hat-based systems like Fedora and CentOS.
- `apk`: For Alpine Linux.
---
#### Metadata Options
- **`homepage`**: Defines the reference URL (e.g., Git repository):
```yaml
homepage: "{{ .GitURL }}"
```
- **`maintainer`**: Provides maintainer information for traceability:
```yaml
maintainer: "{{ .Env.GITHUB_REPOSITORY_OWNER }} <{{ .Env.GITHUB_REPOSITORY_OWNER_ID }}+{{ .Env.GITHUB_REPOSITORY_OWNER }}@users.noreply.github.com>"
```
- **`license`**: Specifies licensing information (e.g., Apache License 2.0):
```yaml
license: "Apache License 2.0"
```
- **`description`**: Offers a brief summary of the package:
```yaml
description: "{{ .ProjectName }} {{ .Version }}"
```
---
# Quoting the GoReleaser documentation:
- https://goreleaser.com/customization/nfpm/
## Linux packages (via nFPM)
GoReleaser can be wired to [nfpm](https://github.com/goreleaser/nfpm) to
generate and publish `.deb`, `.rpm`, `.apk`, `.ipk`, and Archlinux packages.
Available options:
```yaml title=".goreleaser.yaml"
nfpms:
# note that this is an array of nfpm configs
- #
# ID of the nfpm config, must be unique.
#
# Default: 'default'.
id: foo
# Name of the package.
#
# Default: ProjectName.
# Templates: allowed.
package_name: foo
# You can change the file name of the package.
#
# Default: '{{ .PackageName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'.
# Templates: allowed.
file_name_template: "{{ .ConventionalFileName }}"
# Build IDs for the builds you want to create NFPM packages for.
# Default: '' (no filtering).
builds:
- foo
- bar
# Allows to further filter the artifacts.
#
# Artifacts that do not match this expression will be ignored.
#
# <!-- md:inline_pro -->.
# <!-- md:inline_version v2.4 -->.
# Templates: allowed.
if: '{{ eq .Os "linux" }}'
# Your app's vendor.
vendor: Drum Roll Inc.
# Your app's homepage.
#
# Default: inferred from global metadata.
homepage: https://example.com/
# Your app's maintainer (probably you).
#
# Default: inferred from global metadata.
maintainer: Drummer <drum-roll@example.com>
# Your app's description.
#
# Default: inferred from global metadata.
description: |-
Drum rolls installer package.
Software to create fast and easy drum rolls.
# Your app's license.
#
# Default: inferred from global metadata.
license: Apache 2.0
# Formats to be generated.
formats:
- apk
- deb
- rpm
- termux.deb
- archlinux
# Umask to be used on files without explicit mode set. (overridable)
#
# Default: 0o002 (will remove world-writable permissions).
umask: 0o002
# Packages your package depends on. (overridable)
dependencies:
- git
- zsh
# Packages it provides. (overridable)
provides:
- bar
# Packages your package recommends installing. (overridable)
recommends:
- bzr
- gtk
# Packages your package suggests installing. (overridable)
suggests:
- cvs
- ksh
# Packages that conflict with your package. (overridable)
conflicts:
- svn
- bash
# Packages it replaces. (overridable)
replaces:
- fish
# Path that the binaries should be installed.
#
# Default: '/usr/bin'.
bindir: /usr/bin
# Paths to the directories where to put specific types of libraries that
# GoReleaser built.
#
# This should be used together with `builds.buildmode`
#
# Templates: allowed.
libdirs:
# Default: '/usr/include'.
headers: /usr/include/something
# Default: '/usr/lib'.
cshared: /usr/lib/foo
# Default: '/usr/lib'.
carchive: /usr/lib/foobar
# Version Epoch.
#
# Default: extracted from `version` if it is semver compatible.
epoch: 2
# Version Prerelease.
#
# Default: extracted from `version` if it is semver compatible.
prerelease: beta1
# Version Metadata (previously deb.metadata).
# Setting metadata might interfere with version comparisons depending on the
# packager.
#
# Default: extracted from `version` if it is semver compatible.
version_metadata: git
# Version Release.
release: 1
# Section.
section: default
# Priority.
priority: extra
# Makes a meta package - an empty package that contains only supporting
# files and dependencies.
# When set to `true`, the `builds` option is ignored.
meta: true
# Changelog YAML file, see: https://github.com/goreleaser/chglog
#
# You can use goreleaser/chglog to create the changelog for your project,
# pass that changelog yaml file to GoReleaser,
# and it should in turn setup it accordingly for the given available
# formats (deb and rpm at the moment).
#
# Experimental.
changelog: ./foo.yml
# Contents to add to the package.
# GoReleaser will automatically add the binaries.
contents:
# Basic file that applies to all packagers
- src: path/to/foo
dst: /usr/bin/foo
# This will add all files in some/directory or in subdirectories at the
# same level under the directory /etc. This means the tree structure in
# some/directory will not be replicated.
- src: some/directory/
dst: /etc
# This will replicate the directory structure under some/directory at
# /etc, using the "tree" type.
#
# Templates: allowed.
- src: some/directory/
dst: /etc
type: tree
# Simple config file
- src: path/to/foo.conf
dst: /etc/foo.conf
type: config
# Simple symlink.
# Corresponds to `ln -s /sbin/foo /usr/local/bin/foo`
- src: /sbin/foo
dst: /usr/bin/foo
type: "symlink"
# Corresponds to `%config(noreplace)` if the packager is rpm, otherwise it
# is just a config file
- src: path/to/local/bar.conf
dst: /etc/bar.conf
type: "config|noreplace"
# The src and dst attributes also supports name templates
- src: path/{{ .Os }}-{{ .Arch }}/bar.conf
dst: /etc/foo/bar-{{ .ProjectName }}.conf
# Additional templated contents to add to the archive.
# Those files will have their contents pass through the template engine,
# and its results will be added to the package.
#
# This feature is only available in GoReleaser Pro.
# Templates: allowed.
templated_contents:
# a more complete example, check the globbing deep dive below
- src: "LICENSE.md.tpl"
dst: LICENSE.md
# These files are not actually present in the package, but the file names
# are added to the package header. From the RPM directives documentation:
#
# "There are times when a file should be owned by the package but not
# installed - log files and state files are good examples of cases you
# might desire this to happen."
#
# "The way to achieve this, is to use the %ghost directive. By adding this
# directive to the line containing a file, RPM will know about the ghosted
# file, but will not add it to the package."
#
# For non rpm packages ghost files are ignored at this time.
- dst: /etc/casper.conf
type: ghost
- dst: /var/log/boo.log
type: ghost
# You can use the packager field to add files that are unique to a
# specific packager
- src: path/to/rpm/file.conf
dst: /etc/file.conf
type: "config|noreplace"
packager: rpm
- src: path/to/deb/file.conf
dst: /etc/file.conf
type: "config|noreplace"
packager: deb
- src: path/to/apk/file.conf
dst: /etc/file.conf
type: "config|noreplace"
packager: apk
# Sometimes it is important to be able to set the mtime, mode, owner, or
# group for a file that differs from what is on the local build system at
# build time.
- src: path/to/foo
dst: /usr/local/foo
file_info:
mode: 0644
mtime: 2008-01-02T15:04:05Z
owner: notRoot
group: notRoot
# If `dst` ends with a `/`, it'll create the given path and copy the given
# `src` into it, the same way `cp` works with and without trailing `/`.
- src: ./foo/bar/*
dst: /usr/local/myapp/
# Using the type 'dir', empty directories can be created. When building
# RPMs, however, this type has another important purpose: Claiming
# ownership of that directory. This is important because when upgrading or
# removing an RPM package, only the directories for which it has claimed
# ownership are removed. However, you should not claim ownership of a
# directory that is created by the OS or a dependency of your package.
#
# A directory in the build environment can optionally be provided in the
# 'src' field in order copy mtime and mode from that directory without
# having to specify it manually.
- dst: /some/dir
type: dir
file_info:
mode: 0700
# Scripts to execute during the installation of the package. (overridable)
#
# Keys are the possible targets during the installation process
# Values are the paths to the scripts which will be executed.
#
# Templates: allowed.
scripts:
preinstall: "scripts/preinstall.sh"
postinstall: "scripts/postinstall.sh"
preremove: "scripts/preremove.sh"
postremove: "scripts/postremove.sh"
# Templated scripts to execute during the installation of the package. (overridable)
#
# Keys are the possible targets during the installation process
# Values are the paths to the scripts which will be executed.
#
# This feature is only available in GoReleaser Pro.
# Templates: allowed.
templated_scripts:
preinstall: "scripts/preinstall.sh"
postinstall: "scripts/postinstall.sh"
preremove: "scripts/preremove.sh"
postremove: "scripts/postremove.sh"
# All fields above marked as `overridable` can be overridden for a given
# package format in this section.
overrides:
# The dependencies override can for example be used to provide version
# constraints for dependencies where different package formats use
# different versions or for dependencies that are named differently.
deb:
dependencies:
- baz (>= 1.2.3-0)
- some-lib-dev
# ...
rpm:
dependencies:
- baz >= 1.2.3-0
- some-lib-devel
# ...
apk:
# ...
# Custom configuration applied only to the RPM packager.
rpm:
# RPM specific scripts.
scripts:
# The pretrans script runs before all RPM package transactions / stages.
pretrans: ./scripts/pretrans.sh
# The posttrans script runs after all RPM package transactions / stages.
posttrans: ./scripts/posttrans.sh
# The package summary.
#
# Default: first line of the description.
summary: Explicit Summary for Sample Package
# The package group.
# This option is deprecated by most distros but required by old distros
# like CentOS 5 / EL 5 and earlier.
group: Unspecified
# The packager is used to identify the organization that actually packaged
# the software, as opposed to the author of the software.
# `maintainer` will be used as fallback if not specified.
# This will expand any env var you set in the field, eg packager: ${PACKAGER}
packager: GoReleaser <staff@goreleaser.com>
# Compression algorithm (gzip (default), lzma or xz).
compression: lzma
# Prefixes for relocatable packages.
prefixes:
- /usr/bin
# The package is signed if a key_file is set
signature:
# PGP secret key file path (can also be ASCII-armored).
#
# See "Signing key passphrases" below for more information.
#
# Templates: allowed.
key_file: "{{ .Env.GPG_KEY_PATH }}"
# Custom configuration applied only to the Deb packager.
deb:
# Lintian overrides
lintian_overrides:
- statically-linked-binary
- changelog-file-missing-in-native-package
# Custom deb special files.
scripts:
# Deb rules script.
rules: foo.sh
# Deb templates file, when using debconf.
templates: templates
# Custom deb triggers
triggers:
# register interest on a trigger activated by another package
# (also available: interest_await, interest_noawait)
interest:
- some-trigger-name
# activate a trigger for another package
# (also available: activate_await, activate_noawait)
activate:
- another-trigger-name
# Packages which would break if this package would be installed.
# The installation of this package is blocked if `some-package`
# is already installed.
breaks:
- some-package
# The package is signed if a key_file is set
signature:
# PGP secret key file path (can also be ASCII-armored).
#
# See "Signing key passphrases" below for more information.
#
# Templates: allowed.
key_file: "{{ .Env.GPG_KEY_PATH }}"
# The type describes the signers role, possible values are "origin",
# "maint" and "archive".
#
# Default: 'origin'.
type: origin
# Additional fields for the control file. Empty fields are ignored.
# This will expand any env vars you set in the field values, e.g. Vcs-Browser: ${CI_PROJECT_URL}
fields:
Bugs: https://github.com/goreleaser/nfpm/issues
# The Debian-specific "predepends" field can be used to ensure the complete installation of a list of
# packages (including unpacking, pre- and post installation scripts) prior to the installation of the
# built package.
predepends:
- baz (>= 1.2.3-0)
apk:
# APK specific scripts.
scripts:
# The preupgrade script runs before APK upgrade.
preupgrade: ./scripts/preupgrade.sh
# The postupgrade script runs after APK.
postupgrade: ./scripts/postupgrade.sh
# The package is signed if a key_file is set
signature:
# PGP secret key file path (can also be ASCII-armored).
#
# See "Signing key passphrases" below for more information.
#
# Templates: allowed.
key_file: "{{ .Env.GPG_KEY_PATH }}"
# The name of the signing key. When verifying a package, the signature
# is matched to the public key store in /etc/apk/keys/<key_name>.rsa.pub.
#
# Default: maintainer's email address.
# Templates: allowed.
key_name: origin
archlinux:
# Archlinux-specific scripts
scripts:
# The preupgrade script runs before pacman upgrades the package.
preupgrade: ./scripts/preupgrade.sh
# The postupgrade script runs after pacman upgrades the package.
postupgrade: ./scripts/postupgrade.sh
# The pkgbase can be used to explicitly specify the name to be used to refer
# to a group of packages. See: https://wiki.archlinux.org/title/PKGBUILD#pkgbase.
pkgbase: foo
# The packager refers to the organization packaging the software, not to be confused
# with the maintainer, which is the person who maintains the software.
packager: GoReleaser <staff@goreleaser.com>
# Custom configuration applied only to the IPK packager.
#
# <!-- md:inline_version v2.1 -->.
ipk:
# The ABI version to specify.
#
# Default: none
abi_version:
# Alternate names for files created using symlinks
#
# Default: none
alternatives:
- #
# The IPK priority used when creating the alternative link.
priority: 4
# The target path and file the alternative is linked to.
target: /usr/bin/ls
# The alternative path and file created.
link_name: /usr/bin/alternate_ls
# Mark the package to be auto installed.
#
# Default: false
auto_install: false
# Mark the package as essential.
#
# Default: false
essential: false
# Additional fields for the control file. Empty fields are ignored.
# This will expand any env vars you set in the field values, e.g. Vcs-Browser: ${CI_PROJECT_URL}
#
# Default: none
fields:
Bugs: https://github.com/goreleaser/nfpm/issues
# The IPK-specific "predepends" field can be used to ensure the complete installation of a list of
# packages (including unpacking, pre- and post installation scripts) prior to the installation of the
# built package.
#
# Default: none
predepends:
- baz
# A list of tags to associate with the package.
#
# Default: none
tags:
- foo
```
<!-- md:templates -->
!!! info
Fields marked with "overridable" can be overridden for any format.
### Signing key passphrases
GoReleaser will try to get the password from the following environment
variables, in the following order of preference:
1. `$NFPM_[ID]_[FORMAT]_PASSPHRASE`
1. `$NFPM_[ID]_PASSPHRASE`
1. `$NFPM_PASSPHRASE`
Basically, it'll start from the most specific to the most generic.
Also, `[ID]` is the uppercase `id` value, and `[FORMAT]` is the uppercase format
(`deb`, `rpm`, etc).
So, if your `nfpms.id` is `default`, then the deb-specific passphrase
will be set `$NFPM_DEFAULT_DEB_PASSPHRASE`. GoReleaser will try that, then
`$NFPM_DEFAULT_PASSPHRASE`, and finally, `$NFPM_PASSPHRASE`.
### A note about Termux
Termux is the same format as `deb`, the differences are:
- it uses a different `bindir` (prefixed with `/data/data/com.termux/files/`)
- it uses slightly different architecture names than Debian
- it will only package binaries built for Android
### Conventional file names, Debian, and ARMv6
On Debian, both ARMv6 and ARMv7 have the same architecture name: `armhf`.
If you use `{{.ConventionalFileName}}`, and build for both architectures, you'll
get duplicated file names.
You can go around that with something like this:
```yaml title=".goreleaser.yaml"
nfpms:
- # ...
file_name_template: >-
{{- trimsuffix .ConventionalFileName .ConventionalExtension -}}
{{- if and (eq .Arm "6") (eq .ConventionalExtension ".deb") }}6{{ end -}}
{{- if not (eq .Amd64 "v1")}}{{ .Amd64 }}{{ end -}}
{{- .ConventionalExtension -}}
# ...
```
The `brews` section automates the creation and publishing of a Homebrew formula to a GitHub repository.
This streamlines the distribution process for macOS users, allowing them to install your application via a simple `brew install` command.
---
#### Example Configuration
```yaml
brews:
- repository:
owner: "{{ .Env.GITHUB_REPOSITORY_OWNER }}"
name: "{{ if isEnvSet \"HOMEBREW_TAP_REPOSITORY\" }}{{ .Env.HOMEBREW_TAP_REPOSITORY }}{{ else }}homebrew-tap{{ end }}"
branch: update/{{ .ProjectName }}_{{ .Version }}
token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}"
pull_request:
enabled: true
commit_author:
name: github-actions[bot]
email: 41898282+github-actions[bot]@users.noreply.github.com
directory: Formula
homepage: "{{ .GitURL }}"
description: "{{ .ProjectName }} {{ .Version }}"
license: Apache-2.0
test: |
system "#{bin}/{{ .ProjectName }} --version"
```
---
#### Key Benefits
1. **Ease of Installation**: Homebrew formula allows macOS users to install your application with a single `brew install` command.
2. **Enhanced Trust and Transparency**: Includes detailed metadata like version, homepage, description, and license.
3. **Consistency and Automation**: Automatically updates the Homebrew formula, ensuring users always have access to the latest version.
---
### Configuration Options
#### Repository Configuration
Defines the GitHub repository where the Homebrew formula is published:
```yaml
repository:
owner: "{{ .Env.GITHUB_REPOSITORY_OWNER }}"
name: "{{ if isEnvSet \"HOMEBREW_TAP_REPOSITORY\" }}{{ .Env.HOMEBREW_TAP_REPOSITORY }}{{ else }}homebrew-tap{{ end }}"
branch: update/{{ .ProjectName }}_{{ .Version }}
token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}"
pull_request:
enabled: true
```
**Key Details**:
- **`owner`**: The GitHub repository owner (inferred from the `GITHUB_REPOSITORY_OWNER` environment variable).
- **`name`**: The repository name, defaulting to `homebrew-tap` unless overridden by `HOMEBREW_TAP_REPOSITORY`.
- **`branch`**: The branch for the formula update (e.g., `update/example_1.0.0`).
- **`token`**: A GitHub token with permissions for `contents` and `pull_requests`.
**Automation**:
- When `pull_request.enabled` is `true`, GoReleaser automatically creates a pull request to add or update the formula.
---
#### Commit Author
Specifies the author of the commit made to the repository:
```yaml
commit_author:
name: github-actions[bot]
email: 41898282+github-actions[bot]@users.noreply.github.com
```
**Details**:
- **`name`**: Uses GitHub’s default bot account (`github-actions[bot]`).
- **`email`**: Corresponding email for the GitHub Actions bot.
For more information, refer to the [GitHub Actions bot email address documentation](https://github.com/orgs/community/discussions/26560).
---
#### Metadata Configuration
- **`directory`**: Specifies where the formula is stored in the repository:
```yaml
directory: Formula
```
- **`homepage`**: The URL of the project's homepage (e.g., the Git repository):
```yaml
homepage: "{{ .GitURL }}"
```
- **`description`**: A brief summary of the project:
```yaml
description: "{{ .ProjectName }} {{ .Version }}"
```
- **`license`**: Specifies the license (e.g., Apache-2.0):
```yaml
license: Apache-2.0
```
---
#### Testing the Formula
Defines a script to validate that the installed formula works as expected:
```yaml
test: |
system "#{bin}/{{ .ProjectName }} --version"
```
This test ensures that the installed binary runs correctly and outputs the version.
---
# Quoting the GoReleaser documentation:
- https://goreleaser.com/customization/homebrew/
## Homebrew Taps
After releasing to GitHub, GitLab, or Gitea, GoReleaser can generate and publish
a _homebrew-tap_ recipe into a repository that you have access to.
The `brews` section specifies how the formula should be created.
You can check the
[Homebrew documentation](https://github.com/Homebrew/brew/blob/master/docs/How-to-Create-and-Maintain-a-Tap.md),
and the
[formula cookbook](https://github.com/Homebrew/brew/blob/master/docs/Formula-Cookbook.md)
for more details.
```yaml title=".goreleaser.yaml"
brews:
-
# Name of the recipe
#
# Default: the project name.
# Templates: allowed.
name: myproject
# Alternative names for the current recipe.
#
# Useful if you want to publish a versioned formula as well, so users can
# more easily downgrade.
#
# This feature is only available in GoReleaser Pro.
# Templates: allowed.
alternative_names:
- myproject@{{ .Version }}
- myproject@{{ .Major }}
# IDs of the archives to use.
# Empty means all IDs.
ids:
- foo
- bar
# Sets the app file within a DMG.
#
# This feature is only available in GoReleaser Pro.
app: MyApp.app
# GOARM to specify which 32-bit arm version to use if there are multiple
# versions from the build section. Brew formulas support only one 32-bit
# version.
#
# Default: 6.
goarm: 6
# GOAMD64 to specify which amd64 version to use if there are multiple
# versions from the build section.
#
# Default: v1.
goamd64: v1
# NOTE: make sure the url_template, the token and given repo (github or
# gitlab) owner and name are from the same kind.
# We will probably unify this in the next major version like it is
# done with scoop.
# URL which is determined by the given Token (github, gitlab or gitea).
#
# Default depends on the client.
# Templates: allowed.
url_template: "https://github.mycompany.com/foo/bar/releases/download/{{ .Tag }}/{{ .ArtifactName }}"
# Headers to include in the `url` stanza.
# This can be a more modern alternative to `download_strategy` in some
# cases.
url_headers:
- "Accept: application/octet-stream"
- 'Authorization: bearer #{ENV["HOMEBREW_GITHUB_API_TOKEN"]}'
# Allows you to set a custom download strategy. Note that you'll need
# to implement the strategy and add it to your tap repository.
# Example: https://docs.brew.sh/Formula-Cookbook#specifying-the-download-strategy-explicitly
download_strategy: CurlDownloadStrategy
# Allows you to add a custom require_relative at the top of the formula
# template.
custom_require: custom_download_strategy
# Git author used to commit to the repository.
commit_author:
name: goreleaserbot
email: bot@goreleaser.com
# The project name and current git tag are used in the format string.
#
# Templates: allowed.
commit_msg_template: "Brew formula update for {{ .ProjectName }} version {{ .Tag }}"
# Directory inside the repository to put the formula.
directory: Formula
# Caveats for the user of your binary.
caveats: "How to use this binary"
# Your app's homepage.
#
# Default: inferred from global metadata.
homepage: "https://example.com/"
# Your app's description.
#
# Templates: allowed.
# Default: inferred from global metadata.
description: "Software to create fast and easy drum rolls."
# SPDX identifier of your app's license.
#
# Default: inferred from global metadata.
license: "MIT"
# Setting this will prevent goreleaser to actually try to commit the updated
# formula - instead, the formula file will be stored on the dist directory
# only, leaving the responsibility of publishing it to the user.
# If set to auto, the release will not be uploaded to the homebrew tap
# in case there is an indicator for prerelease in the tag e.g. v1.0.0-rc1
#
# Templates: allowed.
skip_upload: true
# Custom block for brew.
# Can be used to specify alternate downloads for devel or head releases.
custom_block: |
head "https://github.com/some/package.git"
...
# Packages your package depends on.
dependencies:
- name: git
# Allow to specify the OS in which the dependency is required.
# Valid options are `mac` and `linux`.
os: mac
- name: zsh
type: optional
- name: fish
version: v1.2.3
# if providing both version and type, only the type will be taken into
# account.
- name: elvish
type: optional
version: v1.2.3
# Packages that conflict with your package.
conflicts:
- svn
- bash
# Specify for packages that run as a service.
plist: |
<?xml version="1.0" encoding="UTF-8"?>
# ...
# Service block.
service: |
run: foo/bar
# ...
# So you can `brew test` your formula.
#
# Template: allowed
test: |
system "#{bin}/foo --version"
# ...
# Custom install script for brew.
#
# Template: allowed
# Default: 'bin.install "BinaryName"'.
install: |
bin.install "some_other_name"
bash_completion.install "completions/foo.bash" => "foo"
# ...
# Additional install instructions so you don't need to override `install`.
#
# Template: allowed
extra_install: |
bash_completion.install "completions/foo.bash" => "foo"
man1.install "man/foo.1.gz"
# ...
# Custom post_install script for brew.
# Could be used to do any additional work after the "install" script
post_install: |
etc.install "app-config.conf"
# ...
{% include-markdown "../includes/repository.md" comments=false start='---\n\n' %}
```
<!-- md:templates -->
By defining the `brew` section, GoReleaser will take care of publishing the
Homebrew tap.
Assuming that the current tag is `v1.2.3`, the above configuration will generate a
`program.rb` formula in the `Formula` directory of `user/homebrew-tap`
repository:
```rb
class Program < Formula
desc "How to use this binary"
homepage "https://github.com/user/repo"
version "v1.2.3"
on_macos do
url "https://github.com/user/repo/releases/download/v1.2.3/program_v1.2.3_macOs_64bit.zip"
sha256 "9ee30fc358fae8d248a2d7538957089885da321dca3f09e3296fe2058e7fff74"
end
on_linux
on_intel do
url "https://github.com/user/repo/releases/download/v1.2.3/program_v1.2.3_Linux_64bit.zip"
sha256 "b41bebd25fd7bb1a67dc2cd5ee12c9f67073094567fdf7b3871f05fd74a45fdd"
end
on_arm do
if !Hardware::CPU.is_64_bit?
url "https://github.com/user/repo/releases/download/v1.2.3/program_v1.2.3_Linux_armv7.zip"
sha256 "78f31239430eaaec01df783e2a3443753a8126c325292ed8ddb1658ddd2b401d"
end
end
on_arm do
if Hardware::CPU.is_64_bit?
url "https://github.com/user/repo/releases/download/v1.2.3/program_v1.2.3_Linux_arm64.zip"
sha256 "97cadca3c3c3f36388a4a601acf878dd356d6275a976bee516798b72bfdbeecf"
end
end
end
depends_on "git"
depends_on "zsh" => :optional
def install
bin.install "program"
end
def post_install
etc.install "app-config.conf"
end
end
```
!!! info
Note that GoReleaser does not generate a valid homebrew-core formula.
The generated formulas are meant to be published as
[homebrew taps](https://docs.brew.sh/Taps.html), and in their current
form will not be accepted in any of the official homebrew repositories.
### Head Formulas
GoReleaser does not generate `head` formulas for you, as it may be very different
from one software to another.
Our suggestion is to create a `my-app-head.rb` file on your tap following
[homebrew's documentation](https://docs.brew.sh/Formula-Cookbook#unstable-versions-head).
### Versioned formulas
<!-- md:pro -->
GoReleaser can also create a versioned formula.
For instance, you might want to make keep previous minor versions available to
your users, so they easily downgrade and/or keep using an older version.
To do that, use `alternative_names`:
```yaml title=".goreleaser.yaml"
brews:
- name: foo
alternative_names:
- "foo@{{ .Major }}.{{ .Minor }}"
# other fields
```
So, if you tag `v1.2.3`, GoReleaser will create and push `foo.rb` and
`foo@1.2.rb`.
Later on, you can tag `v1.3.0`, and then GoReleaser will create and push both
`foo.rb` (thus overriding the previous version) and `foo@1.3.rb`.
Your users can then `brew install foo@1.2` to keep using the previous version.
### GitHub Actions
To publish a formula from one repository to another using GitHub Actions, you cannot use the default action token.
You must use a separate token with content write privileges for the tap repository.
You can check the [resource not accessible by integration](https://goreleaser.com/errors/resource-not-accessible-by-integration/) for more information.
### Limitations
- Only one `GOARM` build is allowed;
{% include-markdown "../includes/prs.md" comments=false start='---\n\n' %}
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.