diff --git a/.github/workflows/cromwell-test-run.yml b/.github/workflows/cromwell-test-run.yml index 7ab0d43..8c70590 100644 --- a/.github/workflows/cromwell-test-run.yml +++ b/.github/workflows/cromwell-test-run.yml @@ -42,15 +42,18 @@ jobs: - name: Pull Cromwell Jarfile run: wget -q https://github.com/broadinstitute/cromwell/releases/download/86/cromwell-86.jar - - name: Execute Test Run of WDL Workflows - run: | - cmd="java -jar cromwell-86.jar run ${{ matrix.wdl }}/${{ matrix.wdl }}.wdl" - if [[ -f "${{ matrix.wdl }}/inputs.json" ]]; then - cmd="$cmd -i ${{ matrix.wdl }}/inputs.json" - fi - if [[ -f "${{ matrix.wdl }}/options.json" ]]; then - cmd="$cmd -o ${{ matrix.wdl }}/options.json" - fi - echo "Running command: $cmd" - eval "$cmd" + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + version: "0.5.16" + - name: Set up Python + run: uv python install 3.13 + + - name: Install dependencies + run: uv sync --all-extras + + - name: Execute Test Run of WDL Workflows + env: + CROMWELL_PATH: cromwell-86.jar + run: uv run pytest tests/cromwelljava/test-run.py --wdl-path=${{ matrix.wdl }} --verbose -s diff --git a/.github/workflows/womtools-validate.yml b/.github/workflows/womtools-validate.yml index 4ac13e9..2e1400b 100644 --- a/.github/workflows/womtools-validate.yml +++ b/.github/workflows/womtools-validate.yml @@ -29,27 +29,30 @@ jobs: matrix: wdl: ${{ fromJson(needs.generate-matrix.outputs.matrix) }} steps: - - - name: Checkout + - name: Checkout uses: actions/checkout@v4 - - - name: Set Up Java + - name: Set Up Java uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '21' - - - name: Pull WOMtool Jarfile + - name: Pull WOMtool Jarfile run: wget -q https://github.com/broadinstitute/cromwell/releases/download/86/womtool-86.jar - - - name: Validate WDL Scripts - run: | - cmd="java -jar womtool-86.jar validate ${{ matrix.wdl }}/${{ matrix.wdl }}.wdl" - if [[ -f "${{ matrix.wdl }}/inputs.json" ]]; then - cmd="$cmd -i ${{ matrix.wdl }}/inputs.json" - fi - echo "Running command: $cmd" - eval "$cmd" + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + version: "0.5.16" + + - name: Set up Python + run: uv python install 3.13 + + - name: Install dependencies + run: uv sync --all-extras + + - name: Validate WDL Scripts + env: + WOMTOOL_PATH: womtool-86.jar + run: uv run pytest tests/cromwelljava/test-validate.py --wdl-path=${{ matrix.wdl }} --verbose -s diff --git a/badFile/badFile.wdl b/badFile/badFile.wdl new file mode 100644 index 0000000..8d6e37a --- /dev/null +++ b/badFile/badFile.wdl @@ -0,0 +1,19 @@ +version 1.0 +## This is a test workflow that fails against womtool. +## From https://github.com/broadinstitute/cromwell + +#### WORKFLOW DEFINITION + +workflow oops { + call oopsie +} + +#### TASK DEFINITIONS + +task oopsie { + input { + String str + } + command { echo ${str} } + runtime { docker: docker_image } +} diff --git a/pyproject.toml b/pyproject.toml index df7ec4f..36615c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,5 +7,6 @@ requires-python = ">=3.13" dependencies = [ "httpx>=0.28.1", "pytest>=8.3.4", + "sh>=2.1.0", "tenacity>=9.0.0", ] diff --git a/tests/cromwelljava/conftest.py b/tests/cromwelljava/conftest.py new file mode 100644 index 0000000..6fdbe42 --- /dev/null +++ b/tests/cromwelljava/conftest.py @@ -0,0 +1,13 @@ +import pytest + +def pytest_addoption(parser): + parser.addoption( + "--wdl-path", + action="store", + default="default_value", + help="Path to a directory with a WDL file to test" + ) + +@pytest.fixture +def wdl_path(pytestconfig): + return pytestconfig.getoption("--wdl-path") diff --git a/tests/cromwelljava/test-run.py b/tests/cromwelljava/test-run.py new file mode 100644 index 0000000..16df9c5 --- /dev/null +++ b/tests/cromwelljava/test-run.py @@ -0,0 +1,11 @@ +from utils import CromwellJava + +cromwell = CromwellJava() + + +def test_cromwell_run(wdl_path): + is_valid = cromwell.run(wdl_path) + if wdl_path.startswith("bad"): + assert not is_valid + else: + assert is_valid diff --git a/tests/cromwelljava/test-validate.py b/tests/cromwelljava/test-validate.py new file mode 100644 index 0000000..78531d1 --- /dev/null +++ b/tests/cromwelljava/test-validate.py @@ -0,0 +1,11 @@ +from utils import Womtool + +wom = Womtool() + + +def test_womtool_validate(wdl_path): + is_valid = wom.validate(wdl_path) + if wdl_path.startswith("bad"): + assert not is_valid + else: + assert is_valid diff --git a/tests/cromwelljava/utils.py b/tests/cromwelljava/utils.py new file mode 100644 index 0000000..f3c46ae --- /dev/null +++ b/tests/cromwelljava/utils.py @@ -0,0 +1,71 @@ +import os +from pathlib import Path + +import sh + + +class Womtool(object): + """Womtool class""" + + def __init__(self): + self.womtool_path = os.getenv("WOMTOOL_PATH") + if not self.womtool_path: + raise Exception("failed setting WOMTOOL_PATH") + self.womtool = sh.Command("java").bake("-jar", self.womtool_path) + + def has_inputs(self, wdl_path): + path = Path(f"{wdl_path}/inputs.json") + if path.exists(): + self.womtool = self.womtool.bake(i=str(path)) + + def validate(self, wdl_path, show_cmd=False): + try: + self.womtool = self.womtool.bake( + "validate", + f"{wdl_path}/{wdl_path}.wdl", + ) + self.has_inputs(wdl_path) + if show_cmd: + print(self.womtool) + self.womtool() + except sh.ErrorReturnCode as e: + print(f"Command {e.full_cmd} exited with {e.exit_code}") + return False + + return True + +class CromwellJava(object): + """Cromwell Java class - run Cromwell Java jar""" + + def __init__(self): + self.cromwell_path = os.getenv("CROMWELL_PATH") + if not self.cromwell_path: + raise Exception("failed setting CROMWELL_PATH") + self.cromwell = sh.Command("java").bake("-jar", self.cromwell_path) + + def has_inputs(self, wdl_path): + path = Path(f"{wdl_path}/inputs.json") + if path.exists(): + self.cromwell = self.cromwell.bake(i=str(path)) + + def has_options(self, wdl_path): + path = Path(f"{wdl_path}/options.json") + if path.exists(): + self.cromwell = self.cromwell.bake(o=str(path)) + + def run(self, wdl_path, show_cmd=False): + try: + self.cromwell = self.cromwell.bake( + "run", + f"{wdl_path}/{wdl_path}.wdl", + ) + self.has_inputs(wdl_path) + self.has_options(wdl_path) + if show_cmd: + print(self.cromwell) + self.cromwell() + except sh.ErrorReturnCode as e: + print(f"Command {e.full_cmd} exited with {e.exit_code}") + return False + + return True