mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
Merge updated dev for v1.63.0
This commit is contained in:
@@ -48,6 +48,7 @@ jobs:
|
||||
BLOCKED: ${{ contains(github.event.issue.labels.*.name, 'blocked') }}
|
||||
EXHAUSTED: ${{ contains(github.event.issue.labels.*.name, 'review-4') }}
|
||||
SMALL: ${{ contains(github.event.issue.labels.*.name, 'small') }}
|
||||
TRIVIAL: ${{ contains(github.event.issue.labels.*.name, 'trivial') }}
|
||||
NUM: ${{ github.event.issue.number }}
|
||||
run: |
|
||||
# Этап определяется первым: от него зависит, какие вердикты считать.
|
||||
@@ -58,8 +59,9 @@ jobs:
|
||||
*) echo "метка $LABEL конвейер не запускает" ;;
|
||||
esac
|
||||
|
||||
# Лимит циклов: 4 обычный, 2 на лёгком треке (PROCESS.md §4).
|
||||
limit=4; [ "$SMALL" = "true" ] && limit=2
|
||||
# Лимит циклов: 4 обычный, 2 на лёгком и коротком треке (PROCESS.md §4).
|
||||
limit=4
|
||||
if [ "$SMALL" = "true" ] || [ "$TRIVIAL" = "true" ]; then limit=2; fi
|
||||
|
||||
# Счётчик считает вердикты ТОЛЬКО своего этапа. Раньше он брал все
|
||||
# подряд, и вердикт по ТЗ съедал цикл из бюджета код-ревью: на #89
|
||||
@@ -134,8 +136,15 @@ jobs:
|
||||
fetch-depth: 0
|
||||
ref: dev
|
||||
|
||||
# Окружение готовит workflow, а не модель своими ходами. Раньше промпт
|
||||
# велел ревьюеру самому выполнить `npm ci`: минуты уходили на установку без
|
||||
# кэша, платились из бюджета 45 минут и из лимитов подписки, а ходы модели
|
||||
# тратились на работу инфраструктуры. В validate.yml кэш стоит на всех
|
||||
# тяжёлых job, здесь его не было.
|
||||
- uses: actions/setup-node@v4
|
||||
with: { node-version: 22 }
|
||||
with:
|
||||
node-version: 22
|
||||
cache: npm
|
||||
|
||||
# Материал ревью живёт в ветке задачи: ТЗ в docs/specs/ и код коммитятся
|
||||
# в issue/<NN>-slug. Если ветка запушена — переключаемся на неё, иначе
|
||||
@@ -156,6 +165,24 @@ jobs:
|
||||
echo "МАТЕРИАЛ НЕ ЗАПУШЕН" >> "$GITHUB_STEP_SUMMARY"
|
||||
fi
|
||||
|
||||
# Зависимости ставятся ПОСЛЕ переключения на ветку задачи: lockfile мог
|
||||
# измениться именно в ней, и установка по копии из dev дала бы не то дерево.
|
||||
- name: Установить зависимости
|
||||
run: npm ci
|
||||
|
||||
# Браузер нужен не всякому ревью (см. правило выбора гейтов в промпте),
|
||||
# но когда нужен — качать его заново дороже, чем держать в кэше.
|
||||
- name: Кэш браузеров Playwright
|
||||
id: pw
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
|
||||
|
||||
- name: Установить Chromium
|
||||
if: steps.pw.outputs.cache-hit != 'true'
|
||||
run: npx playwright install --with-deps chromium
|
||||
|
||||
- name: Review
|
||||
id: review
|
||||
uses: anthropics/claude-code-action@v1
|
||||
@@ -205,10 +232,38 @@ jobs:
|
||||
По каждому AC: либо он доказан автотестом и ты убедился, что тест
|
||||
умеет падать, либо разобран по коду с явной записью «проверено
|
||||
чтением, не исполнением». «Verified» без названной команды и её
|
||||
результата доказательством не является. Зависимостей в рабочей
|
||||
копии нет: перед гейтами выполни `npm ci`. Проверь трейлеры Issue и
|
||||
User-Visible, при User-Visible: yes — правки в оба changelog в том же
|
||||
коммите.
|
||||
результата доказательством не является. Зависимости уже установлены
|
||||
workflow, Chromium тоже — `npm ci` выполнять не нужно. Проверь
|
||||
трейлеры Issue и User-Visible, при User-Visible: yes — правки в оба
|
||||
changelog в том же коммите.
|
||||
|
||||
**Объём гейтов соразмерен задаче.** Прогонять весь набор на каждой
|
||||
правке — не тщательность, а потеря времени: полные наборы это
|
||||
предрелизный гейт (PROCESS.md §8), а не гейт ревью.
|
||||
|
||||
Всегда, они дешёвые:
|
||||
`npx tsc --noEmit`, `npm test`, `npm run build` со сверкой трёх
|
||||
копий бандла.
|
||||
|
||||
По необходимости, и «необходимость» определяется diff'ом и AC:
|
||||
- браузерные смоки `demo/smoke_*.mjs` — названные в AC плюс
|
||||
относящиеся к тронутым поверхностям. Их 127; прогон всех уместен
|
||||
только когда задача действительно задевает всё;
|
||||
- `npm run golden:verify` — если diff может изменить видимый
|
||||
результат: рендер, геометрия, стили, слои;
|
||||
- `python -m pytest tests_backend -q` — если тронут
|
||||
`custom_components/**/*.py`;
|
||||
- performance-профили — если названы в AC либо тронуты
|
||||
чувствительные к перфу пути.
|
||||
|
||||
Дисциплина «тест должен уметь падать» не отменяется, но применяется к
|
||||
тем тестам, которые ты прогонял.
|
||||
|
||||
**В комментарии обязателен перечень: какие гейты прогнал, какие нет и
|
||||
почему.** Это условие честности такого сужения: непрогнанный гейт
|
||||
становится видимым решением, а не молчаливым пропуском. Раздел «чего
|
||||
не проверял» в документе ревью — не формальность, а главный его
|
||||
раздел на коротких задачах.
|
||||
|
||||
Ты НЕ правишь ни ТЗ, ни продуктовый код. Только оцениваешь.
|
||||
|
||||
|
||||
@@ -41,6 +41,15 @@ of a status and `rejected` on a closed issue. Exactly one `S*` label per open
|
||||
issue. [GitHub Projects (v2)](https://github.com/users/Matysh/projects/1) is a
|
||||
human-facing view synchronised from the labels, not the source of truth.
|
||||
|
||||
Two shortcuts exist for small work. `small` — the light track: the spec lives in
|
||||
the issue body and its review is a comment. `trivial` — the short track: no spec
|
||||
stage at all, `S2-analysis` straight to `S5-ready`, with the AC written into the
|
||||
issue body first. `trivial` requires a bug confined to one surface with no new UX
|
||||
contract, no migration, no i18n, no perf or touch impact, at most three checkable
|
||||
AC, **and expected behaviour already on record** — nothing left to decide. Code
|
||||
review is never skipped on either track; it is what stands in for testing.
|
||||
`PROCESS.md` §5 and §5.1 hold the criteria.
|
||||
|
||||
An issue filed by an outsider is worked exactly like one of the owner's own, once
|
||||
the owner has decided to take it. The check sits **at the entrance**, not on every
|
||||
step: while an issue carries no status label it is outside the process and the
|
||||
|
||||
@@ -67,6 +67,12 @@ const CLASS_C = [
|
||||
|
||||
const CHANGELOGS = ['docs/CHANGELOG.md', 'docs/CHANGELOG.ru.md'];
|
||||
|
||||
// Метки, при которых файла ТЗ в docs/specs/ быть не должно: на лёгком треке ТЗ
|
||||
// живёт в теле issue (§5), на коротком — там же, и ревью ТЗ вообще не проводится
|
||||
// (§5.1, issue #128). Офлайн эти случаи неотличимы от «ТЗ не написано», поэтому
|
||||
// проверка 3 краснеет только когда метки прочитаны.
|
||||
export const NO_SPEC_FILE = ['small', 'trivial'];
|
||||
|
||||
export const ALLOWED_STATUS = ['S5-ready', 'S6-in-progress', 'S7-code-review', 'S8-merged'];
|
||||
export const STRICT_STATUS = ['S5-ready', 'S6-in-progress', 'S7-code-review'];
|
||||
|
||||
@@ -235,12 +241,12 @@ export function checkSpecs(commits, specFiles, labelsOf = null) {
|
||||
if (labels === null) {
|
||||
out.push({
|
||||
level: 'warn', rule: 3, sha: c.short,
|
||||
msg: `класс A по ${t}, но ТЗ docs/specs/${nn}-*.md не найдено — допустимо только при метке small`,
|
||||
msg: `класс A по ${t}, но ТЗ docs/specs/${nn}-*.md не найдено — допустимо при метке small или trivial`,
|
||||
});
|
||||
} else if (!labels.includes('small')) {
|
||||
} else if (!labels.some((l) => NO_SPEC_FILE.includes(l))) {
|
||||
out.push({
|
||||
level: 'fail', rule: 3, sha: c.short,
|
||||
msg: `класс A по ${t}: ТЗ docs/specs/${nn}-*.md нет, и метки small на issue нет — код без ТЗ`,
|
||||
msg: `класс A по ${t}: ТЗ docs/specs/${nn}-*.md нет, и метки ${NO_SPEC_FILE.join(' / ')} на issue нет — код без ТЗ`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,8 +134,9 @@ test('a class A commit without a spec warns offline and fails with labels', () =
|
||||
assert.equal(offline[0].level, 'warn');
|
||||
assert.equal(offline[0].rule, 3);
|
||||
|
||||
// С метками: small оправдывает отсутствие файла, его отсутствие — нет.
|
||||
// С метками: small и trivial оправдывают отсутствие файла, их отсутствие — нет.
|
||||
assert.deepEqual(checkSpecs([c], [], () => ['small', 'S5-ready']), []);
|
||||
assert.deepEqual(checkSpecs([c], [], () => ['trivial', 'S5-ready']), []);
|
||||
const strict = checkSpecs([c], [], () => ['S5-ready']);
|
||||
assert.equal(strict.length, 1);
|
||||
assert.equal(strict[0].level, 'fail');
|
||||
|
||||
Reference in New Issue
Block a user