miniwdl check

To aid the workflow development cycle, miniwdl includes a code quality checker which statically analyzes WDL source code to generate warnings and suggestions. Take for example this valid but poorly-written WDL task:

$ cat << 'EOF' > check_demo.wdl
  task t {
      String s = i
      Int? i
      command <<<
         if [ ! -n ~{s} ]; then
             echo Empty
         fi
      >>>
      output {
          String t = read_string(stdout())
      }
  }
EOF

Run this through miniwdl check:

$ miniwdl check check_demo.wdl
check_demo.wdl
     (Ln 1, Col 1) MissingVersion, document should declare WDL version; draft-2 assumed
     task t
         (Ln 2, Col 10) StringCoercion, String s = :Int?:
         (Ln 2, Col 10) UnusedDeclaration, nothing references String s
         (Ln 2, Col 21) ForwardReference, reference to i precedes its declaration
         (Ln 10, Col 14) NameCollision, declaration of 't' collides with a task name

miniwdl parsed the document successfully to produce this outline, but noted several issues within. First, we forgot to specify the WDL language version by starting the file with version 1.0 or version development, causing miniwdl to assume the outdated draft-2 dialect (as required by the WDL specification). This leads to a more serious problem: WDL draft-2 didn’t yet support the ~{expr} interpolation syntax, so it goes unrecognized here, leaving incorrect command logic and the WDL value s unused. This pitfall (a common one!) illustrates how the “lint” warnings, while often stylistic, can indicate critical errors.

If your system has ShellCheck installed, miniwdl check automatically runs it on each task command script and reports any findings, in this case:

(Ln 5, Col 17) CommandShellCheck, SC2236 Use -z instead of ! -n.

The miniwdl check process succeeds (zero exit status code) so long as the WDL document can be parsed and type-checked, even if lint or ShellCheck warnings are reported. With --strict, lint warnings as well as parse/type errors lead to a non-zero exit status.

Suppressing warnings

Individual warnings can be suppressed by a WDL comment containing !WarningName on the same line or the following line, for example:

$ cat << 'EOF' > check_demo2.wdl
  task t {
      String s = i  # !ForwardReference !StringCoercion
      Int? i
      command <<<
         if [ ! -n ~{s} ]; then
             echo Empty
         fi
      >>>
      output {
          String t = read_string(stdout())
          # Meant to do that: !NameCollision
      }
  }
EOF
$ miniwdl check check_demo2.wdl
check_demo2.wdl
    (Ln 1, Col 1) MissingVersion, document should declare WDL version; draft-2 assumed
    task t
        (Ln 5, Col 17) CommandShellCheck, SC2236 Use -z instead of ! -n.
        (Ln 2, Col 10) UnusedDeclaration, nothing references String s

ShellCheck warnings can be suppressed using that tool’s own convention.

Pre-commit hook

In a git repository with WDL workflows, you can use pre-commit with miniwdl check by entering into .pre-commit-config.yaml:

repos:
- repo: local
  hooks:
  - id: miniwdl-check
    name: miniwdl check
    language: system
    files: ".+\\.wdl"
    verbose: true
    entry: miniwdl
    args: [check]

Then try pre-commit run --all-files or install git hooks according to its procedure; add --strict to args if desired.

Command line

usage: miniwdl check [-h] [--strict] [--no-suppress] [--no-shellcheck]
                     [--no-quant-check] [-p DIR] [--debug]
                     WDL_URI [WDL_URI ...]

Positional Arguments

WDL_URI WDL document filename/URI

Named Arguments

--strict exit with nonzero status code if any lint warnings are shown (in addition to syntax and type errors)
--no-suppress show lint warnings even if they have suppression comments
--no-shellcheck
 don’t use shellcheck on task commands even if available, and suppress suggestion if it isn’t

language

--no-quant-check
 relax static typechecking of optional types, and permit coercion of T to Array[T] (discouraged; for backwards compatibility with older WDL)
-p, --path local directory to search for imports

debugging

--debug maximally verbose logging & exception tracebacks