anodizer_core/config/build.rs
1use std::collections::HashMap;
2
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6use super::{
7 AppBundleConfig, ArchiveConfig, ArchivesConfig, BinstallConfig, BlobConfig, ChecksumConfig,
8 DmgConfig, DockerDigestConfig, DockerManifestConfig, DockerV2Config, FlatpakConfig, HookEntry,
9 MsiConfig, NfpmConfig, NsisConfig, PkgConfig, PublishConfig, ReleaseConfig, SnapcraftConfig,
10 StringOrBool, VersionSyncConfig, deserialize_archives_config, deserialize_string_or_bool_opt,
11};
12
13// ---------------------------------------------------------------------------
14// BuildIgnore — exclude specific os/arch combos from builds
15// ---------------------------------------------------------------------------
16
17/// Exclude a specific os/arch combination from the build matrix.
18#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
19pub struct BuildIgnore {
20 /// Operating system to exclude (e.g., "linux", "darwin", "windows").
21 pub os: String,
22 /// Architecture to exclude (e.g., "amd64", "arm64", "386").
23 pub arch: String,
24}
25
26// ---------------------------------------------------------------------------
27// BuildOverride — per-target env, flags, features
28// ---------------------------------------------------------------------------
29
30/// Override env, flags, or features for targets matching glob patterns.
31#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
32#[serde(default)]
33pub struct BuildOverride {
34 /// Glob patterns to match against target triples (e.g., `["x86_64-*", "*-linux-*"]`).
35 pub targets: Vec<String>,
36 /// Extra environment variables to set for matching targets.
37 #[serde(default)]
38 pub env: Option<Vec<String>>,
39 /// Extra flags to append for matching targets, one per list entry.
40 pub flags: Option<Vec<String>>,
41 /// Extra features to enable for matching targets.
42 pub features: Option<Vec<String>>,
43}
44
45// ---------------------------------------------------------------------------
46// CrossStrategy
47// ---------------------------------------------------------------------------
48
49#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
50#[serde(rename_all = "lowercase")]
51pub enum CrossStrategy {
52 Auto,
53 Zigbuild,
54 Cross,
55 Cargo,
56}
57
58// ---------------------------------------------------------------------------
59// CrateConfig
60// ---------------------------------------------------------------------------
61
62#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
63#[serde(default)]
64pub struct CrateConfig {
65 /// Crate name as published (must match the Cargo.toml package name).
66 pub name: String,
67 /// Relative path to the crate directory from the project root.
68 pub path: String,
69 /// Git tag template used to tag and identify releases (supports templates).
70 pub tag_template: String,
71 /// Pinned semver version. When set, `anodizer bump --strict` refuses to
72 /// edit this crate's `Cargo.toml` to anything other than this value;
73 /// without `--strict`, the bump proceeds with a warning. Lets a release
74 /// captain freeze a crate's version while still running broad
75 /// `--workspace` bumps.
76 pub version: Option<String>,
77 /// Other crates this crate depends on; ensures release ordering.
78 pub depends_on: Option<Vec<String>>,
79 /// Build configurations for this crate. One entry per binary by default.
80 pub builds: Option<Vec<BuildConfig>>,
81 /// Cross-compilation strategy for this crate: auto, zigbuild, cross, or cargo.
82 pub cross: Option<CrossStrategy>,
83 #[serde(default, deserialize_with = "deserialize_archives_config")]
84 #[schemars(schema_with = "archives_schema")]
85 pub archives: ArchivesConfig,
86 /// Checksum configuration for this crate.
87 pub checksum: Option<ChecksumConfig>,
88 /// GitHub release configuration for this crate.
89 pub release: Option<ReleaseConfig>,
90 /// Publishing targets (Homebrew, Scoop, AUR, etc.) for this crate.
91 pub publish: Option<PublishConfig>,
92 /// Docker V2 image build configurations for this crate (canonical API:
93 /// images+tags, annotations, build_args, sbom, disable). The legacy
94 /// `docker:` block was removed; this is the only docker surface.
95 pub docker_v2: Option<Vec<DockerV2Config>>,
96 /// Docker image digest file configuration for this crate.
97 pub docker_digest: Option<DockerDigestConfig>,
98 /// Docker multi-platform manifest configurations for this crate.
99 pub docker_manifests: Option<Vec<DockerManifestConfig>>,
100 /// Linux package (deb, rpm, apk) configurations for this crate. Renamed
101 /// from `nfpm:` (singular) for spelling parity with `Defaults.nfpms` and
102 /// the rest of the plural-name per-crate packaging lists (`dmgs`, `msis`,
103 /// `pkgs`, `nsis`, ...). The `nfpm:` spelling is still accepted via serde
104 /// alias for back-compat.
105 #[serde(alias = "nfpm")]
106 pub nfpms: Option<Vec<NfpmConfig>>,
107 /// Snapcraft package configurations for this crate.
108 pub snapcrafts: Option<Vec<SnapcraftConfig>>,
109 /// macOS DMG disk image configurations for this crate.
110 pub dmgs: Option<Vec<DmgConfig>>,
111 /// Windows MSI installer configurations for this crate.
112 pub msis: Option<Vec<MsiConfig>>,
113 /// macOS PKG installer configurations for this crate.
114 pub pkgs: Option<Vec<PkgConfig>>,
115 /// NSIS installer configurations for this crate.
116 pub nsis: Option<Vec<NsisConfig>>,
117 /// macOS app bundle configurations for this crate.
118 pub app_bundles: Option<Vec<AppBundleConfig>>,
119 /// Linux Flatpak bundle configurations for this crate.
120 pub flatpaks: Option<Vec<FlatpakConfig>>,
121 /// Cloud storage (S3/GCS/Azure) upload configurations for this crate.
122 pub blobs: Option<Vec<BlobConfig>>,
123 /// cargo-binstall metadata configuration for this crate.
124 pub binstall: Option<BinstallConfig>,
125 /// Automatic version number synchronization configuration for this crate.
126 pub version_sync: Option<VersionSyncConfig>,
127 /// macOS universal binary (fat binary) configurations for this crate.
128 pub universal_binaries: Option<Vec<UniversalBinaryConfig>>,
129 /// When true (or template evaluating to "true"), all build outputs are
130 /// placed in a flat `dist/` directory instead of `dist/{target}/`.
131 #[serde(default, deserialize_with = "deserialize_string_or_bool_opt")]
132 pub no_unique_dist_dir: Option<StringOrBool>,
133}
134
135/// Helper schema function for archives (accepts false or array).
136pub(super) fn archives_schema(
137 generator: &mut schemars::r#gen::SchemaGenerator,
138) -> schemars::schema::Schema {
139 let mut schema = generator.subschema_for::<Option<Vec<ArchiveConfig>>>();
140 if let schemars::schema::Schema::Object(ref mut obj) = schema {
141 obj.metadata().description = Some("Archive configurations for this crate. Set to false to disable archiving, or provide an array of archive configs.".to_owned());
142 }
143 schema
144}
145
146impl Default for CrateConfig {
147 fn default() -> Self {
148 CrateConfig {
149 name: String::new(),
150 path: String::new(),
151 tag_template: String::new(),
152 version: None,
153 depends_on: None,
154 builds: None,
155 cross: None,
156 archives: ArchivesConfig::Configs(vec![]),
157 checksum: None,
158 release: None,
159 publish: None,
160 docker_v2: None,
161 docker_digest: None,
162 docker_manifests: None,
163 nfpms: None,
164 snapcrafts: None,
165 dmgs: None,
166 msis: None,
167 pkgs: None,
168 nsis: None,
169 app_bundles: None,
170 flatpaks: None,
171 blobs: None,
172 binstall: None,
173 version_sync: None,
174 universal_binaries: None,
175 no_unique_dist_dir: None,
176 }
177 }
178}
179
180// ---------------------------------------------------------------------------
181// UniversalBinaryConfig
182// ---------------------------------------------------------------------------
183
184#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
185#[serde(default)]
186pub struct UniversalBinaryConfig {
187 /// Unique identifier for this universal binary, propagated into the
188 /// artifact's metadata as `id` (GoReleaser universalbinary.go:42-44).
189 #[serde(default)]
190 pub id: Option<String>,
191 /// Output filename template for the universal binary (supports templates).
192 pub name_template: Option<String>,
193 /// When true, remove the individual arch binaries after creating the universal binary.
194 pub replace: Option<bool>,
195 /// Build IDs filter: only combine artifacts from builds whose `id` is in this list.
196 pub ids: Option<Vec<String>>,
197 /// Pre/post hooks around universal binary creation.
198 pub hooks: Option<BuildHooksConfig>,
199 /// Override the modification timestamp for reproducible universal binaries.
200 pub mod_timestamp: Option<String>,
201}
202
203// ---------------------------------------------------------------------------
204// BuildConfig
205// ---------------------------------------------------------------------------
206
207#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
208#[serde(default)]
209pub struct BuildConfig {
210 /// Unique identifier for this build, used to reference it from archives and other configs.
211 pub id: Option<String>,
212 /// Binary name to build (must match a Cargo binary target in the crate).
213 ///
214 /// Optional so that `defaults.builds` (a path-mirrored template that
215 /// applies to every crate) can omit `binary` — the per-crate `builds[]`
216 /// entry supplies it. When the binary is absent at the per-crate level
217 /// it falls back to the crate's `name` field.
218 pub binary: Option<String>,
219 /// When true (or template evaluating to "true"), skip this build entirely.
220 #[serde(default, deserialize_with = "deserialize_string_or_bool_opt")]
221 pub skip: Option<StringOrBool>,
222 /// Target triples to build for. When set, REPLACES `defaults.targets`
223 /// for this build (override semantics — the per-build value wins
224 /// outright, no concat). When `None`, this build inherits
225 /// `defaults.targets` verbatim. Both `cli::commands::helpers::
226 /// collect_build_targets` and `stage-build` enforce this rule.
227 pub targets: Option<Vec<String>>,
228 /// Cargo features to enable for this build.
229 pub features: Option<Vec<String>>,
230 /// When true, pass --no-default-features to cargo build.
231 pub no_default_features: Option<bool>,
232 /// Per-target environment variables keyed as {target: {KEY: VALUE}}.
233 pub env: Option<HashMap<String, HashMap<String, String>>>,
234 /// Copy the binary from another build ID instead of building it.
235 pub copy_from: Option<String>,
236 /// Extra flags passed to cargo build, one per list entry (e.g., `["--release", "--locked"]`).
237 ///
238 /// Each entry is template-rendered then passed verbatim as a single argv
239 /// token — there is no `sh -c` step and no shell tokenization, so a
240 /// rendered value containing spaces stays one argv entry (it is NOT
241 /// re-split). Use one list entry per flag, including the flag and its
242 /// value as separate entries (`["--target-dir", "/tmp/{{ .Version }}"]`)
243 /// when the value itself may contain spaces.
244 pub flags: Option<Vec<String>>,
245 /// When true, enable reproducible builds by stripping timestamps.
246 pub reproducible: Option<bool>,
247 /// Per-build hooks executed before and after compilation.
248 pub hooks: Option<BuildHooksConfig>,
249 /// Exclude specific os/arch combinations from this build's target matrix.
250 /// Falls back to `defaults.builds.ignore` when not set.
251 pub ignore: Option<Vec<BuildIgnore>>,
252 /// Per-target overrides for env, flags, and features for this build.
253 /// Falls back to `defaults.builds.overrides` when not set.
254 pub overrides: Option<Vec<BuildOverride>>,
255 /// Override the cross-compilation tool binary path (e.g., a custom `cross` wrapper).
256 /// When set, this binary is used instead of cargo/cross/zigbuild.
257 pub cross_tool: Option<String>,
258 /// Override the modification timestamp of built binaries for reproducible builds.
259 /// Template string (e.g. `"{{ .CommitTimestamp }}"`) or unix timestamp.
260 pub mod_timestamp: Option<String>,
261 /// Override the cargo subcommand (default: auto-detected "build" or "zigbuild").
262 /// Enables e.g. `cargo auditable build` by setting `command: "auditable build"`.
263 pub command: Option<String>,
264 /// When true (or template evaluating to "true"), place binaries in flat dist/
265 /// instead of dist/{target}/. Overrides the crate-level setting.
266 #[serde(default, deserialize_with = "deserialize_string_or_bool_opt")]
267 pub no_unique_dist_dir: Option<StringOrBool>,
268 /// Deprecated: GoReleaser's `gobinary:` field selects the cargo-like build
269 /// command (named after `go build`). Anodizer's tool is always `cargo`,
270 /// so the field is captured for back-compat YAML import only and
271 /// `apply_build_legacy_aliases` emits a deprecation warning at config-load
272 /// time. GR ref: `internal/pipe/build/build.go:93-95`.
273 #[serde(default, rename = "gobinary")]
274 pub legacy_gobinary: Option<String>,
275}
276
277/// Pre/post hook configuration shared across multiple stages. Despite the
278/// `Build` prefix in the name, this type is used by both the **build** stage
279/// (pre/post compilation hooks) and the **archive** stage (pre/post archiving
280/// hooks). The name is kept for backward compatibility with existing configs.
281/// **Not** to be confused with the top-level `HooksConfig` (which carries a
282/// flat `hooks: Vec<String>` list for `before`/`after` lifecycle hooks).
283#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
284#[serde(default)]
285pub struct BuildHooksConfig {
286 /// Commands to run before the build step.
287 pub pre: Option<Vec<HookEntry>>,
288 /// Commands to run after the build step.
289 pub post: Option<Vec<HookEntry>>,
290}
291
292/// Pre/post archive hook configuration.
293///
294/// Archive hooks use `before`/`after` (matching GoReleaser's archive pipe);
295/// build hooks use `pre`/`post` (matching GoReleaser's build pipe).
296#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
297#[serde(default)]
298pub struct ArchiveHooksConfig {
299 /// Commands to run before the archive step.
300 pub before: Option<Vec<HookEntry>>,
301 /// Commands to run after the archive step.
302 pub after: Option<Vec<HookEntry>>,
303}