Skip to content

Commit

Permalink
feat: respect allow_nested_inputs in workflows.
Browse files Browse the repository at this point in the history
This commit respects `allow_nested_inputs`:

* With `allow_nested_inputs` or `allowNestedInputs` in a workflow `hints`
  section in 1.2.
* With `allowNestedInputs` in a workflow `meta` section in 1.1 and 1.2.
* By default in 1.0.

When set, the check for required inputs will be suppressed.
  • Loading branch information
peterhuene committed Sep 28, 2024
1 parent 48ad131 commit 549375c
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 5 deletions.
71 changes: 67 additions & 4 deletions wdl-analysis/src/scope/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ use wdl_ast::v1::Decl;
use wdl_ast::v1::DocumentItem;
use wdl_ast::v1::Expr;
use wdl_ast::v1::ImportStatement;
use wdl_ast::v1::MetadataValue;
use wdl_ast::v1::ScatterStatement;
use wdl_ast::v1::StructDefinition;
use wdl_ast::v1::TaskDefinition;
use wdl_ast::v1::WorkflowDefinition;
use wdl_ast::v1::WorkflowHintsItemValue;
use wdl_ast::version::V1;

use super::DocumentScope;
Expand Down Expand Up @@ -627,6 +629,58 @@ fn add_workflow(
true
}

/// Determines if nested inputs are allowed for a workflow.
fn allow_nested_inputs(document: &DocumentScope, definition: &WorkflowDefinition) -> bool {
match document.version() {
Some(SupportedVersion::V1(V1::Zero)) => return true,
Some(SupportedVersion::V1(V1::One)) => {
// Fall through to below
}
Some(SupportedVersion::V1(V1::Two)) => {
// Check the hints section
let allow = definition.hints().and_then(|s| {
s.items().find_map(|i| {
if matches!(
i.name().as_str(),
"allow_nested_inputs" | "allowNestedInputs"
) {
match i.value() {
WorkflowHintsItemValue::Boolean(v) => Some(v.value()),
_ => Some(false),
}
} else {
None
}
})
});

if let Some(allow) = allow {
return allow;
}

// Fall through to below
}
_ => return false,
}

// Check the metadata section
definition
.metadata()
.and_then(|s| {
s.items().find_map(|i| {
if i.name().as_str() == "allowNestedInputs" {
match i.value() {
MetadataValue::Boolean(v) => Some(v.value()),
_ => Some(false),
}
} else {
None
}
})
})
.unwrap_or(false)
}

/// Finishes processing a workflow by populating its scope.
fn populate_workflow_scope(
document: &mut DocumentScope,
Expand All @@ -651,6 +705,8 @@ fn populate_workflow_scope(
diagnostics,
);

let allow_nested_inputs = allow_nested_inputs(document, definition);

// Keep a map of scopes from syntax node that introduced the scope to the scope
// index
let mut scopes = HashMap::new();
Expand Down Expand Up @@ -720,6 +776,7 @@ fn populate_workflow_scope(
definition.name().as_str(),
scope,
&statement,
allow_nested_inputs,
diagnostics,
);
}
Expand Down Expand Up @@ -828,6 +885,7 @@ fn add_call_statement(
workflow_name: &str,
scope: ScopeIndex,
statement: &CallStatement,
allow_nested_inputs: bool,
diagnostics: &mut Vec<Diagnostic>,
) {
let target_name = statement
Expand Down Expand Up @@ -891,12 +949,17 @@ fn add_call_statement(
}
}

seen.insert(TokenStrHash::new(input_name));
// Don't bother keeping track of seen inputs in 1.0
if !allow_nested_inputs {
seen.insert(TokenStrHash::new(input_name));
}
}

for (input, (_, required)) in &target.inputs {
if *required && !seen.contains(input.as_str()) {
diagnostics.push(missing_call_input(target.workflow, &target_name, input));
if !allow_nested_inputs {
for (input, (_, required)) in &target.inputs {
if *required && !seen.contains(input.as_str()) {
diagnostics.push(missing_call_input(target.workflow, &target_name, input));
}
}
}

Expand Down
Empty file.
28 changes: 28 additions & 0 deletions wdl-analysis/tests/analysis/allow-nested-inputs-1.0/source.wdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
## This is a test of allowed nested inputs in 1.0.
## This should be accepted without diagnostics.
version 1.0

task my_task {
input {
# Required
String required
# Optional
String? optional
# Defaulted
String defaulted = "default"
}

command <<<>>>
}

workflow my_workflow {
# Missing required input
call my_task

# OK
call my_task as my_task2 { input: required = "required" }

# OK
call my_task as my_task3 { input: required = "required", optional = "optional", defaulted = "defaulted" }
}
Empty file.
32 changes: 32 additions & 0 deletions wdl-analysis/tests/analysis/allow-nested-inputs-1.1/source.wdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
## This is a test of allowed nested inputs in 1.1.
## This should be accepted without diagnostics.
version 1.1

task my_task {
input {
# Required
String required
# Optional
String? optional
# Defaulted
String defaulted = "default"
}

command <<<>>>
}

workflow my_workflow {
meta {
allowNestedInputs: true
}

# Missing required input
call my_task

# OK
call my_task as my_task2 { input: required = "required" }

# OK
call my_task as my_task3 { input: required = "required", optional = "optional", defaulted = "defaulted" }
}
Empty file.
32 changes: 32 additions & 0 deletions wdl-analysis/tests/analysis/allow-nested-inputs-1.2/source.wdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
## This is a test of allowed nested inputs in 1.2.
## This should be accepted without diagnostics.
version 1.2

task my_task {
input {
# Required
String required
# Optional
String? optional
# Defaulted
String defaulted = "default"
}

command <<<>>>
}

workflow my_workflow {
hints {
allow_nested_inputs: true
}

# Missing required input
call my_task

# OK
call my_task as my_task2 { input: required = "required" }

# OK
call my_task as my_task3 { input: required = "required", optional = "optional", defaulted = "defaulted" }
}
2 changes: 1 addition & 1 deletion wdl-ast/src/validation/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ impl Visitor for UniqueKeysVisitor {

check_duplicate_keys(
&mut self.0,
&[],
&[("allow_nested_inputs", "allowNestedInputs")],
section.items().map(|i| i.name()),
Context::HintsSection,
state,
Expand Down

0 comments on commit 549375c

Please sign in to comment.