# The gate every change to this kit has to pass.
#
# A UI kit fails differently from an app: nothing here renders a page a human
# looks at before release, so the only thing standing between a broken export
# map and a consumer's build is this file. The steps are ordered cheapest-first
# so a typo fails in seconds rather than after a four-minute bundle.
#
# ── What each step is actually protecting ────────────────────────────────────
#   lint       the token rules (no raw colours, no `--ui-*` in components) and
#              the import rules (no `radix-ui` barrel, no replaced packages)
#   typecheck  two programs — the kit, and the showcase, which has its own
#   test       845 assertions, including the axe sweep and the SSR sweep
#   build      tsup + the Tailwind CLI + the generated token export
#   verify     the export map, the 'use client' directives, publint, attw
#   size       per-subpath byte budgets — the guard on an accidental barrel import
#   brand      fails while the kit is still wearing the scaffold's identity
#
# `brand:check` is last on purpose: it is the only step that fails for a reason
# that is not a defect. A kit you have not renamed yet is a kit in progress, so
# comment it out until you have run `npm run brand` — and then leave it in, so
# nobody publishes a kit called after the one it was forked from.

name: CI

on:
  push:
    branches: [main]
  pull_request:
  workflow_dispatch:

permissions:
  contents: read

concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: 20

      # `npm install`, not `npm ci`: a scaffolded kit may have been installed
      # with pnpm, in which case there is no package-lock.json to be found.
      # Swap in `pnpm/action-setup` + `pnpm install --frozen-lockfile` if pnpm
      # is what your team uses.
      - run: npm install

      - run: npm run lint
      - run: npm run typecheck
      - run: npm run test:run
      - run: npm run build
      - run: npm run verify
      - run: npm run size

      # The showcase is the kit's documentation and its published doc site, so a
      # break here is a break in the product even though none of it ships in the
      # tarball (`files` is dist-only).
      - run: npm run showcase:build

      # Storybook is optional — a kit scaffolded with `--no-storybook` has no
      # `.storybook/` at all, and this must not fail for that. The guard is the
      # directory, not the script name, because the script is removed with it.
      - name: Storybook (only if this kit kept it)
        run: |
          if [ -d .storybook ]; then
            npm run build:storybook
          else
            echo "No .storybook/ — this kit was scaffolded without it. Skipping."
          fi

      # Advisories that reach a consumer, which `npm audit` cannot see: Radix is
      # compiled into dist and tailwind-merge is vendored into src, so neither
      # appears in any downstream lock file. Never blocks — an advisory is not
      # a broken build, and a red CI nobody can fix teaches people to ignore it.
      - name: Shipped-dependency audit (advisory)
        continue-on-error: true
        run: npm run audit:shipped

      - name: Still wearing the scaffold's identity?
        run: npm run brand:check
