mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-05 14:19:04 +00:00
fix(process): prepare and the usage step run pipeline scripts from one pinned dev snapshot (#765)
The body of _process.yml is read from dev (@dev, #623). After "Перейти на ветку задачи" the working copy of job prepare is the task branch, and a show/ship branch with a clean merge is not rebased before review: its scripts/ may lag dev or be replaced. #749 fixed job integrate; prepare still ran four control scripts from the material — the issue-body digest for the anchor, --reuse of a green verdict (#499), validate-gate (#510) and the spec-change check (#517). The material decided its own admission: a branch whose review-doc-guard.mjs prints reuse=true merges without the model. model_review took model-usage.mjs from the material too: a lagging branch has none, and the publication silently wrote reason=missing. Now prepare extracts one snapshot right after setup-node, before the branch switch: `git rev-parse origin/dev` once and `git archive <sha> scripts .github/workflows/validate.yml`, so the git fetch of the track and rebase steps cannot mix versions. Every repo script of the job runs from it via TOOLS — the track step and the rebase guard lose their own extractions. The SHA goes out as job output tools_sha; the usage step of model_review archives the same commit inside itself, so a snapshot failure is a failure of the reporting step (continue-on-error), not of the stage. The model session runs on that runner, so the usage line stays untrusted input parsed strictly (#556, #737). withMaterialAnchors is idempotent: a repeated call drops the separator the previous call wrote instead of piling up `---` lines. Tests: test/process-prepare-tools.test.mjs — the job contract (no step calls scripts/ from the working copy, one pinned archive before the branch switch, tools_sha reaches model_review) and the steps as they are, on real bash and git: a branch behind dev without model-usage.mjs and with a substituted review-doc-guard.mjs; the anchor digest, reuse and the spec check come from dev, the usage line is data even after dev moved. Red on the old workflow: all four. Harnesses of process-track, rebase-generated, review-doc-guard and model-usage take the prepare snapshot. Three registry mutants (reuse from the material, usage from moving dev, separators). Canon: PROCESS.md §10.4 «Скрипты конвейера — из dev» covers prepare and the usage step; «Расход модели» names it a pipeline step, not the reviewer's. Issue: #765 User-Visible: no
This commit is contained in:
@@ -199,9 +199,19 @@ test('#737 lastUsageIn: последняя строка формата в тек
|
||||
// ---------- К3: проводка в обоих workflow ----------
|
||||
|
||||
const WORKFLOWS = fileURLToPath(new URL('../.github/workflows/', import.meta.url));
|
||||
// #765: в _process.yml рабочая копия model_review — материал ревью (ветка задачи
|
||||
// может отставать от dev или подменять скрипт), поэтому скрипт берётся снимком
|
||||
// того коммита dev, что закрепила подготовка (`tools_sha`). В _ship-review.yml
|
||||
// рабочая копия — кандидат линии dev, и скрипт зовётся из неё.
|
||||
const PIPELINES = [
|
||||
{ file: '_process.yml', publishJob: 'integrate', publishStep: 'Опубликовать документ ревью', consumes: /^ +--usage="\$USAGE" \\$/m },
|
||||
{ file: '_ship-review.yml', publishJob: 'publish', publishStep: 'Опубликовать документ', consumes: /^ +usage: process\.env\.USAGE \?\? "",$/m },
|
||||
{
|
||||
file: '_process.yml', publishJob: 'integrate', publishStep: 'Опубликовать документ ревью', consumes: /^ +--usage="\$USAGE" \\$/m,
|
||||
call: /^line=\$\(node "\$tools\/scripts\/model-usage\.mjs" --execution-file="\$EXEC"\)$/m, snapshot: true,
|
||||
},
|
||||
{
|
||||
file: '_ship-review.yml', publishJob: 'publish', publishStep: 'Опубликовать документ', consumes: /^ +usage: process\.env\.USAGE \?\? "",$/m,
|
||||
call: /^line=\$\(node scripts\/model-usage\.mjs --execution-file="\$EXEC"\)$/m, snapshot: false,
|
||||
},
|
||||
];
|
||||
|
||||
/** Блок job верхнего уровня `jobs:` — до следующего id на двух пробелах. */
|
||||
@@ -234,7 +244,7 @@ const named = (steps, name) => {
|
||||
const hasBash = () => process.platform !== 'win32' && spawnSync('bash', ['--version']).status === 0;
|
||||
|
||||
test('#737 AC5: шаг снятия расхода сразу после Review — always, continue-on-error, выход job usage; публикация его берёт', () => {
|
||||
for (const { file, publishJob, publishStep, consumes } of PIPELINES) {
|
||||
for (const { file, publishJob, publishStep, consumes, call } of PIPELINES) {
|
||||
const text = readFileSync(join(WORKFLOWS, file), 'utf8');
|
||||
const model = jobBlock(text, 'model_review');
|
||||
const steps = stepsOf(model);
|
||||
@@ -247,7 +257,7 @@ test('#737 AC5: шаг снятия расхода сразу после Review
|
||||
assert.match(usage, /^ {8}continue-on-error: true$/m, `${file}: сбой снятия не роняет стадию`);
|
||||
assert.match(usage, /^ {10}EXEC: \$\{\{ steps\.review\.outputs\.execution_file \}\}$/m, file);
|
||||
const run = runOf(usage);
|
||||
assert.match(run, /^line=\$\(node scripts\/model-usage\.mjs --execution-file="\$EXEC"\)$/m, file);
|
||||
assert.match(run, call, file);
|
||||
assert.match(run, /^echo "line=\$line" >> "\$GITHUB_OUTPUT"$/m, file);
|
||||
assert.match(run, /"\$GITHUB_STEP_SUMMARY"$/m, `${file}: строка — в сводку шага`);
|
||||
const head = model.slice(0, model.indexOf('\n steps:\n'));
|
||||
@@ -281,7 +291,9 @@ test('#737 AC5: execution_file никуда не выгружается, гра
|
||||
|
||||
test('#737 AC5: шаг снятия расхода на настоящем bash — выход line и строка в сводке, секрета нет', (t) => {
|
||||
if (!hasBash()) { t.skip('bash недоступен'); return; }
|
||||
for (const { file } of PIPELINES) {
|
||||
// #765: снимок — коммит HEAD этого дерева (скрипт расхода в нём тот же).
|
||||
const head = spawnSync('git', ['rev-parse', 'HEAD'], { cwd: ROOT, encoding: 'utf8' }).stdout.trim();
|
||||
for (const { file, snapshot } of PIPELINES) {
|
||||
const text = readFileSync(join(WORKFLOWS, file), 'utf8');
|
||||
const body = runOf(named(stepsOf(jobBlock(text, 'model_review')), 'Снять расход модели'));
|
||||
const dir = tempDir(t);
|
||||
@@ -293,7 +305,8 @@ test('#737 AC5: шаг снятия расхода на настоящем bash
|
||||
rmSync(output, { force: true });
|
||||
rmSync(summary, { force: true });
|
||||
const r = spawnSync('bash', ['--noprofile', '--norc', '-e', '-c', body], {
|
||||
cwd: ROOT, encoding: 'utf8', env: { ...process.env, EXEC, GITHUB_OUTPUT: output, GITHUB_STEP_SUMMARY: summary },
|
||||
cwd: ROOT, encoding: 'utf8',
|
||||
env: { ...process.env, EXEC, GITHUB_OUTPUT: output, GITHUB_STEP_SUMMARY: summary, ...(snapshot ? { TOOLS_SHA: head, RUNNER_TEMP: dir } : {}) },
|
||||
});
|
||||
assert.equal(r.status, 0, `${file}: ${r.stderr}`);
|
||||
assert.equal(readFileSync(output, 'utf8'), `line=${line}\n`, file);
|
||||
|
||||
Reference in New Issue
Block a user