name: CI on: push: branches: [main] pull_request: branches: [main] jobs: backend: name: Backend (Python) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python 3.12 uses: actions/setup-python@v5 with: python-version: "3.12" - name: Install dependencies working-directory: backend run: | pip install -e ".[dev]" - name: Lint (ruff) working-directory: backend run: ruff check . - name: Type check (mypy) working-directory: backend run: mypy app/ - name: Test (pytest) working-directory: backend run: pytest --tb=short -q env: PAPERJET_DATABASE_PATH: ./test.sqlite PAPERJET_PDF_STORAGE_PATH: ./test_pdfs PAPERJET_THUMBNAILS_PATH: ./test_thumbs frontend: name: Frontend (TypeScript) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Node.js 22 uses: actions/setup-node@v4 with: node-version: "22" cache: "npm" cache-dependency-path: frontend/package-lock.json - name: Install dependencies working-directory: frontend run: npm ci - name: Lint (eslint) working-directory: frontend run: npm run lint - name: Type check (tsc) working-directory: frontend run: npx tsc -b - name: Test (vitest) working-directory: frontend run: npx vitest run container: name: Container (Docker) runs-on: ubuntu-latest needs: [backend, frontend] steps: - uses: actions/checkout@v4 - name: Validate Compose configuration run: docker compose --env-file .env.example config --quiet - name: Build container image run: | IMAGE_PATH=$(printf 'git.elijahkuntz.com/${{ gitea.actor }}/${{ github.event.repository.name }}' | tr '[:upper:]' '[:lower:]') docker build \ -t paperjet:ci \ -t "$IMAGE_PATH:latest" \ -t "$IMAGE_PATH:${{ github.sha }}" \ . - name: Run container smoke test run: | set -Eeuo pipefail docker run \ --detach \ --name paperjet-ci \ --publish 18080:80 \ --env PAPERJET_SECRET_KEY=ci-only-secret \ --env PAPERJET_COOKIE_SECURE=false \ --env PAPERJET_DEBUG=false \ paperjet:ci cleanup() { docker rm --force paperjet-ci >/dev/null 2>&1 || true } trap cleanup EXIT curl --fail --retry 30 --retry-delay 1 --retry-connrefused \ http://127.0.0.1:18080/ curl --fail --retry 30 --retry-delay 1 --retry-connrefused \ http://127.0.0.1:18080/api/v1/health for attempt in $(seq 1 30); do status=$(docker inspect --format '{{.State.Health.Status}}' paperjet-ci) if [ "$status" = "healthy" ]; then exit 0 fi if [ "$status" = "unhealthy" ]; then docker logs paperjet-ci exit 1 fi sleep 1 done docker logs paperjet-ci exit 1 - name: Log into Local Registry if: github.event_name == 'push' && github.ref == 'refs/heads/main' run: | echo "${{ secrets.FORGEJO_PAT }}" | docker login git.elijahkuntz.com -u "${{ gitea.actor }}" --password-stdin - name: Push main image tags if: github.event_name == 'push' && github.ref == 'refs/heads/main' run: | IMAGE_PATH=$(printf 'git.elijahkuntz.com/${{ gitea.actor }}/${{ github.event.repository.name }}' | tr '[:upper:]' '[:lower:]') docker push "$IMAGE_PATH:latest" docker push "$IMAGE_PATH:${{ github.sha }}"