anodizer_core/config/homebrew_core.rs
1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4use super::{CommitAuthorConfig, StringOrBool, deserialize_string_or_bool_opt};
5
6/// homebrew-core formula-bump publisher configuration.
7///
8/// Bumps an EXISTING formula in `Homebrew/homebrew-core` (or any formula
9/// repository override) purely through the GitHub API — no clone, no `brew`
10/// invocation. The formula file's `url` (or `tag:`/`revision:` pair),
11/// `sha256`, and `version` stanzas are rewritten to the new release, the
12/// change is committed to a branch, and a pull request is opened against the
13/// formula repository. Each `homebrew_cores[]` entry bumps one formula.
14///
15/// Every field is optional: the formula name defaults to the crate name, the
16/// target repository defaults to `Homebrew/homebrew-core`, the formula path
17/// defaults to the sharded core layout (`Formula/<letter>/<name>.rb`, falling
18/// back to the flat `Formula/<name>.rb`), and the download URL defaults to
19/// the GitHub source tarball for the release tag.
20///
21/// ```yaml
22/// homebrew_cores:
23/// - name: my-tool
24/// ```
25#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
26#[serde(default, deny_unknown_fields)]
27pub struct HomebrewCoreConfig {
28 /// Unique identifier for selecting this entry from the CLI (`--id=...`).
29 pub id: Option<String>,
30
31 /// Crate scoping: when set, the formula `name` default is derived from
32 /// the first crate named here instead of the workspace's primary crate.
33 /// The workspace per-crate pattern — one `homebrew_cores[]` entry per
34 /// crate, each scoped by `ids:`.
35 pub ids: Option<Vec<String>>,
36
37 /// Formula name (templated). Defaults to the scoped crate name (see
38 /// `ids:`), then the workspace's primary crate name, then the project
39 /// name.
40 pub name: Option<String>,
41
42 /// Target formula repository. Defaults to `Homebrew/homebrew-core`.
43 /// Carries the auth token override (`repository.token`), the base
44 /// branch (`repository.branch`, default: the repo's default branch),
45 /// and PR settings (`repository.pull_request.draft` / `.body`).
46 ///
47 /// ```yaml
48 /// homebrew_cores:
49 /// - repository: { owner: my-org, name: my-formulas }
50 /// ```
51 pub repository: Option<super::RepositoryConfig>,
52
53 /// Formula file path inside the repository (templated). Defaults to the
54 /// homebrew-core sharded layout `Formula/<first-letter>/<name>.rb`,
55 /// falling back to the flat `Formula/<name>.rb` used by most personal
56 /// taps when the sharded path does not exist.
57 pub path: Option<String>,
58
59 /// Templated download URL written into the formula's `url` stanza.
60 /// Defaults to the GitHub source tarball for the release tag:
61 /// `https://github.com/<owner>/<repo>/archive/refs/tags/<tag>.tar.gz`
62 /// (owner/repo derived from the crate's release repository, then the
63 /// git remote).
64 pub download_url: Option<String>,
65
66 /// Hex SHA-256 of the new download (templated). When unset, anodizer
67 /// downloads `download_url` and hashes it — the same behavior as
68 /// `brew bump-formula-pr` without `--sha256`.
69 pub sha256: Option<String>,
70
71 /// Templated commit message (also the PR title). Default:
72 /// `"<formula> <version>"` — the message form homebrew-core's CI
73 /// expects for version bumps.
74 pub commit_msg_template: Option<String>,
75
76 /// Commit author for the formula-bump commit, with optional signing.
77 /// Its `use_github_app_token` is the canonical homebrew-core knob: when
78 /// set, the `author`/`committer` fields are omitted from the contents-API
79 /// commit so GitHub attributes it to the token's own account — the
80 /// `<app-slug>[bot]` identity a GitHub App workflow needs to satisfy
81 /// homebrew-core's DCO/CLA policy. Otherwise the resolved `name`/`email`
82 /// (config → local git identity → the anodizer default) author the commit.
83 ///
84 /// Note: `signing` has no effect here — formula bumps commit through the
85 /// GitHub contents API, which GitHub signs server-side; the git `-c
86 /// commit.gpgsign` path the tap/winget/krew publishers use does not apply.
87 ///
88 /// ```yaml
89 /// homebrew_cores:
90 /// - commit_author:
91 /// use_github_app_token: true
92 /// ```
93 pub commit_author: Option<CommitAuthorConfig>,
94
95 /// Commit straight to the base branch instead of opening a pull
96 /// request. Accepts bool or template string. Only honored for formula
97 /// repositories you can push to — bumps targeting
98 /// `Homebrew/homebrew-core` always go through a fork + PR, because
99 /// homebrew-core never accepts direct pushes.
100 ///
101 /// A back-compat alias for `repository.pull_request.enabled: false`, the
102 /// preferred spelling shared with the tap/scoop/nix publishers — either
103 /// one selects the direct-commit path (both are still overridden by the
104 /// always-fork-and-PR rule for `Homebrew/homebrew-core`).
105 #[serde(default, deserialize_with = "deserialize_string_or_bool_opt")]
106 pub direct_commit: Option<StringOrBool>,
107
108 /// When truthy, refresh the existing bump PR in place instead of skipping
109 /// it: a same-version re-cut force-resets the bump branch to the current
110 /// base and re-commits the rewritten formula, so the open PR carries this
111 /// run's content rather than a stale earlier attempt (and no duplicate PR
112 /// is opened). When falsy (default), an already-open bump PR is left
113 /// untouched and a warning names this toggle. Accepts bool or template
114 /// string. Mirrors `winget` / `krew` / `homebrew_cask`'s
115 /// `update_existing_pr`.
116 #[serde(default, deserialize_with = "deserialize_string_or_bool_opt")]
117 pub update_existing_pr: Option<StringOrBool>,
118
119 /// Skip this publisher. Accepts bool or template string.
120 /// Accepts the legacy `disable:` spelling via serde alias for back-compat.
121 #[serde(
122 default,
123 alias = "disable",
124 deserialize_with = "deserialize_string_or_bool_opt"
125 )]
126 pub skip: Option<StringOrBool>,
127
128 /// Override whether this publisher failing should fail the overall release.
129 ///
130 /// Default: `false` — the bump is a PR that can be re-opened by hand, so
131 /// a failure here is logged but does not abort the release. Set to
132 /// `true` to fail the release on any error.
133 #[serde(default, skip_serializing_if = "Option::is_none")]
134 pub required: Option<bool>,
135
136 /// Template-conditional gate: when the rendered result is falsy
137 /// (`"false"` / `"0"` / `"no"` / empty), this entry is skipped.
138 /// Render failure hard-errors.
139 #[serde(rename = "if")]
140 pub if_condition: Option<String>,
141
142 /// When `true`, a triggered rollback leaves the opened pull request in
143 /// place rather than closing it. Default `false`.
144 pub retain_on_rollback: Option<bool>,
145}