# `Tinfoil.Config`
[🔗](https://github.com/joshrotenberg/tinfoil/blob/v0.2.22/lib/tinfoil/config.ex#L1)

Schema, defaults, and validation for the `:tinfoil` key in `mix.exs`.

The user's configuration lives in `project/0`:

    def project do
      [
        app: :my_cli,
        version: "0.1.0",
        tinfoil: [
          targets: [:darwin_arm64, :linux_x86_64]
        ]
      ]
    end

Everything except `:targets` has a default. `Tinfoil.Config.load/1`
returns a fully-resolved `%Tinfoil.Config{}` struct, merging user
values with defaults and inferring values from the surrounding mix
project where possible.

# `t`

```elixir
@type t() :: %Tinfoil.Config{
  app: atom(),
  archive_format: :tar_gz | :zip,
  archive_name: String.t(),
  attestations: boolean(),
  burrito_names: %{required(Tinfoil.Target.target()) =&gt; atom()},
  checksums: :sha256,
  ci: map(),
  description: String.t() | nil,
  extra_artifacts: [{Path.t(), Path.t()}],
  extra_targets: Tinfoil.Target.extras(),
  github: map(),
  homebrew: map(),
  homepage_url: String.t() | nil,
  installer: map(),
  license: String.t() | nil,
  prerelease_pattern: Regex.t(),
  scoop: map(),
  single_runner_per_os: boolean(),
  targets: [Tinfoil.Target.target()],
  trigger: :tag_push | :release_published | :workflow_call,
  version: String.t()
}
```

# `archive_basename`

```elixir
@spec archive_basename(t(), Tinfoil.Target.target()) :: String.t()
```

Render an archive file name (without extension) for the given target.

Uses `:archive_name` as a template. Available interpolations: `{app}`,
`{version}`, `{target}` (the canonical triple).

# `archive_extension`

```elixir
@spec archive_extension(t(), Tinfoil.Target.target()) :: String.t()
```

Return the archive extension (including the leading dot) for a target.

The target's own `archive_ext` wins when it differs from the
project-wide `:archive_format` -- notably, Windows targets are
always packaged as `.zip` regardless of the project setting since
Windows users don't expect `.tar.gz`.

# `archive_filename`

```elixir
@spec archive_filename(t(), Tinfoil.Target.target()) :: String.t()
```

Full archive file name for a target, including extension.

# `load`

```elixir
@spec load(keyword()) :: {:ok, t()} | {:error, term()}
```

Load and resolve the config from a mix project keyword list.

Accepts the return value of `Mix.Project.config/0` (or an equivalent
keyword list in tests). Returns `{:ok, config}` or `{:error, reason}`.

# `load!`

```elixir
@spec load!(keyword()) :: t()
```

Load the config, raising on any error.

# `prerelease?`

```elixir
@spec prerelease?(String.t(), Regex.t()) :: boolean()
```

Return `true` when `tag` matches the configured prerelease `pattern`.

This is the single source of truth for prerelease detection. The
release-publish step uses it to mark the GitHub Release as a
prerelease, and the Homebrew/Scoop steps use it to decide whether
to skip publishing a package on a prerelease tag. Keeping the rule
here (rather than duplicating it as hardcoded `-rc`/`-beta`/`-alpha`
checks in the generated workflow YAML) means a custom
`prerelease_pattern` is honored everywhere.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
