Skip to main content

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}