Skip to content

Commit beac5e0

Browse files
committed
feat: adds validation and linting
1 parent f24bee7 commit beac5e0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+2209
-348
lines changed

Cargo.lock

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

Gauntlet.toml

Lines changed: 75 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,101 @@
11
version = "v1"
22

3+
[[repositories]]
4+
organization = "stjudecloud"
5+
name = "workflows"
6+
37
[[repositories]]
48
organization = "PacificBiosciences"
59
name = "HiFi-human-WGS-WDL"
610

711
[[repositories]]
8-
organization = "biowdl"
9-
name = "tasks"
12+
organization = "chanzuckerberg"
13+
name = "czid-workflows"
1014

1115
[[repositories]]
12-
organization = "stjudecloud"
13-
name = "workflows"
16+
organization = "biowdl"
17+
name = "tasks"
1418

15-
[[repositories]]
16-
organization = "chanzuckerberg"
17-
name = "czid-workflows"
19+
[[ignored_errors]]
20+
document = "biowdl/tasks:bcftools.wdl"
21+
error = '''validation error: [v1::001] invalid escape character '\_' in string at line 114:75'''
1822

1923
[[ignored_errors]]
2024
document = "biowdl/tasks:bedtools.wdl"
21-
error = """
22-
--> 29:67
23-
|
24-
29 | String memory = \"~{512 + ceil(size([inputBed, faidx], \"MiB\"))}MiB\"
25-
| ^---
26-
|
27-
= expected WHITESPACE or OPTION"""
25+
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 27:48'''
2826

2927
[[ignored_errors]]
3028
document = "biowdl/tasks:bowtie.wdl"
31-
error = """
32-
--> 40:58
33-
|
34-
40 | String memory = \"~{5 + ceil(size(indexFiles, \"GiB\"))}GiB\"
35-
| ^---
36-
|
37-
= expected WHITESPACE or OPTION"""
29+
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 63:32'''
30+
31+
[[ignored_errors]]
32+
document = "biowdl/tasks:centrifuge.wdl"
33+
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 122:57'''
34+
35+
[[ignored_errors]]
36+
document = "biowdl/tasks:common.wdl"
37+
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 275:45'''
38+
39+
[[ignored_errors]]
40+
document = "biowdl/tasks:fastqc.wdl"
41+
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 59:42'''
42+
43+
[[ignored_errors]]
44+
document = "biowdl/tasks:gatk.wdl"
45+
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 127:57'''
46+
47+
[[ignored_errors]]
48+
document = "biowdl/tasks:hisat2.wdl"
49+
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 60:34'''
50+
51+
[[ignored_errors]]
52+
document = "biowdl/tasks:multiqc.wdl"
53+
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 133:45'''
54+
55+
[[ignored_errors]]
56+
document = "biowdl/tasks:picard.wdl"
57+
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 643:51'''
58+
59+
[[ignored_errors]]
60+
document = "biowdl/tasks:sambamba.wdl"
61+
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 91:44'''
62+
63+
[[ignored_errors]]
64+
document = "biowdl/tasks:samtools.wdl"
65+
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 80:42'''
66+
67+
[[ignored_errors]]
68+
document = "biowdl/tasks:umi-tools.wdl"
69+
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 95:49'''
70+
71+
[[ignored_errors]]
72+
document = "biowdl/tasks:umi.wdl"
73+
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 39:60'''
3874

3975
[[ignored_errors]]
4076
document = "stjudecloud/workflows:template/task-templates.wdl"
4177
error = """
78+
parse error:
79+
4280
--> 17:25
4381
|
4482
17 | Int memory_gb = <>
4583
| ^---
4684
|
4785
= expected WHITESPACE, COMMENT, or expression"""
86+
87+
[[ignored_errors]]
88+
document = "stjudecloud/workflows:tools/bwa.wdl"
89+
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 34:17'''
90+
91+
[[ignored_errors]]
92+
document = "stjudecloud/workflows:tools/fq.wdl"
93+
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 123:17'''
94+
95+
[[ignored_errors]]
96+
document = "stjudecloud/workflows:tools/kraken2.wdl"
97+
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 335:17'''
98+
99+
[[ignored_errors]]
100+
document = "stjudecloud/workflows:workflows/rnaseq/rnaseq-standard-fastq.wdl"
101+
error = '''validation error: [v1::001] invalid escape character '\*' in string at line 55:241'''

rustfmt.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
format_code_in_doc_comments = true

wdl-grammar/Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ pest_derive = { workspace = true }
1919
reqwest = { version = "0.11.22", optional = true }
2020
serde = { workspace = true }
2121
serde_with = { workspace = true, optional = true }
22-
tokio = { version = "1.33.0", features = ["full"], optional = true}
22+
to_snake_case = "0.1.1"
23+
tokio = { version = "1.33.0", features = ["full"], optional = true }
2324
toml = { workspace = true, optional = true }
2425

2526
[features]
@@ -36,7 +37,7 @@ binaries = [
3637
"reqwest",
3738
"serde_with",
3839
"tokio",
39-
"toml"
40+
"toml",
4041
]
4142

4243
[[bin]]

wdl-grammar/src/commands/create_test.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! `wdl-grammar create-test`
22
33
use clap::Parser;
4+
use log::warn;
45
use pest::iterators::Pair;
5-
use pest::Parser as _;
66
use pest::RuleType;
77

88
use wdl_grammar as grammar;
@@ -18,8 +18,8 @@ pub enum Error {
1818
/// Multiple root nodes parsed.
1919
MultipleRootNodes,
2020

21-
/// A parsing error from Pest.
22-
Parse(Box<dyn std::error::Error>),
21+
/// An error parsing the grammar.
22+
GrammarV1(grammar::Error<grammar::v1::Rule>),
2323

2424
/// Unknown rule name.
2525
UnknownRule {
@@ -35,11 +35,11 @@ impl std::fmt::Display for Error {
3535
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3636
match self {
3737
Error::Common(err) => write!(f, "{err}"),
38+
Error::GrammarV1(err) => write!(f, "grammar parse error: {err}"),
3839
Error::MultipleRootNodes => write!(f, "multiple root nodes found"),
3940
Error::UnknownRule { name, grammar } => {
4041
write!(f, "unknown rule '{name}' for grammar {grammar}")
4142
}
42-
Error::Parse(err) => write!(f, "parse error: {err}"),
4343
}
4444
}
4545
}
@@ -84,11 +84,15 @@ pub fn create_test(args: Args) -> Result<()> {
8484
.unwrap_or_else(|| get_contents_stdin().map_err(Error::Common))?;
8585

8686
let mut parse_tree = match args.specification_version {
87-
grammar::Version::V1 => {
88-
grammar::v1::Parser::parse(rule, &input).map_err(|err| Error::Parse(Box::new(err)))?
89-
}
87+
grammar::Version::V1 => grammar::v1::parse(rule, &input).map_err(Error::GrammarV1)?,
9088
};
9189

90+
if let Some(warnings) = parse_tree.warnings() {
91+
for warning in warnings {
92+
warn!("{}", warning);
93+
}
94+
}
95+
9296
let root = match parse_tree.len() {
9397
// SAFETY: this should not be possible, as parsing just successfully
9498
// completed. As such, we should always have at least one parsed

wdl-grammar/src/commands/gauntlet.rs

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use clap::Parser;
88
use colored::Colorize as _;
99
use log::debug;
1010
use log::trace;
11-
use pest::Parser as _;
1211

1312
pub mod config;
1413
pub mod document;
@@ -81,12 +80,16 @@ pub struct Args {
8180
#[arg(short, long)]
8281
config_file: Option<PathBuf>,
8382

83+
/// Don't load any configuration from the cache.
84+
#[arg(short, long, global = true)]
85+
no_cache: bool,
86+
8487
/// Only errors are printed to the stderr stream.
8588
#[arg(short, long, global = true)]
8689
quiet: bool,
8790

8891
/// Overwrites the configuration file.
89-
#[arg(short, long, global = true)]
92+
#[arg(long, global = true)]
9093
save_config: bool,
9194

9295
/// Silences printing detailed error information.
@@ -97,6 +100,10 @@ pub struct Args {
97100
#[arg(long, global = true)]
98101
skip_remote: bool,
99102

103+
/// Displays warnings as part of the report output.
104+
#[arg(long, global = true)]
105+
show_warnings: bool,
106+
100107
/// The Workflow Description Language (WDL) specification version to use.
101108
#[arg(value_name = "VERSION", short = 's', long, default_value_t, value_enum)]
102109
specification_version: grammar::Version,
@@ -108,9 +115,16 @@ pub struct Args {
108115

109116
/// Main function for this subcommand.
110117
pub async fn gauntlet(args: Args) -> Result<()> {
111-
let path = args.config_file.unwrap_or(Config::default_path());
112-
let mut config =
113-
Config::load_or_new(path, args.specification_version).map_err(Error::Config)?;
118+
let mut config = match args.no_cache {
119+
true => {
120+
debug!("Skipping loading from cache.");
121+
Config::default()
122+
}
123+
false => {
124+
let path = args.config_file.unwrap_or(Config::default_path());
125+
Config::load_or_new(path, args.specification_version).map_err(Error::Config)?
126+
}
127+
};
114128

115129
if let Some(repositories) = args.repositories {
116130
config.repositories_mut().extend(
@@ -157,13 +171,33 @@ pub async fn gauntlet(args: Args) -> Result<()> {
157171

158172
match config.version() {
159173
grammar::Version::V1 => {
160-
match grammar::v1::Parser::parse(grammar::v1::Rule::document, &content) {
161-
Ok(_) => {
162-
trace!("{}: successfully parsed.", document_identifier);
163-
report
164-
.register(document_identifier, Status::Success)
165-
.map_err(Error::InputOutput)?;
166-
}
174+
match grammar::v1::parse(grammar::v1::Rule::document, &content) {
175+
Ok(tree) => match tree.warnings() {
176+
Some(warnings) => {
177+
trace!(
178+
"{}: successfully parsed with {} warnings.",
179+
document_identifier,
180+
warnings.len()
181+
);
182+
report
183+
.register(document_identifier, Status::Warning)
184+
.map_err(Error::InputOutput)?;
185+
186+
if args.show_warnings {
187+
for warning in warnings {
188+
report
189+
.report_warning(warning)
190+
.map_err(Error::InputOutput)?;
191+
}
192+
}
193+
}
194+
None => {
195+
trace!("{}: succesfully parsed.", document_identifier,);
196+
report
197+
.register(document_identifier, Status::Success)
198+
.map_err(Error::InputOutput)?;
199+
}
200+
},
167201
Err(err) => {
168202
let actual_error = err.to_string();
169203

@@ -273,7 +307,7 @@ pub async fn gauntlet(args: Args) -> Result<()> {
273307
println!(
274308
"\n{}\n",
275309
"Undetected expected errors: you should remove these from your \
276-
Config.toml or run this command with the `-s` option!"
310+
Config.toml or run this command with the `--save-config` option!"
277311
.red()
278312
.bold()
279313
);

wdl-grammar/src/commands/gauntlet/config.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ type Result<T> = std::result::Result<T, Error>;
5858
/// configuration itself. Notably, the path to the configuration file should
5959
/// _not_ be part of the serialized configuration value. Thus, I split the
6060
/// concept of the path and the actual configuration into two different structs.
61+
#[derive(Default)]
6162
pub struct Config {
6263
/// The path to the configuration file.
6364
path: PathBuf,

wdl-grammar/src/commands/gauntlet/config/inner.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub type Repositories = HashSet<repository::Identifier>;
2727
///
2828
/// This object stores the actual configuration values for this subcommand.
2929
#[serde_as]
30-
#[derive(Debug, Deserialize, Serialize)]
30+
#[derive(Debug, Default, Deserialize, Serialize)]
3131
pub struct Inner {
3232
/// The WDL version.
3333
pub(super) version: grammar::Version,

wdl-grammar/src/commands/gauntlet/report.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
33
use std::collections::HashMap;
44

5+
use colored::Colorize as _;
56
use indexmap::IndexMap;
67

7-
use colored::Colorize as _;
8+
use wdl_grammar as grammar;
9+
10+
use grammar::core::lint;
811

912
use crate::commands::gauntlet::repository;
1013
use crate::gauntlet::document;
@@ -198,6 +201,21 @@ impl<T: std::io::Write> Report<T> {
198201
Ok(())
199202
}
200203

204+
/// Report a warning for a registered result.
205+
pub fn report_warning(&mut self, warning: &lint::Warning) -> std::io::Result<()> {
206+
if self.section != Section::Summary {
207+
panic!(
208+
"cannot report a warning when the report phase is {:?}",
209+
self.section
210+
);
211+
}
212+
213+
writeln!(self.inner, " ↳ {}", warning)?;
214+
self.printed = true;
215+
216+
Ok(())
217+
}
218+
201219
/// Reports all unexpected errors for a repository report.
202220
pub fn report_unexpected_errors_for_repository(
203221
&mut self,
@@ -294,12 +312,12 @@ impl<T: std::io::Write> Report<T> {
294312
{
295313
0 => {}
296314
1 => with.push(String::from("1 mismatch error")),
297-
v => with.push(format!("{} mismatched errors", v)),
315+
v => with.push(format!("{} mismatch errors", v)),
298316
};
299317

300318
match results.get(&Status::Warning).copied() {
301-
Some(1) => with.push(String::from("1 error with warnings")),
302-
Some(v) => with.push(format!("{} errors with warnings", v)),
319+
Some(1) => with.push(String::from("1 test containing warnings")),
320+
Some(v) => with.push(format!("{} tests containing warnings", v)),
303321
None => {}
304322
}
305323

0 commit comments

Comments
 (0)