Skip to content

Commit ff8a6f0

Browse files
authored
Merge pull request #174 from grafbase/brabier/zkntuzlvwvvk
Improve text-matrix command
2 parents 382281f + 3f65893 commit ff8a6f0

File tree

3 files changed

+173
-23
lines changed

3 files changed

+173
-23
lines changed

Cargo.lock

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

test-matrix/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ repository.workspace = true
99

1010
[dependencies]
1111
anyhow = "1.0.97"
12+
argh = "0.1.12"
1213
duct = "0.13.7"
1314
serde = { version = "1.0.219", features = ["derive"] }
1415
toml = "0.8.20"

test-matrix/src/main.rs

Lines changed: 133 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,158 @@
1+
use std::collections::HashSet;
12
use std::fs;
3+
use std::path::{Path, PathBuf};
4+
5+
use anyhow::{Context, Result};
6+
use argh::FromArgs;
27

38
mod cargo_toml;
49

5-
fn main() -> anyhow::Result<()> {
6-
let mut found_extensions = false;
7-
let mut test_arguments = vec!["nextest".to_string(), "run".to_string(), "--profile=ci".to_string()];
10+
#[derive(FromArgs)]
11+
/// Test matrix runner for Grafbase extensions
12+
struct Args {
13+
/// skip specific extensions by name (comma-delimited list)
14+
#[argh(option)]
15+
skip: Option<String>,
816

9-
for entry in fs::read_dir("./extensions")? {
10-
let Ok(entry) = entry else {
11-
continue;
12-
};
17+
/// run in verbose mode
18+
#[argh(switch, short = 'v')]
19+
verbose: bool,
20+
21+
/// number of test threads to use (passed to nextest)
22+
#[argh(option, short = 'j')]
23+
test_threads: Option<usize>,
24+
}
25+
26+
fn main() -> Result<()> {
27+
let args: Args = argh::from_env();
28+
let skip_extensions: HashSet<String> = args
29+
.skip
30+
.map(|s| s.split(',').map(|ext| ext.trim().to_string()).collect())
31+
.unwrap_or_default();
32+
33+
if args.verbose {
34+
eprintln!("Test matrix runner started");
35+
if !skip_extensions.is_empty() {
36+
eprintln!(
37+
"Skipping extensions: {}",
38+
skip_extensions.iter().cloned().collect::<Vec<_>>().join(", ")
39+
);
40+
}
41+
}
42+
43+
let extensions_dir = Path::new("./extensions");
44+
let extensions = discover_extensions(extensions_dir, &skip_extensions)?;
45+
46+
if extensions.is_empty() {
47+
println!("No extensions found to build and test.");
48+
return Ok(());
49+
}
1350

51+
println!("Found {} extension(s) to process", extensions.len());
52+
53+
for extension in &extensions {
54+
build_extension(extension, args.verbose)?;
55+
}
56+
57+
run_tests(&extensions, args.verbose, args.test_threads)?;
58+
59+
println!("\n✓ All done!");
60+
Ok(())
61+
}
62+
63+
struct Extension {
64+
name: String,
65+
path: PathBuf,
66+
}
67+
68+
fn discover_extensions(extensions_dir: &Path, skip_set: &HashSet<String>) -> Result<Vec<Extension>> {
69+
let mut extensions = Vec::new();
70+
71+
let entries = fs::read_dir(extensions_dir).with_context(|| {
72+
format!(
73+
"Failed to read extensions directory: {path}",
74+
path = extensions_dir.display()
75+
)
76+
})?;
77+
78+
for entry in entries {
79+
let entry = entry.context("Failed to read directory entry")?;
1480
let path = entry.path();
1581

1682
if !path.is_dir() {
1783
continue;
1884
}
1985

20-
let Ok(cargo_toml) = fs::read_to_string(path.join("Cargo.toml")) else {
86+
let cargo_toml_path = path.join("Cargo.toml");
87+
if !cargo_toml_path.exists() {
88+
continue;
89+
}
90+
91+
let cargo_toml_content = fs::read_to_string(&cargo_toml_path)
92+
.with_context(|| format!("Failed to read {path}", path = cargo_toml_path.display()))?;
93+
94+
let cargo_toml = cargo_toml::parse(&cargo_toml_content)
95+
.with_context(|| format!("Failed to parse {path}", path = cargo_toml_path.display()))?;
96+
97+
let name = cargo_toml.name().to_string();
98+
99+
if skip_set.contains(&name) {
100+
eprintln!(" Skipping extension: {name}");
21101
continue;
22-
};
102+
}
23103

24-
let cargo_toml = cargo_toml::parse(&cargo_toml)?;
104+
extensions.push(Extension { name, path });
105+
}
25106

26-
println!("\n** {} **", cargo_toml.name());
27-
duct::cmd("grafbase", ["extension", "build", "--scratch-dir", "../../target"])
28-
.dir(path)
29-
.run()
30-
.map_err(|e| anyhow::anyhow!("Failed to build extension (is grafbase in your path?): {}", e))?;
107+
Ok(extensions)
108+
}
31109

32-
test_arguments.push("-p".to_string());
33-
test_arguments.push(cargo_toml.name().to_string());
110+
fn build_extension(extension: &Extension, verbose: bool) -> Result<()> {
111+
println!("** Building {name} **", name = extension.name);
112+
113+
let mut cmd = duct::cmd("grafbase", ["extension", "build", "--scratch-dir", "../../target"]).dir(&extension.path);
34114

35-
found_extensions = true;
115+
if !verbose {
116+
cmd = cmd.stdout_null().stderr_null();
36117
}
37118

38-
if !found_extensions {
119+
cmd.run().with_context(|| {
120+
format!(
121+
"Failed to build extension {name} (is grafbase in your path?)",
122+
name = extension.name
123+
)
124+
})?;
125+
126+
Ok(())
127+
}
128+
129+
fn run_tests(extensions: &[Extension], verbose: bool, test_threads: Option<usize>) -> Result<()> {
130+
if extensions.is_empty() {
131+
println!("No extensions to test.");
39132
return Ok(());
40133
}
41134

42-
println!("\n** Running tests **");
43-
duct::cmd("cargo", &test_arguments)
44-
.env("PREBUILT_EXTENSION", "1")
45-
.run()?;
135+
println!("\n** Running tests for {} extension(s) **", extensions.len());
136+
137+
let mut test_arguments = vec!["nextest".to_string(), "run".to_string(), "--profile=ci".to_string()];
138+
139+
if let Some(threads) = test_threads {
140+
test_arguments.push("-j".to_string());
141+
test_arguments.push(threads.to_string());
142+
}
143+
144+
for extension in extensions {
145+
test_arguments.push("-p".to_string());
146+
test_arguments.push(extension.name.clone());
147+
}
148+
149+
let mut cmd = duct::cmd("cargo", &test_arguments).env("PREBUILT_EXTENSION", "1");
150+
151+
if !verbose {
152+
cmd = cmd.stdout_null();
153+
}
154+
155+
cmd.run().context("Failed to run tests")?;
46156

47157
Ok(())
48158
}

0 commit comments

Comments
 (0)