#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Mutates {
Nothing,
Forge,
}
#[derive(Debug)]
pub struct StepSpec {
pub name: &'static str,
pub chapter: &'static str,
pub mutates: Mutates,
pub proves: &'static str,
pub destructive: bool,
pub optional: bool,
pub prereqs: &'static [&'static str],
}
pub const STEPS: [StepSpec; 10] = [
StepSpec {
name: "package-check",
chapter: "§0",
mutates: Mutates::Nothing,
proves: "the package is publishable with no credentials",
destructive: false,
optional: false,
prereqs: &[],
},
StepSpec {
name: "default-branch",
chapter: "§1",
mutates: Mutates::Forge,
proves: "the trunk is the default branch",
destructive: false,
optional: false,
prereqs: &[],
},
StepSpec {
name: "single-trunk",
chapter: "§1",
mutates: Mutates::Forge,
proves: "no long-lived branch besides the trunk remains",
destructive: true,
optional: false,
prereqs: &["default-branch"],
},
StepSpec {
name: "ci-permissions",
chapter: "§2",
mutates: Mutates::Forge,
proves: "CI may write and open requests",
destructive: false,
optional: false,
prereqs: &[],
},
StepSpec {
name: "install-bot",
chapter: "§2",
mutates: Mutates::Forge,
proves: "the bot identity can act on this project",
destructive: false,
optional: false,
prereqs: &[],
},
StepSpec {
name: "bot-secrets",
chapter: "§2",
mutates: Mutates::Forge,
proves: "the bot credentials are stored on the project",
destructive: false,
optional: false,
prereqs: &[],
},
StepSpec {
name: "protect-trunk",
chapter: "§3",
mutates: Mutates::Forge,
proves: "the trunk takes no direct push, merges only by squash, and requires the named check",
destructive: false,
optional: false,
prereqs: &["default-branch"],
},
StepSpec {
name: "protect-tags",
chapter: "§3",
mutates: Mutates::Forge,
proves: "v* is protected as far as the forge allows",
destructive: false,
optional: false,
prereqs: &[],
},
StepSpec {
name: "protect-release-lines",
chapter: "§3",
mutates: Mutates::Forge,
proves: "release/* cannot be force-pushed or deleted",
destructive: false,
optional: true,
prereqs: &[],
},
StepSpec {
name: "protections-check",
chapter: "§3",
mutates: Mutates::Nothing,
proves: "exactly the owned protections, with those rules",
destructive: false,
optional: false,
prereqs: &[],
},
];
#[must_use]
pub fn spec(name: &str) -> Option<&'static StepSpec> {
STEPS.iter().find(|step| step.name == name)
}
#[cfg(test)]
mod tests {
use super::{STEPS, spec};
#[test]
fn every_prereq_is_an_earlier_step() {
for (idx, step) in STEPS.iter().enumerate() {
for prereq in step.prereqs {
let position = STEPS
.iter()
.position(|other| other.name == *prereq)
.unwrap_or(usize::MAX);
assert!(
position < idx,
"{}: prereq {prereq} is not an earlier step",
step.name
);
}
}
assert!(spec("package-check").is_some());
assert!(spec("no-such-step").is_none());
}
}