Skip to content

Commit 2c7d192

Browse files
committed
Add an xtask to help with running tests
During development I often need to run a bunch of tests. Instead of having some unwieldy shell command, I have added this xtask to help with running the testing commands.
1 parent b4c53b9 commit 2c7d192

File tree

6 files changed

+162
-6
lines changed

6 files changed

+162
-6
lines changed

.cargo/config.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[alias]
2+
xtask = "run --manifest-path=crates/xtask/Cargo.toml --"

CONTRIBUTING.md

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,21 @@ The main test harness is described in the [testsuite documentation](tests/testsu
134134
- `cargo clippy --workspace --all-targets --no-deps -- -D warnings` — This makes sure that there are no clippy warnings.
135135
- `RUSTDOCFLAGS="-D warnings" cargo doc --workspace --document-private-items --no-deps` — This verifies that there aren't any rustdoc warnings.
136136
- `cargo fmt --check` — Verifies that everything is formatted correctly.
137+
- `cargo +stable semver-checks` — Verifies that no SemVer breaking changes have been made. You must install [`cargo-semver-checks`](https://crates.io/crates/cargo-semver-checks) first.
138+
139+
To help simplify running all these commands, you can run the following cargo command:
140+
141+
```sh
142+
cargo xtask test-all
143+
```
144+
145+
It is useful to run all tests before submitting a PR. While developing I recommend to run some subset of that command based on what you are working on. There are individual arguments for each one. For example:
146+
147+
```sh
148+
cargo xtask test-workspace clippy doc eslint fmt gui semver-checks
149+
```
150+
151+
While developing, remove any of those arguments that are not relevant to what you are changing, or are really slow.
137152

138153
## Making a pull-request
139154

@@ -208,12 +223,9 @@ Instructions for mdBook maintainers to publish a new release:
208223

209224
1. Create a PR to update the version and update the CHANGELOG:
210225
1. Update the version in `Cargo.toml`
211-
2. Run `cargo test` to verify that everything is passing, and to update `Cargo.lock`.
212-
3. Double-check for any SemVer breaking changes.
213-
Try [`cargo-semver-checks`](https://crates.io/crates/cargo-semver-checks), though beware that the current version of mdBook isn't properly adhering to SemVer due to the lack of `#[non_exhaustive]` and other issues. See https://github.com/rust-lang/mdBook/issues/1835.
214-
4. Update `CHANGELOG.md` with any changes that users may be interested in.
215-
5. Update `continuous-integration.md` to update the version number for the installation instructions.
216-
6. Commit the changes, and open a PR.
226+
2. Run `cargo xtask test-all` to verify that everything is passing, and to update `Cargo.lock`.
227+
3. Update `CHANGELOG.md` with any changes that users may be interested in.
228+
4. Commit the changes, and open a PR.
217229
2. After the PR has been merged, create a release in GitHub. This can either be done in the GitHub web UI, or on the command-line:
218230
```bash
219231
MDBOOK_VERS="`cargo read-manifest | jq -r .version`" ; \

Cargo.lock

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/xtask/Cargo.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "xtask"
3+
publish = false
4+
edition.workspace = true
5+
license.workspace = true
6+
repository.workspace = true
7+
rust-version.workspace = true
8+
9+
[dependencies]
10+
11+
[lints]
12+
workspace = true

crates/xtask/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# xtask
2+
3+
This is a CLI utility for running development commands for mdbook.
4+
See [CONTRIBUTING.md](../../CONTRIBUTING.md) for how to use this.

crates/xtask/src/main.rs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
//! Helper for local development.
2+
3+
use std::collections::BTreeMap;
4+
use std::error::Error;
5+
use std::process::Command;
6+
use std::process::exit;
7+
8+
type Result<T> = std::result::Result<T, Box<dyn Error>>;
9+
10+
fn main() -> Result<()> {
11+
macro_rules! commands {
12+
($($name:literal => $func:ident),* $(,)?) => {
13+
[$(($name, $func as fn() -> Result<()>)),*]
14+
};
15+
}
16+
17+
let cmds: BTreeMap<&'static str, fn() -> Result<()>> = commands! {
18+
"test-all" => test_all,
19+
"test-workspace" => test_workspace,
20+
"clippy" => clippy,
21+
"doc" => doc,
22+
"fmt" => fmt,
23+
"semver-checks" => semver_checks,
24+
"eslint" => eslint,
25+
"gui" => gui,
26+
}
27+
.into_iter()
28+
.collect();
29+
let keys = cmds.keys().copied().collect::<Vec<_>>().join(", ");
30+
let mut args = std::env::args().skip(1).peekable();
31+
if args.peek().is_none() {
32+
eprintln!("error: specify a command (valid options: {keys})");
33+
exit(1);
34+
}
35+
for arg in args {
36+
if let Some(cmd_fn) = cmds.get(arg.as_str()) {
37+
cmd_fn()?;
38+
} else if matches!(arg.as_str(), "-h" | "--help") {
39+
println!("valid options: {keys}");
40+
exit(0)
41+
} else {
42+
eprintln!("error: unknown command `{arg}` (valid options: {keys}");
43+
exit(1);
44+
}
45+
}
46+
println!("all tests passed!");
47+
Ok(())
48+
}
49+
50+
fn test_all() -> Result<()> {
51+
test_workspace()?;
52+
clippy()?;
53+
doc()?;
54+
fmt()?;
55+
semver_checks()?;
56+
eslint()?;
57+
gui()?;
58+
Ok(())
59+
}
60+
61+
fn cargo(args: &str, cb: &dyn Fn(&mut Command)) -> Result<()> {
62+
println!("Running `cargo {args}`");
63+
let mut cmd = Command::new("cargo");
64+
cmd.args(args.split_whitespace());
65+
cb(&mut cmd);
66+
let status = cmd.status().expect("cargo should be installed");
67+
if !status.success() {
68+
return Err("command `cargo {args}` failed".into());
69+
}
70+
Ok(())
71+
}
72+
73+
fn test_workspace() -> Result<()> {
74+
cargo("test --workspace", &|_| {})?;
75+
cargo("test --workspace --no-default-features", &|_| {})?;
76+
Ok(())
77+
}
78+
79+
fn clippy() -> Result<()> {
80+
cargo(
81+
"clippy --workspace --all-targets --no-deps -- -D warnings",
82+
&|_| {},
83+
)?;
84+
Ok(())
85+
}
86+
87+
fn doc() -> Result<()> {
88+
cargo(
89+
"doc --workspace --document-private-items --no-deps",
90+
&|cmd| {
91+
cmd.env("RUSTDOCFLAGS", "-D warnings");
92+
},
93+
)?;
94+
Ok(())
95+
}
96+
97+
fn fmt() -> Result<()> {
98+
cargo("fmt --check", &|_| {})?;
99+
Ok(())
100+
}
101+
102+
fn semver_checks() -> Result<()> {
103+
cargo("+stable semver-checks --workspace", &|_| {})?;
104+
Ok(())
105+
}
106+
107+
fn gui() -> Result<()> {
108+
cargo("test --test gui", &|_| {})?;
109+
Ok(())
110+
}
111+
112+
fn eslint() -> Result<()> {
113+
println!("Running `npm run lint`");
114+
let status = Command::new("npm")
115+
.args(["run", "lint"])
116+
.status()
117+
.expect("npm should be installed");
118+
if !status.success() {
119+
return Err("eslint failed".into());
120+
}
121+
Ok(())
122+
}

0 commit comments

Comments
 (0)