mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-28 19:01:34 +00:00
Three claims a green backend used to make, each slightly wider than the truth — and #392 happened in exactly that gap. The frontend pin said 20260826.1 next to homeassistant==2026.8.3, whose package_constraints.txt requires 20260729.7: a combination that exists in no HA release. It was never derived from anything — someone once picked it. It is now taken from the constraints, the source is named in the file, and a test holds both numbers together so raising HA cannot quietly desync them. ruff's include declared three trees while CI linted one. Narrowed the declaration rather than widening CI: the debt in scripts/ and tests_backend/ (56 findings, mostly E402/I001, plus 7 B023 and 5 B017) has its own cost and its own decisions, and belongs in its own task, not in a visibility fix. test/lint-scope.test.mjs now compares the two, so they can only move together. The pin check skipped a workflow when it found neither the package name nor the requirements path — and both vanish together the moment someone returns to Defaulting to user installation because normal site-packages is not writeable, i.e. the gate switched itself off under precisely the change it exists to catch. It now walks the whole .github/workflows directory and decides per file by a positive sign: if a file installs python packages, it must install them from the pins file. Verified by dropping a rogue workflow into the directory — it reddens without touching any list. Three mutants registered and each run by hand. User-Visible: no Issue: #399
46 lines
2.5 KiB
JavaScript
46 lines
2.5 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { readFileSync } from 'node:fs';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
// #399: конфиг обещал линт по трём деревьям, CI проверял одно. Расхождение
|
|
// само по себе не ломает сборку — оно ломает доверие к зелёному значку, а
|
|
// следом и к выводу «раз зелено, значит проверено». Ровно так в tests_backend
|
|
// проехали F401/F811, которых на v1.69.0 не было.
|
|
|
|
const root = (name) => fileURLToPath(new URL(`../${name}`, import.meta.url));
|
|
const read = (name) => readFileSync(root(name), 'utf8');
|
|
|
|
/** Деревья из `[tool.ruff] include`, приведённые к каталогу. */
|
|
const declaredTrees = () => {
|
|
const pyproject = read('pyproject.toml');
|
|
const section = pyproject.slice(pyproject.indexOf('[tool.ruff]'));
|
|
const include = /include\s*=\s*\[([^\]]*)\]/.exec(section);
|
|
assert.ok(include, '[tool.ruff] include обязан существовать');
|
|
return [...include[1].matchAll(/"([^"]+)"/g)]
|
|
.map((match) => match[1].replace(/\/\*\*\/\*\.py$|\/\*\.py$/, ''))
|
|
.sort();
|
|
};
|
|
|
|
/** Деревья, которые реально проверяет шаг линта в CI. */
|
|
const lintedTrees = () => {
|
|
const workflow = read('.github/workflows/validate.yml');
|
|
const step = /python -m ruff check ([^\n]*)/.exec(workflow);
|
|
assert.ok(step, 'шаг «Линт бэкенда» обязан существовать в validate.yml');
|
|
return step[1].trim().split(/\s+/).filter(Boolean).sort();
|
|
};
|
|
|
|
test('#399 AC2: объявленный скоуп линта равен проверяемому', () => {
|
|
assert.deepEqual(declaredTrees(), lintedTrees(),
|
|
'include в pyproject.toml и аргументы ruff в validate.yml разошлись:'
|
|
+ ' конфиг обещает одно, CI проверяет другое. Расширять список можно'
|
|
+ ' только вместе — иначе объявленное покрытие снова станет фикцией.');
|
|
});
|
|
|
|
test('#399 AC2: расхождение действительно ловится', () => {
|
|
// Проверка, которая не умеет краснеть, ничего не гарантирует.
|
|
const declared = ['custom_components/houseplan', 'tests_backend'];
|
|
const linted = ['custom_components/houseplan'];
|
|
assert.throws(() => assert.deepEqual(declared, linted));
|
|
});
|