From 7e69b4bb2895a151b2bdcc657de685e6a0c528b6 Mon Sep 17 00:00:00 2001 From: Matysh Date: Sun, 23 Aug 2026 09:55:04 +0300 Subject: [PATCH] ci: shard the smoke suite and stop validating review docs Issue: #254 User-Visible: no --- .github/workflows/process.yml | 6 ++-- .github/workflows/validate.yml | 64 +++++++++++++++++++++++++++++++--- PROCESS.md | 6 ++-- 3 files changed, 67 insertions(+), 9 deletions(-) diff --git a/.github/workflows/process.yml b/.github/workflows/process.yml index 6db37b79..f78c6f60 100644 --- a/.github/workflows/process.yml +++ b/.github/workflows/process.yml @@ -372,8 +372,10 @@ jobs: По необходимости, и «необходимость» определяется diff'ом и AC: - браузерные смоки `demo/smoke_*.mjs` — названные в AC плюс те, что печатает `node scripts/smoke-select.mjs --base --head `. - Их 167; прогон всех уместен только когда задача действительно - задевает всё. Выбирать по теме недостаточно: регресс #234 поймал + Сколько их всего — считает `ls demo/smoke_*.mjs | wc -l`; вшитое + в этот текст число трижды расходилось с деревом, поэтому его + здесь больше нет. Прогон всех уместен только когда задача + действительно задевает всё. Выбирать по теме недостаточно: регресс #234 поймал `smoke_wall_junctions`, который по названию про стыки стен, а не про толщину отрезка. Инструмент печатает три вида ответа, и они разные: «прямое совпадение» — смок называет изменённый символ, diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index a77dfdc3..e076bfb0 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -6,6 +6,12 @@ on: # to the same SHA and must not duplicate the browser validation jobs. branches: - '**' + # Документы ревью конвейер пишет пачками — 340 коммитов за месяц, и каждый + # гонял лёгкую половину Validate впустую (≈15 часов раннера в месяц). + # Релизного кандидата это не затрагивает: тег всегда стоит на коммите, + # который меняет версию и бандл, а не только `docs/reviews/**`. + paths-ignore: + - 'docs/reviews/**' pull_request: # A new push supersedes an unfinished validation for the same branch or PR. @@ -24,6 +30,28 @@ jobs: - name: Validate public documentation run: node scripts/check-docs.mjs --external + # Конвейер читает `process.yml` из ветки по умолчанию, поэтому файл обязан + # совпадать в `main` и `dev`. До этой проверки совпадение держалось на + # дисциплине: каждая правка требовала двух пушей и ручной сверки. + process-workflow-sync: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + with: + fetch-depth: 0 + - name: process.yml идентичен в main и dev + run: | + git fetch --quiet origin main dev + if diff <(git show origin/main:.github/workflows/process.yml) \ + <(git show origin/dev:.github/workflows/process.yml); then + echo "main и dev идентичны" + else + echo "РАСХОЖДЕНИЕ: process.yml в main и dev различаются." + echo "Конвейер исполняет версию из ветки по умолчанию, поэтому" + echo "правку нужно отправить в обе ветки." + exit 1 + fi + provenance: runs-on: ubuntu-latest steps: @@ -255,6 +283,13 @@ jobs: needs: [frontend, reuse] if: needs.reuse.outputs.smoke != 'true' runs-on: ubuntu-latest + # Смоки шардируются: последовательный прогон занимал ~7.5 минут и был + # критическим путём всего Validate. Три шарда режут его примерно вдвое; + # цена — трижды `npm ci` и сборка, около двух оплаченных минут раннера. + strategy: + fail-fast: false + matrix: + shard: [1, 2, 3] steps: - uses: actions/checkout@v7 - uses: actions/setup-node@v7 @@ -278,11 +313,21 @@ jobs: run: npx playwright install chromium - name: Build a fresh bundle for the smokes run: npm run build && cp dist/houseplan-card.js demo/srv/assets/houseplan-card.js - - name: Smoke suite + - name: Smoke suite (шард ${{ matrix.shard }} из 3) + env: + SHARD: ${{ matrix.shard }} + SHARDS: '3' run: | fail=0 + index=0 + ran=0 mkdir -p /tmp/smoke-logs + # Деление по порядковому номеру файла: список отсортирован, поэтому + # разбиение детерминировано и не зависит от времени прогона. for f in demo/smoke_*.mjs; do + index=$((index + 1)) + if [ $(( (index - 1) % SHARDS + 1 )) -ne "$SHARD" ]; then continue; fi + ran=$((ran + 1)) name=$(basename "$f" .mjs) if node "$f" > "/tmp/smoke-logs/$name.log" 2>&1; then echo "ok $name" @@ -292,18 +337,27 @@ jobs: fail=1 fi done + echo "--- шард ${SHARD}/${SHARDS}: прогнано ${ran} из ${index}" + # Пустой шард — признак, что деление сломалось, а не что работы нет. + if [ "$ran" -eq 0 ]; then echo "шард пуст: проверьте деление"; exit 1; fi exit $fail - name: Upload smoke logs if: failure() uses: actions/upload-artifact@v7 with: - name: smoke-logs + name: smoke-logs-${{ matrix.shard }} path: /tmp/smoke-logs - # Маркер пишется последним шагом: он существует только если всё выше - # прошло. Кэш сохраняется post-шагом, то есть тоже лишь при успехе job. + + # Маркер переиспользования пишется ОДИН раз и только когда прошли все шарды: + # частично прогнанная матрица не имеет права выглядеть как выполненная работа. + smoke_done: + needs: [smoke, reuse] + if: needs.reuse.outputs.smoke != 'true' + runs-on: ubuntu-latest + steps: - name: Записать маркер успеха run: | - printf '%s\n' "smoke прогнана успешно" \ + printf '%s\n' "smoke прогнана успешно (3 шарда)" \ "SHA: ${{ github.sha }}" \ "прогон: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \ > .reuse-marker diff --git a/PROCESS.md b/PROCESS.md index 77c53068..e8c6753a 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -549,8 +549,10 @@ python -m pytest tests_backend -q # py3.13, если менялся бэке **Объём гейтов на код-ревью соразмерен задаче** (issue #127). Всегда: `typecheck`, `npm test`, `npm run build` со сверкой трёх копий бандла, а при любом diff'е по `src/**` — ещё и `node scripts/check-docs.mjs`. По -необходимости, определяемой diff'ом и AC: браузерные смоки (их 167 — прогон всех -уместен только когда задача задевает всё; какие относятся к диффу, печатает +необходимости, определяемой diff'ом и AC: браузерные смоки (сколько их — +считает `ls demo/smoke_*.mjs | wc -l`, вшитое число здесь трижды отставало от +дерева; прогон всех уместен только когда задача задевает всё; какие относятся к +диффу, печатает `node scripts/smoke-select.mjs --base origin/dev --head HEAD`, и его вывод прикладывается к ревью вместе с решением по каждой строке), `golden:verify` при изменении видимого результата, `pytest tests_backend` при правках в Python, performance-профили при