use std::collections::{BTreeMap, HashMap};
use std::path::PathBuf;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
#[serde(untagged)]
pub enum IncludeSpec {
Path(String),
FromFile { from_file: IncludeFilePath },
FromUrl { from_url: IncludeUrlConfig },
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct IncludeFilePath {
pub path: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct IncludeUrlConfig {
pub url: String,
pub headers: Option<HashMap<String, String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(default, deny_unknown_fields)]
pub struct Config {
pub version: Option<u32>,
pub project_name: String,
#[serde(default = "default_dist")]
pub dist: PathBuf,
pub includes: Option<Vec<IncludeSpec>>,
pub env_files: Option<EnvFilesConfig>,
pub defaults: Option<Defaults>,
pub before: Option<HooksConfig>,
pub after: Option<HooksConfig>,
pub on_error: Option<HooksConfig>,
pub before_publish: Option<HooksConfig>,
pub crates: Vec<CrateConfig>,
pub changelog: Option<ChangelogConfig>,
#[serde(default, deserialize_with = "deserialize_signs")]
#[schemars(schema_with = "signs_schema")]
pub signs: Vec<SignConfig>,
#[serde(default, deserialize_with = "deserialize_binary_signs")]
#[schemars(schema_with = "signs_schema")]
pub binary_signs: Vec<SignConfig>,
pub docker_signs: Option<Vec<DockerSignConfig>>,
#[serde(default, deserialize_with = "deserialize_upx")]
#[schemars(schema_with = "upx_schema")]
pub upx: Vec<UpxConfig>,
pub snapshot: Option<SnapshotConfig>,
pub nightly: Option<NightlyConfig>,
pub announce: Option<AnnounceConfig>,
pub report_sizes: Option<bool>,
#[serde(default)]
pub env: Option<Vec<String>>,
pub variables: Option<BTreeMap<String, String>>,
pub publishers: Option<Vec<PublisherConfig>>,
pub dockerhub: Option<Vec<DockerHubConfig>>,
pub artifactories: Option<Vec<ArtifactoryConfig>>,
pub cloudsmiths: Option<Vec<CloudSmithConfig>>,
pub homebrew_casks: Option<Vec<HomebrewCaskConfig>>,
pub version_files: Option<Vec<String>>,
pub tag: Option<TagConfig>,
pub git: Option<GitConfig>,
pub partial: Option<PartialConfig>,
pub workspaces: Option<Vec<WorkspaceConfig>>,
pub source: Option<SourceConfig>,
#[serde(default, deserialize_with = "deserialize_sboms")]
#[schemars(schema_with = "sboms_schema")]
pub sboms: Vec<SbomConfig>,
pub attestations: Option<AttestationConfig>,
pub release: Option<ReleaseConfig>,
pub github_urls: Option<GitHubUrlsConfig>,
pub gitlab_urls: Option<GitLabUrlsConfig>,
pub gitea_urls: Option<GiteaUrlsConfig>,
pub force_token: Option<ForceTokenKind>,
pub notarize: Option<NotarizeConfig>,
pub metadata: Option<MetadataConfig>,
pub template_files: Option<Vec<TemplateFileConfig>>,
pub monorepo: Option<MonorepoConfig>,
#[serde(default, deserialize_with = "deserialize_makeselfs")]
#[schemars(schema_with = "makeselfs_schema")]
pub makeselfs: Vec<MakeselfConfig>,
#[serde(default, deserialize_with = "deserialize_install_scripts")]
#[schemars(schema_with = "install_scripts_schema")]
pub install_scripts: Vec<InstallScriptConfig>,
#[serde(default, deserialize_with = "deserialize_appimages")]
#[schemars(schema_with = "appimages_schema")]
pub appimages: Vec<AppImageConfig>,
#[serde(default)]
pub verify_release: VerifyReleaseConfig,
#[serde(default)]
pub preflight: PreflightConfig,
#[serde(alias = "srpm")]
pub srpms: Option<SrpmConfig>,
pub milestones: Option<Vec<MilestoneConfig>>,
pub uploads: Option<Vec<UploadConfig>>,
pub aur_sources: Option<Vec<AurSourceConfig>>,
pub retry: Option<RetryConfig>,
#[serde(default)]
pub mcp: McpConfig,
#[serde(default)]
pub schemastore: crate::config::publishers::SchemastoreConfig,
pub npms: Option<Vec<NpmConfig>>,
#[serde(alias = "furies")]
pub gemfury: Option<Vec<GemFuryConfig>>,
pub pypis: Option<Vec<PypiConfig>>,
pub homebrew_cores: Option<Vec<HomebrewCoreConfig>>,
#[serde(skip)]
#[schemars(skip)]
pub derived_metadata: BTreeMap<String, MetadataConfig>,
}
fn signs_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
let mut schema = generator.subschema_for::<Vec<SignConfig>>();
schema.ensure_object().insert(
"description".to_owned(),
"Artifact signing configurations (cosign, GPG, etc.). Accepts a single object or array."
.into(),
);
schema
}
fn upx_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
let mut schema = generator.subschema_for::<Vec<UpxConfig>>();
schema.ensure_object().insert(
"description".to_owned(),
"UPX binary compression configurations. Accepts a single object or array.".into(),
);
schema
}
fn sboms_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
let mut schema = generator.subschema_for::<Vec<SbomConfig>>();
schema.ensure_object().insert(
"description".to_owned(),
"SBOM generation configurations. Accepts a single object or array.".into(),
);
schema
}
fn default_dist() -> PathBuf {
PathBuf::from("./dist")
}
impl Default for Config {
fn default() -> Self {
Config {
version: None,
project_name: String::new(),
dist: default_dist(),
includes: None,
env_files: None,
defaults: None,
before: None,
after: None,
on_error: None,
before_publish: None,
crates: Vec::new(),
changelog: None,
signs: Vec::new(),
binary_signs: Vec::new(),
docker_signs: None,
upx: Vec::new(),
snapshot: None,
nightly: None,
announce: None,
report_sizes: None,
env: None,
variables: None,
publishers: None,
dockerhub: None,
artifactories: None,
cloudsmiths: None,
homebrew_casks: None,
version_files: None,
tag: None,
git: None,
partial: None,
workspaces: None,
source: None,
sboms: Vec::new(),
attestations: None,
release: None,
github_urls: None,
gitlab_urls: None,
gitea_urls: None,
force_token: None,
notarize: None,
metadata: None,
template_files: None,
monorepo: None,
makeselfs: Vec::new(),
install_scripts: Vec::new(),
appimages: Vec::new(),
verify_release: VerifyReleaseConfig::default(),
preflight: PreflightConfig::default(),
srpms: None,
milestones: None,
uploads: None,
aur_sources: None,
retry: None,
mcp: McpConfig::default(),
schemastore: crate::config::publishers::SchemastoreConfig::default(),
npms: None,
gemfury: None,
pypis: None,
homebrew_cores: None,
derived_metadata: BTreeMap::new(),
}
}
}
mod accessors;
mod schema;
pub use schema::*;
pub fn deserialize_on_worker<F, T>(f: F) -> anyhow::Result<T>
where
F: FnOnce() -> anyhow::Result<T> + Send + 'static,
T: Send + 'static,
{
use anyhow::Context as _;
const WORKER_STACK_SIZE: usize = 8 * 1024 * 1024;
let handle = std::thread::Builder::new()
.stack_size(WORKER_STACK_SIZE)
.name("anodizer-config-deserialize".to_string())
.spawn(f)
.context("failed to spawn config deserialization worker thread")?;
match handle.join() {
Ok(result) => result,
Err(payload) => std::panic::resume_unwind(payload),
}
}
mod validate;
pub use validate::*;
mod publish_axis;
pub(crate) use publish_axis::*;
mod legacy;
pub use legacy::*;
mod env_files;
pub use env_files::*;
mod defaults;
pub use defaults::*;
mod build;
pub use build::*;
mod archives;
pub use archives::*;
mod completions;
pub use completions::*;
mod release;
pub use release::*;
mod publishers;
pub use publishers::*;
mod docker;
pub use docker::*;
mod nfpm;
pub use nfpm::*;
mod snapcraft;
pub use snapcraft::*;
mod installers;
pub use installers::*;
mod blob;
pub use blob::*;
mod partial;
pub use partial::*;
mod binstall;
pub use binstall::*;
mod notarize;
pub use notarize::*;
mod source;
pub use source::*;
mod sbom;
pub use sbom::*;
mod attestation;
pub use attestation::*;
mod version_sync;
pub use version_sync::*;
mod changelog;
pub use changelog::*;
pub use crate::signing::{AuthenticodeConfig, DockerSignConfig, SignConfig, SignVerifyConfig};
mod upx;
pub use upx::*;
mod snapshot_nightly;
pub use snapshot_nightly::*;
mod cargo_metadata;
pub use cargo_metadata::derive_metadata_from_cargo_toml;
mod workspace_deps;
pub use workspace_deps::{
derive_depends_on_from_cargo_toml, discover_cargo_workspace_member_names,
extract_workspace_deps,
};
pub fn maintainer_name_only(maintainer: &str) -> Option<String> {
let name = maintainer.split('<').next().unwrap_or(maintainer).trim();
(!name.is_empty()).then(|| name.to_string())
}
mod templatefiles;
pub use templatefiles::*;
mod announce;
pub use announce::*;
mod dockerhub;
pub use dockerhub::*;
mod artifactory;
pub use artifactory::*;
mod cloudsmith;
pub use cloudsmith::*;
mod publisher;
pub use publisher::*;
mod hooks;
pub use hooks::*;
mod git_config;
pub use git_config::*;
mod monorepo;
pub use monorepo::*;
mod tag;
pub use tag::*;
mod workspace;
pub use workspace::*;
mod retry;
pub use retry::*;
mod post_publish_poll;
pub use post_publish_poll::*;
mod verify_release;
pub use verify_release::*;
mod preflight;
pub use preflight::*;
mod string_or_bool;
pub use string_or_bool::*;
pub use crate::packagers::{
AppImageConfig, AppImageExtra, InstallScriptConfig, MakeselfConfig, MakeselfFile,
RuntimeHarvest, SrpmConfig,
};
pub(crate) use crate::packagers::{
appimages_schema, deserialize_appimages, deserialize_install_scripts, deserialize_makeselfs,
install_scripts_schema, makeselfs_schema,
};
mod milestone;
pub use milestone::*;
mod upload;
pub use upload::*;
mod aur_source;
pub use aur_source::*;
mod mcp;
pub use mcp::*;
mod npm;
pub use npm::*;
mod gemfury;
pub use gemfury::*;
mod pypi;
pub use pypi::*;
mod homebrew_core;
pub use homebrew_core::*;
mod discovery;
pub use discovery::*;
#[cfg(test)]
mod tests;