mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
infra: portable Windows gate, CI toolchain pins, task packet, deterministic wait, gate:small --smokes
Windows portability (the three red tests on the owner's machine at green CI):
- scripts/spawn-portable.mjs: isMainModule via pathToFileURL (the
`file://${argv[1]}` form gives file:///C:/C:/... and the CLI stays silent);
portableCommand — a shell only for npm/npx/.cmd, node and git run directly
(spawn via shell dropped the quotes of `node -e "…"`). Applied to
classify-changes, mutation-gate-report, review-doc-guard, check-inputs,
merge-candidate, gate-small, rebase-on-dev.
- the rebase-on-dev test pins core.autocrlf=false / core.eol=lf through
GIT_CONFIG_* for its temp repository instead of touching the user's git
config; test/windows-portability.test.mjs forbids both anti-patterns.
Pins: scripts/toolchain-pins.mjs reads Node/Python from validate.yml, the HA
stack from tests_backend/requirements.txt, Playwright/Chromium from the
lockfile — no second dictionary; `npm run toolchain:check` compares the
machine; .nvmrc/.python-version are derived and tested equal;
scripts/wsl-setup.sh provisions WSL/Linux with those pins.
scripts/task-packet.mjs: one derived view of an issue (status, rights, owner
decisions, branch vs dev, Validate on the tip, previous verdict with recorded
tree, AC → evidence, unwitnessed). scripts/wait-verdict.mjs: polls labels,
pipeline comments and optionally Validate, prints only on state change, exit
0/3/4, writes nothing.
gate:small --smokes: after build the browser phase runs bundle-sync and then
the directly matched and registered smokes, two at a time; broad matches stay
with the reviewer. package.json changed, so the bundle is rebuilt here.
Issue: #496
User-Visible: no
This commit is contained in:
@@ -33,3 +33,37 @@ test('сводка: информационный шаг не падение, у
|
||||
assert.match(lines[1], /^info/);
|
||||
assert.match(lines[2], /^FAIL.*→ npm run bundle:sync/);
|
||||
});
|
||||
|
||||
// #496: browser-consumers отделены от подготовки артефактов и идут после неё.
|
||||
import { runLimited, smokesToRun } from '../scripts/gate-small.mjs';
|
||||
|
||||
test('smokesToRun берёт прямые и зарегистрированные смоки, не «широкие»; без диффа — пусто (#496)', () => {
|
||||
assert.deepEqual(smokesToRun({ noExecutableDiff: true, direct: [{ smoke: 'smoke_x.mjs' }] }), []);
|
||||
assert.deepEqual(smokesToRun({
|
||||
direct: [{ smoke: 'smoke_b.mjs', strong: true }, { smoke: 'smoke_a.mjs', strong: false }],
|
||||
registered: [{ smoke: 'smoke_b.mjs' }, { smoke: 'smoke_c.mjs' }],
|
||||
broad: [{ smoke: 'smoke_everything.mjs' }],
|
||||
}), ['smoke_a.mjs', 'smoke_b.mjs', 'smoke_c.mjs']);
|
||||
assert.deepEqual(smokesToRun(null), []);
|
||||
assert.deepEqual(parseArgs(['--smokes', '--jobs=3']), { base: 'origin/dev', smokes: true, jobs: 3 });
|
||||
assert.deepEqual(parseArgs(['--jobs=abc']).jobs, 2);
|
||||
});
|
||||
|
||||
test('runLimited держит не больше N одновременных consumers и сохраняет порядок (#496)', async () => {
|
||||
let active = 0; let peak = 0;
|
||||
const out = await runLimited([1, 2, 3, 4, 5], 2, async (n) => {
|
||||
active++; peak = Math.max(peak, active);
|
||||
await new Promise((r) => setTimeout(r, 5));
|
||||
active--; return n * 10;
|
||||
});
|
||||
assert.deepEqual(out, [10, 20, 30, 40, 50]);
|
||||
assert.equal(peak, 2);
|
||||
});
|
||||
|
||||
test('gate-small: смоки идут только после bundle-sync и только с --smokes (#496)', () => {
|
||||
const source = readFileSync(new URL('../scripts/gate-small.mjs', import.meta.url), 'utf8');
|
||||
const smokesAt = source.indexOf("args: [`demo/${smoke}`]");
|
||||
const syncAt = source.indexOf("args: ['scripts/bundle-sync.mjs']");
|
||||
assert.ok(syncAt > 0 && smokesAt > syncAt, 'bundle-sync предшествует запуску смоков');
|
||||
assert.match(source, /if \(smokes && buildOk\)/);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user