From ae010701f2993360a6864308e182a13e5bdafebb Mon Sep 17 00:00:00 2001 From: Adam Nichols Date: Thu, 2 Jul 2026 10:54:37 -0400 Subject: [PATCH 1/4] Fix bash list syntax --- build_all.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_all.sh b/build_all.sh index 04912cc2..cc1f55cb 100755 --- a/build_all.sh +++ b/build_all.sh @@ -13,7 +13,7 @@ # 8- terra-jupyter-bioconductor # 9- terra-rstudio-aou # 10- wondershaper -images=("terra-base", "terra-jupyter-base" "terra-jupyter-python" "terra-jupyter-r" "terra-jupyter-gatk" "terra-jupyter-hail" "terra-jupyter-aou" "terra-jupyter-bioconductor" "terra-rstudio-aou" "wondershaper") +images=("terra-base" "terra-jupyter-base" "terra-jupyter-python" "terra-jupyter-r" "terra-jupyter-gatk" "terra-jupyter-hail" "terra-jupyter-aou" "terra-jupyter-bioconductor" "terra-rstudio-aou" "wondershaper") # Loop over each image to build in the correct order for image in "${images[@]}"; do From d27a77b0f48e3e249ab83d0500d84e864991eef4 Mon Sep 17 00:00:00 2001 From: Adam Nichols Date: Thu, 2 Jul 2026 10:55:06 -0400 Subject: [PATCH 2/4] New GHA to build & test `terra-base` --- .github/workflows/test-terra-base.yml | 29 +++++++++ terra-base/tests/smoke_test.py | 87 +++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 .github/workflows/test-terra-base.yml create mode 100644 terra-base/tests/smoke_test.py diff --git a/.github/workflows/test-terra-base.yml b/.github/workflows/test-terra-base.yml new file mode 100644 index 00000000..10b80201 --- /dev/null +++ b/.github/workflows/test-terra-base.yml @@ -0,0 +1,29 @@ +name: Test terra-base +# Smoke-test the terra-base image on pull requests that touch it. + +on: + pull_request: + branches: [ master ] + + workflow_dispatch: + # Allows manually triggering the workflow on a selected branch via the GitHub Actions tab. + +jobs: + + test_docker_image: + runs-on: self-hosted + + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: Build the terra-base image locally + run: ./build_smoke_test_image.sh terra-base + + - name: Smoke test + run: | + docker run --rm \ + --volume "$GITHUB_WORKSPACE/terra-base/tests:/tests:ro" \ + --entrypoint="" \ + terra-base:smoke-test \ + /etc/jupyter/bin/python /tests/smoke_test.py diff --git a/terra-base/tests/smoke_test.py b/terra-base/tests/smoke_test.py new file mode 100644 index 00000000..9f3c14fc --- /dev/null +++ b/terra-base/tests/smoke_test.py @@ -0,0 +1,87 @@ +"""Smoke tests for the terra-base image. + +Verifies that both the user-facing conda kernel env and the Jupyter server venv run the +image's target Python (the PYTHON_VERSION set in the Dockerfile), and that the Jupyter +stack and the Terra (Leonardo) notebook extensions import on that Python. + +Has no third-party dependencies, so CI can run it without installing anything: + + docker run --rm --entrypoint="" terra-base:smoke-test \ + /etc/jupyter/bin/python /tests/smoke_test.py + +Run it with the Jupyter *server* venv python (it shells out to check the kernel env too). +The functions are also pytest-discoverable if pytest is available in that interpreter. +""" +import os +import subprocess +import sys + +# The Jupyter server runs in this venv; user notebook code runs in the conda kernel env. +SERVER_PY = "/etc/jupyter/bin/python" +KERNEL_PY = "/home/jupyter/.envs/python3/bin/python" +# Where the Dockerfile copies the Leonardo extensions (loaded via run-jupyter.sh). +CUSTOM_DIR = "/etc/jupyter/custom" + + +def _target_version(): + """The image's target Python as 'major.minor' (from ENV PYTHON_VERSION), or None.""" + return os.environ.get("PYTHON_VERSION", "").strip() or None + + +def _minor(python_path): + out = subprocess.check_output( + [python_path, "-c", "import sys; print('%d.%d' % sys.version_info[:2])"] + ) + return out.decode().strip() + + +def test_kernel_env_matches_target(): + target = _target_version() + got = _minor(KERNEL_PY) + if target: + assert got == target, f"conda kernel env is Python {got}, expected {target}" + + +def test_server_venv_matches_target(): + target = _target_version() + got = _minor(SERVER_PY) + if target: + assert got == target, f"jupyter server venv is Python {got}, expected {target}" + + +def test_server_and_kernel_agree(): + assert _minor(SERVER_PY) == _minor(KERNEL_PY), "server venv and kernel env Python differ" + + +def test_jupyter_stack_imports(): + # Runs under the server venv python, where the Jupyter stack lives. + import notebook # noqa: F401 + import jupyterlab # noqa: F401 + import jupyter_server # noqa: F401 + import nbclassic # noqa: F401 + import jupyter_core # noqa: F401 + import traitlets # noqa: F401 + import notebook.utils # noqa: F401 exercises the distutils->setuptools shim on 3.12+ + + +def test_terra_extensions_import(): + sys.path.insert(0, CUSTOM_DIR) + import jupyter_localize_extension # noqa: F401 + import jupyter_delocalize # noqa: F401 + + +if __name__ == "__main__": + import traceback + + tests = [v for k, v in sorted(globals().items()) if k.startswith("test_") and callable(v)] + failed = 0 + for test in tests: + try: + test() + print(f"PASS {test.__name__}") + except Exception: + failed += 1 + print(f"FAIL {test.__name__}") + traceback.print_exc() + print(f"\n{len(tests) - failed}/{len(tests)} passed") + sys.exit(1 if failed else 0) From cac1746621610aea69bd8d1d9bda7a13c607ff2a Mon Sep 17 00:00:00 2001 From: Adam Nichols Date: Thu, 2 Jul 2026 12:33:00 -0400 Subject: [PATCH 3/4] Simplify build --- .github/workflows/test-terra-base.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-terra-base.yml b/.github/workflows/test-terra-base.yml index 10b80201..b1a6ce90 100644 --- a/.github/workflows/test-terra-base.yml +++ b/.github/workflows/test-terra-base.yml @@ -18,7 +18,8 @@ jobs: uses: actions/checkout@v7 - name: Build the terra-base image locally - run: ./build_smoke_test_image.sh terra-base + run: | + docker build --pull ./terra-base --tag terra-base:smoke-test - name: Smoke test run: | From d0dc7fd6f9ac59a2ddf937dfdd1204f860b098fd Mon Sep 17 00:00:00 2001 From: Adam Nichols Date: Thu, 2 Jul 2026 16:23:07 -0400 Subject: [PATCH 4/4] =?UTF-8?q?Add=20simple=20beginner-friendly=20tests=20?= =?UTF-8?q?=F0=9F=98=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/test-terra-base.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/test-terra-base.yml b/.github/workflows/test-terra-base.yml index b1a6ce90..7705aa49 100644 --- a/.github/workflows/test-terra-base.yml +++ b/.github/workflows/test-terra-base.yml @@ -21,6 +21,19 @@ jobs: run: | docker build --pull ./terra-base --tag terra-base:smoke-test + - name: Test Python version + run: | + version=$(docker run --rm --entrypoint="" terra-base:smoke-test python --version) + echo "$version" + [[ "$version" == "Python 3.10"* ]] + + - name: Test OS version + run: | + version=$(docker run --rm --entrypoint="" terra-base:smoke-test \ + bash -c 'source /etc/os-release && echo "$VERSION"') + echo "$version" + [[ "$version" == "22.04"* ]] + - name: Smoke test run: | docker run --rm \