Linux and macOS: a program asked is now waited for with waitid and WNOWAIT, which leaves it unreaped. Once it has exited, its process group gets SIGKILL, and only then is it reaped. While the leader is an unreaped zombie, its group's number cannot be given to another group. So this ends what the program left running behind it, whether or not it answered, and nothing else. A program that does not answer in time is stopped with its group before it is reaped, as before. Other Unix systems keep the polling wait. On Windows the job's kill-on-close does the same, and the new test runs there too. A program file that is open for writing somewhere cannot be run for a moment (ETXTBSY), for example one just written while another thread of this process starts a program. A spawn refused so is now tried again for up to 200 ms. This was a real flake in the tests that write stand-in programs, and wai doctor itself asks several programs at once. CI: wai/quickstart/test/archive_doctor.py runs bin/wai doctor --json from an unpacked archive, with the archive's bin first on PATH. It fails unless every install and stack check passes and each piece those checks found is inside the archive. Without that, a relay elsewhere on PATH or Studio's files from WAI_STUDIO would hide a piece the archive lacks. Ports, browsers and the keystore are printed, not required. stack.web and stack.studio now name their path in facts. The release runs it on every leg that builds an archive: macOS where the triple is the host's, Linux x86_64 and arm64, and Windows on the staged directory. At PR time it runs on the macOS archive wai-examples builds, the only archive built then. archive_doctor_test.py runs it against stand-ins in wai-examples' portable job. Real browsers on Linux: wai-studio's webkit job runs in the browser image and builds wai. It now requires browser.conformance to pass with that wai. Co-Authored-By: Claude Opus 5.5 <[email protected]>
199 lines
8.9 KiB
YAML
199 lines
8.9 KiB
YAML
name: WAI Studio
|
|
|
|
# WAI Studio on the web (wai/wai-studio): one front end, its core in WebAssembly, served by
|
|
# `wai dev` at /_wai/ and hosted by the WAI site.
|
|
#
|
|
# - catalogue · linux: Studio's actions hold to the operation catalogue (scripts/actions.mjs
|
|
# --check: an action with no operation, an operation placed for the browser with no action,
|
|
# a mismatched name), the unit tests that need no core build (the generation and every rule
|
|
# of the drift check broken in a copy, the palette, the local core's calls), and the core's
|
|
# own tests and clippy (core/, wai-studio-core, on the http-conformance vectors);
|
|
# - browser · macos: e2e/run.sh builds wai, the relay, the room service, the core, the room
|
|
# client's packages, the quantum engine, Quantum Studio and Studio; runs every unit test,
|
|
# the core's calls among them, and the drift check; then e2e/studio.e2e.mjs against a
|
|
# `wai dev` stack in Chromium and Firefox: each panel on both hosts, Inspect and Verify on
|
|
# conformance vectors with the results their cases expect, a room joined as a viewer, the
|
|
# palette, axe (WCAG 2.2 A and AA), no console error or failed request;
|
|
# - webkit · linux: the same in WebKit, in the browser image of the Playwright release
|
|
# package-lock.json pins (by digest). The macOS runner is started from SSH, and a process of
|
|
# an SSH session there cannot open WebKit's helper processes: WebKit never launches. Then
|
|
# `wai doctor --json` there must pass browser.conformance: it finds the browsers the image
|
|
# holds, and its chromium runs (wai/quickstart/test/archive_doctor.py --require).
|
|
#
|
|
# `wai dev`'s side (/_wai/ on its origin, nothing listening beyond loopback) is tested in the
|
|
# WAI conformance workflow's quickstart step (tests/cli_studio.rs and the binary's own tests).
|
|
#
|
|
# Push filters match the push's delta, so every path Studio builds on is listed.
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
paths:
|
|
- 'wai/wai-studio/**'
|
|
- 'wai/wai-rs/**'
|
|
- 'wai/catalogue/**'
|
|
- 'wai/quantum-studio/**'
|
|
- 'wai/wai-web/**'
|
|
- 'wai/wai-quantum/**'
|
|
- 'wai/wai-ops/**'
|
|
- 'wai/wai-live-web/**'
|
|
- 'wai/quickstart/build-web.sh'
|
|
- 'wai/quickstart/test/archive_doctor.py'
|
|
- 'wai/http-conformance/**'
|
|
- 'wai/pack-conformance/stills/**'
|
|
- 'joule-code/joule-code-rs/crates/joule-moq-web/**'
|
|
- 'joule-code/joule-code-rs/crates/joule-moq-relay/**'
|
|
- 'joule-code/joule-code-rs/crates/joule-moq-room/**'
|
|
- 'rust-toolchain.toml'
|
|
- '.github/workflows/wai-studio.yml'
|
|
pull_request:
|
|
paths:
|
|
- 'wai/wai-studio/**'
|
|
- 'wai/wai-rs/**'
|
|
- 'wai/catalogue/**'
|
|
- 'wai/quantum-studio/**'
|
|
- 'wai/wai-web/**'
|
|
- 'wai/wai-quantum/**'
|
|
- 'wai/wai-ops/**'
|
|
- 'wai/wai-live-web/**'
|
|
- 'wai/quickstart/build-web.sh'
|
|
- 'wai/quickstart/test/archive_doctor.py'
|
|
- 'wai/http-conformance/**'
|
|
- 'wai/pack-conformance/stills/**'
|
|
- 'joule-code/joule-code-rs/crates/joule-moq-web/**'
|
|
- 'joule-code/joule-code-rs/crates/joule-moq-relay/**'
|
|
- 'joule-code/joule-code-rs/crates/joule-moq-room/**'
|
|
- 'rust-toolchain.toml'
|
|
- '.github/workflows/wai-studio.yml'
|
|
|
|
jobs:
|
|
# The path filters gate the trigger; this job gates the work from the pull request's own
|
|
# diff (scripts/pr-touches-paths.py, reading the list above), as wai-pack.yml explains.
|
|
relevant:
|
|
name: does this change touch it
|
|
runs-on: gate
|
|
outputs:
|
|
run: ${{ steps.gate.outputs.run }}
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
with:
|
|
fetch-depth: 0
|
|
- id: gate
|
|
run: |
|
|
set -euo pipefail
|
|
r=$(python3 scripts/pr-touches-paths.py .github/workflows/wai-studio.yml \
|
|
"${{ github.event.pull_request.base.sha }}" \
|
|
"${{ github.event.pull_request.head.sha }}")
|
|
echo "this change touches WAI Studio: $r"
|
|
echo "run=$r" >> "$GITHUB_OUTPUT"
|
|
|
|
catalogue:
|
|
name: the catalogue's actions, the unit tests and the core · linux
|
|
needs: relevant
|
|
if: needs.relevant.outputs.run == 'true'
|
|
runs-on: linux
|
|
timeout-minutes: 60
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
- name: Install Rust 1.99.1
|
|
shell: bash
|
|
run: |
|
|
export PATH="$HOME/.cargo/bin:$PATH"
|
|
command -v rustup >/dev/null 2>&1 || \
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.99.1
|
|
rustup toolchain install 1.99.1 --profile minimal --component clippy
|
|
rustup default 1.99.1
|
|
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '22'
|
|
- name: Studio's actions hold to the catalogue
|
|
working-directory: wai/wai-studio
|
|
run: node scripts/actions.mjs --check
|
|
# The core's calls (test/core.test.mjs) need the core built for the web; the browser
|
|
# job runs them. These need nothing built.
|
|
- name: Unit tests
|
|
shell: bash
|
|
working-directory: wai/wai-studio
|
|
run: |
|
|
set -euo pipefail
|
|
node --test --test-reporter=tap test/actions.test.mjs test/palette.test.mjs test/local-core.test.mjs 2>&1 | tee "$RUNNER_TEMP/unit.log"
|
|
grep -qE '^# pass [1-9]' "$RUNNER_TEMP/unit.log" && grep -qE '^# fail 0$' "$RUNNER_TEMP/unit.log" || { echo "::error::no unit test ran, or one failed"; exit 1; }
|
|
- name: The core's tests and clippy
|
|
shell: bash
|
|
working-directory: wai/wai-studio/core
|
|
run: |
|
|
set -euo pipefail
|
|
cargo test --locked 2>&1 | tee "$RUNNER_TEMP/core.log"
|
|
grep -qE '^test result: ok\. [1-9][0-9]* passed; 0 failed' "$RUNNER_TEMP/core.log" || { echo "::error::no test ran"; exit 1; }
|
|
cargo clippy --locked --all-targets -- -D warnings
|
|
|
|
browser:
|
|
name: Studio in Chromium and Firefox · macos
|
|
needs: relevant
|
|
if: needs.relevant.outputs.run == 'true'
|
|
runs-on: macos
|
|
timeout-minutes: 120
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
# launchd's PATH omits cargo and node on the macOS host runner.
|
|
- name: Put cargo and node on PATH
|
|
shell: bash
|
|
run: |
|
|
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
|
echo "/opt/homebrew/bin" >> "$GITHUB_PATH"
|
|
- name: wasm32 target and wasm-bindgen CLI 0.2.127
|
|
shell: bash
|
|
run: |
|
|
rustup target add wasm32-unknown-unknown
|
|
command -v wasm-bindgen >/dev/null && wasm-bindgen --version | grep -q ' 0\.2\.127$' || cargo install --locked wasm-bindgen-cli --version 0.2.127
|
|
- name: The browsers Playwright drives
|
|
shell: bash
|
|
working-directory: wai/wai-studio
|
|
run: |
|
|
set -euo pipefail
|
|
npm ci --ignore-scripts --no-audit --no-fund
|
|
npx playwright install chromium firefox
|
|
- name: Build everything, the unit tests, the drift check, and Studio in Chromium and Firefox
|
|
shell: bash
|
|
env:
|
|
STUDIO_OUT: ${{ runner.temp }}/wai-studio-e2e
|
|
run: nice -n 10 bash wai/wai-studio/e2e/run.sh --browsers chromium,firefox
|
|
|
|
webkit:
|
|
name: Studio in WebKit · linux
|
|
needs: relevant
|
|
if: needs.relevant.outputs.run == 'true'
|
|
runs-on: linux
|
|
timeout-minutes: 150
|
|
# Playwright 1.60.0's image (package-lock.json pins 1.60.0): Node, and WebKit with every
|
|
# library it needs.
|
|
container:
|
|
image: mcr.microsoft.com/playwright@sha256:9bd26ad900bb5e0f4dee75839e957a89ae89c2b7ab1e76050e559790e946b948
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
# The floor's zstd is C, compiled for wasm32 by clang and archived by llvm-ar.
|
|
- name: Rust 1.99.1 with the wasm32 target, clang and llvm, wasm-bindgen CLI 0.2.127
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
apt-get update -qq
|
|
apt-get install -y -qq --no-install-recommends curl ca-certificates build-essential pkg-config clang llvm python3 git > /dev/null
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.99.1
|
|
"$HOME/.cargo/bin/rustup" target add wasm32-unknown-unknown
|
|
"$HOME/.cargo/bin/cargo" install --locked wasm-bindgen-cli --version 0.2.127
|
|
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
|
- name: Build everything, the unit tests, the drift check, and Studio in WebKit
|
|
shell: bash
|
|
env:
|
|
STUDIO_OUT: ${{ runner.temp }}/wai-studio-e2e
|
|
run: bash wai/wai-studio/e2e/run.sh --browsers webkit
|
|
# The wai run.sh built (its target directory: target-studio), in this image, finds the
|
|
# automation package's browsers (PLAYWRIGHT_BROWSERS_PATH) and its chromium runs.
|
|
- name: wai doctor finds the image's browsers, and its chromium runs
|
|
shell: bash
|
|
run: python3 -I wai/quickstart/test/archive_doctor.py --wai target-studio/wai-rs/release/wai --require browser.conformance
|