Skip to content

Commit 70628fb

Browse files
bfopsKasama
andauthored
cargo ci on windows (#3859)
# Description of Changes Make `cargo ci` work properly on Windows, in preparation for #3702. # API and ABI breaking changes No. CI-only. # Expected complexity level and risk 2. Not trivial, but not complicated. # Testing - [x] CI output seems to be genuinely running the tests, and it's passing on Windows - [x] Make a change to `crates/bindings-csharp` and see that `cargo ci test` fails - [x] I can manually run a minimal `cargo ci smoketests` invocation on a Windows machine --------- Signed-off-by: Zeke Foppa <196249+bfops@users.noreply.github.com> Co-authored-by: Kasama <robertoaall@gmail.com> Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
1 parent 13614d7 commit 70628fb

4 files changed

Lines changed: 127 additions & 77 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,9 @@ jobs:
111111
if: runner.os == 'Windows'
112112
- name: Install python deps
113113
run: python -m pip install -r smoketests/requirements.txt
114-
- name: Run smoketests (windows)
115-
# Note: clear_database and replication only work in private
116-
run: python -m smoketests ${{ matrix.smoketest_args }} -x clear_database replication teams
117-
if: runner.os == 'Windows'
118-
- name: Run smoketests (Linux)
114+
- name: Run smoketests
119115
# Note: clear_database and replication only work in private
120116
run: cargo ci smoketests -- ${{ matrix.smoketest_args }} -x clear_database replication teams
121-
if: runner.os != 'Windows'
122117
- name: Stop containers (Linux)
123118
if: always() && runner.os == 'Linux'
124119
run: docker compose -f .github/docker-compose.yml down

Cargo.lock

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

tools/ci/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ chrono = { workspace = true, features=["clock"] }
1010
clap.workspace = true
1111
regex.workspace = true
1212
duct.workspace = true
13+
tempfile.workspace = true
14+
env_logger.workspace = true

tools/ci/src/main.rs

Lines changed: 122 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use anyhow::{bail, Result};
22
use clap::{CommandFactory, Parser, Subcommand};
33
use duct::cmd;
4-
use std::collections::HashMap;
54
use std::path::Path;
65
use std::{env, fs};
76

@@ -93,15 +92,6 @@ enum CiCmd {
9392
},
9493
}
9594

96-
macro_rules! bash {
97-
($cmdline:expr) => {
98-
run_bash($cmdline, &Vec::new())
99-
};
100-
($cmdline:expr, $envs:expr) => {
101-
run_bash($cmdline, $envs)
102-
};
103-
}
104-
10595
fn run_all_clap_subcommands(skips: &[String]) -> Result<()> {
10696
let subcmds = Cli::command()
10797
.get_subcommands()
@@ -114,98 +104,164 @@ fn run_all_clap_subcommands(skips: &[String]) -> Result<()> {
114104
continue;
115105
}
116106
log::info!("executing cargo ci {subcmd}");
117-
bash!(&format!("cargo ci {subcmd}"))?;
107+
cmd!("cargo", "ci", &subcmd).run()?;
118108
}
119-
120109
Ok(())
121110
}
122111

123-
fn run_bash(cmdline: &str, additional_env: &[(&str, &str)]) -> Result<()> {
124-
let mut env = env::vars().collect::<HashMap<_, _>>();
125-
env.extend(additional_env.iter().map(|(k, v)| (k.to_string(), v.to_string())));
126-
log::debug!("$ {cmdline}");
127-
let status = cmd!("bash", "-lc", cmdline).full_env(env).run()?;
128-
if !status.status.success() {
129-
let e = anyhow::anyhow!("command failed: {cmdline}");
130-
log::error!("{e}");
131-
return Err(e);
112+
fn infer_python() -> String {
113+
let py3_available = cmd!("python3", "--version").run().is_ok();
114+
if py3_available {
115+
"python3".to_string()
116+
} else {
117+
"python".to_string()
132118
}
133-
Ok(())
134119
}
135120

136121
fn main() -> Result<()> {
122+
env_logger::init();
123+
137124
let cli = Cli::parse();
138125

139126
match cli.cmd {
140127
Some(CiCmd::Test) => {
141-
bash!("cargo test --all -- --skip unreal")?;
128+
// TODO: This doesn't work on at least user Linux machines, because something here apparently uses `sudo`?
129+
130+
cmd!("cargo", "test", "--all", "--", "--skip", "unreal").run()?;
131+
// TODO: This should check for a diff at the start. If there is one, we should alert the user
132+
// that we're disabling diff checks because they have a dirty git repo, and to re-run in a clean one
133+
// if they want those checks.
134+
142135
// The fallocate tests have been flakely when running in parallel
143-
bash!("cargo test -p spacetimedb-durability --features fallocate -- --test-threads=1")?;
144-
bash!("bash tools/check-diff.sh")?;
145-
bash!("cargo run -p spacetimedb-codegen --example regen-csharp-moduledef && bash tools/check-diff.sh crates/bindings-csharp")?;
146-
bash!("(cd crates/bindings-csharp && dotnet test -warnaserror)")?;
136+
cmd!(
137+
"cargo",
138+
"test",
139+
"-p",
140+
"spacetimedb-durability",
141+
"--features",
142+
"fallocate",
143+
"--",
144+
"--test-threads=1",
145+
)
146+
.run()?;
147+
cmd!("bash", "tools/check-diff.sh").run()?;
148+
cmd!(
149+
"cargo",
150+
"run",
151+
"-p",
152+
"spacetimedb-codegen",
153+
"--example",
154+
"regen-csharp-moduledef",
155+
)
156+
.run()?;
157+
cmd!("bash", "tools/check-diff.sh", "crates/bindings-csharp").run()?;
158+
cmd!("dotnet", "test", "-warnaserror")
159+
.dir("crates/bindings-csharp")
160+
.run()?;
147161
}
148162

149163
Some(CiCmd::Lint) => {
150-
bash!("cargo fmt --all -- --check")?;
151-
bash!("cargo clippy --all --tests --benches -- -D warnings")?;
152-
bash!("(cd crates/bindings-csharp && dotnet tool restore && dotnet csharpier --check .)")?;
164+
cmd!("cargo", "fmt", "--all", "--", "--check").run()?;
165+
cmd!(
166+
"cargo",
167+
"clippy",
168+
"--all",
169+
"--tests",
170+
"--benches",
171+
"--",
172+
"-D",
173+
"warnings",
174+
)
175+
.run()?;
176+
cmd!("dotnet", "tool", "restore").dir("crates/bindings-csharp").run()?;
177+
cmd!("dotnet", "csharpier", "--check", ".")
178+
.dir("crates/bindings-csharp")
179+
.run()?;
153180
// `bindings` is the only crate we care strongly about documenting,
154181
// since we link to its docs.rs from our website.
155182
// We won't pass `--no-deps`, though,
156183
// since we want everything reachable through it to also work.
157184
// This includes `sats` and `lib`.
158-
bash!(
159-
"cd crates/bindings && cargo doc",
185+
cmd!("cargo", "doc")
186+
.dir("crates/bindings")
160187
// Make `cargo doc` exit with error on warnings, most notably broken links
161-
&[("RUSTDOCFLAGS", "--deny warnings")]
162-
)?;
188+
.env("RUSTDOCFLAGS", "--deny warnings")
189+
.run()?;
163190
}
164191

165192
Some(CiCmd::WasmBindings) => {
166-
bash!("cargo test -p spacetimedb-codegen")?;
193+
cmd!("cargo", "test", "-p", "spacetimedb-codegen").run()?;
167194
// Make sure the `Cargo.lock` file reflects the latest available versions.
168195
// This is what users would end up with on a fresh module, so we want to
169196
// catch any compile errors arising from a different transitive closure
170197
// of dependencies than what is in the workspace lock file.
171198
//
172199
// For context see also: https://github.com/clockworklabs/SpacetimeDB/pull/2714
173-
bash!("cargo update")?;
174-
bash!("cargo run -p spacetimedb-cli -- build --project-path modules/module-test")?;
200+
cmd!("cargo", "update").run()?;
201+
cmd!(
202+
"cargo",
203+
"run",
204+
"-p",
205+
"spacetimedb-cli",
206+
"--",
207+
"build",
208+
"--project-path",
209+
"modules/module-test",
210+
)
211+
.run()?;
175212
}
176213

177-
Some(CiCmd::Smoketests { args }) => {
178-
// On some systems, there is no `python`, but there is `python3`.
179-
let py3_available = bash!("command -v python3 >/dev/null 2>&1").is_ok();
180-
let python = if py3_available { "python3" } else { "python" };
181-
bash!(&format!("{python} -m smoketests {}", args.join(" ")))?;
214+
Some(CiCmd::Smoketests { args: smoketest_args }) => {
215+
let python = infer_python();
216+
cmd(
217+
python,
218+
["-m", "smoketests"]
219+
.into_iter()
220+
.map(|s| s.to_string())
221+
.chain(smoketest_args),
222+
)
223+
.run()?;
182224
}
183225

184226
Some(CiCmd::UpdateFlow {
185227
target,
186228
github_token_auth,
187229
}) => {
188-
let target = target.map(|t| format!("--target {t}")).unwrap_or_default();
189-
let github_token_auth_flag = if github_token_auth {
190-
"--features github-token-auth "
230+
let mut common_args = vec![];
231+
if let Some(target) = target.as_ref() {
232+
common_args.push("--target");
233+
common_args.push(target);
234+
log::info!("checking update flow for target: {target}");
191235
} else {
192-
""
193-
};
236+
log::info!("checking update flow");
237+
}
238+
if github_token_auth {
239+
common_args.push("--features");
240+
common_args.push("github-token-auth");
241+
}
194242

195-
bash!(&format!("echo 'checking update flow for target: {target}'"))?;
196-
bash!(&format!(
197-
"cargo build {github_token_auth_flag}{target} -p spacetimedb-update"
198-
))?;
243+
cmd(
244+
"cargo",
245+
["build", "-p", "spacetimedb-update"]
246+
.into_iter()
247+
.chain(common_args.clone()),
248+
)
249+
.run()?;
199250
// NOTE(bfops): We need the `github-token-auth` feature because we otherwise tend to get ratelimited when we try to fetch `/releases/latest`.
200251
// My best guess is that, on the GitHub runners, the "anonymous" ratelimit is shared by *all* users of that runner (I think this because it
201252
// happens very frequently on the `macos-runner`, but we haven't seen it on any others).
202-
bash!(&format!(
203-
r#"
204-
ROOT_DIR="$(mktemp -d)"
205-
cargo run {github_token_auth_flag}{target} -p spacetimedb-update -- self-install --root-dir="${{ROOT_DIR}}" --yes
206-
"${{ROOT_DIR}}"/spacetime --root-dir="${{ROOT_DIR}}" help
207-
"#
208-
))?;
253+
let root_dir = tempfile::tempdir()?;
254+
let root_dir_string = root_dir.path().to_string_lossy().to_string();
255+
let root_arg = format!("--root-dir={}", root_dir_string);
256+
cmd(
257+
"cargo",
258+
["run", "-p", "spacetimedb-update"]
259+
.into_iter()
260+
.chain(common_args.clone())
261+
.chain(["--", "self-install", &root_arg, "--yes"].into_iter()),
262+
)
263+
.run()?;
264+
cmd!(format!("{}/spacetime", root_dir_string), &root_arg, "help",).run()?;
209265
}
210266

211267
Some(CiCmd::CliDocs { spacetime_path }) => {
@@ -220,19 +276,14 @@ cargo run {github_token_auth_flag}{target} -p spacetimedb-update -- self-install
220276
);
221277
}
222278

223-
bash!("cd docs && pnpm generate-cli-docs")?;
224-
bash!(
225-
r#"
226-
if [ -z "$(git status --porcelain)" ]; then
227-
echo "No docs changes detected"
228-
else
229-
echo "It looks like the CLI docs have changed:"
230-
exit 1
231-
fi
232-
"#
233-
)?;
234-
bash!("git status")?;
235-
bash!("git diff")?;
279+
cmd!("pnpm", "install", "--recursive").run()?;
280+
cmd!("pnpm", "generate-cli-docs").dir("docs").run()?;
281+
let out = cmd!("git", "status", "--porcelain", "--", "docs").read()?;
282+
if out.is_empty() {
283+
log::info!("No docs changes detected");
284+
} else {
285+
anyhow::bail!("CLI docs are out of date:\n{out}");
286+
}
236287
}
237288

238289
Some(CiCmd::SelfDocs { check }) => {

0 commit comments

Comments
 (0)