fix(dx): broaden lefthook eslint glob to lint top-level app files (ma… #5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| pull_request: {} | |
| push: | |
| branches: [refactor/auth-ui-rebuild, main] | |
| paths-ignore: | |
| - 'docs/**' | |
| - 'README.md' | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| env: | |
| BUN_CACHE: ~/.bun/install/cache | |
| CYPRESS_CACHE_FOLDER: ~/.cache/Cypress | |
| jobs: | |
| install: | |
| name: Install Dependencies | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: { bun-version: 1.3.14 } # renovate: datasource=docker depName=oven/bun | |
| - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 | |
| id: cache-deps | |
| with: | |
| path: | | |
| ${{ env.BUN_CACHE }} | |
| **/node_modules | |
| key: ${{ runner.os }}-deps-${{ hashFiles('**/bun.lock', '**/package.json') }} | |
| - if: steps.cache-deps.outputs.cache-hit != 'true' | |
| run: bun install --frozen-lockfile | |
| lint: | |
| name: Lint | |
| needs: install | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: { bun-version: 1.3.14 } # renovate: datasource=docker depName=oven/bun | |
| - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 | |
| with: | |
| path: | | |
| ${{ env.BUN_CACHE }} | |
| **/node_modules | |
| key: ${{ runner.os }}-deps-${{ hashFiles('**/bun.lock', '**/package.json') }} | |
| - run: bun run lint:ci | |
| typecheck: | |
| name: Type Check | |
| needs: install | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: { bun-version: 1.3.14 } # renovate: datasource=docker depName=oven/bun | |
| - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 | |
| with: | |
| path: | | |
| ${{ env.BUN_CACHE }} | |
| **/node_modules | |
| key: ${{ runner.os }}-deps-${{ hashFiles('**/bun.lock', '**/package.json') }} | |
| - run: bun run typecheck | |
| unit-tests: | |
| name: Unit Tests | |
| needs: install | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: { bun-version: 1.3.14 } # renovate: datasource=docker depName=oven/bun | |
| - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 | |
| with: | |
| path: | | |
| ${{ env.BUN_CACHE }} | |
| **/node_modules | |
| key: ${{ runner.os }}-deps-${{ hashFiles('**/bun.lock', '**/package.json') }} | |
| - run: bun run test:unit | |
| i18n-check: | |
| name: i18n Catalogs Fresh | |
| needs: install | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: { bun-version: 1.3.14 } # renovate: datasource=docker depName=oven/bun | |
| - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 | |
| with: | |
| path: | | |
| ${{ env.BUN_CACHE }} | |
| **/node_modules | |
| key: ${{ runner.os }}-deps-${{ hashFiles('**/bun.lock', '**/package.json') }} | |
| # Catches commits made with --no-verify that bypass the lefthook i18n hook. | |
| - run: bun run i18n:extract && bun run i18n:compile | |
| env: | |
| CI: '1' | |
| - run: git diff --exit-code -- app/modules/i18n/locales | |
| supply-chain: | |
| name: Supply Chain (audit + SBOM) | |
| needs: install | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: { bun-version: 1.3.14 } # renovate: datasource=docker depName=oven/bun | |
| - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 | |
| with: | |
| path: | | |
| ${{ env.BUN_CACHE }} | |
| **/node_modules | |
| key: ${{ runner.os }}-deps-${{ hashFiles('**/bun.lock', '**/package.json') }} | |
| - name: Dependency audit (blocking) | |
| # All ignored advisories are dev/build-only — they never ship (the Dockerfile | |
| # installs --production). Runtime advisories (js-yaml, @opentelemetry/core) were | |
| # fixed via dependency bumps, so none are ignored here. | |
| # GHSA-hmw2-7cc7-3qxx form-data <- cypress, start-server-and-test (dev) | |
| # GHSA-gv7w-rqvm-qjhr esbuild <- @lingui/cli, vite (build) | |
| # GHSA-g7r4-m6w7-qqqr esbuild <- @lingui/cli, vite (build) | |
| run: >- | |
| bun audit | |
| --ignore=GHSA-hmw2-7cc7-3qxx | |
| --ignore=GHSA-gv7w-rqvm-qjhr | |
| --ignore=GHSA-g7r4-m6w7-qqqr | |
| - name: Generate SBOM (CycloneDX) | |
| run: bunx @cyclonedx/cdxgen@11.10.0 -t js -o sbom.cdx.json --spec-version 1.5 | |
| - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 | |
| with: | |
| name: sbom-cyclonedx | |
| path: sbom.cdx.json | |
| retention-days: 90 | |
| build: | |
| name: Build | |
| needs: [lint, typecheck] | |
| runs-on: ubuntu-latest | |
| if: ${{ !failure() && !cancelled() }} | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: { bun-version: 1.3.14 } # renovate: datasource=docker depName=oven/bun | |
| - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 | |
| with: | |
| path: | | |
| ${{ env.BUN_CACHE }} | |
| **/node_modules | |
| key: ${{ runner.os }}-deps-${{ hashFiles('**/bun.lock', '**/package.json') }} | |
| - run: bun run build | |
| - run: bun run size | |
| - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 | |
| with: | |
| path: build | |
| key: build-${{ github.sha }} | |
| e2e: | |
| name: E2E (fast, fake provider) | |
| needs: install | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: { bun-version: 1.3.14 } # renovate: datasource=docker depName=oven/bun | |
| - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 | |
| with: | |
| path: | | |
| ${{ env.BUN_CACHE }} | |
| **/node_modules | |
| key: ${{ runner.os }}-deps-${{ hashFiles('**/bun.lock', '**/package.json') }} | |
| - run: bunx cypress install | |
| - run: bun run test:e2e:fast | |
| - if: failure() | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 | |
| with: | |
| name: e2e-artifacts-${{ github.run_id }} | |
| path: | | |
| cypress/videos | |
| cypress/screenshots | |
| retention-days: 7 | |
| if-no-files-found: warn | |
| status-check: | |
| name: Final Status Check | |
| needs: [install, lint, typecheck, unit-tests, i18n-check, supply-chain, build, e2e] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check Workflow Status | |
| run: | | |
| if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" ]]; then | |
| echo "❌ One or more jobs failed" | |
| exit 1 | |
| elif [[ "${{ contains(needs.*.result, 'cancelled') }}" == "true" ]]; then | |
| echo "⚠️ One or more jobs were cancelled" | |
| exit 1 | |
| else | |
| echo "✅ All jobs passed" | |
| fi | |
| publish-container-image: | |
| name: Publish Container Image | |
| needs: [status-check] | |
| if: ${{ github.event_name == 'push' && !failure() && !cancelled() }} | |
| permissions: | |
| id-token: write | |
| contents: read | |
| packages: write | |
| attestations: write | |
| uses: datum-cloud/actions/.github/workflows/publish-docker.yaml@545f34cd6f35e9688c9a04a7e890281bcdbaefd2 # v1.14.0 | |
| with: | |
| image-name: auth-ui | |
| # NOTE: `secrets: inherit` is required because the upstream workflow | |
| # references `secrets.SENTRY_AUTH_TOKEN` without declaring it under | |
| # `workflow_call.secrets`. Once upstream declares it, switch to an | |
| # explicit `secrets:` block passing only SENTRY_AUTH_TOKEN. | |
| secrets: inherit | |
| publish-kustomize-bundle: | |
| name: Publish Kustomize Bundle | |
| needs: [publish-container-image] | |
| if: ${{ github.event_name == 'push' && !failure() && !cancelled() }} | |
| permissions: | |
| id-token: write | |
| contents: read | |
| packages: write | |
| uses: datum-cloud/actions/.github/workflows/publish-kustomize-bundle.yaml@545f34cd6f35e9688c9a04a7e890281bcdbaefd2 # v1.14.0 | |
| with: | |
| bundle-name: ghcr.io/datum-cloud/auth-ui-kustomize | |
| bundle-path: config | |
| image-overlays: config/base | |
| image-name: ghcr.io/datum-cloud/auth-ui | |
| pr-comment: | |
| name: PR Test Summary | |
| needs: [unit-tests, e2e] | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'pull_request' | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| actions: read | |
| steps: | |
| - name: Build test summary | |
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 | |
| with: | |
| script: | | |
| const runId = context.runId; | |
| const fs = require('fs'); | |
| const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}`; | |
| const { data: jobs } = await github.rest.actions.listJobsForWorkflowRun({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| run_id: runId, | |
| }); | |
| const testJobs = jobs.jobs.filter(j => | |
| j.name === 'Unit Tests' || j.name.startsWith('E2E') | |
| ); | |
| const statusEmoji = (c) => { | |
| if (!c || c === 'skipped') return '⏭️'; | |
| if (c === 'success') return '✅'; | |
| if (c === 'failure') return '❌'; | |
| if (c === 'cancelled') return '🚫'; | |
| return '❓'; | |
| }; | |
| let table = '| Job | Status |\n|-----|--------|\n'; | |
| for (const job of testJobs.sort((a, b) => a.name.localeCompare(b.name))) { | |
| table += `| ${job.name} | ${statusEmoji(job.conclusion)} ${job.conclusion || 'pending'} |\n`; | |
| } | |
| let body = `## 🧪 Test Summary\n\n${table}\n\n[View workflow run](${runUrl})`; | |
| fs.writeFileSync('pr-summary.md', body); | |
| - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 | |
| with: | |
| issue-number: ${{ github.event.pull_request.number }} | |
| body-path: pr-summary.md | |
| edit-mode: replace |