Current section
Files
Jump to
Current section
Files
docs/configuration.md
# Configuration reference
Every option in the `:tinfoil` keyword of `project/0` in `mix.exs`.
The only required key is `:targets`; everything else has a sensible
default.
```elixir
tinfoil: [
# Required. Targets to build.
targets: [:darwin_arm64, :linux_x86_64],
# Optional: user-defined targets merged on top of the built-in
# matrix. Each entry needs the full spec shape.
extra_targets: %{},
# Optional: collapse every target in an OS family onto one CI
# runner that builds them sequentially. Defaults to false -- one
# job per target.
single_runner_per_os: false,
# Regex matched against the git tag to auto-mark a release as
# prerelease. Default covers -rc / -beta / -alpha; override if you
# use different conventions. See the caveat about Homebrew / Scoop
# skip logic under "Release channels" in the distribution guide.
prerelease_pattern: ~r/-(rc|beta|alpha)(\.|$)/,
# Archive naming template. Interpolations: {app}, {version}, {target}.
archive_name: "{app}-{version}-{target}",
archive_format: :tar_gz,
# What event the generated workflow fires on, and therefore who owns
# the GitHub Release.
#
# :tag_push (default) -- `on: push: tags: ["v*"]`. Tinfoil creates
# the release and generates its notes.
# :release_published -- `on: release: types: [published]`. Another
# tool (release-please, changesets) creates the release and
# tinfoil only attaches assets, leaving the body, prerelease
# flag, and draft state untouched.
# :workflow_call -- `on: workflow_call:` + `workflow_dispatch:`.
# Your release workflow invokes this one directly with `uses:`,
# in the same run.
#
# Both non-default triggers run the publish step with --attach, and
# `github: [draft: ...]` no longer applies since attach mode never
# edits the release.
#
# Reach for :workflow_call when a stock release-please setup never
# triggers anything: GitHub does not start workflow runs from events
# created with the default GITHUB_TOKEN, so neither the tag push nor
# the release publish fires, silently. Being called directly avoids
# event attribution entirely. See the release-please guide.
trigger: :tag_push,
# GitHub Release configuration. :repo is inferred from
# `git remote get-url origin` if omitted.
github: [
repo: "owner/my_cli",
draft: false
],
# Homebrew formula generation. Requires auth material for the tap
# repo -- either HOMEBREW_TAP_TOKEN (PAT) or an SSH deploy key.
homebrew: [
enabled: true,
tap: "owner/homebrew-tap",
formula_name: "my_cli", # defaults to the app name
auth: :token, # or :deploy_key (default :token)
token_secret: "HOMEBREW_TAP_TOKEN", # GitHub secret name for the PAT
deploy_key_secret: "HOMEBREW_TAP_DEPLOY_KEY" # GitHub secret name for the SSH key
],
# Scoop manifest generation (Windows). Same auth model as Homebrew.
# Requires :windows_x86_64 in :targets.
scoop: [
enabled: true,
bucket: "owner/scoop-bucket",
manifest_name: "my_cli", # defaults to the app name
auth: :token, # or :deploy_key (default :token)
token_secret: "SCOOP_BUCKET_TOKEN", # GitHub secret name for the PAT
deploy_key_secret: "SCOOP_BUCKET_DEPLOY_KEY"
],
# Shell installer script.
installer: [
enabled: true,
install_dir: "~/.local/bin"
],
checksums: :sha256,
# GitHub build provenance attestations on every uploaded artifact.
# Defaults to true; set false to opt out (which also drops the
# `id-token: write` and `attestations: write` permissions from the
# generated workflow).
attestations: true,
# Extra files to bundle alongside the binary in every archive.
# Bare strings use the same relative path inside the archive; a
# source/dest map places the file at a custom location.
extra_artifacts: [
"LICENSE",
%{source: "man/myapp.1", dest: "share/man/man1/myapp.1"}
],
ci: [
provider: :github_actions,
# All three are auto-detected if not set, and the values below are
# only the fallbacks used when detection fails:
#
# elixir_version System.version(), as MAJOR.MINOR
# otp_version System.otp_release()
# zig_version Burrito.get_versions().zig
#
# Elixir and OTP both come from the machine running
# `mix tinfoil.generate`, so the pair is always one that actually
# exists. The project's `:elixir` requirement is deliberately not
# used: `~> 1.17` says which Elixir versions may *consume* the
# library, which for a library is often several minor versions
# below what you build releases with, and pairing that floor with
# the running OTP produced combinations setup-beam cannot resolve.
#
# Run `mix tinfoil.plan` to see the resolved values before you tag.
elixir_version: "1.19",
otp_version: "28",
zig_version: "0.16.0"
]
]
```
## How it's loaded
`Tinfoil.Config.load/1` reads the keyword, validates it, and
auto-detects a handful of values (elixir/OTP/zig versions, GitHub
repo) when they aren't set. Anything invalid returns an error at
plan time rather than at CI time.
## Regenerating after changes
After editing the `:tinfoil` keyword, run:
```sh
mix tinfoil.generate
```
This rewrites `.github/workflows/release.yml` and any enabled
installer / formula / manifest templates. Commit the regenerated
files.
Tinfoil version bumps usually don't require regeneration -- the
workflow invokes `mix tinfoil.build` and `mix tinfoil.publish`
directly, so logic changes take effect the next CI run. Regenerate
when the workflow template itself changes between tinfoil versions.