name: CI on: push: branches: [main] pull_request: # Cancel superseded runs on the same branch — saves runner minutes on rapid pushes. concurrency: group: ci-${{ github.ref }} cancel-in-progress: true env: PNPM_VERSION: 10.33.0 NODE_VERSION: 22 jobs: check: name: Lint · Typecheck · Test · Build runs-on: ubuntu-latest timeout-minutes: 15 steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 with: version: ${{ env.PNPM_VERSION }} - uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} - name: Install dependencies run: pnpm install --frozen-lockfile - name: Generate Prisma client run: pnpm -C packages/db exec prisma generate - name: Lint run: pnpm lint - name: Typecheck run: pnpm typecheck - name: Unit tests (with coverage on api) run: | pnpm -C packages/shared test pnpm -C apps/api test:coverage - name: Build run: pnpm build - name: Upload API coverage uses: actions/upload-artifact@v4 if: always() with: name: api-coverage path: apps/api/coverage if-no-files-found: ignore retention-days: 7 e2e: name: Playwright (smoke) runs-on: ubuntu-latest timeout-minutes: 20 # E2E needs a real DB + running stack. Flip this on by setting the `ENABLE_E2E` # repo variable to `true` in Gitea after the Postgres-in-CI follow-up lands. if: ${{ vars.ENABLE_E2E == 'true' }} steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 with: version: ${{ env.PNPM_VERSION }} - uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} - run: pnpm install --frozen-lockfile - run: pnpm -C packages/db exec prisma generate - run: pnpm -C apps/e2e exec playwright install --with-deps chromium - run: pnpm -C apps/e2e test env: BASE_URL: ${{ secrets.E2E_BASE_URL }} TEST_USERNAME: ${{ secrets.E2E_USERNAME }} TEST_PASSWORD: ${{ secrets.E2E_PASSWORD }} - uses: actions/upload-artifact@v4 if: always() with: name: playwright-report path: apps/e2e/playwright-report retention-days: 7 docker: name: Build & push images runs-on: ubuntu-latest needs: check # Only push from main, and only on direct pushes (not PRs from forks). if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} timeout-minutes: 30 steps: - uses: actions/checkout@v4 - name: Log in to ${{ vars.REGISTRY_URL }} run: echo "${{ secrets.REGISTRY_TOKEN }}" | docker login "${{ vars.REGISTRY_URL }}" --username "${{ github.actor }}" --password-stdin - name: Build & push API image run: | IMAGE="${{ vars.REGISTRY_URL }}/vector-api" docker build \ -f apps/api/Dockerfile \ -t "$IMAGE:${{ github.sha }}" \ -t "$IMAGE:latest" \ . docker push "$IMAGE:${{ github.sha }}" docker push "$IMAGE:latest" - name: Build & push Web image run: | IMAGE="${{ vars.REGISTRY_URL }}/vector-web" docker build \ -f apps/web/Dockerfile \ -t "$IMAGE:${{ github.sha }}" \ -t "$IMAGE:latest" \ . docker push "$IMAGE:${{ github.sha }}" docker push "$IMAGE:latest" - name: Log out if: always() run: docker logout "${{ vars.REGISTRY_URL }}"