ci speed: desktop boot check runs its cases in parallel (one browser, killed at the end; a page per case; condition waits instead of fixed sleeps: element, text or a quiet window of host calls and DOM); shots capture / render close the browser with a 3 s cap, then kill it; console engine waits injectable for tests (WAITS / engineWaits: poll rounds, a missing step ends once its loaded page stays quiet, team switch settle, field-miss grace), fillPage looks up each data type's dialog once per round and skips dialog sections when no dialog is open; browser tests run 4 at a time per file (testScope().concurrent with a scope per test, --max-concurrency in ci), 20 ms rounds; capture-web counts boots per test and runs its browser tests concurrently; console-session / -persist Chrome tests concurrent; recorded test timings smoothed (mergeTimings) so one loaded run does not skew the shard split
This commit is contained in:
parent
f2d7062bcb
commit
9ba8471002
16 changed files with 390 additions and 178 deletions
16
tools/ci.ts
16
tools/ci.ts
|
|
@ -5,8 +5,9 @@
|
|||
// bun run ci:quick inner loop: typecheck + the tests related to the change (git diff against origin/main,
|
||||
// mapped through imports) + scrub
|
||||
// The tests run as shards: N = CPU cores - 1 (max 8; STOREBOUND_CI_SHARDS=n overrides) parallel `bun test <files>`
|
||||
// processes, balanced by the durations recorded after the last run (node_modules/.cache/storebound-ci/, falling back
|
||||
// to file size). Browser suites (tools/ci-plan.ts HEAVY) each get a shard of their own.
|
||||
// processes, balanced by the durations recorded after earlier runs (node_modules/.cache/storebound-ci/, smoothed by
|
||||
// mergeTimings so one run on a loaded machine does not skew the split; falling back to file size). Browser suites
|
||||
// (tools/ci-plan.ts HEAVY) each get a shard of their own and run their opted-in tests BROWSER_CONCURRENCY at a time.
|
||||
// `bun test` covers the CLI and the desktop webview (apps/desktop/tests), the site overflow check and the
|
||||
// no-hand-written-SVG guard; the desktop boot check (tools/desktop-boot-check.ts: the built window in headless
|
||||
// Chromium, needs playwright's browser or Google Chrome) runs after the desktop build.
|
||||
|
|
@ -17,7 +18,7 @@ import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
|
|||
import { homedir, tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { hostTarget, OUT_DIR, outName } from './build-sidecars';
|
||||
import { changedFiles, HEAVY, junitTimes, listTests, planShards, readTimings, relatedTests, ROOT, rustNeeded, writeTimings } from './ci-plan';
|
||||
import { BROWSER_CONCURRENCY, changedFiles, HEAVY, junitTimes, listTests, mergeTimings, planShards, readTimings, relatedTests, ROOT, rustNeeded, writeTimings } from './ci-plan';
|
||||
|
||||
interface Task { name: string; cmd: string[]; cwd?: string; env?: Record<string, string>; after?: string[]; junit?: string }
|
||||
|
||||
|
|
@ -39,7 +40,8 @@ function addTests(files: string[]) {
|
|||
// the built-bundle check in apps/desktop/tests/webview.test.ts runs as "desktop bundle check" once the build is
|
||||
// done; here it would read dist/ while vite rewrites it
|
||||
// browser suites share the machine with the other steps: a browser start or close can pass bun's 5 s default
|
||||
const timeout = shard.some(f => HEAVY.includes(f)) ? ['--timeout=30000'] : [];
|
||||
// browser tests that opt in (testScope().concurrent) run BROWSER_CONCURRENCY at a time within their file
|
||||
const timeout = shard.some(f => HEAVY.includes(f)) ? ['--timeout=30000', `--max-concurrency=${BROWSER_CONCURRENCY}`] : [];
|
||||
add({ name: `tests ${i + 1}/${all.length}`, cmd: ['bun', 'test', ...timeout, '--reporter=junit', `--reporter-outfile=${junit}`, ...shard.map(f => `./${f}`)],
|
||||
env: { STOREBOUND_SKIP_DIST_CHECK: '1' }, junit });
|
||||
});
|
||||
|
|
@ -156,12 +158,12 @@ while ((pending.size || active.size) && !failed) {
|
|||
if (failed) await Promise.allSettled([...active]);
|
||||
|
||||
// record per-file durations for the next split (only from shards that finished)
|
||||
const timings = readTimings();
|
||||
const fresh: Record<string, number> = {};
|
||||
for (const r of runs.values()) {
|
||||
if (!r.task.junit || r.end === undefined) continue;
|
||||
try { Object.assign(timings, junitTimes(readFileSync(r.task.junit, 'utf8'))); } catch { /* no report */ }
|
||||
try { Object.assign(fresh, junitTimes(readFileSync(r.task.junit, 'utf8'))); } catch { /* no report */ }
|
||||
}
|
||||
writeTimings(timings);
|
||||
writeTimings(mergeTimings(readTimings(), fresh));
|
||||
rmSync(junitDir, { recursive: true, force: true });
|
||||
|
||||
console.log(`\n${quick ? 'ci:quick' : 'ci'} summary (wall ${((Date.now() - t0) / 1000).toFixed(1)}s)`);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue