mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-27 22:15:33 +00:00
* feat(ci): scripts/run-verify-parallel.sh — parallel verify dispatcher Fans out the 21 pre-test grep guards via & + wait, captures per-check exit codes in a tempdir, aggregates failures with named check + log tail to stderr on miss. Wallclock 27s sequential → 13s parallel locally (2x). Bigger CI win is shard 1 deload (workflow restructure in a later commit). Pinned by test/scripts/run-verify-parallel.test.ts (6 cases: CLI contract + synthetic dispatcher failure-surfacing). * feat(ci): weight-aware LPT bin-packer + auto SHA cache hash scripts/sharding.ts (NEW) — pure TypeScript LPT bin-packer. Sort weights desc, assign each file to the shard with current minimum total. Worst-case makespan within 4/3 of optimal, O(n log n). Missing weights fall back to corpus median (not 0). New test file → ships immediately without regenerating weights. Pinned by test/scripts/sharding.test.ts (23 cases). scripts/mine-shard-weights.ts (NEW) — scrapes per-file timing from gh run view --log via timestamp delta between ##[group]test/foo.test.ts: headers within a shard. Three input modes: --run <ID>, --from-file <PATH>, stdin. Stable JSON output (sorted keys). Initial weights mined from run 26398061007. Pinned by test/scripts/mine-shard-weights.test.ts (15 cases). scripts/ci-cache-hash.sh (NEW) — deterministic 16-char sha256 over git ls-files -s minus deny-list (CHANGELOG/TODOS/README/LICENSE/ docs/**/*.md). CLAUDE.md, AGENTS.md, skills/**/* deliberately INCLUDED (8+ test files read them; deny-listing would create false-pass holes). ~40ms on 1891 files. Pinned by test/scripts/ci-cache-hash.test.ts (24 cases: 8 CRITICAL false-pass guards + 7 SAFE deny-list invariants + 9 edge cases). scripts/test-weights.json (NEW) — 712 weights. Total 3306s observed runtime; median 30ms; max 6 min outlier. * chore: bump version and changelog (v0.41.6.0) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
75 lines
3.2 KiB
TypeScript
75 lines
3.2 KiB
TypeScript
/**
|
|
* Regression guard: scripts/check-privacy.sh must run in CI's auto-pipeline.
|
|
*
|
|
* CLAUDE.md bans the private OpenClaw fork name from public artifacts.
|
|
* scripts/check-privacy.sh is the enforcement mechanism. If someone
|
|
* refactors the script chain and drops the privacy check, this test
|
|
* fails loudly.
|
|
*
|
|
* v0.26.4 split: `bun run test` is now the fast parallel loop and does
|
|
* NOT chain pre-checks; the privacy gate moved to `bun run verify`,
|
|
* which CI's test.yml runs as its own job before the matrix fans out.
|
|
*
|
|
* v0.41.4+ wave: `bun run verify` now delegates to
|
|
* scripts/run-verify-parallel.sh which fans out all 20 checks in
|
|
* parallel via & + wait. The privacy check is one entry in that
|
|
* script's CHECKS[] array. Regression guard updated to follow the
|
|
* indirection: (1) verify points at the parallel dispatcher,
|
|
* (2) the dispatcher's CHECKS array contains check:privacy,
|
|
* (3) CI workflow's verify job calls `bun run verify`.
|
|
*/
|
|
|
|
import { describe, it, expect } from 'bun:test';
|
|
import { readFileSync, existsSync } from 'fs';
|
|
import { resolve } from 'path';
|
|
import { spawnSync } from 'child_process';
|
|
|
|
const REPO_ROOT = resolve(import.meta.dir, '..');
|
|
const PACKAGE_JSON = resolve(REPO_ROOT, 'package.json');
|
|
const PRIVACY_SCRIPT = resolve(REPO_ROOT, 'scripts/check-privacy.sh');
|
|
const VERIFY_DISPATCHER = resolve(REPO_ROOT, 'scripts/run-verify-parallel.sh');
|
|
const TEST_WORKFLOW = resolve(REPO_ROOT, '.github/workflows/test.yml');
|
|
|
|
describe('check-privacy.sh CI wiring', () => {
|
|
it('scripts/check-privacy.sh exists and is executable', () => {
|
|
expect(existsSync(PRIVACY_SCRIPT)).toBe(true);
|
|
const stat = require('fs').statSync(PRIVACY_SCRIPT);
|
|
// eslint-disable-next-line no-bitwise
|
|
expect((stat.mode & 0o100) !== 0).toBe(true);
|
|
});
|
|
|
|
it('package.json "verify" script delegates to run-verify-parallel.sh', () => {
|
|
const pkg = JSON.parse(readFileSync(PACKAGE_JSON, 'utf-8'));
|
|
expect(typeof pkg.scripts?.verify).toBe('string');
|
|
// verify body is now `bash scripts/run-verify-parallel.sh`. The
|
|
// direct check:privacy substring assertion broke when the && chain
|
|
// was replaced with the parallel dispatcher. Follow the indirection.
|
|
expect(pkg.scripts.verify).toContain('run-verify-parallel.sh');
|
|
});
|
|
|
|
it('run-verify-parallel.sh dispatches check:privacy', () => {
|
|
expect(existsSync(VERIFY_DISPATCHER)).toBe(true);
|
|
// The dispatcher exposes --dry-list which prints one check name per
|
|
// line. Authoritative check than substring-grepping the script body
|
|
// (which could pass on a commented-out entry).
|
|
const r = spawnSync('bash', [VERIFY_DISPATCHER, '--dry-list'], {
|
|
cwd: REPO_ROOT,
|
|
encoding: 'utf-8',
|
|
});
|
|
expect(r.status).toBe(0);
|
|
const checks = r.stdout.trim().split('\n');
|
|
expect(checks).toContain('check:privacy');
|
|
});
|
|
|
|
it('package.json "check:privacy" alias points at the script', () => {
|
|
const pkg = JSON.parse(readFileSync(PACKAGE_JSON, 'utf-8'));
|
|
expect(pkg.scripts?.['check:privacy']).toContain('check-privacy.sh');
|
|
});
|
|
|
|
it('CI test.yml runs `bun run verify` so the privacy gate fires', () => {
|
|
expect(existsSync(TEST_WORKFLOW)).toBe(true);
|
|
const yml = readFileSync(TEST_WORKFLOW, 'utf-8');
|
|
expect(yml).toContain('bun run verify');
|
|
});
|
|
});
|