Add the Gitea Actions workflows
Ports n3xd's four: pre-commit, backend tests, sharded Playwright and a compose smoke test. Everything comes from the committed .env.example, so no repository secrets are needed; Actions still has to be enabled per repository and a runner registered with the ubuntu-latest label. container_name, published ports and image tags are all daemon-global, so two shards on one runner would fight over them. compose.ci.yml resets them and tags per project. test-backend keeps the fixed names because it reaches Postgres from the runner host. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkmeRiyeYmVZqJVwuyHq9o
This commit is contained in:
co-authored by
Claude Opus 5
parent
9cede8dbb5
commit
8a221bfe50
@@ -0,0 +1,107 @@
|
||||
name: Playwright Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- backend/**
|
||||
- frontend/**
|
||||
- docker/compose*.yml
|
||||
- .env.example
|
||||
- .gitea/workflows/playwright.yml
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
paths:
|
||||
- backend/**
|
||||
- frontend/**
|
||||
- docker/compose*.yml
|
||||
- .env.example
|
||||
- .gitea/workflows/playwright.yml
|
||||
|
||||
env:
|
||||
# The playwright runner service comes from the dev overlay. It loads the SPA
|
||||
# from the nginx `frontend` service and reaches the API as http://backend:8000
|
||||
# on the project network — both wired up in compose.ci.yml.
|
||||
COMPOSE_FILE: docker/compose.yml:docker/compose.dev.yml:docker/compose.ci.yml
|
||||
# frontend/playwright.config.ts keys the blob reporter, the retries and
|
||||
# forbidOnly off CI, and compose.dev.yml forwards it into the container.
|
||||
CI: "true"
|
||||
|
||||
jobs:
|
||||
test-playwright:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Two spec files (tests/flows.spec.ts, tests/admin.spec.ts) plus
|
||||
# tests/auth.setup.ts, which every shard reruns as its setup project.
|
||||
# More shards than that would only pay container startup twice over.
|
||||
shardIndex: [1, 2]
|
||||
shardTotal: [2]
|
||||
env:
|
||||
# One stack per shard, so a `down -v` cannot reach the other shard's
|
||||
# volumes. compose.ci.yml above drops the fixed container_names and host
|
||||
# ports, which the project name does not cover — without it two shards on
|
||||
# the same runner host collide on the daemon-global names.
|
||||
COMPOSE_PROJECT_NAME: fluksio-app-ci-pw-${{ matrix.shardIndex }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Write .env
|
||||
# Not committed; compose interpolates it and the runner container reads
|
||||
# FIRST_SUPERUSER / FIRST_SUPERUSER_PASSWORD out of it (tests/config.ts).
|
||||
run: cp .env.example .env
|
||||
- run: docker compose build backend frontend playwright
|
||||
- run: docker compose down -v --remove-orphans
|
||||
# PLAYWRIGHT_BASE_URL points the browser at `frontend`, which is not a
|
||||
# dependency of the playwright service, so bring it up explicitly.
|
||||
- run: docker compose up -d --wait backend frontend
|
||||
- name: Run Playwright tests
|
||||
run: >-
|
||||
docker compose run --rm playwright
|
||||
bunx playwright test --trace=retain-on-failure
|
||||
--shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
|
||||
- name: Tear down
|
||||
if: always()
|
||||
run: docker compose down -v --remove-orphans
|
||||
- name: Upload blob report
|
||||
if: ${{ !cancelled() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: blob-report-${{ matrix.shardIndex }}
|
||||
path: frontend/blob-report
|
||||
include-hidden-files: true
|
||||
retention-days: 1
|
||||
|
||||
merge-reports:
|
||||
needs:
|
||||
- test-playwright
|
||||
# Merge even when a shard failed — that report is the one worth reading.
|
||||
if: ${{ !cancelled() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- name: Install dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
- name: Download blob reports
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: frontend/all-blob-reports
|
||||
pattern: blob-report-*
|
||||
merge-multiple: true
|
||||
- name: Merge into an HTML report
|
||||
run: bunx playwright merge-reports --reporter html ./all-blob-reports
|
||||
working-directory: frontend
|
||||
- name: Upload HTML report
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: html-report--attempt-${{ github.run_attempt }}
|
||||
path: frontend/playwright-report
|
||||
include-hidden-files: true
|
||||
retention-days: 7
|
||||
@@ -0,0 +1,53 @@
|
||||
name: pre-commit
|
||||
|
||||
# Gitea Actions. `uses:` is resolved against the instance's action mirror, the
|
||||
# same convention the sibling N3XD repositories use — plain `owner/action@tag`.
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
|
||||
jobs:
|
||||
pre-commit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
# Matches backend/Dockerfile, so the gate type-checks and formats against
|
||||
# the interpreter the image ships.
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- name: Set up uv
|
||||
uses: astral-sh/setup-uv@v7
|
||||
with:
|
||||
cache-dependency-glob: |
|
||||
pyproject.toml
|
||||
backend/pyproject.toml
|
||||
uv.lock
|
||||
- name: Write .env
|
||||
# Not committed, and the generate-frontend-sdk hook imports the backend
|
||||
# settings, which read ../.env from backend/.
|
||||
run: cp .env.example .env
|
||||
# The hooks call `uv run ruff` from the repo root, so the workspace .venv
|
||||
# (pyproject.toml → [tool.uv.workspace]) is what has to exist.
|
||||
- name: Install backend dependencies
|
||||
run: uv sync
|
||||
- name: Install frontend dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
# The formatting hooks rewrite files; pre-commit exits non-zero when they
|
||||
# do, which fails the run. No auto-commit branch here: that needs a push
|
||||
# token, and pre-commit-ci/lite-action talks to a GitHub-only service.
|
||||
- name: Run pre-commit
|
||||
run: uvx pre-commit run --all-files --show-diff-on-failure
|
||||
# The hooks cover ruff and biome but not mypy, which `make lint-backend`
|
||||
# runs and which is strict for everything outside the flow prototypes.
|
||||
- name: Typecheck backend
|
||||
run: uv run mypy app
|
||||
working-directory: backend
|
||||
@@ -0,0 +1,58 @@
|
||||
name: Test Backend
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
|
||||
env:
|
||||
# The compose files live in docker/, so a bare `docker compose` from the repo
|
||||
# root finds nothing. With COMPOSE_FILE set, compose reads .env from the
|
||||
# working directory — the same file the backend settings load as ../.env.
|
||||
# The CI-only project name keeps the `down -v` steps away from a dev stack.
|
||||
COMPOSE_FILE: docker/compose.yml:docker/compose.dev.yml
|
||||
COMPOSE_PROJECT_NAME: fluksio-app-ci
|
||||
|
||||
jobs:
|
||||
test-backend:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- name: Set up uv
|
||||
uses: astral-sh/setup-uv@v7
|
||||
with:
|
||||
cache-dependency-glob: |
|
||||
pyproject.toml
|
||||
backend/pyproject.toml
|
||||
uv.lock
|
||||
- name: Write .env
|
||||
# Not committed, and both compose and the backend settings need it.
|
||||
# POSTGRES_SERVER=localhost there matches the port db publishes in the
|
||||
# dev overlay, so the suite runs on the runner against the container.
|
||||
run: cp .env.example .env
|
||||
- run: docker compose down -v --remove-orphans
|
||||
# Postgres is the only service the suite needs: the mail paths are
|
||||
# patched in tests/, and the flow engine falls back to in-memory state
|
||||
# while REDIS_HOST is empty.
|
||||
- run: docker compose up -d --wait db
|
||||
- run: uv sync
|
||||
- name: Migrate DB and seed the superuser
|
||||
run: uv run bash scripts/prestart.sh
|
||||
working-directory: backend
|
||||
# scripts/tests-start.sh waits for the DB, then runs pytest under
|
||||
# coverage and prints the report (see backend/scripts/test.sh).
|
||||
- name: Run tests with coverage
|
||||
run: uv run bash scripts/tests-start.sh "Coverage for ${{ github.sha }}"
|
||||
working-directory: backend
|
||||
- name: Tear down
|
||||
if: always()
|
||||
run: docker compose down -v --remove-orphans
|
||||
@@ -0,0 +1,63 @@
|
||||
name: Compose Smoke Test
|
||||
|
||||
# Lives in this repository rather than the workspace root: the stack it starts
|
||||
# is entirely app-local (docker/compose*.yml + .env.example). A root workflow
|
||||
# would additionally need a token to check out the private submodules and would
|
||||
# have to run scripts/setup.sh to generate secrets, for the same coverage.
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- backend/**
|
||||
- frontend/**
|
||||
- docker/compose*.yml
|
||||
- .env.example
|
||||
- .gitea/workflows/test-compose.yml
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
paths:
|
||||
- backend/**
|
||||
- frontend/**
|
||||
- docker/compose*.yml
|
||||
- .env.example
|
||||
- .gitea/workflows/test-compose.yml
|
||||
|
||||
env:
|
||||
# compose.ci.yml drops the fixed container_names and host ports so this job
|
||||
# can share a runner host with the Playwright shards.
|
||||
COMPOSE_FILE: docker/compose.yml:docker/compose.dev.yml:docker/compose.ci.yml
|
||||
# Own project name so this job's `down -v` cannot reach another stack.
|
||||
COMPOSE_PROJECT_NAME: fluksio-app-ci-compose
|
||||
|
||||
jobs:
|
||||
test-compose:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Write .env
|
||||
run: cp .env.example .env
|
||||
# The Playwright job runs the SPA off a Vite server inside its own
|
||||
# container, so the nginx image is only ever built there. This job is what
|
||||
# covers it — the SPA fallback in frontend/nginx.conf is the part that
|
||||
# breaks silently.
|
||||
- run: docker compose build backend frontend
|
||||
- run: docker compose down -v --remove-orphans
|
||||
# db and prestart come along as depends_on; --wait blocks on the backend
|
||||
# healthcheck in docker/compose.yml.
|
||||
- run: docker compose up -d --wait backend frontend
|
||||
# Nothing is published on the host (compose.ci.yml), so the checks run
|
||||
# from inside the backend container against the project network.
|
||||
- name: Backend is up
|
||||
run: docker compose exec -T backend curl -f http://localhost:8000/api/v1/utils/health-check/
|
||||
- name: Frontend is up
|
||||
run: docker compose exec -T backend curl -f http://frontend/
|
||||
- name: An authenticated route serves the SPA shell
|
||||
run: docker compose exec -T backend curl -f http://frontend/flows
|
||||
- name: Tear down
|
||||
if: always()
|
||||
run: docker compose down -v --remove-orphans
|
||||
Reference in New Issue
Block a user