Skip to content

Commit b5f445b

Browse files
authored
Merge pull request #13 from zhuravel/exclude_glob_option
Add exclude glob option
2 parents e362c36 + 106c381 commit b5f445b

File tree

3 files changed

+124
-3
lines changed

3 files changed

+124
-3
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,20 @@ You'll get:
5555

5656
Please be sure to increment `--node-index` arg.
5757

58+
You can exclude specific test files from being split using the `--tests-exclude-glob` option:
59+
60+
```
61+
$ split-test --junit-xml-report-dir report --node-index 0 --node-total 2 --tests-glob 'spec/**/*_spec.rb' --tests-exclude-glob 'spec/system/**/*_spec.rb'
62+
```
63+
64+
This will include all files matching `spec/**/*_spec.rb` but exclude any files matching `spec/system/**/*_spec.rb`. This is useful when you want to run system specs separately from unit tests, as system specs typically take longer and may require different setup.
65+
66+
You can also specify multiple exclude patterns by using the `--tests-exclude-glob` option multiple times:
67+
68+
```
69+
$ split-test --junit-xml-report-dir report --node-index 0 --node-total 2 --tests-glob 'spec/**/*_spec.rb' --tests-exclude-glob 'spec/system/**/*_spec.rb' --tests-exclude-glob 'spec/integration/**/*_spec.rb'
70+
```
71+
5872
You can use `--debug` option to make sure how it's grouped:
5973

6074
```

src/main.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ struct Opt {
2121
#[structopt(long, required = true)]
2222
tests_glob: Vec<String>,
2323
#[structopt(long)]
24+
tests_exclude_glob: Vec<String>,
25+
#[structopt(long)]
2426
node_index: usize,
2527
#[structopt(long)]
2628
node_total: usize,
@@ -63,7 +65,7 @@ impl<'a> Node<'a> {
6365
}
6466
}
6567

66-
fn expand_globs(patterns: &Vec<String>) -> Result<Vec<PathBuf>> {
68+
fn expand_globs(patterns: &Vec<String>, exclude_patterns: &Vec<String>) -> Result<Vec<PathBuf>> {
6769
let mut files = HashSet::new();
6870

6971
for pattern in patterns {
@@ -72,6 +74,16 @@ fn expand_globs(patterns: &Vec<String>) -> Result<Vec<PathBuf>> {
7274
}
7375
}
7476

77+
if !exclude_patterns.is_empty() {
78+
let mut exclude_files = HashSet::new();
79+
for exclude_pattern in exclude_patterns {
80+
for path in glob(&exclude_pattern)? {
81+
exclude_files.insert(canonicalize(path?)?);
82+
}
83+
}
84+
files = files.difference(&exclude_files).cloned().collect();
85+
}
86+
7587
let mut files = files.into_iter().collect::<Vec<_>>();
7688
files.sort();
7789

@@ -87,7 +99,7 @@ fn get_test_file_results(junit_xml_report_dir: &PathBuf) -> Result<HashMap<PathB
8799

88100
let mut test_file_results = HashMap::new();
89101

90-
for xml_path in expand_globs(&vec![String::from(xml_glob)])? {
102+
for xml_path in expand_globs(&vec![String::from(xml_glob)], &vec![])? {
91103
let reader = BufReader::new(File::open(&xml_path)?);
92104
let test_result_xml: TestResultXml = from_reader(reader).unwrap_or_else(|err| {
93105
warn!("Failed to parse XML file {:?}: {}", xml_path, err);
@@ -146,7 +158,7 @@ fn main() -> Result<()> {
146158

147159
let test_file_results = get_test_file_results(&args.junit_xml_report_dir)?;
148160

149-
let test_files = expand_globs(&args.tests_glob)?;
161+
let test_files = expand_globs(&args.tests_glob, &args.tests_exclude_glob)?;
150162
if test_files.len() == 0 {
151163
bail!("Test file is not found. pattern: {:?}", args.tests_glob);
152164
}

tests/integration_test.rs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,3 +240,98 @@ fn test_invalid_report() -> Result<(), Box<dyn std::error::Error>> {
240240

241241
Ok(())
242242
}
243+
244+
#[test]
245+
fn test_exclude_glob() -> Result<(), Box<dyn std::error::Error>> {
246+
let mut cmd = Command::cargo_bin("split-test")?;
247+
248+
// Test excluding specific files - should include a_test.rb and c_test.rb, exclude b_test.rb
249+
cmd.current_dir("tests/fixtures/minitest")
250+
.arg("--junit-xml-report-dir")
251+
.arg("report")
252+
.arg("--node-index")
253+
.arg("0")
254+
.arg("--node-total")
255+
.arg("1")
256+
.arg("--tests-glob")
257+
.arg("*_test.rb")
258+
.arg("--tests-exclude-glob")
259+
.arg("b_test.rb");
260+
261+
cmd.assert()
262+
.success()
263+
.stdout(predicate::str::contains("a_test.rb"))
264+
.stdout(predicate::str::contains("b_test.rb").not())
265+
.stdout(predicate::str::contains("c_test.rb"))
266+
.stderr(predicate::str::is_empty());
267+
268+
// Test excluding with wildcard - exclude all files starting with 'a'
269+
cmd = Command::cargo_bin("split-test")?;
270+
271+
cmd.current_dir("tests/fixtures/minitest")
272+
.arg("--junit-xml-report-dir")
273+
.arg("report")
274+
.arg("--node-index")
275+
.arg("0")
276+
.arg("--node-total")
277+
.arg("1")
278+
.arg("--tests-glob")
279+
.arg("*_test.rb")
280+
.arg("--tests-exclude-glob")
281+
.arg("a*_test.rb");
282+
283+
cmd.assert()
284+
.success()
285+
.stdout(predicate::str::contains("a_test.rb").not())
286+
.stdout(predicate::str::contains("b_test.rb"))
287+
.stdout(predicate::str::contains("c_test.rb"))
288+
.stderr(predicate::str::is_empty());
289+
290+
// Test with split across nodes and exclude
291+
cmd = Command::cargo_bin("split-test")?;
292+
293+
cmd.current_dir("tests/fixtures/minitest")
294+
.arg("--junit-xml-report-dir")
295+
.arg("report")
296+
.arg("--node-index")
297+
.arg("0")
298+
.arg("--node-total")
299+
.arg("2")
300+
.arg("--tests-glob")
301+
.arg("*_test.rb")
302+
.arg("--tests-exclude-glob")
303+
.arg("c_test.rb");
304+
305+
cmd.assert()
306+
.success()
307+
.stdout(predicate::str::contains("a_test.rb"))
308+
.stdout(predicate::str::contains("b_test.rb").not())
309+
.stdout(predicate::str::contains("c_test.rb").not())
310+
.stderr(predicate::str::is_empty());
311+
312+
// Test with multiple exclude patterns - exclude both a_test.rb and c_test.rb
313+
cmd = Command::cargo_bin("split-test")?;
314+
315+
cmd.current_dir("tests/fixtures/minitest")
316+
.arg("--junit-xml-report-dir")
317+
.arg("report")
318+
.arg("--node-index")
319+
.arg("0")
320+
.arg("--node-total")
321+
.arg("1")
322+
.arg("--tests-glob")
323+
.arg("*_test.rb")
324+
.arg("--tests-exclude-glob")
325+
.arg("a_test.rb")
326+
.arg("--tests-exclude-glob")
327+
.arg("c_test.rb");
328+
329+
cmd.assert()
330+
.success()
331+
.stdout(predicate::str::contains("a_test.rb").not())
332+
.stdout(predicate::str::contains("b_test.rb"))
333+
.stdout(predicate::str::contains("c_test.rb").not())
334+
.stderr(predicate::str::is_empty());
335+
336+
Ok(())
337+
}

0 commit comments

Comments
 (0)