Skip to content

Commit

Permalink
feat: adds validation and linting
Browse files Browse the repository at this point in the history
  • Loading branch information
claymcleod committed Nov 16, 2023
1 parent f24bee7 commit d6c3755
Show file tree
Hide file tree
Showing 38 changed files with 1,742 additions and 91 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

82 changes: 76 additions & 6 deletions Gauntlet.toml
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
version = "v1"

[[repositories]]
organization = "PacificBiosciences"
name = "HiFi-human-WGS-WDL"

[[repositories]]
organization = "biowdl"
name = "tasks"

[[repositories]]
organization = "chanzuckerberg"
name = "czid-workflows"

[[repositories]]
organization = "stjudecloud"
name = "workflows"

[[repositories]]
organization = "chanzuckerberg"
name = "czid-workflows"
organization = "PacificBiosciences"
name = "HiFi-human-WGS-WDL"

[[ignored_errors]]
document = "biowdl/tasks:bcftools.wdl"
error = '''validation error: [v1::001] invalid escape character '\_' in string at line 114:75'''

[[ignored_errors]]
document = "biowdl/tasks:bedtools.wdl"
error = """
parse error:
--> 29:67
|
29 | String memory = \"~{512 + ceil(size([inputBed, faidx], \"MiB\"))}MiB\"
Expand All @@ -29,19 +35,83 @@ error = """
[[ignored_errors]]
document = "biowdl/tasks:bowtie.wdl"
error = """
parse error:
--> 40:58
|
40 | String memory = \"~{5 + ceil(size(indexFiles, \"GiB\"))}GiB\"
| ^---
|
= expected WHITESPACE or OPTION"""

[[ignored_errors]]
document = "biowdl/tasks:centrifuge.wdl"
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 122:57'''

[[ignored_errors]]
document = "biowdl/tasks:common.wdl"
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 275:45'''

[[ignored_errors]]
document = "biowdl/tasks:fastqc.wdl"
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 59:42'''

[[ignored_errors]]
document = "biowdl/tasks:gatk.wdl"
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 127:57'''

[[ignored_errors]]
document = "biowdl/tasks:hisat2.wdl"
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 60:34'''

[[ignored_errors]]
document = "biowdl/tasks:multiqc.wdl"
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 133:45'''

[[ignored_errors]]
document = "biowdl/tasks:picard.wdl"
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 643:51'''

[[ignored_errors]]
document = "biowdl/tasks:sambamba.wdl"
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 91:44'''

[[ignored_errors]]
document = "biowdl/tasks:samtools.wdl"
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 80:42'''

[[ignored_errors]]
document = "biowdl/tasks:umi-tools.wdl"
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 95:49'''

[[ignored_errors]]
document = "biowdl/tasks:umi.wdl"
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 39:60'''

[[ignored_errors]]
document = "stjudecloud/workflows:template/task-templates.wdl"
error = """
parse error:
--> 17:25
|
17 | Int memory_gb = <>
| ^---
|
= expected WHITESPACE, COMMENT, or expression"""

[[ignored_errors]]
document = "stjudecloud/workflows:tools/bwa.wdl"
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 34:17'''

[[ignored_errors]]
document = "stjudecloud/workflows:tools/fq.wdl"
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 123:17'''

[[ignored_errors]]
document = "stjudecloud/workflows:tools/kraken2.wdl"
error = '''validation error: [v1::001] invalid escape character '\.' in string at line 335:17'''

[[ignored_errors]]
document = "stjudecloud/workflows:workflows/rnaseq/rnaseq-standard-fastq.wdl"
error = '''validation error: [v1::001] invalid escape character '\*' in string at line 55:241'''
1 change: 1 addition & 0 deletions rustfmt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
format_code_in_doc_comments = true
5 changes: 3 additions & 2 deletions wdl-grammar/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ pest_derive = { workspace = true }
reqwest = { version = "0.11.22", optional = true }
serde = { workspace = true }
serde_with = { workspace = true, optional = true }
tokio = { version = "1.33.0", features = ["full"], optional = true}
to_snake_case = "0.1.1"
tokio = { version = "1.33.0", features = ["full"], optional = true }
toml = { workspace = true, optional = true }

[features]
Expand All @@ -36,7 +37,7 @@ binaries = [
"reqwest",
"serde_with",
"tokio",
"toml"
"toml",
]

[[bin]]
Expand Down
18 changes: 11 additions & 7 deletions wdl-grammar/src/commands/create_test.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! `wdl-grammar create-test`
use clap::Parser;
use log::warn;
use pest::iterators::Pair;
use pest::Parser as _;
use pest::RuleType;

use wdl_grammar as grammar;
Expand All @@ -18,8 +18,8 @@ pub enum Error {
/// Multiple root nodes parsed.
MultipleRootNodes,

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

/// Unknown rule name.
UnknownRule {
Expand All @@ -35,11 +35,11 @@ impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::Common(err) => write!(f, "{err}"),
Error::GrammarV1(err) => write!(f, "grammar parse error: {err}"),
Error::MultipleRootNodes => write!(f, "multiple root nodes found"),
Error::UnknownRule { name, grammar } => {
write!(f, "unknown rule '{name}' for grammar {grammar}")
}
Error::Parse(err) => write!(f, "parse error: {err}"),
}
}
}
Expand Down Expand Up @@ -84,11 +84,15 @@ pub fn create_test(args: Args) -> Result<()> {
.unwrap_or_else(|| get_contents_stdin().map_err(Error::Common))?;

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

if let Some(warnings) = parse_tree.warnings() {
for warning in warnings {
warn!("{}", warning);
}
}

let root = match parse_tree.len() {
// SAFETY: this should not be possible, as parsing just successfully
// completed. As such, we should always have at least one parsed
Expand Down
56 changes: 45 additions & 11 deletions wdl-grammar/src/commands/gauntlet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use clap::Parser;
use colored::Colorize as _;
use log::debug;
use log::trace;
use pest::Parser as _;

pub mod config;
pub mod document;
Expand Down Expand Up @@ -81,6 +80,10 @@ pub struct Args {
#[arg(short, long)]
config_file: Option<PathBuf>,

/// Don't load any configuration from the cache.
#[arg(short, long, global = true)]
no_cache: bool,

/// Only errors are printed to the stderr stream.
#[arg(short, long, global = true)]
quiet: bool,
Expand All @@ -97,6 +100,10 @@ pub struct Args {
#[arg(long, global = true)]
skip_remote: bool,

/// Displays warnings as part of the report output.
#[arg(short, long, global = true)]
show_warnings: bool,

/// The Workflow Description Language (WDL) specification version to use.
#[arg(value_name = "VERSION", short = 's', long, default_value_t, value_enum)]
specification_version: grammar::Version,
Expand All @@ -108,9 +115,16 @@ pub struct Args {

/// Main function for this subcommand.
pub async fn gauntlet(args: Args) -> Result<()> {
let path = args.config_file.unwrap_or(Config::default_path());
let mut config =
Config::load_or_new(path, args.specification_version).map_err(Error::Config)?;
let mut config = match args.no_cache {
true => {
debug!("Skipping loading from cache.");
Config::default()
}
false => {
let path = args.config_file.unwrap_or(Config::default_path());
Config::load_or_new(path, args.specification_version).map_err(Error::Config)?
}
};

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

match config.version() {
grammar::Version::V1 => {
match grammar::v1::Parser::parse(grammar::v1::Rule::document, &content) {
Ok(_) => {
trace!("{}: successfully parsed.", document_identifier);
report
.register(document_identifier, Status::Success)
.map_err(Error::InputOutput)?;
}
match grammar::v1::parse(grammar::v1::Rule::document, &content) {
Ok(tree) => match tree.warnings() {
Some(warnings) => {
trace!(
"{}: successfully parsed with {} warnings.",
document_identifier,
warnings.len()
);
report
.register(document_identifier, Status::Warning)
.map_err(Error::InputOutput)?;

if args.show_warnings {
for warning in warnings {
report
.report_warning(warning)
.map_err(Error::InputOutput)?;
}
}
}
None => {
trace!("{}: succesfully parsed.", document_identifier,);
report
.register(document_identifier, Status::Success)
.map_err(Error::InputOutput)?;
}
},
Err(err) => {
let actual_error = err.to_string();

Expand Down
1 change: 1 addition & 0 deletions wdl-grammar/src/commands/gauntlet/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ type Result<T> = std::result::Result<T, Error>;
/// configuration itself. Notably, the path to the configuration file should
/// _not_ be part of the serialized configuration value. Thus, I split the
/// concept of the path and the actual configuration into two different structs.
#[derive(Default)]
pub struct Config {
/// The path to the configuration file.
path: PathBuf,
Expand Down
2 changes: 1 addition & 1 deletion wdl-grammar/src/commands/gauntlet/config/inner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub type Repositories = HashSet<repository::Identifier>;
///
/// This object stores the actual configuration values for this subcommand.
#[serde_as]
#[derive(Debug, Deserialize, Serialize)]
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct Inner {
/// The WDL version.
pub(super) version: grammar::Version,
Expand Down
26 changes: 22 additions & 4 deletions wdl-grammar/src/commands/gauntlet/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
use std::collections::HashMap;

use indexmap::IndexMap;

use colored::Colorize as _;

use wdl_grammar as grammar;

use grammar::core::lint;

use crate::commands::gauntlet::repository;
use crate::gauntlet::document;

Expand Down Expand Up @@ -198,6 +201,21 @@ impl<T: std::io::Write> Report<T> {
Ok(())
}

/// Report a warning for a registered result.
pub fn report_warning(&mut self, warning: &lint::Warning) -> std::io::Result<()> {
if self.section != Section::Summary {
panic!(
"cannot report a warning when the report phase is {:?}",
self.section
);
}

writeln!(self.inner, " ↳ {}", warning)?;
self.printed = true;

Ok(())
}

/// Reports all unexpected errors for a repository report.
pub fn report_unexpected_errors_for_repository(
&mut self,
Expand Down Expand Up @@ -294,12 +312,12 @@ impl<T: std::io::Write> Report<T> {
{
0 => {}
1 => with.push(String::from("1 mismatch error")),
v => with.push(format!("{} mismatched errors", v)),
v => with.push(format!("{} mismatch errors", v)),
};

match results.get(&Status::Warning).copied() {
Some(1) => with.push(String::from("1 error with warnings")),
Some(v) => with.push(format!("{} errors with warnings", v)),
Some(1) => with.push(String::from("1 test containing warnings")),
Some(v) => with.push(format!("{} tests containing warnings", v)),
None => {}
}

Expand Down
Loading

0 comments on commit d6c3755

Please sign in to comment.