anodizer_core/config/publishers/mod.rs
1use std::path::PathBuf;
2
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6use super::aur_source::AurSourceConfig;
7use super::{StringOrBool, deserialize_string_or_bool_opt};
8
9mod homebrew;
10pub use homebrew::*;
11
12mod chocolatey;
13pub use chocolatey::*;
14
15mod winget;
16pub use winget::*;
17
18mod aur;
19pub use aur::*;
20
21mod krew;
22pub use krew::*;
23
24mod nix;
25pub use nix::*;
26
27// ---------------------------------------------------------------------------
28// Shared publisher config types: RepositoryConfig, CommitAuthorConfig
29// ---------------------------------------------------------------------------
30
31/// Shared repository configuration used by all git-based publishers
32/// (Homebrew, Scoop, Winget, Krew, Nix). Equivalent to GoReleaser's `RepoRef`.
33#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
34#[serde(default)]
35pub struct RepositoryConfig {
36 /// Repository owner (GitHub user or organization).
37 pub owner: Option<String>,
38 /// Repository name.
39 pub name: Option<String>,
40 /// Auth token for the repository. Falls back to env-based resolution.
41 pub token: Option<String>,
42 /// Token type: "github" (default), "gitlab", "gitea".
43 pub token_type: Option<String>,
44 /// Branch to push to (default: repo default branch).
45 pub branch: Option<String>,
46 /// Git-specific settings for SSH-based publishing.
47 pub git: Option<GitRepoConfig>,
48 /// Pull request settings for fork-based workflows.
49 pub pull_request: Option<PullRequestConfig>,
50}
51
52/// Git-specific repository settings for SSH-based publishing.
53#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
54#[serde(default)]
55pub struct GitRepoConfig {
56 /// Git URL (e.g. `ssh://git@github.com/owner/repo.git`).
57 pub url: Option<String>,
58 /// Custom SSH command (e.g. `ssh -i /path/to/key`).
59 pub ssh_command: Option<String>,
60 /// Path to SSH private key file.
61 pub private_key: Option<String>,
62}
63
64/// Pull request configuration for fork-based publisher workflows.
65#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
66#[serde(default)]
67pub struct PullRequestConfig {
68 /// Enable PR creation instead of direct push.
69 pub enabled: Option<bool>,
70 /// Create PR as draft.
71 pub draft: Option<bool>,
72 /// Body text for the pull request.
73 pub body: Option<String>,
74 /// Target base repository/branch for the PR.
75 pub base: Option<PullRequestBaseConfig>,
76}
77
78/// Target base for pull requests (upstream repo to PR against).
79#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
80#[serde(default)]
81pub struct PullRequestBaseConfig {
82 /// Owner of the upstream repository to PR against.
83 pub owner: Option<String>,
84 /// Name of the upstream repository to PR against.
85 pub name: Option<String>,
86 /// Base branch of the upstream repository to target with the PR.
87 pub branch: Option<String>,
88}
89
90/// Shared commit author configuration with optional GPG/SSH signing.
91/// Equivalent to GoReleaser's `CommitAuthor`.
92#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
93#[serde(default)]
94pub struct CommitAuthorConfig {
95 /// Git commit author display name.
96 pub name: Option<String>,
97 /// Git commit author email address.
98 pub email: Option<String>,
99 /// Commit signing configuration.
100 pub signing: Option<CommitSigningConfig>,
101 /// When true, omit the explicit `-c user.name=` / `-c user.email=`
102 /// overrides at commit time and let the running git client use the
103 /// invoking GitHub App's identity (i.e. the `<app-slug>[bot]@users.noreply.github.com`
104 /// account that the GitHub Actions checkout step has already configured
105 /// in the repo's local git config).
106 ///
107 /// Mirrors GoReleaser's `CommitAuthor.UseGithubAppToken`
108 /// (`internal/git/config/github.go:381`); the canonical use-case is
109 /// PRs against `homebrew/homebrew-core` / `kubernetes-sigs/krew-index`
110 /// / `microsoft/winget-pkgs` opened from a GitHub App workflow, where
111 /// EasyCLA / DCO / signed-commit policies require the App's identity
112 /// (rather than a per-user bot identity) to land the merge.
113 #[serde(default)]
114 pub use_github_app_token: bool,
115}
116
117impl CommitAuthorConfig {
118 /// Fill in the anodizer default name/email when either field is empty.
119 /// Matches GoReleaser's `commitauthor.Default(brew.CommitAuthor)` which
120 /// runs during the Default pass — so validation messages that reference
121 /// commit-author identity see non-empty strings rather than blanks.
122 pub fn normalize_defaults(&mut self) {
123 if self.name.as_deref().is_none_or(str::is_empty) {
124 self.name = Some("anodizer".to_string());
125 }
126 if self.email.as_deref().is_none_or(str::is_empty) {
127 self.email = Some("bot@anodizer.dev".to_string());
128 }
129 }
130}
131
132/// Commit signing configuration (GPG, x509, or SSH).
133#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
134#[serde(default)]
135pub struct CommitSigningConfig {
136 /// Enable commit signing.
137 pub enabled: Option<bool>,
138 /// Signing key identifier.
139 pub key: Option<String>,
140 /// Signing program (e.g. `gpg`, `gpg2`).
141 pub program: Option<String>,
142 /// Signing format: "openpgp" (default), "x509", or "ssh".
143 pub format: Option<String>,
144}
145
146// ---------------------------------------------------------------------------
147// PublishConfig
148// ---------------------------------------------------------------------------
149
150#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
151#[serde(default, deny_unknown_fields)]
152pub struct PublishConfig {
153 /// Publish to crates.io. Presence opts in; use `cargo: { skip: true }` to opt out.
154 pub cargo: Option<CargoPublishConfig>,
155 /// Homebrew formula publishing configuration.
156 pub homebrew: Option<HomebrewConfig>,
157 /// Homebrew Cask publishing configuration (macOS .app bundles).
158 ///
159 /// Uses the unified `HomebrewCaskConfig` which carries all fields from both
160 /// the per-crate cask config and the top-level `homebrew_casks:` config.
161 pub homebrew_cask: Option<HomebrewCaskConfig>,
162 /// Scoop manifest publishing configuration.
163 pub scoop: Option<ScoopConfig>,
164 /// Chocolatey package publishing configuration.
165 pub chocolatey: Option<ChocolateyConfig>,
166 /// WinGet manifest publishing configuration.
167 pub winget: Option<WingetConfig>,
168 /// AUR (Arch User Repository) binary package publishing configuration.
169 pub aur: Option<AurConfig>,
170 /// AUR source package publishing configuration (source-only PKGBUILD, not -bin).
171 pub aur_source: Option<AurSourceConfig>,
172 /// Krew (kubectl plugin manager) manifest publishing configuration.
173 pub krew: Option<KrewConfig>,
174 /// Nix derivation publishing configuration.
175 pub nix: Option<NixConfig>,
176}
177
178/// `cargo publish` flag surface.
179///
180/// Presence under `publish:` opts the crate in; use `skip: true` (or a
181/// truthy template) to opt out. There is no `enabled` field — presence is
182/// the on-switch.
183///
184/// Fields intentionally omitted because anodizer owns them:
185/// - `--package` / `--workspace` / `--exclude`: the top-level `crates[]`
186/// axis owns crate selection.
187/// - `--dry-run`: pipeline-level CLI ergonomics (`anodizer release --dry-run`).
188/// - `-v` / `-q` / `--color`: CLI ergonomics, not config.
189/// - `--config` / `-Z`: cargo CLI escape hatches; out of scope.
190#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
191#[serde(default, deny_unknown_fields)]
192pub struct CargoPublishConfig {
193 // ----- Registry selection -----
194 /// Alternate registry name from `~/.cargo/config.toml` (`--registry`).
195 pub registry: Option<String>,
196 /// Registry index URL (`--index`).
197 pub index: Option<String>,
198 /// Seconds to wait for the crates.io sparse index to publish a crate
199 /// before its dependents are pushed (anodizer-original — no `cargo
200 /// publish` equivalent).
201 pub index_timeout: Option<u64>,
202
203 // ----- Verify / dirty -----
204 /// Skip the local `cargo build --release` verification step (`--no-verify`).
205 pub no_verify: Option<bool>,
206 /// Allow publishing with an uncommitted working tree (`--allow-dirty`).
207 pub allow_dirty: Option<bool>,
208
209 // ----- Feature selection -----
210 /// Crate features to activate (`--features`).
211 pub features: Option<Vec<String>>,
212 /// Activate every feature, including `default` (`--all-features`).
213 pub all_features: Option<bool>,
214 /// Disable the `default` feature set (`--no-default-features`).
215 pub no_default_features: Option<bool>,
216
217 // ----- Compilation -----
218 /// Build target triple for the verification step (`--target`).
219 pub target: Option<String>,
220 /// Override the cargo target directory (`--target-dir`).
221 pub target_dir: Option<PathBuf>,
222 /// Number of parallel compile jobs for verification (`--jobs`).
223 pub jobs: Option<u32>,
224 /// Continue on errors when verifying multiple crates (`--keep-going`).
225 pub keep_going: Option<bool>,
226
227 // ----- Manifest -----
228 /// Path to the crate's `Cargo.toml` (`--manifest-path`).
229 pub manifest_path: Option<PathBuf>,
230 /// Require an up-to-date `Cargo.lock` matching the resolver (`--locked`).
231 pub locked: Option<bool>,
232 /// Require offline resolution; never hit the network (`--offline`).
233 pub offline: Option<bool>,
234 /// Both `--locked` and `--offline` (`--frozen`).
235 pub frozen: Option<bool>,
236
237 // ----- Peer-publisher pattern -----
238 /// Skip this publisher; supports template strings or bool.
239 /// Truthy renders disable the publisher without removing the block.
240 #[serde(default, deserialize_with = "deserialize_string_or_bool_opt")]
241 pub skip: Option<StringOrBool>,
242}