mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-01 04:09:17 +00:00
ci: перф-смок по диффу — изометрия и взаимодействие в код-ревью
Классификация changes вынесена в scripts/classify-changes.mjs (выходы perf_iso/perf_interaction, fallback --all). performance_smoke добавляет large-house-isometric-v1 при правке src/iso-* и large-house-interaction-v1 при правке живого пути, по 3 образца против hardMaxMs полных профилей (budgets-*-smoke.json). Набор профилей входит в ключ reuse. PROCESS.md §8. Issue: #473 User-Visible: no
This commit is contained in:
Executable
+59
@@ -0,0 +1,59 @@
|
||||
// Классификация изменённых файлов для job `changes` в validate.yml (#473 AC8).
|
||||
//
|
||||
// Шаблоны жили inline в shell-шаге `classify` как `has('regex')`. Пока выходов
|
||||
// было три, это терпимо; с диффозависимыми профилями перф-смока (#473) их
|
||||
// пять, и вопрос «запустит ли правка src/iso-x.ts изометрический профиль»
|
||||
// стал вопросом к workflow, на который нельзя ответить тестом — shell в YAML
|
||||
// не исполняется локально. Теперь ответ даёт функция, а shell только
|
||||
// переписывает её вывод в `$GITHUB_OUTPUT`.
|
||||
//
|
||||
// Контракт неизменен: каждый выход — строка 'true'/'false', как её и читают
|
||||
// условия `if: needs.changes.outputs.X == 'true'`. Fallback «полный прогон
|
||||
// без классификации» (--all) выставляет все выходы в 'true' — в том числе те,
|
||||
// что появятся позже: пропущенный ключ в fallback-е означал бы, что job
|
||||
// с этим условием молча не запускается ровно в тех прогонах, где база
|
||||
// недоказуема и проверять надо всё.
|
||||
|
||||
import { readFileSync } from 'node:fs';
|
||||
|
||||
export const CLASSIFIERS = {
|
||||
frontend: /^(src\/|demo\/|test\/|dist\/|custom_components\/houseplan\/frontend\/|package(-lock)?\.json$|rollup\.config\.mjs$|tsconfig)/,
|
||||
backend: /^(custom_components\/.*\.py$|tests_backend\/|scripts\/support-relay\/|pytest\.ini$)/,
|
||||
integration: /^(custom_components\/houseplan\/manifest\.json$|hacs\.json$|custom_components\/.*\.py$|custom_components\/.*\/translations\/)/,
|
||||
// Перф-смок (#473 §5): изометрический профиль — при правке изометрии,
|
||||
// профиль взаимодействия — при правке живого пути и оркестраторов кадра.
|
||||
// Только `src/**`: тесты и демо кадр не замедляют.
|
||||
perf_iso: /^src\/iso-[^/]+\.ts$/,
|
||||
perf_interaction: /^src\/(live-[^/]+|render-[^/]+|houseplan-render-lifecycle|houseplan-card)\.ts$/,
|
||||
};
|
||||
|
||||
export const OUTPUTS = Object.keys(CLASSIFIERS);
|
||||
|
||||
/** Список файлов → выходы job `changes` ('true'/'false' по каждому ключу). */
|
||||
export function classifyChanges(files) {
|
||||
const list = (Array.isArray(files) ? files : String(files).split('\n'))
|
||||
.map((file) => file.trim()).filter(Boolean);
|
||||
const result = {};
|
||||
for (const [name, pattern] of Object.entries(CLASSIFIERS)) {
|
||||
result[name] = list.some((file) => pattern.test(file)) ? 'true' : 'false';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Fallback без классификации: всё прогоняется. */
|
||||
export function classifyAll() {
|
||||
return Object.fromEntries(OUTPUTS.map((name) => [name, 'true']));
|
||||
}
|
||||
|
||||
/** Формат `$GITHUB_OUTPUT`. */
|
||||
export function formatOutputs(outputs) {
|
||||
return OUTPUTS.map((name) => `${name}=${outputs[name]}`).join('\n') + '\n';
|
||||
}
|
||||
|
||||
const invokedDirectly = process.argv[1]
|
||||
&& import.meta.url === new URL(`file://${process.argv[1]}`).href;
|
||||
if (invokedDirectly) {
|
||||
const all = process.argv.includes('--all');
|
||||
const outputs = all ? classifyAll() : classifyChanges(readFileSync(0, 'utf8'));
|
||||
process.stdout.write(formatOutputs(outputs));
|
||||
}
|
||||
Reference in New Issue
Block a user