Skip to main content

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