ci(web): replace wasm freshness gate with CI-side rebuild-and-commit
The rebuild-and-diff freshness gate (#93) could never pass: the Bevy wasm artifacts aren't byte-reproducible across machines. Confirmed conclusively — identical rustc 1.95.0 / LLVM 22.1.2, identical flags, Cargo.lock and remapped source paths still yield host-dependent output (CI's build was 248 KB smaller than a local one), while same-machine rebuilds are bit-identical. Path remapping (kept in build_wasm.sh) is necessary but not sufficient. Make CI the single source of truth instead: `web-wasm-rebuild` rebuilds pkg/ on every master change to a wasm-feeding crate and commits it back. The deployed artifacts can't silently rot and contributors no longer hand-run build_wasm.sh. The pkg/ commit isn't in this workflow's trigger paths (no loop) but is in docker-build's, so the refreshed wasm deploys. Removes the false-failing web-wasm-freshness workflow. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -36,12 +36,12 @@ jobs:
|
|||||||
id: meta
|
id: meta
|
||||||
run: echo "sha=${GITHUB_SHA::8}" >> "$GITHUB_OUTPUT"
|
run: echo "sha=${GITHUB_SHA::8}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
# WASM artifact freshness is enforced precisely by the dedicated
|
# WASM artifact freshness is owned by the `web-wasm-rebuild` workflow,
|
||||||
# `web-wasm-freshness` workflow (rebuild-and-diff on every PR + master
|
# which rebuilds pkg/ in CI on every master change to a wasm-feeding crate
|
||||||
# push), which supersedes the previous changed-files heuristic here.
|
# and commits it back (CI is the single source of truth — the artifacts
|
||||||
# That heuristic only hard-failed on direct solitaire_web/ edits and
|
# aren't byte-reproducible on contributor machines). That pkg/ commit then
|
||||||
# treated solitaire_engine/_core changes as a non-blocking notice, which
|
# triggers this workflow, so the deployed image always ships fresh wasm.
|
||||||
# let the whole card_game migration ship a stale pkg/.
|
# No drift check is needed here.
|
||||||
|
|
||||||
- name: Log in to Gitea registry
|
- name: Log in to Gitea registry
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
name: Web WASM Freshness
|
|
||||||
|
|
||||||
# Guards against the committed solitaire_server/web/pkg/ artifacts going stale.
|
|
||||||
#
|
|
||||||
# A fresh build on a pinned toolchain is byte-for-byte reproducible (verified),
|
|
||||||
# so this job rebuilds the artifacts and fails if they differ from what is
|
|
||||||
# committed. Unlike a changed-files heuristic, this catches *any* drift in the
|
|
||||||
# wasm-feeding crates — solitaire_core / _engine / _data / _sync / _wasm / _web —
|
|
||||||
# including gameplay-logic changes that do not alter the JS API surface (e.g.
|
|
||||||
# the v4->v5 save-schema change that the old heuristic let through as a
|
|
||||||
# non-blocking "notice", leaving the deployed web build stale for ~3 weeks).
|
|
||||||
#
|
|
||||||
# Tool versions are pinned to whatever produced the committed artifacts. When
|
|
||||||
# you regenerate the artifacts with a newer toolchain, bump these in lockstep:
|
|
||||||
# rust 1.95.0 · wasm-bindgen 0.2.120 · wasm-pack 0.14.0 · binaryen 130
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [master]
|
|
||||||
paths:
|
|
||||||
- 'solitaire_core/**'
|
|
||||||
- 'solitaire_engine/**'
|
|
||||||
- 'solitaire_data/**'
|
|
||||||
- 'solitaire_sync/**'
|
|
||||||
- 'solitaire_wasm/**'
|
|
||||||
- 'solitaire_web/**'
|
|
||||||
- 'solitaire_server/web/pkg/**'
|
|
||||||
- 'Cargo.toml'
|
|
||||||
- 'Cargo.lock'
|
|
||||||
- 'build_wasm.sh'
|
|
||||||
- '.gitea/workflows/web-wasm-freshness.yml'
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- 'solitaire_core/**'
|
|
||||||
- 'solitaire_engine/**'
|
|
||||||
- 'solitaire_data/**'
|
|
||||||
- 'solitaire_sync/**'
|
|
||||||
- 'solitaire_wasm/**'
|
|
||||||
- 'solitaire_web/**'
|
|
||||||
- 'solitaire_server/web/pkg/**'
|
|
||||||
- 'Cargo.toml'
|
|
||||||
- 'Cargo.lock'
|
|
||||||
- 'build_wasm.sh'
|
|
||||||
- '.gitea/workflows/web-wasm-freshness.yml'
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
freshness:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install Rust 1.95.0 (pinned for reproducible wasm output)
|
|
||||||
uses: dtolnay/rust-toolchain@master
|
|
||||||
with:
|
|
||||||
toolchain: 1.95.0
|
|
||||||
targets: wasm32-unknown-unknown
|
|
||||||
|
|
||||||
- name: Cache cargo build
|
|
||||||
uses: Swatinem/rust-cache@v2
|
|
||||||
|
|
||||||
- name: Install wasm-bindgen-cli + wasm-pack (pinned)
|
|
||||||
uses: taiki-e/install-action@v2
|
|
||||||
with:
|
|
||||||
tool: wasm-bindgen-cli@0.2.120,wasm-pack@0.14.0
|
|
||||||
|
|
||||||
- name: Install binaryen 130 (wasm-opt, pinned)
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
curl -sSL \
|
|
||||||
https://github.com/WebAssembly/binaryen/releases/download/version_130/binaryen-version_130-x86_64-linux.tar.gz \
|
|
||||||
| tar xz
|
|
||||||
echo "$PWD/binaryen-version_130/bin" >> "$GITHUB_PATH"
|
|
||||||
|
|
||||||
- name: Rebuild WASM artifacts
|
|
||||||
run: ./build_wasm.sh
|
|
||||||
|
|
||||||
- name: Fail if committed pkg differs from a fresh build
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
if [ -z "$(git status --porcelain -- solitaire_server/web/pkg/)" ]; then
|
|
||||||
echo "pkg/ artifacts match a fresh build."
|
|
||||||
else
|
|
||||||
echo "::error::solitaire_server/web/pkg/ is stale — a wasm-feeding crate changed without regenerating the artifacts."
|
|
||||||
echo "Fix: run ./build_wasm.sh and commit the updated solitaire_server/web/pkg/."
|
|
||||||
git status --porcelain -- solitaire_server/web/pkg/
|
|
||||||
git diff --stat -- solitaire_server/web/pkg/
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
name: Web WASM Rebuild
|
||||||
|
|
||||||
|
# CI is the single source of truth for solitaire_server/web/pkg/.
|
||||||
|
#
|
||||||
|
# The wasm artifacts cannot be reproduced byte-for-byte on an arbitrary
|
||||||
|
# contributor machine: even with identical rustc 1.95.0 / LLVM 22.1.2, the same
|
||||||
|
# flags, the same Cargo.lock and remapped source paths, the output still differs
|
||||||
|
# by host environment. So rather than police freshness with a rebuild-and-diff
|
||||||
|
# gate (which false-failed for exactly that reason), CI rebuilds the artifacts
|
||||||
|
# itself on every master change to a wasm-feeding crate and commits them back.
|
||||||
|
#
|
||||||
|
# Result: the deployed pkg/ can't silently rot, and contributors never need to
|
||||||
|
# run build_wasm.sh by hand. The commit touches only pkg/, which is not in this
|
||||||
|
# workflow's trigger paths (so it does not re-trigger here) but does match
|
||||||
|
# docker-build's, so the refreshed wasm deploys.
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
paths:
|
||||||
|
- 'solitaire_core/**'
|
||||||
|
- 'solitaire_engine/**'
|
||||||
|
- 'solitaire_data/**'
|
||||||
|
- 'solitaire_sync/**'
|
||||||
|
- 'solitaire_wasm/**'
|
||||||
|
- 'solitaire_web/**'
|
||||||
|
- 'Cargo.toml'
|
||||||
|
- 'Cargo.lock'
|
||||||
|
- 'build_wasm.sh'
|
||||||
|
- '.gitea/workflows/web-wasm-rebuild.yml'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: web-wasm-rebuild
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
rebuild:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.CI_TOKEN }}
|
||||||
|
|
||||||
|
- name: Install Rust 1.95.0
|
||||||
|
uses: dtolnay/rust-toolchain@master
|
||||||
|
with:
|
||||||
|
toolchain: 1.95.0
|
||||||
|
targets: wasm32-unknown-unknown
|
||||||
|
|
||||||
|
- name: Cache cargo build
|
||||||
|
uses: Swatinem/rust-cache@v2
|
||||||
|
|
||||||
|
- name: Install wasm-bindgen-cli + wasm-pack (pinned)
|
||||||
|
uses: taiki-e/install-action@v2
|
||||||
|
with:
|
||||||
|
tool: wasm-bindgen-cli@0.2.120,wasm-pack@0.14.0
|
||||||
|
|
||||||
|
- name: Install binaryen 130 (wasm-opt, pinned)
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
curl -sSL \
|
||||||
|
https://github.com/WebAssembly/binaryen/releases/download/version_130/binaryen-version_130-x86_64-linux.tar.gz \
|
||||||
|
| tar xz
|
||||||
|
echo "$PWD/binaryen-version_130/bin" >> "$GITHUB_PATH"
|
||||||
|
|
||||||
|
- name: Rebuild WASM artifacts
|
||||||
|
run: ./build_wasm.sh
|
||||||
|
|
||||||
|
- name: Commit refreshed artifacts if changed
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
if git diff --quiet -- solitaire_server/web/pkg/; then
|
||||||
|
echo "pkg/ already up to date — nothing to commit."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
git config user.email "ci@gitea.local"
|
||||||
|
git config user.name "Gitea CI"
|
||||||
|
git add solitaire_server/web/pkg/
|
||||||
|
git commit -m "chore(web): regenerate wasm artifacts"
|
||||||
|
# master is unprotected; retry once if the tip moved under us.
|
||||||
|
git push origin HEAD:master || {
|
||||||
|
git fetch origin master
|
||||||
|
git rebase origin/master
|
||||||
|
git push origin HEAD:master
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user