Skip to content

docs(adr): πŸ“ mark ADR 0007 as accepted (#5348) #7686

docs(adr): πŸ“ mark ADR 0007 as accepted (#5348)

docs(adr): πŸ“ mark ADR 0007 as accepted (#5348) #7686

Workflow file for this run

# PR Checks Workflow
#
# Runs build, test, lint, and type-check in parallel for faster feedback.
# Build runs first (required by all others), then test/lint/types fan out.
#
# Path filtering:
# - code or tooling config -> full checks (build + test + lint + types)
# - other non-code changes -> build + lint only
# - manual dispatch -> full checks
#
# Addresses: https://github.com/equinor/design-system/issues/4624
name: Checks
permissions:
contents: read
on:
workflow_dispatch:
pull_request:
branches:
- main
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
NODE_VERSION: '24.16.0'
CACHE_KEY: ${{ github.sha }}-checks
jobs:
# ─── Setup: checkout + install + cache ───────────────────────────
setup:
uses: ./.github/workflows/_setup.yml
secrets: inherit
with:
cacheKey: ${{ github.sha }}-checks
# ─── Detect what changed to skip unnecessary jobs ───────────────
changes:
runs-on: ubuntu-latest
# dorny/paths-filter fetches the PR's changed-file list via the REST API on
# pull_request events, which needs pull-requests: read on top of the
# workflow's contents: read.
permissions:
contents: read
pull-requests: read
outputs:
# Manual runs are an explicit request for the complete suite.
code: ${{ github.event_name == 'workflow_dispatch' || steps.filter.outputs.code == 'true' }}
steps:
# fetch-depth: 2 so dorny/paths-filter can diff against the previous
# commit on push events (the default depth of 1 omits it).
- uses: actions/checkout@v7
with:
fetch-depth: 2
# SHA-pinned (v3.0.2) β€” third-party action running on every PR; pin to an
# immutable commit so a compromised tag can't inject code into CI.
- uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4.0.3
if: github.event_name != 'workflow_dispatch'
id: filter
with:
filters: |
code:
- 'packages/**'
- 'apps/**'
- 'scripts/**'
- '.github/actions/**'
# Root dependencies and tooling config warrant full checks.
- '.npmrc'
- '.node-version'
- '.nvmrc'
- '.prettier*'
- '.stylelintrc*'
- 'package.json'
- 'pnpm-lock.yaml'
- 'pnpm-workspace.yaml'
- 'tsconfig*.json'
- 'babel.config.cjs'
- 'eslint.config.mjs'
# ─── Build (required before test/lint/types) ─────────────────────
build:
name: Build
runs-on: ubuntu-latest
needs: [setup, changes]
if: needs.changes.outputs.code == 'true'
steps:
- name: Restore workspace cache
id: cache
uses: actions/cache/restore@v6
with:
path: |
./*
~/.pnpm-store
key: ${{ env.CACHE_KEY }}
# Cache misses are rare (setup runs first and saves the workspace) but
# not impossible β€” a cache-service hiccup, eviction, or size limit
# shouldn't fail the run when a plain checkout + install can proceed.
- name: Fallback checkout (cache miss)
if: steps.cache.outputs.cache-hit != 'true'
uses: actions/checkout@v7
- name: Install Node.js
uses: actions/setup-node@v7
with:
node-version: ${{ env.NODE_VERSION }}
package-manager-cache: false
- name: Setup pnpm
uses: pnpm/action-setup@v6
- name: Fallback install (cache miss)
if: steps.cache.outputs.cache-hit != 'true'
run: pnpm install --frozen-lockfile
# Must run BEFORE the build: `prebuild` regenerates the index in the
# workspace, which would mask a stale committed file.
- name: Check AI component index freshness
run: pnpm run generate:component-index --check
- name: Build packages
run: pnpm run build
- name: Cache build output
uses: actions/cache/save@v6
with:
path: |
./*
~/.pnpm-store
key: ${{ env.CACHE_KEY }}-built
# ─── Test (parallel, depends on build) ───────────────────────────
test:
name: Test
runs-on: ubuntu-latest
needs: [build, changes]
if: needs.changes.outputs.code == 'true'
steps:
- name: Restore build cache
id: cache
uses: actions/cache/restore@v6
with:
path: |
./*
~/.pnpm-store
key: ${{ env.CACHE_KEY }}-built
# On a build-cache miss, reconstruct from scratch (checkout + install +
# build) rather than failing β€” the build job's output cache is not
# guaranteed to survive a cache-service hiccup or eviction.
- name: Fallback checkout (cache miss)
if: steps.cache.outputs.cache-hit != 'true'
uses: actions/checkout@v7
- name: Install Node.js
uses: actions/setup-node@v7
with:
node-version: ${{ env.NODE_VERSION }}
package-manager-cache: false
- name: Setup pnpm
uses: pnpm/action-setup@v6
- name: Fallback build (cache miss)
if: steps.cache.outputs.cache-hit != 'true'
run: |
pnpm install --frozen-lockfile
pnpm run build
- name: Test packages
run: pnpm run test
# ─── Lint (parallel, depends on build) ───────────────────────────
lint:
name: Lint
runs-on: ubuntu-latest
needs: [build, changes]
if: needs.changes.outputs.code == 'true'
steps:
- name: Restore build cache
id: cache
uses: actions/cache/restore@v6
with:
path: |
./*
~/.pnpm-store
key: ${{ env.CACHE_KEY }}-built
# On a build-cache miss, reconstruct from scratch (checkout + install +
# build) rather than failing β€” the build job's output cache is not
# guaranteed to survive a cache-service hiccup or eviction.
- name: Fallback checkout (cache miss)
if: steps.cache.outputs.cache-hit != 'true'
uses: actions/checkout@v7
- name: Install Node.js
uses: actions/setup-node@v7
with:
node-version: ${{ env.NODE_VERSION }}
package-manager-cache: false
- name: Setup pnpm
uses: pnpm/action-setup@v6
- name: Fallback build (cache miss)
if: steps.cache.outputs.cache-hit != 'true'
run: |
pnpm install --frozen-lockfile
pnpm run build
- name: Lint packages
run: pnpm run lint:all
# ─── Type check (parallel, depends on build) ────────────────────
types:
name: Type check
runs-on: ubuntu-latest
needs: [build, changes]
if: needs.changes.outputs.code == 'true'
steps:
- name: Restore build cache
id: cache
uses: actions/cache/restore@v6
with:
path: |
./*
~/.pnpm-store
key: ${{ env.CACHE_KEY }}-built
# On a build-cache miss, reconstruct from scratch (checkout + install +
# build) rather than failing β€” the build job's output cache is not
# guaranteed to survive a cache-service hiccup or eviction.
- name: Fallback checkout (cache miss)
if: steps.cache.outputs.cache-hit != 'true'
uses: actions/checkout@v7
- name: Install Node.js
uses: actions/setup-node@v7
with:
node-version: ${{ env.NODE_VERSION }}
package-manager-cache: false
- name: Setup pnpm
uses: pnpm/action-setup@v6
- name: Fallback build (cache miss)
if: steps.cache.outputs.cache-hit != 'true'
run: |
pnpm install --frozen-lockfile
pnpm run build
- name: Type check packages
run: pnpm run types
# ─── Lint-only for non-code changes (workflows, docs) ───────────
#
# Trade-off (decided 2026-06): this job runs a full `pnpm run build`
# before linting because `lint:all` is type-aware and needs every
# workspace package's built `.d.ts` to resolve cross-package imports.
# So a docs/workflow-only PR still pays for a full build here.
#
# We deliberately did NOT add granular per-package affected detection
# (e.g. pnpm `--filter "...[origin/main]"` or Turborepo) because CI is
# currently fast enough and the existing binary `changes.code` gate +
# cross-job `-built` cache already cover the common cases. Revisit only
# if build time becomes a real bottleneck β€” Turborepo (input-hash
# caching + affected filtering) is the preferred next step if so.
lint-only:
name: Lint (non-code changes)
runs-on: ubuntu-latest
needs: [setup, changes]
if: needs.changes.outputs.code != 'true'
steps:
- name: Restore workspace cache
id: cache
uses: actions/cache/restore@v6
with:
path: |
./*
~/.pnpm-store
key: ${{ env.CACHE_KEY }}
# Cache misses are rare (setup runs first and saves the workspace) but
# not impossible β€” a cache-service hiccup, eviction, or size limit
# shouldn't fail the run when a plain checkout + install can proceed.
- name: Fallback checkout (cache miss)
if: steps.cache.outputs.cache-hit != 'true'
uses: actions/checkout@v7
- name: Install Node.js
uses: actions/setup-node@v7
with:
node-version: ${{ env.NODE_VERSION }}
package-manager-cache: false
- name: Setup pnpm
uses: pnpm/action-setup@v6
- name: Fallback install (cache miss)
if: steps.cache.outputs.cache-hit != 'true'
run: pnpm install --frozen-lockfile
# lint:all runs type-aware ESLint across the whole monorepo, which
# needs each workspace package's built type declarations. Without a
# build, cross-package imports resolve to `any`/error and trip
# no-unsafe-* / no-redundant-type-constituents. Build first.
- name: Build packages
run: pnpm run build
- name: Lint packages
run: pnpm run lint:all
# ─── Status check (single gate for branch protection) ───────────
checks-passed:
name: All checks passed
runs-on: ubuntu-latest
if: always()
needs: [setup, changes, build, test, lint, types, lint-only]
steps:
- name: Evaluate results
run: |
# Each needs.<job>.result must be expanded as a static expression:
# template expressions are evaluated at render time, before bash runs,
# so a bash loop variable cannot index the needs context.
# A "skipped" result is expected (path filtering) and is not a failure.
for result in \
"setup:${{ needs.setup.result }}" \
"changes:${{ needs.changes.result }}" \
"build:${{ needs.build.result }}" \
"test:${{ needs.test.result }}" \
"lint:${{ needs.lint.result }}" \
"types:${{ needs.types.result }}" \
"lint-only:${{ needs.lint-only.result }}"; do
job="${result%%:*}"
status="${result#*:}"
if [ "$status" = "failure" ] || [ "$status" = "cancelled" ]; then
echo "::error::Job '$job' $status"
exit 1
fi
done
echo "All checks passed βœ…"
- name: log-errors-to-slack
if: failure()
uses: act10ns/slack@v2
with:
status: ${{ job.status }}