name: CI on: push: branches: [develop, 'hotfix/*'] tags: ['v*'] paths-ignore: ['docs/**', '*.md', '!SECURITY.md', '.github/issue_template/**', '.github/assets/**'] pull_request: branches: [develop] paths-ignore: ['docs/**', '*.md', '!SECURITY.md', '.github/issue_template/**', '.github/assets/**'] concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true permissions: contents: read jobs: # ─── Build ────────────────────────────────────────────────────────────── build: name: Build runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: denoland/setup-deno@v2 with: deno-version: v2.x - name: Cache deps uses: actions/cache@v5 with: path: | ~/.cache/deno node_modules key: deno-${{ runner.os }}-${{ hashFiles('deno.lock') }} restore-keys: deno-${{ runner.os }}- - run: deno install --node-modules-dir - name: Build run: deno task build - name: Upload build artifact uses: actions/upload-artifact@v7 with: name: profilarr-build path: | dist/build/profilarr dist/build/server.js dist/build/static/ retention-days: 1 # ─── Quality gates (all run in parallel with build) ───────────────────── lint: name: Lint runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: denoland/setup-deno@v2 with: deno-version: v2.x - name: Cache deps uses: actions/cache@v5 with: path: | ~/.cache/deno node_modules key: deno-${{ runner.os }}-${{ hashFiles('deno.lock') }} restore-keys: deno-${{ runner.os }}- - run: deno install --node-modules-dir - name: Lint run: deno task lint type-check: name: Type Check runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: denoland/setup-deno@v2 with: deno-version: v2.x - uses: actions/setup-node@v6 with: node-version: 22 - name: Cache deps uses: actions/cache@v5 with: path: | ~/.cache/deno node_modules key: deno-${{ runner.os }}-${{ hashFiles('deno.lock') }} restore-keys: deno-${{ runner.os }}- - run: deno install --node-modules-dir - name: Sync SvelteKit types run: npx svelte-kit sync - name: Type check run: deno task check unit: name: Unit Tests runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: denoland/setup-deno@v2 with: deno-version: v2.x - name: Cache deps uses: actions/cache@v5 with: path: | ~/.cache/deno node_modules key: deno-${{ runner.os }}-${{ hashFiles('deno.lock') }} restore-keys: deno-${{ runner.os }}- - name: Clear corrupted native libraries run: rm -rf ~/.cache/deno/plug - run: deno install --node-modules-dir - name: Run unit tests run: deno task test semgrep: name: Semgrep runs-on: ubuntu-latest container: image: semgrep/semgrep steps: - uses: actions/checkout@v6 - name: Run Semgrep run: | semgrep scan \ --config tests/scan/semgrep/ \ --config p/default \ --config p/typescript \ --config p/javascript \ --config p/owasp-top-ten \ --config p/nodejs \ --config p/security-audit \ --config p/csharp \ --error # ─── Tests that need the binary ───────────────────────────────────────── integration: name: Integration Tests needs: [build] runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: denoland/setup-deno@v2 with: deno-version: v2.x - uses: actions/setup-node@v6 with: node-version: 22 - name: Cache deps uses: actions/cache@v5 with: path: | ~/.cache/deno node_modules key: deno-${{ runner.os }}-${{ hashFiles('deno.lock') }} restore-keys: deno-${{ runner.os }}- - name: Clear corrupted native libraries run: rm -rf ~/.cache/deno/plug - run: deno install --node-modules-dir - name: Download build artifact uses: actions/download-artifact@v8 with: name: profilarr-build path: dist/build - name: Make binary executable run: chmod +x dist/build/profilarr - name: Warm native library cache run: | mkdir -p /tmp/ffi-warmup/data/databases /tmp/ffi-warmup/logs /tmp/ffi-warmup/backups APP_BASE_PATH=/tmp/ffi-warmup PORT=9999 timeout 30 ./dist/build/profilarr || true rm -rf /tmp/ffi-warmup - name: Cache Docker images id: docker-cache uses: actions/cache@v5 with: path: /tmp/docker-images.tar key: docker-images-${{ hashFiles('tests/integration/auth/docker-compose.yml') }} - name: Load cached Docker images if: steps.docker-cache.outputs.cache-hit == 'true' run: docker load -i /tmp/docker-images.tar - name: Pull and save Docker images if: steps.docker-cache.outputs.cache-hit != 'true' run: | docker pull ghcr.io/navikt/mock-oauth2-server:3.0.1 docker pull caddy:2-alpine docker pull nginx:alpine docker save ghcr.io/navikt/mock-oauth2-server:3.0.1 caddy:2-alpine nginx:alpine -o /tmp/docker-images.tar - name: Run integration tests run: deno task test integration e2e-auth: name: E2E Tests needs: [build] runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: denoland/setup-deno@v2 with: deno-version: v2.x - uses: actions/setup-node@v6 with: node-version: 22 - name: Cache deps uses: actions/cache@v5 with: path: | ~/.cache/deno node_modules key: deno-${{ runner.os }}-${{ hashFiles('deno.lock') }} restore-keys: deno-${{ runner.os }}- - name: Clear corrupted native libraries run: rm -rf ~/.cache/deno/plug - run: deno install --node-modules-dir - name: Install Playwright browsers run: npx playwright install --with-deps chromium - name: Download build artifact uses: actions/download-artifact@v8 with: name: profilarr-build path: dist/build - name: Make binary executable run: chmod +x dist/build/profilarr - name: Cache Docker images id: docker-cache uses: actions/cache@v5 with: path: /tmp/docker-images.tar key: docker-images-${{ hashFiles('tests/integration/auth/docker-compose.yml') }} - name: Load cached Docker images if: steps.docker-cache.outputs.cache-hit == 'true' run: docker load -i /tmp/docker-images.tar - name: Pull and save Docker images if: steps.docker-cache.outputs.cache-hit != 'true' run: | docker pull ghcr.io/navikt/mock-oauth2-server:3.0.1 docker pull caddy:2-alpine docker pull nginx:alpine docker save ghcr.io/navikt/mock-oauth2-server:3.0.1 caddy:2-alpine nginx:alpine -o /tmp/docker-images.tar - name: Run E2E auth tests run: deno task test e2e auth