use super::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum RollbackMode {
None,
#[default]
BestEffort,
}
pub(super) const NON_PUBLISHER_RELEASE_SKIPS: &[&str] = &[
"publish",
"sign",
"validate",
"sbom",
"attest",
"snapcraft",
"nfpm",
"makeself",
"install-script",
"appimage",
"flatpak",
"srpm",
"before",
"before-publish",
"notarize",
"archive",
"source",
"build",
"changelog",
"release",
"checksum",
"upx",
"templatefiles",
"dmg",
"msi",
"nsis",
"pkg",
"appbundle",
"verify-release",
];
pub static VALID_RELEASE_SKIPS: LazyLock<Vec<&'static str>> = LazyLock::new(|| {
NON_PUBLISHER_RELEASE_SKIPS
.iter()
.copied()
.chain(PublisherKind::iter().map(PublisherKind::token))
.collect()
});
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub struct ReleaseToken {
pub token: &'static str,
pub is_publisher: bool,
pub is_publish_stage: bool,
}
pub fn release_skip_vocabulary() -> Vec<ReleaseToken> {
NON_PUBLISHER_RELEASE_SKIPS
.iter()
.map(|&token| ReleaseToken {
token,
is_publisher: false,
is_publish_stage: false,
})
.chain(PublisherKind::iter().map(|k| ReleaseToken {
token: k.token(),
is_publisher: true,
is_publish_stage: k.is_publish_stage(),
}))
.collect()
}
pub const VALID_BUILD_SKIPS: &[&str] = &["pre-hooks", "post-hooks", "validate", "before"];
pub fn validate_skip_values(skip: &[String], valid: &[&str]) -> Result<(), String> {
let invalid: Vec<&str> = dedup_preserving_order(
skip.iter()
.map(|s| s.as_str())
.filter(|s| !valid.contains(s)),
);
if invalid.is_empty() {
Ok(())
} else {
Err(format!(
"invalid --skip value(s): {}. Valid options: {}",
invalid.join(", "),
dedup_preserving_order(valid.iter().copied()).join(", "),
))
}
}
fn dedup_preserving_order<'a>(items: impl Iterator<Item = &'a str>) -> Vec<&'a str> {
let mut seen = std::collections::HashSet::new();
items.filter(|s| seen.insert(*s)).collect()
}
impl Context {
pub fn should_skip(&self, stage_name: &str) -> bool {
self.options.skip_stages.iter().any(|s| s == stage_name)
}
pub fn publisher_deselected(&self, name: &str) -> bool {
self.should_skip(name)
|| (!self.options.publisher_allowlist.is_empty()
&& !self.options.publisher_allowlist.iter().any(|s| s == name))
}
pub fn any_publisher_selected(&self, names: &[&str]) -> bool {
names.iter().any(|n| !self.publisher_deselected(n))
}
pub fn deselected_reason(&self, name: &str) -> String {
let reason = if self.should_skip(name) {
"excluded via --skip"
} else {
"not in --publishers allowlist"
};
format!("skipped {name} — {reason}")
}
pub fn skip_validate(&self) -> bool {
self.should_skip("validate")
}
}