anodizer_core/config/mod.rs
1use std::collections::{BTreeMap, HashMap};
2use std::path::PathBuf;
3
4use schemars::JsonSchema;
5use serde::{Deserialize, Serialize};
6
7// ---------------------------------------------------------------------------
8// Include specification types
9// ---------------------------------------------------------------------------
10
11/// An include specification: either a plain path string or a structured from_file/from_url.
12///
13/// YAML examples:
14/// ```yaml
15/// includes:
16/// - ./defaults.yaml # plain string (backward compat)
17/// - from_file:
18/// path: ./config/release.yaml # structured file path
19/// - from_url:
20/// url: https://example.com/config.yaml # URL fetch
21/// headers:
22/// x-api-token: "${MYCOMPANY_TOKEN}" # env var expansion in headers
23/// ```
24#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
25#[serde(untagged)]
26pub enum IncludeSpec {
27 /// Plain string path (backward compatible): "path/to/file.yaml"
28 Path(String),
29 /// Structured file include with `from_file.path`.
30 FromFile { from_file: IncludeFilePath },
31 /// Structured URL include with `from_url.url` and optional headers.
32 FromUrl { from_url: IncludeUrlConfig },
33}
34
35/// File path for a structured include.
36#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
37#[serde(deny_unknown_fields)]
38pub struct IncludeFilePath {
39 /// Path to the include file (relative to the config file).
40 pub path: String,
41}
42
43/// URL configuration for a structured include.
44#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
45#[serde(deny_unknown_fields)]
46pub struct IncludeUrlConfig {
47 /// URL to fetch. If it does not start with `http://` or `https://`,
48 /// `https://raw.githubusercontent.com/` is prepended (GitHub shorthand).
49 pub url: String,
50 /// Optional HTTP headers. Values support `${VAR_NAME}` environment variable expansion.
51 pub headers: Option<HashMap<String, String>>,
52}
53
54// ---------------------------------------------------------------------------
55// Top-level config
56// ---------------------------------------------------------------------------
57
58/// `deny_unknown_fields` rejects typos and unknown config
59/// fields at parse time (strict YAML unmarshalling).
60#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
61#[serde(default, deny_unknown_fields)]
62pub struct Config {
63 /// Schema version. Currently supports 1 (implicit default) and 2.
64 pub version: Option<u32>,
65 /// Human-readable project name used in templates and release titles.
66 pub project_name: String,
67 /// Output directory for build artifacts (default: ./dist).
68 #[serde(default = "default_dist")]
69 pub dist: PathBuf,
70 /// Additional config files to merge into this config.
71 /// Supports plain string paths, `from_file:` for structured file paths,
72 /// and `from_url:` for fetching configs from URLs with optional headers.
73 pub includes: Option<Vec<IncludeSpec>>,
74 /// Environment file configuration. Accepts either:
75 /// - A list of `.env` file paths: `[".env", ".release.env"]`
76 /// - A struct with token file paths: `{ github_token: "~/.config/goreleaser/github_token" }`
77 pub env_files: Option<EnvFilesConfig>,
78 /// Default values applied to all crates unless overridden.
79 pub defaults: Option<Defaults>,
80 /// Hooks run before the release pipeline starts.
81 ///
82 /// Use `--skip=before` to bypass — one token covers this block and every
83 /// `crates[].before:` block.
84 pub before: Option<HooksConfig>,
85 /// Hooks run after the release pipeline completes SUCCESSFULLY.
86 ///
87 /// A failed run never reaches them — route failure handling through
88 /// `on_error:`, and teardown that must happen either way through
89 /// `always:`.
90 ///
91 /// Use `--skip=after` to bypass — one token covers this block and every
92 /// `crates[].after:` block.
93 ///
94 /// ```yaml
95 /// after:
96 /// hooks:
97 /// - cmd: ./notify-release-succeeded.sh
98 /// ```
99 pub after: Option<HooksConfig>,
100 /// Hooks run when the release pipeline fails at ANY stage (build,
101 /// sign, publish, ...). The pipeline holds on failure: published state
102 /// is left exactly where the failed run put it, so `{{ .RolledBack }}`
103 /// is always `false`. Recover by re-running the identical command
104 /// (publishers reconcile against what already shipped and skip it), or
105 /// withdraw the release deliberately with `anodizer tag rollback`.
106 ///
107 /// Notification / cleanup hooks: a hook's own failure is logged as a
108 /// warning and never masks the pipeline error. The failure context is
109 /// exposed both as template vars (`{{ .Error }}`, `{{ .RolledBack }}`)
110 /// and as `ANODIZER_*` env vars (`ANODIZER_ERROR`,
111 /// `ANODIZER_ROLLED_BACK`, `ANODIZER_VERSION`, `ANODIZER_TAG`) so
112 /// hooks can consume the error text without shell interpolation.
113 ///
114 /// Use `--skip=on-error` to bypass — one token covers this block and
115 /// every `publish.on_error:` block.
116 ///
117 /// ```yaml
118 /// on_error:
119 /// hooks:
120 /// - cmd: ./notify-release-failed.sh
121 /// ```
122 pub on_error: Option<HooksConfig>,
123 /// Hooks run LAST on every terminal path — the release's `finally`.
124 ///
125 /// Ordering: on success they run after `after:`; on failure they run
126 /// after `on_error:`. They also fire on the one exit neither of those
127 /// reaches — a `before:` hook that failed before the pipeline started.
128 /// Use them for teardown that has to happen either way: removing a
129 /// staging directory, releasing a lock, stopping a sidecar container.
130 ///
131 /// They fire once per `anodizer release` / `anodizer build` invocation,
132 /// pairing 1:1 with `before:` — including on each `--split` shard and on
133 /// `--merge`, which are separate invocations that each run `before:` of
134 /// their own.
135 ///
136 /// Use `--skip=always` to bypass. Skipping the `finally` lane is
137 /// supported on purpose — `--skip=before` already suppresses the lane it
138 /// pairs with — but the consequence is that teardown does not run, so
139 /// anything the run staged stays staged.
140 ///
141 /// The run's outcome is exposed as template vars (`{{ .Success }}`,
142 /// `{{ .Error }}`) and as `ANODIZER_*` env vars (`ANODIZER_SUCCESS`,
143 /// `ANODIZER_ERROR`, `ANODIZER_VERSION`, `ANODIZER_TAG`), so a hook can
144 /// branch on the outcome and read the error text without interpolating
145 /// untrusted text into the shell command. `ANODIZER_ERROR` is empty on
146 /// success.
147 ///
148 /// A failing `always:` hook never masks a release failure: on the
149 /// failure path it is logged as a warning and the original pipeline
150 /// error is still what the run exits with. On the success path there is
151 /// no error to mask, so the hook's own failure fails the run — the same
152 /// contract `after:` has.
153 ///
154 /// ```yaml
155 /// always:
156 /// hooks:
157 /// - cmd: ./teardown-staging.sh
158 /// ```
159 pub always: Option<HooksConfig>,
160 /// Hooks run after build/archive/sign/sbom/checksum complete but
161 /// immediately before the publish phase dispatches any publisher.
162 ///
163 /// Use cases: smoke-test artifacts against the staged dist tree,
164 /// run external validators (antivirus, vulnerability scanners),
165 /// stage external state, or abort the release before any
166 /// publisher writes to a registry.
167 ///
168 /// A non-zero exit code from any hook aborts the release before
169 /// publish runs. Hooks fire in declared order. Use `--skip=before-publish`
170 /// to bypass.
171 pub before_publish: Option<HooksConfig>,
172 /// List of crates in this project.
173 pub crates: Vec<CrateConfig>,
174 /// Changelog generation configuration.
175 pub changelog: Option<ChangelogConfig>,
176 /// Signing configurations for binaries, archives, and checksums.
177 #[serde(default, deserialize_with = "deserialize_signs")]
178 #[schemars(schema_with = "signs_schema")]
179 pub signs: Vec<SignConfig>,
180 /// Binary-specific signing configs (same shape as `signs` but only for
181 /// binary artifacts). The `artifacts` field on each entry is constrained
182 /// at parse time to `binary` / `none` (or omitted) — a broader filter on
183 /// `binary_signs` would silently match nothing because the loop only
184 /// iterates Binary artifacts. Constraint lives in `deserialize_binary_signs`.
185 #[serde(default, deserialize_with = "deserialize_binary_signs")]
186 #[schemars(schema_with = "signs_schema")]
187 pub binary_signs: Vec<SignConfig>,
188 /// Docker image signing configurations.
189 pub docker_signs: Option<Vec<DockerSignConfig>>,
190 // No `alias` attribute needed: unlike `signs`/`sign`, "upx" is already
191 // both singular and plural, so a separate alias adds no value.
192 /// UPX binary compression configurations.
193 #[serde(default, deserialize_with = "deserialize_upx")]
194 #[schemars(schema_with = "upx_schema")]
195 pub upx: Vec<UpxConfig>,
196 /// Snapshot release configuration (local/non-tag builds).
197 pub snapshot: Option<SnapshotConfig>,
198 /// Nightly release configuration.
199 pub nightly: Option<NightlyConfig>,
200 /// Announcement configuration (Slack, Discord, email, etc.).
201 pub announce: Option<AnnounceConfig>,
202 /// When true, log artifact file sizes after building.
203 pub report_sizes: Option<bool>,
204 /// Environment variables available to all template expressions.
205 ///
206 /// List of `KEY=VALUE` strings:
207 /// `env: ["MY_VAR=hello", "DEPLOY_ENV=staging"]`. Order is preserved so
208 /// chained env applications (sign + sbom + notarize) see entries in
209 /// declared order. Values are rendered through the template engine before
210 /// being set, so expressions like `{{ Tag }}` or `{{ Date }}` are
211 /// expanded.
212 #[serde(default)]
213 pub env: Option<Vec<String>>,
214 /// Custom template variables accessible as `{{ Var.<key> }}` in templates.
215 /// Provides a way to define reusable values, especially useful with config includes.
216 ///
217 /// Stored as a `BTreeMap` so rendering iterates in deterministic
218 /// (sorted) key order — without this guarantee, a value that references
219 /// another variable (`b: "{{ Var.a }}_v2"`) could render before its
220 /// dependency on a different process / host. The current resolver is
221 /// single-pass (one render per value), so cross-variable references
222 /// only resolve when the referenced key sorts earlier.
223 pub variables: Option<BTreeMap<String, String>>,
224 /// Generic artifact publisher configurations.
225 pub publishers: Option<Vec<PublisherConfig>>,
226 /// DockerHub description sync configurations.
227 pub dockerhub: Option<Vec<DockerHubConfig>>,
228 /// Artifactory upload configurations.
229 pub artifactories: Option<Vec<ArtifactoryConfig>>,
230 /// CloudSmith publisher configurations.
231 pub cloudsmiths: Option<Vec<CloudSmithConfig>>,
232 /// Top-level Homebrew Cask configurations.
233 /// `homebrew_casks` is a top-level array with its own
234 /// repository, commit_author, directory, skip_upload, hooks, dependencies,
235 /// conflicts, completions, manpages, structured uninstall/zap, etc.
236 pub homebrew_casks: Option<Vec<HomebrewCaskConfig>>,
237 /// Repo-committed files that embed the release version outside
238 /// `Cargo.toml` (e.g. a Helm `Chart.yaml`, an install doc, a README
239 /// badge), given as repo-root-relative path strings. At `tag` time each
240 /// listed file has its occurrences of the old version rewritten to the new
241 /// version — both the bare (`0.1.0`) and `v`-prefixed (`v0.1.0`) forms,
242 /// word-boundary anchored — and is staged into the same bump commit as
243 /// `Cargo.toml` / `Cargo.lock`, so these files never drift from the tag.
244 ///
245 /// ```yaml
246 /// version_files:
247 /// - charts/cfgd/Chart.yaml
248 /// - docs/installation.md
249 /// ```
250 pub version_files: Option<Vec<String>>,
251 /// Automatic semantic version tagging configuration.
252 pub tag: Option<TagConfig>,
253 /// Git-level tag discovery and sorting settings.
254 pub git: Option<GitConfig>,
255 /// Partial/split build configuration for fan-out CI pipelines.
256 pub partial: Option<PartialConfig>,
257 /// Independent workspace roots in a monorepo.
258 pub workspaces: Option<Vec<WorkspaceConfig>>,
259 /// Source archive configuration.
260 pub source: Option<SourceConfig>,
261 /// Software bill of materials (SBOM) generation configurations.
262 #[serde(default, deserialize_with = "deserialize_sboms")]
263 #[schemars(schema_with = "sboms_schema")]
264 pub sboms: Vec<SbomConfig>,
265 /// SLSA build-provenance / attestation configuration for binaries and
266 /// archives. In the default `subjects` mode, anodizer writes a subjects
267 /// manifest for `actions/attest-build-provenance`; in `emit` mode it
268 /// generates and signs a self-contained in-toto SLSA provenance statement.
269 /// When omitted (or `enabled: false`), the attestation stage is a no-op.
270 pub attestations: Option<AttestationConfig>,
271 /// GitHub release configuration shared by all crates.
272 pub release: Option<ReleaseConfig>,
273 /// Custom GitHub API/upload/download URLs for GitHub Enterprise installations.
274 pub github_urls: Option<GitHubUrlsConfig>,
275 /// Custom GitLab API/download URLs for self-hosted GitLab installations.
276 pub gitlab_urls: Option<GitLabUrlsConfig>,
277 /// Custom Gitea API/download URLs for self-hosted Gitea installations.
278 pub gitea_urls: Option<GiteaUrlsConfig>,
279 /// Force a specific token type for authentication.
280 /// When set, overrides automatic token detection from environment variables.
281 pub force_token: Option<ForceTokenKind>,
282 /// macOS code signing and notarization configuration.
283 pub notarize: Option<NotarizeConfig>,
284 /// Project metadata configuration (applied to metadata.json output files).
285 pub metadata: Option<MetadataConfig>,
286 /// Template files to render and include as release artifacts.
287 /// File contents are processed through the template engine.
288 pub template_files: Option<Vec<TemplateFileConfig>>,
289 /// Monorepo configuration.
290 /// When configured, tag discovery filters by tag_prefix and the working
291 /// directory is scoped to dir.
292 pub monorepo: Option<MonorepoConfig>,
293 /// Makeself self-extracting archive configurations.
294 #[serde(default, deserialize_with = "deserialize_makeselfs")]
295 #[schemars(schema_with = "makeselfs_schema")]
296 pub makeselfs: Vec<MakeselfConfig>,
297 /// `curl | sh` installer-script configurations. Each entry emits a
298 /// deterministic POSIX `install.sh` release asset that detects the host
299 /// OS + arch, downloads and sha256-verifies the matching archive, and
300 /// installs the binary.
301 #[serde(default, deserialize_with = "deserialize_install_scripts")]
302 #[schemars(schema_with = "install_scripts_schema")]
303 pub install_scripts: Vec<InstallScriptConfig>,
304 /// AppImage configurations. Each entry bundles a built Linux binary plus
305 /// its desktop integration into a single self-contained `.AppImage` via
306 /// linuxdeploy.
307 #[serde(default, deserialize_with = "deserialize_appimages")]
308 #[schemars(schema_with = "appimages_schema")]
309 pub appimages: Vec<AppImageConfig>,
310 /// Opt-in post-release verification gate. Runs LAST (after the release is
311 /// created and every publisher has run) and REPORTS post-publish defects —
312 /// missing assets, failed install smoke-tests, glibc-ceiling violations.
313 /// Because it runs after the irreversible publish, a failure exits
314 /// non-zero to flag CI but never undoes the release. Off unless
315 /// `verify_release.enabled: true`.
316 #[serde(default)]
317 pub verify_release: VerifyReleaseConfig,
318 /// Pre-publish preflight tuning. `preflight.strict: true` promotes
319 /// indeterminate probe outcomes (5xx / rate-limit / network failure /
320 /// undeterminable permissions) from warnings to hard blockers. The
321 /// probes themselves always run read-only before any publisher mutates
322 /// a registry; the default (lenient) behavior needs no config.
323 #[serde(default)]
324 pub preflight: PreflightConfig,
325 /// Source RPM configuration. Renamed from `srpm:` (singular) for spelling
326 /// parity with `Defaults.srpms` and the rest of the plural-name packaging
327 /// fields. The `srpm:` spelling is still accepted via serde alias for
328 /// back-compat.
329 #[serde(alias = "srpm")]
330 pub srpms: Option<SrpmConfig>,
331 /// Milestone closing configurations.
332 pub milestones: Option<Vec<MilestoneConfig>>,
333 /// Generic HTTP upload configurations.
334 pub uploads: Option<Vec<UploadConfig>>,
335 /// AUR source package publishing configurations (source-only PKGBUILD, not -bin).
336 pub aur_sources: Option<Vec<AurSourceConfig>>,
337 /// Top-level retry configuration applied to network-bound operations
338 /// (announcers, git providers, HTTP uploads, docker pipes). When omitted,
339 /// `RetryConfig::default()` is used (10 attempts, 10s base, 5m cap —
340 /// the project-level retry policy).
341 pub retry: Option<RetryConfig>,
342 /// MCP (Model Context Protocol) server registry publishing
343 /// configuration. When `name` is empty (the default), the publisher is
344 /// skipped. The `mcp:` publisher block.
345 #[serde(default)]
346 pub mcp: McpConfig,
347 /// SchemaStore publisher. Registers the project's JSON Schema(s) on
348 /// SchemaStore at release time. When `schemas` is empty (the default),
349 /// the publisher is skipped. The `schemastore:` publisher block.
350 #[serde(default)]
351 pub schemastore: crate::config::publishers::SchemastoreConfig,
352 /// NPM package registry publishing configurations. One entry per
353 /// published package. In the default `optional-deps` mode anodizer emits
354 /// npm's native per-platform packages (biome / git-cliff pattern); in
355 /// `postinstall` mode it emits a download shim (the `npms:`
356 /// parity).
357 pub npms: Option<Vec<NpmConfig>>,
358 /// GemFury (fury.io) deb/rpm/apk publishing configurations. Mirrors
359 /// The `gemfury:` block. The legacy spelling
360 /// `furies:` is accepted via serde alias; a one-time deprecation
361 /// warning is emitted by [`warn_on_legacy_furies_alias`].
362 #[serde(alias = "furies")]
363 pub gemfury: Option<Vec<GemFuryConfig>>,
364 /// PyPI publishing configurations. One entry per published project.
365 /// Emits native `py3-none-<platform>` binary wheels from the built
366 /// binaries (plus an optional `maturin sdist`) and uploads them via
367 /// PyPI's legacy (twine-protocol) upload API. The `pypis:` block.
368 pub pypis: Option<Vec<PypiConfig>>,
369 /// homebrew-core formula-bump configurations. One entry per formula.
370 /// Bumps an existing formula in `Homebrew/homebrew-core` (or a formula
371 /// repository override) via the GitHub API and opens a pull request.
372 /// The `homebrew_cores:` block.
373 pub homebrew_cores: Option<Vec<HomebrewCoreConfig>>,
374 /// Per-crate metadata derived from each crate's `Cargo.toml [package]`
375 /// table (description / license / homepage / authors). Populated at
376 /// config-load time by [`Config::populate_derived_metadata`], keyed by
377 /// crate name. NOT a user-facing YAML field — it backs the
378 /// crate-aware `meta_*_for` accessors so a plain Rust project gets its
379 /// publisher metadata without repeating it in a top-level `metadata:`
380 /// block. A hand-written `metadata:` field and per-publisher overrides
381 /// still win.
382 #[serde(skip)]
383 #[schemars(skip)]
384 pub derived_metadata: BTreeMap<String, MetadataConfig>,
385}
386
387/// Helper schema function for the signs field (accepts object or array).
388fn signs_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
389 let mut schema = generator.subschema_for::<Vec<SignConfig>>();
390 schema.ensure_object().insert(
391 "description".to_owned(),
392 "Artifact signing configurations (cosign, GPG, etc.). Accepts a single object or array."
393 .into(),
394 );
395 schema
396}
397
398/// Helper schema function for the upx field (accepts object or array).
399fn upx_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
400 let mut schema = generator.subschema_for::<Vec<UpxConfig>>();
401 schema.ensure_object().insert(
402 "description".to_owned(),
403 "UPX binary compression configurations. Accepts a single object or array.".into(),
404 );
405 schema
406}
407
408/// Helper schema function for the sboms field (accepts object or array).
409fn sboms_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
410 let mut schema = generator.subschema_for::<Vec<SbomConfig>>();
411 schema.ensure_object().insert(
412 "description".to_owned(),
413 "SBOM generation configurations. Accepts a single object or array.".into(),
414 );
415 schema
416}
417
418fn default_dist() -> PathBuf {
419 PathBuf::from("./dist")
420}
421
422impl Default for Config {
423 fn default() -> Self {
424 Config {
425 version: None,
426 project_name: String::new(),
427 dist: default_dist(),
428 includes: None,
429 env_files: None,
430 defaults: None,
431 before: None,
432 after: None,
433 on_error: None,
434 always: None,
435 before_publish: None,
436 crates: Vec::new(),
437 changelog: None,
438 signs: Vec::new(),
439 binary_signs: Vec::new(),
440 docker_signs: None,
441 upx: Vec::new(),
442 snapshot: None,
443 nightly: None,
444 announce: None,
445 report_sizes: None,
446 env: None,
447 variables: None,
448 publishers: None,
449 dockerhub: None,
450 artifactories: None,
451 cloudsmiths: None,
452 homebrew_casks: None,
453 version_files: None,
454 tag: None,
455 git: None,
456 partial: None,
457 workspaces: None,
458 source: None,
459 sboms: Vec::new(),
460 attestations: None,
461 release: None,
462 github_urls: None,
463 gitlab_urls: None,
464 gitea_urls: None,
465 force_token: None,
466 notarize: None,
467 metadata: None,
468 template_files: None,
469 monorepo: None,
470 makeselfs: Vec::new(),
471 install_scripts: Vec::new(),
472 appimages: Vec::new(),
473 verify_release: VerifyReleaseConfig::default(),
474 preflight: PreflightConfig::default(),
475 srpms: None,
476 milestones: None,
477 uploads: None,
478 aur_sources: None,
479 retry: None,
480 mcp: McpConfig::default(),
481 schemastore: crate::config::publishers::SchemastoreConfig::default(),
482 npms: None,
483 gemfury: None,
484 pypis: None,
485 homebrew_cores: None,
486 derived_metadata: BTreeMap::new(),
487 }
488 }
489}
490
491mod accessors;
492
493mod schema;
494pub use schema::*;
495
496/// Run a deserialization closure on a worker thread sized large enough that
497/// the `Config` derive (60+ `Option<NestedStruct>` fields) cannot exhaust
498/// the host's main-thread stack.
499///
500/// Background: debug builds of `serde_yaml_ng::from_value::<Config>` and
501/// `toml::from_str::<Config>` consume several MiB of stack because each
502/// generated visitor branch for the giant struct lives in a single
503/// monomorphised frame and debug builds neither inline nor tail-call. The
504/// Windows main-thread default reservation is 1 MiB, so any debug-built
505/// integration test that triggers full-config deserialization overflows
506/// before reaching the visitor's body.
507///
508/// Routing every full-`Config` deserialization through this helper keeps
509/// every entry-point platform-agnostic without resorting to per-platform
510/// linker flags or `RUST_MIN_STACK`.
511pub fn deserialize_on_worker<F, T>(f: F) -> anyhow::Result<T>
512where
513 F: FnOnce() -> anyhow::Result<T> + Send + 'static,
514 T: Send + 'static,
515{
516 use anyhow::Context as _;
517
518 // 8 MiB matches the Linux/macOS process default and comfortably exceeds
519 // the ~2 MiB peak observed for debug `Config` deserialization.
520 const WORKER_STACK_SIZE: usize = 8 * 1024 * 1024;
521
522 let handle = std::thread::Builder::new()
523 .stack_size(WORKER_STACK_SIZE)
524 .name("anodizer-config-deserialize".to_string())
525 .spawn(f)
526 .context("failed to spawn config deserialization worker thread")?;
527 match handle.join() {
528 Ok(result) => result,
529 Err(payload) => std::panic::resume_unwind(payload),
530 }
531}
532
533mod validate;
534pub use validate::*;
535
536mod publish_axis;
537pub(crate) use publish_axis::*;
538
539mod legacy;
540pub use legacy::*;
541
542// ---------------------------------------------------------------------------
543// EnvFilesConfig — accepts list of .env paths OR structured token file paths
544// ---------------------------------------------------------------------------
545
546mod env_files;
547pub use env_files::*;
548
549// ---------------------------------------------------------------------------
550// Defaults
551// ---------------------------------------------------------------------------
552
553mod defaults;
554pub use defaults::*;
555
556// ---------------------------------------------------------------------------
557// BuildIgnore — exclude specific os/arch combos from builds
558// ---------------------------------------------------------------------------
559
560mod build;
561pub use build::*;
562
563// ---------------------------------------------------------------------------
564// ArchivesConfig — untagged enum: false => Disabled, array => Configs
565// ---------------------------------------------------------------------------
566
567mod archives;
568pub use archives::*;
569
570mod completions;
571pub use completions::*;
572
573// ---------------------------------------------------------------------------
574// ReleaseConfig
575// ---------------------------------------------------------------------------
576
577mod release;
578pub use release::*;
579
580// ---------------------------------------------------------------------------
581// Shared publisher config types: RepositoryConfig, CommitAuthorConfig
582// ---------------------------------------------------------------------------
583
584mod publishers;
585pub use publishers::*;
586
587// ---------------------------------------------------------------------------
588// DockerV2Config
589// ---------------------------------------------------------------------------
590
591mod docker;
592pub use docker::*;
593
594// ---------------------------------------------------------------------------
595// NfpmConfig
596// ---------------------------------------------------------------------------
597
598mod nfpm;
599pub use nfpm::*;
600
601// ---------------------------------------------------------------------------
602// SnapcraftConfig
603// ---------------------------------------------------------------------------
604
605mod snapcraft;
606pub use snapcraft::*;
607// ---------------------------------------------------------------------------
608// DmgConfig / MsiConfig / PkgConfig / NsisConfig / AppBundleConfig / FlatpakConfig
609// ---------------------------------------------------------------------------
610
611mod installers;
612pub use installers::*;
613
614// ---------------------------------------------------------------------------
615// BlobConfig (S3/GCS/Azure cloud storage)
616// ---------------------------------------------------------------------------
617
618mod blob;
619pub use blob::*;
620
621// ---------------------------------------------------------------------------
622// PartialConfig (split/merge CI fan-out)
623// ---------------------------------------------------------------------------
624
625mod partial;
626pub use partial::*;
627
628// ---------------------------------------------------------------------------
629// BinstallConfig
630// ---------------------------------------------------------------------------
631
632mod binstall;
633pub use binstall::*;
634
635// ---------------------------------------------------------------------------
636// NotarizeConfig (macOS code signing and notarization)
637// ---------------------------------------------------------------------------
638
639mod notarize;
640pub use notarize::*;
641// ---------------------------------------------------------------------------
642// SourceConfig
643// ---------------------------------------------------------------------------
644
645mod source;
646pub use source::*;
647
648// ---------------------------------------------------------------------------
649// SbomConfig
650// ---------------------------------------------------------------------------
651
652mod sbom;
653pub use sbom::*;
654
655// ---------------------------------------------------------------------------
656// AttestationConfig
657// ---------------------------------------------------------------------------
658
659mod attestation;
660pub use attestation::*;
661
662// ---------------------------------------------------------------------------
663// VersionSyncConfig
664// ---------------------------------------------------------------------------
665
666mod version_sync;
667pub use version_sync::*;
668
669// ---------------------------------------------------------------------------
670// ChangelogConfig
671// ---------------------------------------------------------------------------
672
673mod changelog;
674pub use changelog::*;
675// ---------------------------------------------------------------------------
676// SignConfig / DockerSignConfig — lifted to `crate::signing`
677// ---------------------------------------------------------------------------
678//
679// see `crate::signing` for the type definitions. The
680// re-exports below preserve the historical
681// `anodizer_core::config::{SignConfig, DockerSignConfig}` import paths
682// used by every stage that consumes a sign config.
683
684pub use crate::signing::{AuthenticodeConfig, DockerSignConfig, SignConfig, SignVerifyConfig};
685
686// ---------------------------------------------------------------------------
687// UpxConfig
688// ---------------------------------------------------------------------------
689
690mod upx;
691pub use upx::*;
692
693// ---------------------------------------------------------------------------
694// SnapshotConfig
695// ---------------------------------------------------------------------------
696
697mod snapshot_nightly;
698pub use snapshot_nightly::*;
699
700mod cargo_metadata;
701pub use cargo_metadata::derive_metadata_from_cargo_toml;
702
703mod workspace_deps;
704pub use workspace_deps::{
705 derive_depends_on_from_cargo_toml, discover_cargo_workspace_member_names,
706 extract_workspace_deps,
707};
708
709/// Extract the name portion of a `"Name <email>"` maintainer/author string,
710/// dropping any `<…>` email suffix. Returns `None` when the result is empty
711/// (e.g. a bare-email `<ada@example.com>`), so a derived Vendor / OCI `vendor`
712/// value is never emitted blank.
713pub fn maintainer_name_only(maintainer: &str) -> Option<String> {
714 let name = maintainer.split('<').next().unwrap_or(maintainer).trim();
715 (!name.is_empty()).then(|| name.to_string())
716}
717
718// ---------------------------------------------------------------------------
719// TemplateFileConfig
720// ---------------------------------------------------------------------------
721
722mod templatefiles;
723pub use templatefiles::*;
724
725// ---------------------------------------------------------------------------
726// AnnounceConfig
727// ---------------------------------------------------------------------------
728mod announce;
729pub use announce::*;
730// ---------------------------------------------------------------------------
731// DockerHub description sync
732// ---------------------------------------------------------------------------
733
734mod dockerhub;
735pub use dockerhub::*;
736
737// ---------------------------------------------------------------------------
738// Artifactory publisher
739// ---------------------------------------------------------------------------
740
741mod artifactory;
742pub use artifactory::*;
743
744// ---------------------------------------------------------------------------
745// CloudSmith publisher
746// ---------------------------------------------------------------------------
747
748mod cloudsmith;
749pub use cloudsmith::*;
750
751// ---------------------------------------------------------------------------
752// PublisherConfig
753// ---------------------------------------------------------------------------
754
755mod publisher;
756pub use publisher::*;
757
758// ---------------------------------------------------------------------------
759// HooksConfig
760// ---------------------------------------------------------------------------
761
762mod hooks;
763pub use hooks::*;
764
765// ---------------------------------------------------------------------------
766// GitConfig
767// ---------------------------------------------------------------------------
768
769mod git_config;
770pub use git_config::*;
771
772// ---------------------------------------------------------------------------
773// MonorepoConfig
774// ---------------------------------------------------------------------------
775
776mod monorepo;
777pub use monorepo::*;
778
779// ---------------------------------------------------------------------------
780// TagConfig
781// ---------------------------------------------------------------------------
782
783mod tag;
784pub use tag::*;
785
786// ---------------------------------------------------------------------------
787// WorkspaceConfig
788// ---------------------------------------------------------------------------
789
790mod workspace;
791pub use workspace::*;
792
793// ---------------------------------------------------------------------------
794// RetryConfig (top-level `retry:` block — bridges to crate::retry::RetryPolicy)
795// ---------------------------------------------------------------------------
796
797mod retry;
798pub use retry::*;
799
800// ---------------------------------------------------------------------------
801// PostPublishPollConfig (per-publisher post-publish polling)
802// ---------------------------------------------------------------------------
803
804mod post_publish_poll;
805pub use post_publish_poll::*;
806
807// ---------------------------------------------------------------------------
808// VerifyReleaseConfig (top-level `verify_release:` post-publish gate)
809// ---------------------------------------------------------------------------
810
811mod verify_release;
812pub use verify_release::*;
813
814// ---------------------------------------------------------------------------
815// PreflightConfig (top-level `preflight:` pre-publish probe tuning)
816// ---------------------------------------------------------------------------
817
818mod preflight;
819pub use preflight::*;
820
821// ---------------------------------------------------------------------------
822// StringOrBool — accepts bool or template string in YAML
823// ---------------------------------------------------------------------------
824
825mod string_or_bool;
826pub use string_or_bool::*;
827
828// ---------------------------------------------------------------------------
829// MakeselfConfig + SrpmConfig — lifted to `crate::packagers`
830// ---------------------------------------------------------------------------
831//
832// All packaging config types live in their own modules under
833// `crate::packagers`. The re-exports below preserve the historical
834// `anodizer_core::config::{MakeselfConfig, MakeselfFile, SrpmConfig}`
835// import paths used by stages and tests.
836
837pub use crate::packagers::{
838 AppImageConfig, AppImageExtra, InstallScriptConfig, MakeselfConfig, MakeselfFile,
839 RuntimeHarvest, SrpmConfig,
840};
841pub(crate) use crate::packagers::{
842 appimages_schema, deserialize_appimages, deserialize_install_scripts, deserialize_makeselfs,
843 install_scripts_schema, makeselfs_schema,
844};
845
846// ---------------------------------------------------------------------------
847// MilestoneConfig
848// ---------------------------------------------------------------------------
849
850mod milestone;
851pub use milestone::*;
852
853// ---------------------------------------------------------------------------
854// UploadConfig (generic HTTP upload)
855// ---------------------------------------------------------------------------
856
857mod upload;
858pub use upload::*;
859
860// ---------------------------------------------------------------------------
861// AurSourceConfig
862// ---------------------------------------------------------------------------
863
864mod aur_source;
865pub use aur_source::*;
866
867// ---------------------------------------------------------------------------
868// McpConfig (MCP registry publisher)
869// ---------------------------------------------------------------------------
870
871mod mcp;
872pub use mcp::*;
873
874// ---------------------------------------------------------------------------
875// NpmConfig (NPM package registry publisher)
876// ---------------------------------------------------------------------------
877
878mod npm;
879pub use npm::*;
880
881// ---------------------------------------------------------------------------
882// GemFuryConfig (Gemfury / fury.io publisher)
883// ---------------------------------------------------------------------------
884
885mod gemfury;
886pub use gemfury::*;
887
888// ---------------------------------------------------------------------------
889// PypiConfig (PyPI binary-wheel publisher)
890// ---------------------------------------------------------------------------
891
892mod pypi;
893pub use pypi::*;
894
895// ---------------------------------------------------------------------------
896// HomebrewCoreConfig (homebrew-core formula-bump publisher)
897// ---------------------------------------------------------------------------
898
899mod homebrew_core;
900pub use homebrew_core::*;
901
902// ---------------------------------------------------------------------------
903// Well-known config file discovery
904// ---------------------------------------------------------------------------
905
906mod discovery;
907pub use discovery::*;
908
909// ---------------------------------------------------------------------------
910// Tests
911// ---------------------------------------------------------------------------
912
913#[cfg(test)]
914mod tests;