From e00e713f2ed85023373ecafc3adfc1a7af188108 Mon Sep 17 00:00:00 2001 From: Shruthi Sankepelly Date: Mon, 17 Nov 2025 10:36:26 -0500 Subject: [PATCH 1/3] Enhance CI/CD for notebook execution - Updated Makefile to include new test targets for notebook execution and overall testing. - Added a new test script for executing notebooks using papermill, ensuring they run without errors. - Modified GitHub Actions workflow to set up Python, install dependencies, and execute all notebooks as part of the CI process. --- .github/workflows/execute-all-notebooks.yml | 20 +++++ Makefile | 15 +++- tests/test_notebook_execution.py | 95 +++++++++++++++++++++ 3 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 tests/test_notebook_execution.py diff --git a/.github/workflows/execute-all-notebooks.yml b/.github/workflows/execute-all-notebooks.yml index 523fc94..aa982fa 100644 --- a/.github/workflows/execute-all-notebooks.yml +++ b/.github/workflows/execute-all-notebooks.yml @@ -70,6 +70,26 @@ jobs: run: | echo "hello. i'm running from inside of EC2 instance ${{ needs.launch-ec2-runner.outputs.ec2-instance-id }}" + - uses: actions/checkout@v5 + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.12" + cache: pip + + - name: Install Dependencies + run: | + pip install -r requirements-dev.txt + pip install papermill ipykernel jupyter + ipython kernel install --name "python3" --user + + - name: Execute All Notebooks via Pytest + run: | + cd tests + python -m pytest test_notebook_execution.py -v --tb=short + + stop-ec2-runner: permissions: id-token: write # This is required for OIDC (AWS auth) diff --git a/Makefile b/Makefile index 059614b..57cedcb 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: format-python format-notebook format-python-check format-notebooks-check test-notebook-parameters +.PHONY: format-python format-notebook format-python-check format-notebooks-check test-notebook-parameters test-notebook-execution test-kfp-components test-notebooks test-all USE_CASES := $(wildcard notebooks/use-cases/*.ipynb) TUTORIALS := $(wildcard notebooks/tutorials/*.ipynb) @@ -29,3 +29,16 @@ test-notebook-parameters: @echo "Running notebook parameters validation..." pytest tests/test_notebook_parameters.py -v @echo "Notebook parameters test passed :)" + +test-notebook-execution: + @echo "Running notebook execution tests..." + pytest tests/test_notebook_execution.py -v + @echo "Notebook execution tests passed :)" + +test-notebooks: format-notebooks-check test-notebook-parameters test-notebook-execution + @echo "All notebook validations completed successfully (formatting, parameters, execution) :)" + +test-all: + @echo "Running all tests..." + pytest tests/ -v + @echo "All tests passed :)" diff --git a/tests/test_notebook_execution.py b/tests/test_notebook_execution.py new file mode 100644 index 0000000..1581cb4 --- /dev/null +++ b/tests/test_notebook_execution.py @@ -0,0 +1,95 @@ +""" +Simple notebook execution tests for CI/CD integration. + +This module provides basic notebook execution testing using papermill, +designed to be lightweight and integrate easily with GitHub Actions. +""" + +import os +import tempfile +from pathlib import Path + +import papermill as pm +import pytest + +from conftest import get_notebook_files + + +def get_test_parameters(): + """Get default test parameters for notebook execution.""" + return { + "files": [], # Empty files list for basic testing + "test_mode": True, + "quick_run": True, + } + + +def execute_single_notebook(notebook_path: Path, timeout: int = 300) -> bool: + """ + Execute a single notebook with papermill. + + Args: + notebook_path: Path to notebook to execute + timeout: Execution timeout in seconds + + Returns: + True if successful, raises exception if failed + """ + with tempfile.NamedTemporaryFile(suffix='.ipynb', delete=False) as tmp_file: + output_path = Path(tmp_file.name) + + try: + pm.execute_notebook( + input_path=str(notebook_path), + output_path=str(output_path), + parameters=get_test_parameters(), + timeout=timeout, + kernel_name="python3" + ) + return True + except Exception as e: + raise Exception(f"Notebook execution failed: {str(e)}") from e + finally: + if output_path.exists(): + output_path.unlink() + + +@pytest.mark.parametrize("notebook_path", get_notebook_files()) +def test_notebook_executes_without_error(notebook_path): + """Test that each notebook executes without errors.""" + + # Skip backup/duplicate files + if any(skip in str(notebook_path) for skip in ["copy.ipynb", ".checkpoint"]): + pytest.skip(f"Skipping backup/checkpoint file: {notebook_path}") + + # Execute the notebook + success = execute_single_notebook(notebook_path, timeout=300) + assert success, f"Failed to execute notebook: {notebook_path}" + + +def test_notebooks_directory_exists(): + """Verify the notebooks directory exists and contains files.""" + notebooks = get_notebook_files() + assert len(notebooks) > 0, "No notebook files found in notebooks directory" + + for notebook in notebooks: + assert notebook.exists(), f"Notebook file does not exist: {notebook}" + assert notebook.suffix == '.ipynb', f"File is not a notebook: {notebook}" + + +if __name__ == "__main__": + # Allow running directly for testing + import sys + + if len(sys.argv) > 1: + notebook_file = Path(sys.argv[1]) + if notebook_file.exists(): + print(f"Testing {notebook_file}...") + try: + execute_single_notebook(notebook_file) + print("✅ Success!") + except Exception as e: + print(f"❌ Failed: {e}") + sys.exit(1) + else: + print("Usage: python test_notebook_execution.py ") From 770fec65f8d8baabed71ce1ee4ec267ec755ca16 Mon Sep 17 00:00:00 2001 From: Shruthi Sankepelly Date: Mon, 17 Nov 2025 10:51:30 -0500 Subject: [PATCH 2/3] Modify to run the workflow on pull request --- .github/workflows/execute-all-notebooks.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/execute-all-notebooks.yml b/.github/workflows/execute-all-notebooks.yml index aa982fa..4dc67d4 100644 --- a/.github/workflows/execute-all-notebooks.yml +++ b/.github/workflows/execute-all-notebooks.yml @@ -11,6 +11,11 @@ on: description: "Pull request number or branch name" required: true default: "main" + pull_request: + types: [opened, synchronize, reopened] + paths: + - "notebooks/**/*.ipynb" + - ".github/workflows/execute-all-notebooks.yml" env: INSTANCE_TYPE: "g6e.xlarge" From 34675026e75f0bf4b8e62fcbc212710822172fbb Mon Sep 17 00:00:00 2001 From: Shruthi Sankepelly Date: Mon, 17 Nov 2025 11:28:53 -0500 Subject: [PATCH 3/3] Update GitHub Actions workflow to trigger on push events for notebook execution --- .github/workflows/execute-all-notebooks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/execute-all-notebooks.yml b/.github/workflows/execute-all-notebooks.yml index 4dc67d4..0fecf40 100644 --- a/.github/workflows/execute-all-notebooks.yml +++ b/.github/workflows/execute-all-notebooks.yml @@ -16,7 +16,7 @@ on: paths: - "notebooks/**/*.ipynb" - ".github/workflows/execute-all-notebooks.yml" - + push: env: INSTANCE_TYPE: "g6e.xlarge"