fix: polish the four newest examples #39
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Blender Smoke Test | |
| # Executes the snippets' and skills' headline examples inside REAL Blender, headless, | |
| # on the current stable (5.1.x) and the active LTS (4.5.x), and fails on any error or | |
| # empty-output assertion. py_compile (in validate.yml) cannot catch API-level regressions | |
| # like the EEVEE-id inversion, the slotted-actions boundary, the driver TypeError, or the | |
| # dead SDF link -- this gate runs the code so those surface in CI, not in users' files. | |
| on: | |
| workflow_dispatch: {} | |
| schedule: | |
| - cron: "0 7 * * 1" # weekly, Monday 07:00 UTC | |
| pull_request: | |
| branches: [main] | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: blender-smoke-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| smoke: | |
| name: Blender ${{ matrix.series }} smoke | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - series: "5.1" # current stable | |
| - series: "4.5" # active LTS | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Install Blender runtime libraries | |
| run: | | |
| set -euo pipefail | |
| sudo apt-get update | |
| # Blender needs these shared libs even in --background (GPU/GL module init); | |
| # xvfb provides a virtual display so GL/EGL init does not abort the process. | |
| sudo apt-get install -y --no-install-recommends \ | |
| xvfb libgl1 libegl1 libxrender1 libxxf86vm1 libxfixes3 libxi6 \ | |
| libxkbcommon0 libsm6 libice6 | |
| - name: Resolve and download Blender ${{ matrix.series }} | |
| run: | | |
| set -euo pipefail | |
| series="${{ matrix.series }}" | |
| base="https://download.blender.org/release/Blender${series}/" | |
| echo "Listing $base" | |
| # pick the highest point release for this series (linux x64 portable) | |
| file=$(curl -fsSL "$base" \ | |
| | grep -oE "blender-${series}\.[0-9]+-linux-x64\.tar\.xz" \ | |
| | sort -V | uniq | tail -1) | |
| if [ -z "$file" ]; then | |
| echo "::error::Could not resolve a linux-x64 build for Blender ${series} at $base" | |
| exit 1 | |
| fi | |
| url="${base}${file}" | |
| echo "Downloading $url" | |
| mkdir -p "$RUNNER_TEMP/bl" | |
| curl -fSL --retry 3 -o "$RUNNER_TEMP/bl.tar.xz" "$url" | |
| tar -xf "$RUNNER_TEMP/bl.tar.xz" -C "$RUNNER_TEMP/bl" | |
| bl=$(find "$RUNNER_TEMP/bl" -maxdepth 2 -type f -name blender | head -1) | |
| if [ -z "$bl" ]; then | |
| echo "::error::blender binary not found after extraction" | |
| exit 1 | |
| fi | |
| echo "BLENDER=$bl" >> "$GITHUB_ENV" | |
| - name: Print Blender version | |
| run: | | |
| set -euo pipefail | |
| "$BLENDER" --version | head -1 | |
| # series guard: confirm we actually got the matrix series | |
| "$BLENDER" --version | head -1 | grep -q "Blender ${{ matrix.series }}\." \ | |
| || { echo "::error::version does not match series ${{ matrix.series }}"; exit 1; } | |
| - name: Run in-Blender smoke driver | |
| run: | | |
| set -euo pipefail | |
| mkdir -p "$RUNNER_TEMP/out" | |
| xvfb-run -a "$BLENDER" --background --python tests/smoke/run_smoke.py -- "$RUNNER_TEMP/out" | |
| - name: Build template input scene | |
| run: | | |
| set -euo pipefail | |
| xvfb-run -a "$BLENDER" --background --python tests/smoke/make_input.py -- "$RUNNER_TEMP/out/input.blend" | |
| - name: Headless glTF template runs (exit 0, .glb produced) | |
| run: | | |
| set -euo pipefail | |
| xvfb-run -a "$BLENDER" --background "$RUNNER_TEMP/out/input.blend" \ | |
| --python tests/smoke/tmpl_gltf.py -- \ | |
| --output "$RUNNER_TEMP/out/out.glb" --apply-modifier SUBSURF | |
| test -s "$RUNNER_TEMP/out/out.glb" || { echo "::error::glTF output missing/empty"; exit 1; } | |
| head -c4 "$RUNNER_TEMP/out/out.glb" | grep -q "glTF" || { echo "::error::not a glTF binary"; exit 1; } | |
| - name: Headless template no-mesh path returns exit 2 | |
| run: | | |
| set +e | |
| xvfb-run -a "$BLENDER" --background "$RUNNER_TEMP/out/empty.blend" \ | |
| --python tests/smoke/tmpl_gltf.py -- --output "$RUNNER_TEMP/out/none.glb" | |
| code=$? | |
| set -e | |
| [ "$code" -eq 2 ] || { echo "::error::expected exit 2 for no-mesh input, got $code"; exit 1; } | |
| echo "no-mesh exit code = $code (correct)" | |
| - name: Headless render template runs (exit 0, PNG produced) | |
| run: | | |
| set -euo pipefail | |
| # Cycles (CPU) so this is reliable on GPU-less runners; the EEVEE-id regression | |
| # itself is gated in run_smoke.py via engine assignment. | |
| xvfb-run -a "$BLENDER" --background "$RUNNER_TEMP/out/input.blend" \ | |
| --python tests/smoke/tmpl_render.py -- \ | |
| --output "$RUNNER_TEMP/out/render.png" --engine CYCLES | |
| test -s "$RUNNER_TEMP/out/render.png" || { echo "::error::render PNG missing/empty"; exit 1; } | |
| - name: Shipped example - swatch grid renders and self-verifies | |
| run: | | |
| set -euo pipefail | |
| # Run the SHIPPED example file (not a copy). It asserts non-black AND | |
| # distinct-region-count == material-count internally and exits non-zero on | |
| # failure. Cycles (CPU) for pixels on the GPU-less runner; the example still | |
| # asserts the version-correct EEVEE engine id before rendering. Small/low-sample | |
| # for speed -- region detection holds at this size. | |
| xvfb-run -a "$BLENDER" --background \ | |
| --python examples/swatch-grid/swatch_grid.py -- \ | |
| --output "$RUNNER_TEMP/out/swatch.png" --engine cycles --samples 8 --width 640 | |
| test -s "$RUNNER_TEMP/out/swatch.png" || { echo "::error::swatch grid output missing/empty"; exit 1; } | |
| - name: Shipped example - turntable correctness (slotted actions) | |
| run: | | |
| set -euo pipefail | |
| # Frame-independent check only (no render): asserts the rotation keys drive | |
| # playback via the cross-version channelbag path; exits non-zero on failure. | |
| xvfb-run -a "$BLENDER" --background \ | |
| --python examples/turntable/turntable.py -- | |
| - name: Shipped example - GN SDF remesh correctness (GridToMesh) | |
| run: | | |
| set -euo pipefail | |
| # Frame-independent check only (no render): asserts the SDF->GridToMesh remesh | |
| # yields geometry (eval vcount > 0 and != base); exits non-zero on failure. | |
| xvfb-run -a "$BLENDER" --background \ | |
| --python examples/gn-sdf-remesh/gn_sdf_remesh.py -- | |
| - name: Shipped example - depsgraph-evaluated export | |
| run: | | |
| set -euo pipefail | |
| # Frame-independent check only (no render): asserts wm.obj_export ships the | |
| # depsgraph-evaluated (modifier-applied) geometry -- exported vcount == evaluated | |
| # > base. Exits non-zero on failure. | |
| xvfb-run -a "$BLENDER" --background \ | |
| --python examples/depsgraph-export/depsgraph_export.py -- | |
| - name: Shipped example - wave displace (foreach bulk IO) | |
| run: | | |
| set -euo pipefail | |
| # Frame-independent check only (no render): 9409 verts displaced via one | |
| # foreach_get + one foreach_set; asserts count unchanged, Z span matches the | |
| # amplitude, and a probe vertex matches the closed-form wave. Exits non-zero | |
| # on failure. | |
| xvfb-run -a "$BLENDER" --background \ | |
| --python examples/wave-displace/wave_displace.py -- | |
| - name: Shipped example - driver wave (driver_namespace + depsgraph) | |
| run: | | |
| set -euo pipefail | |
| # Frame-independent check only (no render): sixteen SCRIPTED drivers call a | |
| # driver_namespace function; asserts the driven values on the evaluated copy | |
| # AND the flushed-back original both match the closed form. Exits non-zero | |
| # on failure. | |
| xvfb-run -a "$BLENDER" --background \ | |
| --python examples/driver-wave/driver_wave.py -- | |
| - name: Shipped example - bmesh gear (ownership + watertight topology) | |
| run: | | |
| set -euo pipefail | |
| # Frame-independent check only (no render): parametric gear via bmesh with | |
| # bm.free() in try/finally; asserts closed-form vert/edge/face counts and | |
| # that every edge borders exactly two faces. Exits non-zero on failure. | |
| xvfb-run -a "$BLENDER" --background \ | |
| --python examples/bmesh-gear/bmesh_gear.py -- | |
| - name: Shipped example - shader node group (interface sockets + sharing) | |
| run: | | |
| set -euo pipefail | |
| # Frame-independent check only (no render): TintedGloss group declared via | |
| # tree.interface.new_socket, instanced by two materials; asserts the sockets | |
| # exist, the group datablock is shared (users == 2), and the per-instance | |
| # Tint values differ. Exits non-zero on failure. | |
| xvfb-run -a "$BLENDER" --background \ | |
| --python examples/shader-node-group/shader_node_group.py -- | |
| - name: Shipped example - temp-override join (context override) | |
| run: | | |
| set -euo pipefail | |
| # Frame-independent check only (no render): three-step staircase joined under | |
| # bpy.context.temp_override; asserts one mesh remains, sources are gone, | |
| # topology verts=24 faces=18, and local Z spans all steps. Exits non-zero | |
| # on failure. | |
| xvfb-run -a "$BLENDER" --background \ | |
| --python examples/temp-override-join/temp_override_join.py -- | |
| - name: Shipped example - GN instance grid (Instance on Points) | |
| run: | | |
| set -euo pipefail | |
| # Frame-independent check only (no render): generative GN tree instances a | |
| # cube on a 3x3 grid and realizes; asserts eval verts=72 faces=54, Set | |
| # Material carries Lime, and corner center matches the grid. Exits non-zero | |
| # on failure. | |
| xvfb-run -a "$BLENDER" --background \ | |
| --python examples/gn-instance-grid/gn_instance_grid.py -- | |
| - name: Shipped example - shape-key blend (data API + evaluated mesh) | |
| run: | | |
| set -euo pipefail | |
| # Frame-independent check only (no render): relative Tall key lifts+flares | |
| # at value=0.5; asserts undeformed mesh stays at Basis and every evaluated | |
| # vert matches basis + value*(key-basis). Exits non-zero on failure. | |
| xvfb-run -a "$BLENDER" --background \ | |
| --python examples/shape-key-blend/shape_key_blend.py -- | |
| - name: Shipped example - curve bevel arc (Bezier + bevel_depth) | |
| run: | | |
| set -euo pipefail | |
| # Frame-independent check only (no render): beveled Bezier semicircle via | |
| # curve data API; asserts 8 points, bevel_depth=0.15, fill caps, eval | |
| # verts=1044 faces=1028, tube rests on floor. Exits non-zero on failure. | |
| xvfb-run -a "$BLENDER" --background \ | |
| --python examples/curve-bevel-arc/curve_bevel_arc.py -- |