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