Skip to content

Commit b6c34d9

Browse files
TMHSDigitalclaude
andcommitted
feat(ci): weekly non-gating smoke against Blender daily builds
The pack learned about a Blender API break only after a release shipped. blender-next.yml resolves every linux x86_64 daily build newer than the newest stable from builder.blender.org's JSON listing (today 5.3.0-beta and 5.4.0-alpha), verifies each against its published sha256, and runs the smoke catalog (happy paths and falsifiers) under xvfb. Failing rows go into one 'Blender X.Y compatibility (daily builds)' issue per series, which the job closes again once that build is green. Nothing here gates a PR or a release. A version moves into blender-smoke.yml once it ships. Closes #457 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com>
1 parent ea56f39 commit b6c34d9

2 files changed

Lines changed: 156 additions & 1 deletion

File tree

‎.github/workflows/blender-next.yml‎

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
name: Blender next (daily builds)
2+
3+
# Smokes the shipped examples against Blender's in-development daily builds
4+
# (beta and alpha, from builder.blender.org), so an API break in the next
5+
# release becomes a dated tracking issue before users hit it (#457).
6+
# Non-gating: nothing here blocks a PR or a release, and upstream instability
7+
# only updates the issue. When a version reaches release, the regular
8+
# blender-smoke.yml matrix takes it over (as 5.1 and 5.2 were).
9+
10+
on:
11+
workflow_dispatch:
12+
schedule:
13+
- cron: "0 9 * * 3" # weekly, Wednesday 09:00 UTC
14+
15+
permissions:
16+
contents: read
17+
18+
concurrency:
19+
group: blender-next
20+
cancel-in-progress: true
21+
22+
jobs:
23+
resolve:
24+
name: Resolve daily builds newer than the newest stable
25+
runs-on: ubuntu-latest
26+
timeout-minutes: 5
27+
outputs:
28+
builds: ${{ steps.pick.outputs.builds }}
29+
steps:
30+
- id: pick
31+
run: |
32+
set -euo pipefail
33+
curl -fsSL -A "blender-developer-tools-ci" \
34+
"https://builder.blender.org/download/daily/?format=json&v=1" -o daily.json
35+
python3 - <<'PYEOF'
36+
import json, os
37+
38+
def key(v):
39+
return tuple(int(p) for p in v.split("."))
40+
41+
rows = [r for r in json.load(open("daily.json"))
42+
if r.get("platform") == "linux" and r.get("architecture") == "x86_64"
43+
and r.get("file_extension") == "xz"]
44+
stable = max((key(r["version"]) for r in rows if r["risk_id"] == "stable"), default=(0,))
45+
nxt = sorted((r for r in rows if r["risk_id"] != "stable" and key(r["version"]) > stable),
46+
key=lambda r: key(r["version"]))
47+
builds = [{"version": r["version"], "risk": r["risk_id"],
48+
"series": ".".join(r["version"].split(".")[:2]), "url": r["url"]} for r in nxt]
49+
print(f"newest stable {'.'.join(map(str, stable))}; next: "
50+
f"{[b['version'] + '-' + b['risk'] for b in builds] or 'none'}")
51+
with open(os.environ["GITHUB_OUTPUT"], "a") as fh:
52+
fh.write(f"builds={json.dumps(builds)}\n")
53+
PYEOF
54+
55+
smoke:
56+
name: Blender ${{ matrix.build.version }}-${{ matrix.build.risk }} smoke
57+
needs: resolve
58+
if: needs.resolve.outputs.builds != '[]'
59+
runs-on: ubuntu-latest
60+
timeout-minutes: 75
61+
strategy:
62+
fail-fast: false
63+
matrix:
64+
build: ${{ fromJSON(needs.resolve.outputs.builds) }}
65+
permissions:
66+
contents: read
67+
issues: write
68+
steps:
69+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
70+
71+
- name: Install Blender runtime libraries
72+
run: |
73+
set -euo pipefail
74+
sudo apt-get update
75+
sudo apt-get install -y --no-install-recommends \
76+
xvfb libgl1 libegl1 libxrender1 libxxf86vm1 libxfixes3 libxi6 \
77+
libxkbcommon0 libsm6 libice6
78+
79+
- name: Download the daily build and verify its sha256
80+
env:
81+
URL: ${{ matrix.build.url }}
82+
run: |
83+
set -euo pipefail
84+
mkdir -p "$RUNNER_TEMP/bl"
85+
curl -fSL --retry 3 -A "blender-developer-tools-ci" -o "$RUNNER_TEMP/bl.tar.xz" "$URL"
86+
expected=$(curl -fsSL --retry 3 -A "blender-developer-tools-ci" "$URL.sha256" | awk '{print $1}')
87+
[ -n "$expected" ] || { echo "::error::no sha256 published for $URL"; exit 1; }
88+
echo "${expected} $RUNNER_TEMP/bl.tar.xz" | sha256sum -c - \
89+
|| { echo "::error::sha256 mismatch for $URL; refusing to extract"; exit 1; }
90+
tar -xf "$RUNNER_TEMP/bl.tar.xz" -C "$RUNNER_TEMP/bl"
91+
bl=$(find "$RUNNER_TEMP/bl" -maxdepth 2 -type f -name blender | head -1)
92+
[ -n "$bl" ] || { echo "::error::blender binary not found"; exit 1; }
93+
"$bl" --version | head -1
94+
echo "BLENDER=$bl" >> "$GITHUB_ENV"
95+
echo "BDT_SMOKE_STATUS=$RUNNER_TEMP/smoke-status.jsonl" >> "$GITHUB_ENV"
96+
: > "$RUNNER_TEMP/smoke-status.jsonl"
97+
98+
- name: Shipped examples (happy paths and falsifiers)
99+
id: catalog
100+
continue-on-error: true
101+
run: |
102+
set -euo pipefail
103+
mkdir -p "$RUNNER_TEMP/out"
104+
python3 tests/smoke/run_catalog.py \
105+
--blender "$BLENDER" \
106+
--series "${{ matrix.build.series }}" \
107+
--status "$BDT_SMOKE_STATUS" \
108+
--out "$RUNNER_TEMP/out" \
109+
--xvfb \
110+
--catalog tests/smoke/catalog.json
111+
112+
- name: Summary
113+
id: summary
114+
continue-on-error: true
115+
run: python3 tests/smoke/summarize.py --status "$BDT_SMOKE_STATUS"
116+
117+
- name: Update the tracking issue
118+
env:
119+
GH_TOKEN: ${{ github.token }}
120+
GH_REPO: ${{ github.repository }}
121+
VERSION: ${{ matrix.build.version }}
122+
RISK: ${{ matrix.build.risk }}
123+
SERIES: ${{ matrix.build.series }}
124+
OUTCOME: ${{ steps.catalog.outcome }}
125+
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
126+
run: |
127+
set -euo pipefail
128+
failed=$(python3 - <<'PYEOF'
129+
import json, os
130+
rows = [json.loads(l) for l in open(os.environ["BDT_SMOKE_STATUS"]) if l.strip()]
131+
bad = [r for r in rows if r.get("status") == "FAIL"]
132+
for r in bad:
133+
kind = "falsifier" if r.get("falsifier") else "happy path"
134+
print(f"- `{r['name']}` ({kind}): {str(r.get('detail', ''))[:200]}")
135+
PYEOF
136+
)
137+
if [ -z "$failed" ] && [ "$OUTCOME" != "success" ]; then
138+
failed="- the catalog run itself failed before recording a FAIL row; see the run log"
139+
fi
140+
title="Blender $SERIES compatibility (daily builds)"
141+
num=$(gh issue list --state open --search "\"$title\" in:title" --json number --jq '.[0].number // empty')
142+
if [ -n "$failed" ]; then
143+
body="Daily build **$VERSION-$RISK**, run: $RUN_URL
144+
145+
Failing catalog rows:
146+
$failed
147+
148+
Non-gating; opened by blender-next.yml (#457). Fix the example or the skill when the change is intended upstream, or report it to Blender when it is a regression."
149+
if [ -n "$num" ]; then gh issue comment "$num" --body "$body"
150+
else gh issue create --title "$title" --body "$body" --label "ci,testing,priority: medium"; fi
151+
elif [ -n "$num" ]; then
152+
gh issue comment "$num" --body "Daily build **$VERSION-$RISK** is green again ($RUN_URL); closing."
153+
gh issue close "$num"
154+
fi
155+
echo "catalog outcome: $OUTCOME"

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ Releases ship often; [CHANGELOG.md](CHANGELOG.md) lists what each one changed.
125125
| Blender 5.1 | Prior stable (weekly cron; PR via `needs-5.1` or manual dispatch) |
126126
| Blender 4.5 LTS | Fallback supported (skills show both code paths where 4.x and 5.x APIs diverge) |
127127

128-
**Support policy.** The current LTS and the previous LTS are smoke-tested on every pull request and every push to `main`; the newest non-LTS stable runs on the weekly cron. When a new LTS ships, it becomes the primary target and the older of the two supported LTS lines leaves support in a release whose notes say so. Its code paths stay in the skills for that release, then go. CI follows the highest point release of each series, so a fix in a point release reaches the checks without a change here.
128+
**Support policy.** The current LTS and the previous LTS are smoke-tested on every pull request and every push to `main`; the newest non-LTS stable runs on the weekly cron. When a new LTS ships, it becomes the primary target and the older of the two supported LTS lines leaves support in a release whose notes say so. Its code paths stay in the skills for that release, then go. CI follows the highest point release of each series, so a fix in a point release reaches the checks without a change here. Every week the examples also run against Blender's in-development daily builds (beta and alpha), and a failure there updates a "Blender X.Y compatibility" issue without blocking anything, so an upcoming API break is tracked before that version ships.
129129

130130
## Falsifiers
131131

0 commit comments

Comments
 (0)