mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-28 19:01:34 +00:00
ci: строгий режим свежести скриншотов включается на кандидате (#586)
Проверка #479 обязана быть строгой на кандидате беты и на релизном гейте. Фактически она не была строгой ни разу: preflight сравнивал со строкой `heavy=true` ВЕСЬ вывод `classify-changes.mjs --heavy`, а вывод двухстрочный — `heavy=…` и `mutants_requested=…`. В `$(…)` строки схлопываются через пробел, сравнение не совпадало никогда, режим оставался `warn`. Видно построчно в логе прогона 35091507839 на кандидате `4c44ef60`: скриншоты документации: режим warn (heavy=true WARN screenshot source fingerprint is stale; ... ok документация То есть проверка увидела устаревший индекс и пропустила кандидата. Обе беты после `699ab471` уехали с ним; на чистом checkout того же SHA `node scripts/check-docs.mjs --strict` падает с ERROR. Правило, которое из этого следует: формат `$GITHUB_OUTPUT` — построчный `ключ=значение`, читать его надо по ключу либо не читать вовсе. Где нужен один ответ, CLI отдаёт один ответ: `--screenshots-mode` печатает `warn` или `strict`, и в shell не остаётся ни разбора, ни развилки. Свидетели в `test/classify-changes.test.mjs`: режим по каждому событию, форма вызова в workflow (сравнение со строкой `heavy=true` не должно вернуться) и прямая проверка того, что вывод `--heavy` многострочный — то есть целиком сравнивать его нельзя. Мутант `screenshot-freshness-never-strict` возвращает прежнее «никогда не strict» и обязан краснеть. Issue: #586 User-Visible: no
This commit is contained in:
@@ -82,10 +82,12 @@ jobs:
|
||||
HEAD_MESSAGE: ${{ github.event.head_commit.message }}
|
||||
FULL_INPUT: ${{ inputs.full }}
|
||||
run: |
|
||||
heavy=$(node scripts/classify-changes.mjs --heavy)
|
||||
mode=warn
|
||||
[ "$heavy" = "heavy=true" ] && mode=strict
|
||||
echo "скриншоты документации: режим $mode ($heavy)"
|
||||
# #586: CLI отдаёт ОДИН ответ. Прежде здесь сравнивался со строкой
|
||||
# `heavy=true` весь вывод `--heavy`, а он двухстрочный: в `$(…)`
|
||||
# строки схлопываются через пробел, сравнение не совпадало никогда,
|
||||
# и строгий режим не включился ни на одном кандидате.
|
||||
mode=$(node scripts/classify-changes.mjs --screenshots-mode)
|
||||
echo "скриншоты документации: режим $mode"
|
||||
node scripts/check-docs.mjs --external --screenshots=$mode
|
||||
|
||||
# Конвейер читает `process.yml` из ветки по умолчанию, поэтому файл обязан
|
||||
|
||||
@@ -109,6 +109,25 @@ export function mutantsRequested({ eventName, headMessage, fullInput, mutantsInp
|
||||
return hasReleaseTrailer(headMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Режим гейта свежести скриншотов документации (#479, починен в #586).
|
||||
*
|
||||
* Значение одно, и считается оно здесь, а не в shell. Прежде preflight сравнивал
|
||||
* со строкой `heavy=true` ВЕСЬ вывод `--heavy`, а вывод из двух строк
|
||||
* (`heavy=…` и `mutants_requested=…`) в `$(…)` схлопывается в одну через
|
||||
* пробел. Сравнение не совпадало никогда: строгий режим не включился ни на
|
||||
* одном кандидате, проверка деградировала в предупреждение, а предупреждения
|
||||
* в сводке не видно. Так обе беты после `699ab471` уехали с устаревшим
|
||||
* индексом кадров.
|
||||
*
|
||||
* Правило разбора, которое из этого следует: формат `$GITHUB_OUTPUT` —
|
||||
* построчный `ключ=значение`, и читать его надо по ключу либо не читать вовсе.
|
||||
* Где нужен один ответ — CLI отдаёт один ответ.
|
||||
*/
|
||||
export function screenshotsGateMode(inputs) {
|
||||
return heavyGatesRequested(inputs) ? 'strict' : 'warn';
|
||||
}
|
||||
|
||||
/** Трейлер `Release: vX.Y.Z` в конце сообщения коммита — признак кандидата. */
|
||||
export function hasReleaseTrailer(message) {
|
||||
return /^Release:\s*v?\d+\.\d+\.\d+\S*\s*$/m.test(String(message || ''));
|
||||
@@ -125,7 +144,15 @@ export function formatOutputs(outputs) {
|
||||
// `file:///C:/C:/...`, CLI считал себя импортированным и молчал.
|
||||
const invokedDirectly = isMainModule(import.meta.url);
|
||||
if (invokedDirectly) {
|
||||
if (process.argv.includes('--heavy')) {
|
||||
if (process.argv.includes('--screenshots-mode')) {
|
||||
// #586: один вопрос — один ответ. Разбирать многострочный вывод в shell
|
||||
// больше негде и нечем.
|
||||
process.stdout.write(`${screenshotsGateMode({
|
||||
eventName: process.env.EVENT_NAME,
|
||||
headMessage: process.env.HEAD_MESSAGE,
|
||||
fullInput: process.env.FULL_INPUT,
|
||||
})}\n`);
|
||||
} else if (process.argv.includes('--heavy')) {
|
||||
// Отдельный вызов: у `heavy` другие входы (событие, сообщение head-коммита),
|
||||
// и на dev он нужен даже там, где классификация путей выключена.
|
||||
const heavy = heavyGatesRequested({
|
||||
|
||||
@@ -9917,6 +9917,21 @@ const MUTANT_DEFINITIONS = [
|
||||
replace: " if (settings?.fill_mode === 'never-a-fill-mode') return spaceFill;",
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'screenshot-freshness-never-strict',
|
||||
guard: 'node --test --test-name-pattern="#586" test/classify-changes.test.mjs',
|
||||
because: '#586: preflight сравнивал со строкой `heavy=true` ВЕСЬ двухстрочный вывод CLI, '
|
||||
+ 'поэтому строгий режим свежести скриншотов не включился ни на одном кандидате, и обе '
|
||||
+ 'беты после 699ab471 уехали с устаревшим индексом кадров. Проверка, которая умеет '
|
||||
+ 'только предупреждать, не гейт',
|
||||
patches: [{
|
||||
file: 'scripts/classify-changes.mjs',
|
||||
// рантайм-ложь, а не мёртвая ветка (#568): модуль обязан импортироваться
|
||||
find: ' return heavyGatesRequested(inputs) ? \'strict\' : \'warn\';',
|
||||
replace: ' return heavyGatesRequested(inputs) && String(inputs?.eventName) === \'mutant-never-an-event\'\n'
|
||||
+ ' ? \'strict\' : \'warn\';',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'stable-candidate-compares-against-itself',
|
||||
guard: 'node --test --test-name-pattern="AC2" test/performance-baseline.test.mjs',
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import {
|
||||
CHECK_OF_OUTPUT, CLASSIFIERS, OUTPUTS, PERF_PROFILES, classifyAll, classifyChanges, formatOutputs, mutantsRequested,
|
||||
screenshotsGateMode,
|
||||
} from '../scripts/classify-changes.mjs';
|
||||
import { manifest } from '../scripts/check-inputs.mjs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
@@ -185,6 +187,34 @@ test('CLI --heavy читает событие и сообщение из окр
|
||||
assert.equal(run({ EVENT_NAME: 'workflow_dispatch', FULL_INPUT: 'false', MUTANTS_INPUT: 'true', HEAD_MESSAGE: '' }), 'heavy=false\nmutants_requested=true');
|
||||
});
|
||||
|
||||
test('#586: режим гейта скриншотов приходит одним значением и на кандидате строгий', () => {
|
||||
assert.equal(screenshotsGateMode({ eventName: 'push', headMessage: 'fix: x\n\nIssue: #1\nUser-Visible: no' }), 'warn');
|
||||
assert.equal(screenshotsGateMode({ eventName: 'push', headMessage: 'x\n\nRelease: v1.2.3' }), 'strict', 'кандидат беты');
|
||||
assert.equal(screenshotsGateMode({ eventName: 'push', headMessage: 'x\n\nRelease: v1.76.0' }), 'strict', 'кандидат стабильного');
|
||||
assert.equal(screenshotsGateMode({ eventName: 'workflow_dispatch', fullInput: 'true' }), 'strict');
|
||||
assert.equal(screenshotsGateMode({ eventName: 'workflow_dispatch', fullInput: 'false' }), 'warn');
|
||||
assert.equal(screenshotsGateMode({ eventName: 'pull_request' }), 'strict');
|
||||
assert.equal(screenshotsGateMode({ eventName: 'schedule' }), 'strict');
|
||||
|
||||
// Регрессия, ради которой заведён #586: у `--heavy` вывод ДВУХСТРОЧНЫЙ, и
|
||||
// сравнение всего вывода со строкой `heavy=true` не совпадает никогда.
|
||||
const run = (args, env) => execFileSync(process.execPath, ['scripts/classify-changes.mjs', ...args], {
|
||||
encoding: 'utf8', env: { ...process.env, ...env },
|
||||
}).trim();
|
||||
const candidate = { EVENT_NAME: 'push', HEAD_MESSAGE: 'x\n\nRelease: v1.2.3' };
|
||||
assert.notEqual(run(['--heavy'], candidate), 'heavy=true', 'вывод --heavy многострочный — сравнивать его целиком нельзя');
|
||||
assert.equal(run(['--screenshots-mode'], candidate), 'strict');
|
||||
assert.equal(run(['--screenshots-mode'], { EVENT_NAME: 'push', HEAD_MESSAGE: 'fix: x' }), 'warn');
|
||||
});
|
||||
|
||||
test('#586: preflight спрашивает режим одним значением, а не разбирает вывод --heavy', () => {
|
||||
const workflow = readFileSync(new URL('../.github/workflows/validate.yml', import.meta.url), 'utf8');
|
||||
assert.match(workflow, /classify-changes\.mjs --screenshots-mode/);
|
||||
assert.ok(!/=\s*"heavy=true"/.test(workflow),
|
||||
'сравнение со строкой «heavy=true» вернулось — строгий режим снова не включится');
|
||||
assert.match(workflow, /check-docs\.mjs --external --screenshots=\$mode/);
|
||||
});
|
||||
|
||||
test('#510 AC1: мутанты по диффу запрашиваются кандидатом, PR, ночью и по кнопке — не обычным пушем', () => {
|
||||
const t = (env) => mutantsRequested(env);
|
||||
assert.equal(t({ eventName: 'push', headMessage: 'fix: x\n\nIssue: #1\nUser-Visible: no' }), false, 'обычный push');
|
||||
|
||||
Reference in New Issue
Block a user