gendesign/.forgejo/workflows/ci.yml
Light1YT 795661557f ci(frontend): add vitest job to Forgejo Actions gate
Run the merged frontend vitest suite on every frontend-touching PR so the
tests don't rot. Mirrors the #1032 backend gate: per-job dorny/paths-filter
(new `frontend` output, `frontend/**`), node:20 + npm cache on the lockfile,
`npm ci --legacy-peer-deps --no-audit --no-fund` (exact frontend/Dockerfile
flags), then `npm run test`. Additive — backend-tests job unchanged; no
top-level paths filter so frontend-only PRs already trigger the workflow.
Making frontend-tests a required check is a follow-up in the Forgejo UI.

Refs #999.
2026-06-07 11:52:10 +00:00

154 lines
7.2 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

name: CI
# Forgejo Actions pytest gate for the MAIN backend (backend/).
# WHY THIS FILE EXISTS: Forgejo runs ONLY .forgejo/workflows/* — the
# .github/workflows/ci.yml pytest gate does NOT execute on git.gendsgn.ru
# (proven: Forgejo Actions runs показывают только deploy/build jobs). Без этого
# backend-изменения мержились + деплоились БЕЗ автотестов → live-баг #994
# (district 500) уехал в прод необнаруженным. Этот workflow добавляет реальный
# gate: backend-сьют GREEN (1687 passed / 0 failed) после CI-rehab 1+2.
#
# Lane = MOCK-ONLY (day 1): нет postgres service-контейнера — сьют мокает БД,
# единственный real-Postgres тест (tests/sql/ mv_layout) self-skip'ается через
# connectivity-probe. PDF-тесты (WeasyPrint) РЕАЛЬНО ИДУТ здесь (libpango
# установлен ниже), тогда как на macOS-dev они runtime-skip'аются.
# FUTURE: добавить `postgis/postgis:16-3.4` service + гонять mv_layout — см.
# .github/workflows/ci.yml как образец service-блока.
on:
pull_request:
branches: [main]
push:
branches:
# Mirror the bot-PR / feature-branch flow в .claude/rules/git-pr.md:
# PR получает gate, прямые пуши в feature-ветки — тоже.
- "feat/**"
- "fix/**"
- "refactor/**"
- "chore/**"
- "docs/**"
- "perf/**"
- "test/**"
- "ci/**"
- "hotfix/**"
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# Paths-filter: gate бежит ТОЛЬКО когда поменялся backend-код или SQL,
# которые этот backend читает (mirror deploy.yml changes-job). На чисто
# frontend/docs PR job no-op'ится → дёшево.
changes:
runs-on: ubuntu-latest
outputs:
backend: ${{ steps.filter.outputs.backend }}
frontend: ${{ steps.filter.outputs.frontend }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
backend:
- 'backend/**'
- 'data/sql/**'
- '.forgejo/workflows/ci.yml'
frontend:
- 'frontend/**'
- '.forgejo/workflows/ci.yml'
backend-tests:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.backend == 'true'
defaults:
run:
working-directory: backend
env:
# TESTING=1 активирует RBAC-bypass (app/main.py rbac_guard пропускает
# запросы при settings.testing=True) — иначе 401 на всём /api/v1.
TESTING: "1"
# Stub DSN: psycopg v3 требует parseable URL на импорте; реального коннекта
# нет — DB-тесты мокаются, real-DB тест (tests/sql/) self-skip'ается через
# connectivity-probe к этому хосту (5432 недоступен → skip).
DATABASE_URL: postgresql+psycopg://test:test@localhost:5432/test
REDIS_URL: redis://localhost:6379/0
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install uv
# Официальный standalone-инсталлер. НЕ astral-sh/setup-uv — он ломается
# на Forgejo-runner с PEP 668 externally-managed-environment (#666 CI).
run: |
curl -LsSf https://astral.sh/uv/install.sh | sh
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
- name: Install system deps for geo + WeasyPrint
# libpq/gdal/proj/geos — geo-стек (geopandas/shapely/pyproj).
# libcairo2/libpango* — нативные либы WeasyPrint: с ними PDF-тесты
# (tests/test_layout_tz_pdf.py) РЕАЛЬНО ИДУТ на CI (на macOS-dev они
# module-skip'аются probe'ом native-libs). Mirror .github ci.yml:55-57.
run: |
sudo apt-get update
sudo apt-get install -y libpq-dev libgdal-dev libproj-dev libgeos-dev \
libcairo2 libpango-1.0-0 libpangoft2-1.0-0
- name: Install Python deps (incl. dev group — ruff, pytest)
# backend/uv.lock закоммичен → --frozen (детерминированно, fail при
# дрейфе lock vs pyproject). dev-группа ставится по умолчанию (ruff/pytest).
run: uv sync --frozen
- name: Lint (ruff check)
# Дешёвый fail-fast. NB: `ruff format --check` НАМЕРЕННО НЕ в gate —
# на момент создания 17 файлов repo-wide дали бы day-1 red. Отдельный
# format-pass = future enhancement. `ruff check .` сейчас green.
run: uv run ruff check .
- name: Test (pytest)
# --ignore=tests/smoke: prod-smoke бьёт по live https://gendsgn.ru
# (помечены @pytest.mark.prod_smoke; pyproject addopts уже их deselect'ит,
# но --ignore — belt-and-suspenders на случай сбора фикстур).
# tests/integration self-skip'ается через requires_test_db (skipif на
# TEST_DATABASE_URL, который тут не задан) → НЕ игнорим, оно чисто skip'ается.
# tests/sql/ mv_layout self-skip'ается через Postgres-connectivity probe
# (5432 недоступен в этом mock-lane) → SKIP. Это intended.
# PDF-тесты ИДУТ (libpango выше). Target: 0 failed, skips OK.
run: uv run pytest -q --ignore=tests/smoke
frontend-tests:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.frontend == 'true'
defaults:
run:
working-directory: frontend
steps:
- uses: actions/checkout@v4
- name: Set up Node
# Node 20 — совпадает с major из frontend/Dockerfile (node:20-alpine).
# cache=npm + cache-dependency-path на lockfile → переиспользуем ~/.npm
# между прогонами (mirror Dockerfile's `--mount=type=cache,target=/root/.npm`).
uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
cache-dependency-path: frontend/package-lock.json
- name: Install deps (npm ci, frozen lockfile)
# ТОЧНЫЕ флаги из frontend/Dockerfile (deps stage):
# --legacy-peer-deps — Tailwind 4 alpha + React 19 peer-dep mismatches;
# --no-audit --no-fund — тише и быстрее в CI. `ci` (не `install`) =
# детерминированно из package-lock.json, fail при дрейфе lock vs package.json.
run: npm ci --legacy-peer-deps --no-audit --no-fund
- name: Test (vitest)
# `npm run test` = `vitest run` (single-shot, не watch). Только тесты —
# `next build` НАМЕРЕННО не здесь (тяжёлый, verified в deploy.yml build).
run: npm run test