Homebrew Casks¶
This will be available in the next release (v2.10). Stay tuned!
After releasing to GitHub, GitLab, or Gitea, GoReleaser can generate and publish a Homebrew Cask into a repository (Tap) that you have access to.
The homebrew_casks
section specifies how the cask should be created. You can check the Homebrew Cask documentation, for more details.
homebrew_casks:
-
# Name of the cask
#
# Default: the project name.
# Templates: allowed.
name: myproject
# Alternative names for the current cask.
#
# Useful if you want to publish a versioned cask 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
# Binary name inside the cask
#
# Default: the cask name.
# Templates: allowed.
binary: myapp
# Path to the manpage file
#
# Templates: allowed.
manpage: man/myapp.1
# Completions for different shells
#
# Templates: allowed.
completions:
bash: completions/myapp.bash
zsh: completions/myapp.zsh
fish: completions/myapp.fish
# This information will be used to build the URL section of your Cask.
#
# You can set the template, as well as additional parameters.
# These parameters can be used to provide extra headers, cookies, or other
# download requirements for your application.
# See https://docs.brew.sh/Cask-Cookbook#additional-url-parameters for more details.
#
# All fields are optional.
url:
# URL which is determined by the given Token (github, gitlab or gitea).
#
# Default depends on the client.
# Templates: allowed.
template: "https://github.mycompany.com/foo/bar/releases/download/{{ .Tag }}/{{ .ArtifactName }}"
# Used when the domains of `url` and `homepage` differ.
# Templates: allowed.
verified: "github.com/owner/repo/"
# Download strategy or format specification
# See official Cask Cookbook for allowed values.
# Templates: allowed.
using: ":homebrew_curl"
# HTTP cookies to send with the download request
# Templates: allowed.
cookies:
license: "accept-backup"
# HTTP referer header
# Templates: allowed.
referer: "https://example.com/download-page"
# Additional HTTP headers
# Templates: allowed.
headers:
- "X-Version: {{ .Version }}"
# Custom User-Agent header
# Templates: allowed.
user_agent: "MyApp/1.0 (macOS)"
# Custom body when using POST request
# Templates: allowed.
data:
format: "dmg"
platform: "mac"
# Git author used to commit to the repository.
# Templates: allowed.
commit_author:
name: goreleaserbot
email: [email protected]
# The project name and current git tag are used in the format string.
#
# Templates: allowed.
commit_msg_template: "Brew cask update for {{ .ProjectName }} version {{ .Tag }}"
# Directory inside the repository to put the cask.
# Default: Casks
directory: Casks
# 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
# cask - instead, the cask 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"
...
# Dependencies for the cask.
dependencies:
- cask: some-cask
- formula: some-formula
# Packages that conflict with your cask.
conflicts:
- cask: some-cask
- formula: some-formula
# Hooks for the cask lifecycle.
hooks:
pre:
install: |
system_command "/usr/bin/defaults", args: ["write", "com.example.app", "key", "value"]
uninstall: |
system_command "/usr/bin/defaults", args: ["delete", "com.example.app"]
post:
install: |
system_command "/usr/bin/open", args: ["#{appdir}/MyApp.app"]
uninstall: |
system_command "/usr/bin/rm", args: ["-rf", "~/.myapp"]
# Relative path to a Service that should be moved into the
# ~/Library/Services folder on installation.
service: "myapp.service"
# Additional procedures for a more complete uninstall, including user files
# and shared resources.
zap:
launchctl:
- "my.fancy.package.service"
quit:
- "my.fancy.package"
login_item:
- "my.fancy.package"
trash:
- "~/.foo/bar"
- "~/otherfile"
delete:
- "~/.foo/bar"
- "~/otherfile"
# Procedures to uninstall a cask.
# Optional unless a pkg or installer artifact stanza is used.
uninstall:
launchctl:
- "my.fancy.package.service"
quit:
- "my.fancy.package"
login_item:
- "my.fancy.package"
trash:
- "~/.foo/bar"
- "~/otherfile"
delete:
- "~/.foo/bar"
- "~/otherfile"
# Repository to push the generated files to.
repository:
# Repository owner.
#
# Templates: allowed.
owner: caarlos0
# Repository name.
#
# Templates: allowed.
name: my-repo
# Optionally a branch can be provided.
#
# Default: default repository branch.
# Templates: allowed.
branch: main
# Optionally a token can be provided, if it differs from the token
# provided to GoReleaser
#
# Templates: allowed.
token: "{{ .Env.GITHUB_PERSONAL_AUTH_TOKEN }}"
# Optionally specify if this is a token from another SCM, allowing to
# cross-publish.
#
# Only taken into account if `token` is set.
#
# Valid options:
# - 'github'
# - 'gitlab'
# - 'gitea'
#
# This feature is only available in GoReleaser Pro.
token_type: "github"
# Sets up pull request creation instead of just pushing to the given branch.
# Make sure the 'branch' property is different from base before enabling
# it.
#
# This might require a personal access token.
pull_request:
# Whether to enable it or not.
enabled: true
# Whether to open the PR as a draft or not.
draft: true
# If the pull request template has checkboxes, enabling this will
# check all of them.
#
# This feature is only available in GoReleaser Pro, and when the pull
# request is being opened on GitHub.
check_boxes: true
# Base can also be another repository, in which case the owner and name
# above will be used as HEAD, allowing cross-repository pull requests.
base:
owner: goreleaser
name: my-repo
branch: main
# Clone, create the file, commit and push, to a regular Git repository.
#
# Notice that this will only have any effect if the given URL is not
# empty.
git:
# The Git URL to push.
#
# Templates: allowed.
url: 'ssh://[email protected]:repo.git'
# The SSH private key that should be used to commit to the Git
# repository.
# This can either be a path or the key contents.
#
# IMPORTANT: the key must not be password-protected.
#
# WARNING: do not expose your private key in the configuration file!
#
# Templates: allowed.
private_key: '{{ .Env.PRIVATE_KEY_PATH }}'
# The value to be passed to `GIT_SSH_COMMAND`.
# This is mainly used to specify the SSH private key used to pull/push
# to the Git URL.
#
# Default: 'ssh -i {{ .KeyPath }} -o StrictHostKeyChecking=accept-new -F /dev/null'.
# Templates: allowed.
ssh_command: 'ssh -i {{ .Env.KEY }} -o SomeOption=yes'
Template Language
Discover more about the name template engine.
Signing and Notarizing¶
Casks are supposed to be signed, even if they are coming from a tap.
GoReleaser can sign and notarize both binaries and apps, but, Apple charges a yearly fee for that.
If you don't want to do it, you still have the option to tell macOS to remove the quarantine bit from the binary on a post install hook:
homebrew_casks:
- name: foo
hooks:
post:
# replace foo with the actual binary name
install: |
system_command "/usr/bin/xattr", args: ["-dr", "com.apple.quarantine", "#{staged_path}/foo"]
What happens if I don't follow the steps above?
Not following this might lead to your app/binary to not run.
In these cases, users will see the infamous "App Name is damaged and cannot be opened" alert.
If you don't want to do any of the steps above, you may want to instruct your users to run the appropriate xattr
command manually.
You may do so in using the caveats
property, for example.
Versioned Casks¶
GoReleaser Pro
One or more features are exclusively available with GoReleaser Pro.
GoReleaser can also create a versioned Cask. 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
:
homebrew_casks:
- name: foo
alternative_names:
- "foo@{{ .Major }}.{{ .Minor }}"
# other fields
So, if you tag v1.2.3
, GoReleaser will create and push foo.rb
and [email protected]
.
Later on, you can tag v1.3.0
, and then GoReleaser will create and push both foo.rb
(thus overriding the previous version) and [email protected]
. Your users can then brew install [email protected]
to keep using the previous version.
GitHub Actions¶
To publish a cask 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 for more information.
Limitations¶
- Only one
GOARM
build is allowed;
Pull Requests¶
GoReleaser allows you to, instead of pushing directly to the main branch, push to a feature branch, and open a pull requests with the changes.
Templates¶
GoReleaser will check for a .github/PULL_REQUEST_TEMPLATE.md
, and set it in the pull request body if it exists.
We do that to prevent extra work for maintainers of things like winget-pkgs
, nixpkgs
, and so on.
Cross-repository pull requests¶
You can also push to a fork, and open the pull request in the original branch.
Here's an example on how to set it up:
# ...
something: # can be nix, brews, etc...
- repository:
owner: john
name: repo
branch: "{{.ProjectName}}-{{.Version}}"
pull_request:
enabled: true
base:
owner: mike
name: repo
branch: main
This will:
- Try to sync the
john/repo
fork withmike/repo:main
(if on GitHub). - Create the files into
john/repo
, in the branchfoo-1.2.3
(assumingProjectName=foo
andVersion=1.2.3
). 1 - Open a pull request from
john/repo
intomike/repo
, with the branchmain
as target. 2
Things that don't work¶
- Opening pull requests to a forked repository (
go-github
does not have the required fields to do it). - Since this can fail for a myriad of reasons, if an error happen, it'll log it to the release output, but will not fail the pipeline.