From 568b8705e7add97679cb439a2cb6d9a4952d0778 Mon Sep 17 00:00:00 2001 From: Jammy2211 Date: Wed, 24 Jun 2026 13:16:34 +0100 Subject: [PATCH] workspace-validation: add generate_notebooks + run_notebooks (full parity) Pulse now covers Build's full scripts+notebooks validation signal. generate_notebooks converts each of the 6 doc workspaces' scripts to .ipynb (Build's generate.py); run_notebooks executes them against the libraries' current source main (same source-shadow + nufftax install as run_scripts), gated to skip *_test workspaces (no notebooks). analyze now aggregates both results-scripts-* and results-notebooks-* into report.json. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/workspace-validation.yml | 145 ++++++++++++++++++++- 1 file changed, 139 insertions(+), 6 deletions(-) diff --git a/.github/workflows/workspace-validation.yml b/.github/workflows/workspace-validation.yml index 4be04d3..9489b49 100644 --- a/.github/workflows/workspace-validation.yml +++ b/.github/workflows/workspace-validation.yml @@ -3,11 +3,12 @@ name: Workspace Validation # Pulse-owned workspace-integration validation (Stage 4 Phase B). # # This is the "heavy validation CI" that used to live in PyAutoBuild's -# release.yml (find_scripts / run_scripts / analyze_results). Pulse owns it now: -# Build is a pure executor. It runs every workspace's scripts against the CURRENT -# source `main` of the 5 libraries (source-shadowed via PYTHONPATH), aggregates -# into the same report.json contract, and uploads it as the -# `workspace-validation-report` artifact. Pulse's test_run check reads that run's +# release.yml (find_scripts / generate_notebooks / run_scripts / run_notebooks / +# analyze_results). Pulse owns it now: Build is a pure executor. It runs every +# workspace's scripts AND generated notebooks against the CURRENT source `main` +# of the 5 libraries (source-shadowed via PYTHONPATH), aggregates into the same +# report.json contract, and uploads it as the `workspace-validation-report` +# artifact. Pulse's test_run check reads that run's # conclusion + timestamp into the authoritative `readiness` verdict (with a # staleness window). # @@ -64,6 +65,52 @@ jobs: howtogalaxy howtolens howtofit)" echo "matrix=$matrix" >> "$GITHUB_OUTPUT" + generate_notebooks: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + # Notebooks exist only for the 6 doc workspaces (the *_test workspaces + # publish none). generate.py just converts scripts → .ipynb (no lib run). + project: + - { name: autofit, workspace: autofit_workspace } + - { name: autogalaxy, workspace: autogalaxy_workspace } + - { name: autolens, workspace: autolens_workspace } + - { name: howtogalaxy, workspace: HowToGalaxy } + - { name: howtolens, workspace: HowToLens } + - { name: howtofit, workspace: HowToFit } + steps: + - name: Checkout PyAutoBuild (generate.py) + uses: actions/checkout@v4 + with: + repository: PyAutoLabs/PyAutoBuild + path: PyAutoBuild + - name: Checkout workspace + uses: actions/checkout@v4 + with: + repository: PyAutoLabs/${{ matrix.project.workspace }} + ref: main + path: workspace + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: pip + - name: Install notebook tooling + run: pip install jupyter ipynb-py-convert PyYAML + - name: Generate notebooks + run: | + export PYTHONPATH="$PYTHONPATH:$(pwd)/PyAutoBuild" + pushd workspace + python3 "$(pwd)/../PyAutoBuild/autobuild/generate.py" "${{ matrix.project.name }}" + - name: Upload generated notebooks + if: always() + uses: actions/upload-artifact@v4 + with: + name: notebooks-${{ matrix.project.name }} + path: workspace/notebooks/ + retention-days: 7 + run_scripts: runs-on: ubuntu-latest needs: find_scripts @@ -138,9 +185,95 @@ jobs: path: workspace/test-results/ retention-days: 30 + run_notebooks: + runs-on: ubuntu-latest + needs: [find_scripts, generate_notebooks] + strategy: + fail-fast: false + matrix: + python-version: ["3.12"] + project: ${{ fromJSON(needs.find_scripts.outputs.matrix) }} + steps: + - name: Gate (*_test workspaces have no notebooks) + id: gate + run: | + if [[ "${{ matrix.project.name }}" == *_test ]]; then + echo "run=false" >> "$GITHUB_OUTPUT" + else + echo "run=true" >> "$GITHUB_OUTPUT" + fi + - name: Checkout PyAutoBuild (run primitives) + if: steps.gate.outputs.run == 'true' + uses: actions/checkout@v4 + with: + repository: PyAutoLabs/PyAutoBuild + path: PyAutoBuild + - name: Resolve workspace repo + if: steps.gate.outputs.run == 'true' + id: ws + run: | + case "${{ matrix.project.name }}" in + autofit) echo "repo=autofit_workspace" >> "$GITHUB_OUTPUT" ;; + autogalaxy) echo "repo=autogalaxy_workspace" >> "$GITHUB_OUTPUT" ;; + autolens) echo "repo=autolens_workspace" >> "$GITHUB_OUTPUT" ;; + howtogalaxy) echo "repo=HowToGalaxy" >> "$GITHUB_OUTPUT" ;; + howtolens) echo "repo=HowToLens" >> "$GITHUB_OUTPUT" ;; + howtofit) echo "repo=HowToFit" >> "$GITHUB_OUTPUT" ;; + *) echo "repo=autolens_workspace" >> "$GITHUB_OUTPUT" ;; + esac + - name: Checkout workspace + if: steps.gate.outputs.run == 'true' + uses: actions/checkout@v4 + with: + repository: PyAutoLabs/${{ steps.ws.outputs.repo }} + ref: main + path: workspace + - name: Checkout libraries (source-shadowed via PYTHONPATH) + if: steps.gate.outputs.run == 'true' + run: | + set -e + for lib in PyAutoConf PyAutoArray PyAutoFit PyAutoGalaxy PyAutoLens; do + git clone --depth 1 "https://github.com/PyAutoLabs/$lib" "libs/$lib" + done + - name: Download generated notebooks + if: steps.gate.outputs.run == 'true' + uses: actions/download-artifact@v4 + with: + name: notebooks-${{ matrix.project.name }} + path: workspace/notebooks/ + - name: Set up Python ${{ matrix.python-version }} + if: steps.gate.outputs.run == 'true' + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + cache: pip + - name: Install deps (libs from source) + jupyter + if: steps.gate.outputs.run == 'true' + run: | + pip install "autolens[optional]" + pip install "jax>=0.7,<0.11" "jaxlib>=0.7,<0.11" + pip install "nufftax>=0.4.0,<0.5.0" + pip install jupyter ipynb-py-convert + - name: Run notebooks + if: steps.gate.outputs.run == 'true' + run: | + LIBS="$(pwd)/libs" + export PYTHONPATH="$LIBS/PyAutoConf:$LIBS/PyAutoArray:$LIBS/PyAutoFit:$LIBS/PyAutoGalaxy:$LIBS/PyAutoLens:$(pwd)/PyAutoBuild:$PYTHONPATH" + pushd workspace + python3 "$(pwd)/../PyAutoBuild/autobuild/run.py" \ + "${{ matrix.project.name }}" "notebooks/${{ matrix.project.directory }}" \ + --report-dir test-results + - name: Upload notebook results + if: always() && steps.gate.outputs.run == 'true' + uses: actions/upload-artifact@v4 + with: + name: results-notebooks-${{ matrix.project.name }}-${{ matrix.project.directory }} + path: workspace/test-results/ + retention-days: 30 + analyze: runs-on: ubuntu-latest - needs: run_scripts + needs: [run_scripts, run_notebooks] if: always() steps: - name: Checkout PyAutoBuild (aggregate_results)