# Packet Station CI. Runs on every push to main, every v* tag and every pull request. # server and frontend run in parallel. image builds and pushes :sha- only on a push to # main or a v* tag, after both pass. release.yml re-tags that image. Nothing is ever :latest. name: ci on: push: branches: [main] tags: ["v*"] pull_request: env: REGISTRY: gt.pescoinc.biz IMAGE_NAME: gt.pescoinc.biz/spencerm/packetstation # PESCO's Gitea index. It serves visualkit, mfileskit and their dependencies only. PESCO_INDEX_URL: https://gt.pescoinc.biz/api/packages/spencerm/pypi/simple/ jobs: server: runs-on: ubuntu-latest services: # Throwaway database for the tests. Trust auth inside the job network, so no password. postgres: image: postgres:16-bookworm env: POSTGRES_HOST_AUTH_METHOD: trust options: >- --health-cmd "pg_isready -U postgres" --health-interval 5s --health-timeout 5s --health-retries 20 env: # act_runner runs the job in a container on the service network, so the host is "postgres". TEST_PG_SUPERUSER_URL: postgresql://postgres@postgres:5432/postgres STACK: ci steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.12" cache: pip cache-dependency-path: | server/requirements.txt server/requirements-pesco.txt - name: unixODBC for pyodbc imports run: | set -euo pipefail sudo_cmd="" if [ "$(id -u)" != "0" ]; then sudo_cmd="sudo"; fi $sudo_cmd apt-get update $sudo_cmd apt-get install -y --no-install-recommends unixodbc - name: Install dependencies run: | set -euo pipefail python -m pip install --upgrade pip # Public packages from PyPI. pip install -r server/requirements.txt # PESCO packages from Gitea only. Never --extra-index-url. pip install --index-url "$PESCO_INDEX_URL" -r server/requirements-pesco.txt # The package itself, editable, with its dependencies already in place. pip install --no-deps -e . # Dev tools from pyproject's dev extra, installed by name so pip never # resolves visualkit or mfileskit against PyPI. python -c 'import tomllib; print("\n".join(tomllib.load(open("pyproject.toml", "rb"))["project"]["optional-dependencies"]["dev"]))' > "$RUNNER_TEMP/dev-requirements.txt" pip install -r "$RUNNER_TEMP/dev-requirements.txt" pip check - name: Lint (ruff) run: | ruff check . ruff format --check . - name: Types (mypy) run: mypy - name: Tests (pytest) run: pytest frontend: runs-on: ubuntu-latest defaults: run: working-directory: frontend steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: "22" cache: npm cache-dependency-path: frontend/package-lock.json - name: Install run: npm ci --no-audit --no-fund - name: Lint run: npm run lint - name: Types (tsc) run: npm run typecheck - name: Unit tests run: npm test - name: Build run: npm run build image: needs: [server, frontend] if: gitea.event_name == 'push' && (gitea.ref == 'refs/heads/main' || startsWith(gitea.ref, 'refs/tags/v')) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: docker/setup-buildx-action@v3 - uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ secrets.REGISTRY_USER }} password: ${{ secrets.REGISTRY_TOKEN }} - name: Build and push sha image uses: docker/build-push-action@v6 with: context: . file: Dockerfile platforms: linux/amd64 push: true tags: ${{ env.IMAGE_NAME }}:sha-${{ gitea.sha }} build-args: | PS_BUILD=sha-${{ gitea.sha }} cache-from: type=registry,ref=${{ env.IMAGE_NAME }}:buildcache cache-to: type=registry,ref=${{ env.IMAGE_NAME }}:buildcache,mode=max provenance: false # End to end. Compose up with the CI overlay and the throwaway Samba DC, run the Playwright # scenarios, upload the report, then down -v. The runner needs a Docker daemon whose bind # mounts see this checkout (open question 15, deploy/samba/README.md). e2e: needs: [server, frontend] runs-on: ubuntu-latest timeout-minutes: 30 env: COMPOSE: >- docker compose -p packetstation-ci --env-file deploy/ci/ci.env -f deploy/compose.yaml -f deploy/compose.ci.yaml steps: - uses: actions/checkout@v4 - name: Throwaway secrets run: bash deploy/ci/make-secrets.sh - name: Stack up (app, worker, postgres, Samba DC) run: $COMPOSE up -d --build --wait --wait-timeout 300 - name: Playwright run: $COMPOSE --profile e2e run --rm playwright - name: Stack logs if: failure() run: $COMPOSE logs --no-color --tail 300 samba-dc migrate app worker - name: Upload Playwright report if: always() uses: actions/upload-artifact@v3 with: name: playwright-report path: tests/e2e/playwright-report if-no-files-found: ignore - name: Stack down if: always() run: $COMPOSE --profile e2e down -v