mdbook/crates/xtask/src/main.rs
Eric Huss 2a93606727 Add a script to help update the changelog
This adds `cargo xtask changelog` to automatically add a new changelog
entry for a release.
2025-09-28 09:13:16 -07:00

125 lines
3 KiB
Rust

//! Helper for local development.
use std::collections::BTreeMap;
use std::error::Error;
use std::process::Command;
use std::process::exit;
mod changelog;
type Result<T> = std::result::Result<T, Box<dyn Error>>;
fn main() -> Result<()> {
macro_rules! commands {
($($name:literal => $func:expr),* $(,)?) => {
[$(($name, $func as fn() -> Result<()>)),*]
};
}
let cmds: BTreeMap<&'static str, fn() -> Result<()>> = commands! {
"test-all" => test_all,
"test-workspace" => test_workspace,
"clippy" => clippy,
"doc" => doc,
"fmt" => fmt,
"semver-checks" => semver_checks,
"eslint" => eslint,
"gui" => gui,
"changelog" => changelog::changelog,
}
.into_iter()
.collect();
let keys = cmds.keys().copied().collect::<Vec<_>>().join(", ");
let mut args = std::env::args().skip(1).peekable();
if args.peek().is_none() {
eprintln!("error: specify a command (valid options: {keys})");
exit(1);
}
for arg in args {
if let Some(cmd_fn) = cmds.get(arg.as_str()) {
cmd_fn()?;
} else if matches!(arg.as_str(), "-h" | "--help") {
println!("valid options: {keys}");
exit(0)
} else {
eprintln!("error: unknown command `{arg}` (valid options: {keys}");
exit(1);
}
}
println!("all tests passed!");
Ok(())
}
fn test_all() -> Result<()> {
test_workspace()?;
clippy()?;
doc()?;
fmt()?;
semver_checks()?;
eslint()?;
gui()?;
Ok(())
}
fn cargo(args: &str, cb: &dyn Fn(&mut Command)) -> Result<()> {
println!("Running `cargo {args}`");
let mut cmd = Command::new("cargo");
cmd.args(args.split_whitespace());
cb(&mut cmd);
let status = cmd.status().expect("cargo should be installed");
if !status.success() {
return Err("command `cargo {args}` failed".into());
}
Ok(())
}
fn test_workspace() -> Result<()> {
cargo("test --workspace", &|_| {})?;
cargo("test --workspace --no-default-features", &|_| {})?;
Ok(())
}
fn clippy() -> Result<()> {
cargo(
"clippy --workspace --all-targets --no-deps -- -D warnings",
&|_| {},
)?;
Ok(())
}
fn doc() -> Result<()> {
cargo(
"doc --workspace --document-private-items --no-deps",
&|cmd| {
cmd.env("RUSTDOCFLAGS", "-D warnings");
},
)?;
Ok(())
}
fn fmt() -> Result<()> {
cargo("fmt --check", &|_| {})?;
Ok(())
}
fn semver_checks() -> Result<()> {
cargo("+stable semver-checks --workspace", &|_| {})?;
Ok(())
}
fn gui() -> Result<()> {
cargo("test --test gui", &|_| {})?;
Ok(())
}
fn eslint() -> Result<()> {
println!("Running `npm run lint`");
let status = Command::new("npm")
.args(["run", "lint"])
.status()
.expect("npm should be installed");
if !status.success() {
return Err("eslint failed".into());
}
Ok(())
}