mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-02 21:01:21 +00:00
fix(process): слияние не обрывает дифф кандидата и называет причину сбоя запуска
Шаг слияния конвейера считает patch-id материала и кандидата через `git diff --full-index`, когда `dev` сдвинулся за время ревью. Дифф задачи, пересобирающей бандл, несёт три копии `houseplan-card.js` — у #594 это 7 103 616 байт. `sh()` не задавал `maxBuffer`, умолчание `spawnSync` — 1 МиБ, и процесс убивался по ENOBUFS на 1 027 868 байтах. Вторая половина дефекта прятала первую: `r.error` нигде не читался, а `status: r.status ?? 1` выдавало `null` за «git вернул 1». `must()` брал `r.stderr || r.stdout`, stderr был пуст — и в issue уезжало «Слияние не выполнено: diff: <огрызок диффа>». Огрызок выглядит осмысленным и уводит разбор в сторону. Путь исполняется только при сдвинувшемся `dev`, поэтому дефект дремал. Но конвейер сам пушит в `dev` документ ревью на каждом раунде, так что `devMoved` — норма, а не исключение. Что изменено: - `MAX_COMMAND_OUTPUT_BYTES` (256 МиБ) и явный `maxBuffer` в `sh()`; - `sh()` называет сбой запуска в `stderr` результата вместо молчания; - `sh()` экспортирован, у обоих пунктов есть исполнимый свидетель; - мутант `merge-candidate-truncates-the-candidate-diff` возвращает 1 МиБ. Issue: #596 User-Visible: no
This commit is contained in:
@@ -99,9 +99,25 @@ export function commentFor(action, ctx) {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Исполнение: git + gh через `ops`, чтобы тест подменял их целиком.
|
||||
|
||||
const sh = (cmd, args, opts = {}) => {
|
||||
const r = spawnSync(cmd, args, { encoding: 'utf8', ...opts });
|
||||
return { status: r.status ?? 1, stdout: (r.stdout || '').trim(), stderr: (r.stderr || '').trim() };
|
||||
/**
|
||||
* #596: сколько вывода готов принять один вызов. Умолчание `spawnSync` — 1 МиБ,
|
||||
* а `git diff` кандидата несёт три копии бандла: у #594 это 7,1 МБ. Процесс
|
||||
* убивался по ENOBUFS, `status` становился `null`, и `status ?? 1` выдавало это
|
||||
* за «git вернул 1» — с УСЕЧЁННЫМ stdout в сообщении об ошибке. Разбор уходил
|
||||
* в сторону: огрызок диффа выглядит осмысленным.
|
||||
*/
|
||||
export const MAX_COMMAND_OUTPUT_BYTES = 256 * 1024 * 1024;
|
||||
|
||||
/**
|
||||
* Запуск с двумя гарантиями: вывод не обрезается молча, а сбой самого запуска
|
||||
* не выдаёт себя за ненулевой код возврата. `r.error` (ENOBUFS, ENOENT, таймаут)
|
||||
* уезжает в `stderr` результата, откуда его печатает `must()`.
|
||||
*/
|
||||
export const sh = (cmd, args, opts = {}) => {
|
||||
const r = spawnSync(cmd, args, { encoding: 'utf8', maxBuffer: MAX_COMMAND_OUTPUT_BYTES, ...opts });
|
||||
const failure = r.error ? `${cmd} не выполнился: ${r.error.code || r.error.message}` : '';
|
||||
const stderr = [failure, (r.stderr || '').trim()].filter(Boolean).join('\n');
|
||||
return { status: failure ? 1 : (r.status ?? 1), stdout: (r.stdout || '').trim(), stderr };
|
||||
};
|
||||
|
||||
export function realOps({
|
||||
|
||||
@@ -9937,6 +9937,18 @@ const MUTANT_DEFINITIONS = [
|
||||
replace: ' const mismatch = evidenceMismatch(proof.evidence, proof.evidence);',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'merge-candidate-truncates-the-candidate-diff',
|
||||
guard: 'node --test --test-name-pattern="#596" test/merge-candidate.test.mjs',
|
||||
because: '#596: дифф кандидата с тремя копиями бандла — семь мегабайт. Без явного maxBuffer '
|
||||
+ 'spawnSync убивает git по ENOBUFS, patch-id считается по огрызку, и слияние падает '
|
||||
+ 'с усечённым диффом вместо причины',
|
||||
patches: [{
|
||||
file: 'scripts/merge-candidate.mjs',
|
||||
find: " const r = spawnSync(cmd, args, { encoding: 'utf8', maxBuffer: MAX_COMMAND_OUTPUT_BYTES, ...opts });",
|
||||
replace: " const r = spawnSync(cmd, args, { encoding: 'utf8', maxBuffer: 1024 * 1024, ...opts });",
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'declared-baseline-review-run-never-checked',
|
||||
guard: 'node --test --test-name-pattern="#595" test/release-gate.test.mjs',
|
||||
|
||||
Reference in New Issue
Block a user