mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-14 18:41:42 +08:00
042daeee71
Pin every CI surface to Bun 1.4.0 to avoid extra-stdio finalizers closing reused live sockets. Add an isolated GC/listener regression that fails on Bun 1.3.13, and prevent coordinated rollback to an affected CI runtime. Check renderer cleanup against the render's own staging directory so concurrent renders cannot invalidate the assertion. Make the no-pgrep process-tree walk tolerate disappearing /proc entries, and synchronize its test fixture through child readiness and pipe EOF instead of sleeps. Validation: 9,157 passed, 31 skipped, zero failures across 556 files with retries disabled. Build, all-host generation freshness, and skill checks passed. All three races have failing-before/passing-after regressions.
166 lines
7.5 KiB
YAML
166 lines
7.5 KiB
YAML
name: Free Tests
|
|
|
|
# The free suite (~400 files: test/, browse/test/, make-pdf/test/, design/test/)
|
|
# had ZERO Linux CI coverage before this lane — only a curated Windows subset
|
|
# ran anywhere. This job runs the whole thing through the canonical runner
|
|
# (scripts/test-free-shards.ts): N concurrent shard processes (serial within
|
|
# each, plus a trailing serial tree-mutating shard) with strict-output
|
|
# classification per shard, so a truncated or summary-less run can never
|
|
# report green.
|
|
#
|
|
# Deliberately SECRETLESS: free tests make no API calls, so this lane gets no
|
|
# provider keys at all — least privilege, and fork PRs get real test signal
|
|
# here (the eval matrix skips fork PRs because repository secrets can't reach
|
|
# them). test/free-tests-workflow-wiring.test.ts fails CI if a secret sneaks in.
|
|
#
|
|
# This is a REQUIRED check from day one (branch protection lists it). If it's
|
|
# red, fix or quarantine-with-issue — don't make it advisory; an advisory lane
|
|
# is permanent false comfort.
|
|
#
|
|
# Sizing note (decision V3): single job first. If PR runs show it slower than
|
|
# the eval matrix wall, switch to a matrix of `--shards N --shard i` jobs
|
|
# (indices are stable, empty shards no-op).
|
|
|
|
on:
|
|
pull_request:
|
|
branches: [main]
|
|
# Also on main pushes: two individually-green PRs can merge into a red
|
|
# main; without this nothing runs the free suite on main until the next PR.
|
|
push:
|
|
branches: [main]
|
|
workflow_dispatch:
|
|
|
|
# Keyed on the PR number, not head_ref: a bare branch name carries no fork
|
|
# prefix, so same-name branches from two forks would share one group and a
|
|
# push to fork B's PR would cancel fork A's in-flight REQUIRED check.
|
|
concurrency:
|
|
group: free-tests-${{ github.event.pull_request.number || github.run_id }}
|
|
cancel-in-progress: true
|
|
|
|
# Least privilege: this job executes PR-controlled code (install lifecycle
|
|
# scripts + the test suite), so the GITHUB_TOKEN gets read-only contents and
|
|
# the checkout doesn't persist it into .git/config.
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
free-tests:
|
|
runs-on: ubicloud-standard-8
|
|
timeout-minutes: 20
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- uses: oven-sh/setup-bun@v2
|
|
with:
|
|
bun-version: 1.4.0
|
|
|
|
- uses: actions/cache@v6
|
|
with:
|
|
path: ~/.bun/install/cache
|
|
key: linux-bun-${{ hashFiles('bun.lock') }}
|
|
# A lockfile bump starts from the previous cache instead of cold.
|
|
restore-keys: |
|
|
linux-bun-
|
|
|
|
- name: Install dependencies
|
|
run: bun install --frozen-lockfile
|
|
|
|
- uses: actions/cache@v6
|
|
with:
|
|
path: ~/.cache/ms-playwright
|
|
key: linux-playwright-${{ hashFiles('bun.lock') }}
|
|
restore-keys: |
|
|
linux-playwright-
|
|
|
|
# Cache restores browser binaries; install is still required for system
|
|
# deps and is a fast no-op for already-present browsers.
|
|
- name: Install Playwright Chromium
|
|
run: npx playwright install --with-deps chromium
|
|
|
|
# Headed-browser tests (handoff, extension sidepanel DOM) need a real
|
|
# DISPLAY — first Linux run failed with Playwright's "launched a headed
|
|
# browser without an XServer" banner. xvfb-run below provides it;
|
|
# x11-utils ships xdpyinfo for display probing. poppler-utils ships
|
|
# pdftotext/pdffonts/pdftoppm for the make-pdf e2e gates;
|
|
# fonts-noto-color-emoji is the emoji-gate's render font (playwright
|
|
# --with-deps usually installs it, but the gate must not depend on a
|
|
# transitive package list). Fonts must land BEFORE the first browse
|
|
# daemon launch — Chromium snapshots fontconfig at startup.
|
|
- name: Install Xvfb + X11 utilities + gate tools
|
|
run: sudo apt-get install -y --no-install-recommends xvfb x11-utils poppler-utils fonts-noto-color-emoji
|
|
|
|
- name: Configure git identity (tests init temp repos)
|
|
run: |
|
|
git config --global user.email "free-tests-ci@gstack.test"
|
|
git config --global user.name "Free Tests CI"
|
|
git config --global init.defaultBranch main
|
|
# Some tests run git against the checkout itself; CI checkouts can be
|
|
# owned by a different uid than the runner user.
|
|
git config --global --add safe.directory '*'
|
|
|
|
- name: Generate host SKILL.md outputs (.agents, .factory)
|
|
# Golden-file tests read generated host outputs that are gitignored.
|
|
run: bun run gen:skill-docs --host all
|
|
|
|
- name: Vendor xterm assets into the extension
|
|
# extension/lib/xterm* are gitignored (vendored from npm at build
|
|
# time). Without them the sidepanel's terminal script bails and the
|
|
# sidepanel DOM tests time out waiting on init that never happens.
|
|
run: bun run vendor:xterm
|
|
|
|
- name: Build server-node bundle (loaded by browse cli imports)
|
|
run: bash browse/scripts/build-node-server.sh
|
|
|
|
# Narrowed gate build: the make-pdf e2e gates probe make-pdf/dist/pdf,
|
|
# browse/dist/browse, and the diagram-render bundle, then self-skip when
|
|
# absent — which made them silently skip on Linux for their whole life
|
|
# (this lane never built binaries). Full `bun run build` compiles five
|
|
# binaries and would add ~60-90s to the ONLY required check; the gates
|
|
# need exactly these three artifacts.
|
|
- name: Build gate binaries (make-pdf e2e gates)
|
|
run: bun run build:gates
|
|
|
|
# GSTACK_EXPECT_BINARIES=1 arms make-pdf/test/e2e/ci-prereqs.test.ts:
|
|
# if a future edit drops the gate build (or poppler), the lane FAILS
|
|
# instead of the gates silently self-skipping back to false green.
|
|
- name: Run free suite
|
|
run: xvfb-run -a bun run test:free
|
|
env:
|
|
GSTACK_EXPECT_BINARIES: "1"
|
|
# WS1 flake telemetry: a single timing flake must not red the only
|
|
# required lane — the runner's attribution-gated retry pass (cap 5,
|
|
# truncation veto) re-runs failing files once, serially, and a
|
|
# clean retry downgrades to a LOUD flaky-pass. Every flaky-pass is
|
|
# appended to the ledger (single writer: the parent runner) and
|
|
# uploaded below, so repeat offenders are an enumerable series —
|
|
# recorded and ranked, never masked. Pinned by
|
|
# test/free-tests-workflow-wiring.test.ts.
|
|
GSTACK_FREE_RETRY_FLAKY: "1"
|
|
GSTACK_FLAKE_LEDGER: ${{ runner.temp }}/flake-ledger.jsonl
|
|
|
|
# Uploaded unconditionally (not just on failure): a flaky-pass run is
|
|
# GREEN — that's the point — so its evidence must survive green runs.
|
|
- name: Upload flake ledger
|
|
if: always()
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: flake-ledger
|
|
path: ${{ runner.temp }}/flake-ledger.jsonl
|
|
if-no-files-found: ignore
|
|
retention-days: 90
|
|
|
|
# The runner streams the full child output to per-run logs under the OS
|
|
# tmpdir and prints only the quiet contract to the console. Without this
|
|
# upload, a red required check names WHICH test failed but the why
|
|
# (assertion detail, stack) dies with the runner — every diagnosis would
|
|
# need a local re-run, which fork contributors can't do on this image.
|
|
- name: Upload shard logs on failure
|
|
if: failure()
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: free-test-shard-logs
|
|
path: /tmp/gstack-free-test-*.log
|
|
if-no-files-found: ignore
|