docs: ADR-0034 — trunk-based + PR-per-goal + ruleset-gated main (CI o… #12
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: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| concurrency: | |
| group: ci-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # Mirrors lefthook.yml's own file-loc-limit job -- same script, so the | |
| # two can't drift. No checkout-heavy setup needed (just git ls-files + | |
| # wc), so this doesn't depend on the frontend job below. | |
| file-loc-limit: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - run: ./scripts/check-loc.sh | |
| # Mirrors lefthook.yml's own rules-frontmatter job -- same script. | |
| # Catches a real bug class: a .claude/rules/*.md with an invalid | |
| # frontmatter key (e.g. a `globs:` typo instead of `paths:`) silently | |
| # never scopes the way it looks like it should, with no error anywhere | |
| # else to surface it. | |
| rules-frontmatter: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - run: ./scripts/check-rules-frontmatter.sh | |
| # Enforces the root-layout rule (exactly one root Go file, main.go; | |
| # services live under internal/services/<ctx>svc) via ls-lint | |
| # (adopted, not hand-rolled -- unlike file-loc-limit, a real commodity | |
| # tool covers this: see .ls-lint.yml's own header comment for the | |
| # config shape verified empirically before relying on it). go install | |
| # matches how this repo already sets up gopls/wails3 -- no | |
| # npm/Homebrew step. | |
| root-file-naming: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-go@v7 | |
| with: | |
| go-version: '1.25' | |
| cache: true | |
| - run: go install github.com/loeffel-io/ls-lint/v2/cmd/ls_lint@v2.3.1 | |
| - run: ls_lint | |
| # Lints and builds frontend/dist once; Go jobs below need frontend/dist | |
| # present (main.go embeds it via //go:embed all:frontend/dist), so they | |
| # download it instead of rebuilding it redundantly per job/OS. | |
| frontend: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: '22' | |
| cache: 'npm' | |
| cache-dependency-path: frontend/package-lock.json | |
| - run: npm ci | |
| working-directory: frontend | |
| - run: npm run lint | |
| working-directory: frontend | |
| - run: npm run boundaries | |
| working-directory: frontend | |
| - run: npm run test | |
| working-directory: frontend | |
| - run: npm run build | |
| working-directory: frontend | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: frontend-dist | |
| path: frontend/dist | |
| retention-days: 1 | |
| lint-go: | |
| runs-on: ubuntu-latest | |
| needs: frontend | |
| env: | |
| # Same reason as build-go's ubuntu-latest entry: without this, | |
| # golangci-lint's own package-loading step needs cgo + X11 dev | |
| # headers for internal/adapters/hotkey's desktop-tagged file. | |
| # Real failure the first time this ran in actual CI, not caught | |
| # locally beforehand -- golangci-lint-action has no CGO_ENABLED | |
| # input, hence the job-level env instead. | |
| CGO_ENABLED: '0' | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: frontend-dist | |
| path: frontend/dist | |
| - uses: actions/setup-go@v7 | |
| with: | |
| go-version: '1.25' | |
| cache: true | |
| - uses: golangci/golangci-lint-action@v9 | |
| with: | |
| version: v2.12 | |
| args: --build-tags=server | |
| build-go: | |
| needs: frontend | |
| strategy: | |
| matrix: | |
| include: | |
| # macOS: desktop build (default tags) — primary target, per SPEC.md. | |
| # Needs Xcode CLI tools for the hotkey package's cgo/Objective-C | |
| # backend; GitHub's macos-latest runners ship these preinstalled. | |
| - os: macos-latest | |
| tags: '' | |
| cgo: '1' | |
| # Linux: server-mode build only. CGO_ENABLED=0 is required, not | |
| # optional -- Wails3's own internal/operatingsystem and | |
| # internal/assetserver/webview packages are cgo-gated onto | |
| # GTK4/webkitgtk-6.0 pkg-config packages this runner doesn't have, | |
| # and pull them in regardless of the `server` build tag unless | |
| # cgo itself is disabled. Confirmed by actually building natively | |
| # in a linux/amd64 container, not assumed: `go build -tags server | |
| # .` fails on missing gtk4/webkitgtk-6.0 pkg-config with the | |
| # default CGO_ENABLED=1, and only succeeds with CGO_ENABLED=0 -- | |
| # matching build/docker/Dockerfile.server's own default for | |
| # exactly this reason. | |
| - os: ubuntu-latest | |
| tags: server | |
| cgo: '0' | |
| runs-on: ${{ matrix.os }} | |
| env: | |
| CGO_ENABLED: ${{ matrix.cgo }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: frontend-dist | |
| path: frontend/dist | |
| - uses: actions/setup-go@v7 | |
| with: | |
| go-version: '1.25' | |
| cache: true | |
| # Scoped to the root package + internal/, not `./...`: build/ios, | |
| # build/android etc. are gomobile-toolchain scaffold with no main() | |
| # outside that toolchain, and frontend/node_modules happens to bundle | |
| # unrelated vendored Go source neither is part of Mill's own build. | |
| - run: go build ${{ matrix.tags && format('-tags {0}', matrix.tags) || '' }} . | |
| - run: go vet ${{ matrix.tags && format('-tags {0}', matrix.tags) || '' }} . ./internal/... | |
| test-go: | |
| needs: frontend | |
| runs-on: ubuntu-latest | |
| # CGO_ENABLED=0: same reason as build-go's ubuntu-latest+server-tag | |
| # entry -- Wails3's internal/operatingsystem and internal/assetserver/ | |
| # webview packages are cgo-gated onto GTK4/webkitgtk-6.0 this runner | |
| # doesn't have, pulled in regardless of the server tag unless cgo | |
| # itself is disabled. Now load-bearing here too, not just for | |
| # build-go: the root package (added below) transitively imports them. | |
| env: | |
| CGO_ENABLED: '0' | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: frontend-dist | |
| path: frontend/dist | |
| - uses: actions/setup-go@v7 | |
| with: | |
| go-version: '1.25' | |
| cache: true | |
| # -tags server: internal/adapters/hotkey's desktop-tagged file needs | |
| # cgo + X11 dev headers this runner doesn't have; the server-tagged | |
| # stub has zero cgo deps and is what's actually exercised here either | |
| # way (hotkey has no automated tests -- see docs/adr/0002, it can't | |
| # be verified headlessly regardless of build tag). The root package | |
| # (`.`) is included alongside ./internal/... as of this line -- | |
| # previously excluded, leaving configureservice_test.go, | |
| # settingsservice_test.go, triggerservice_test.go, | |
| # executionservice_test.go, and executionchildworkflow_test.go | |
| # (1000+ lines) running in neither CI nor Lefthook. Needs | |
| # frontend/dist now: main.go's //go:embed all:frontend/dist makes | |
| # the root package fail to compile without it, even for tests that | |
| # never touch the embedded assets themselves. | |
| - run: go test -tags server . ./internal/... -race -cover | |
| e2e: | |
| runs-on: ubuntu-latest | |
| needs: frontend | |
| env: | |
| # Required for the same reason as build-go's ubuntu-latest entry: | |
| # playwright.config.ts's webServer builds the real server-mode | |
| # binary inline, which needs CGO disabled on Linux to avoid pulling | |
| # in Wails3's GTK-gated desktop code. | |
| CGO_ENABLED: '0' | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: frontend-dist | |
| path: frontend/dist | |
| - uses: actions/setup-go@v7 | |
| with: | |
| go-version: '1.25' | |
| cache: true | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: '22' | |
| cache: 'npm' | |
| cache-dependency-path: frontend/package-lock.json | |
| - run: npm ci | |
| working-directory: frontend | |
| - run: npx playwright install --with-deps chromium | |
| working-directory: frontend | |
| - run: npx playwright test | |
| working-directory: frontend | |
| - uses: actions/upload-artifact@v7 | |
| if: failure() | |
| with: | |
| name: playwright-report | |
| path: frontend/playwright-report | |
| retention-days: 7 | |
| govulncheck: | |
| # macos-latest, not ubuntu-latest: govulncheck-action has no way to pass | |
| # -tags, and the default (desktop) build tags only compile cleanly | |
| # without extra system deps on macOS -- see build-go's ubuntu-latest | |
| # comment for why that's not true on Linux. macOS is also Mill's | |
| # primary target per SPEC.md, so this is the more representative scan | |
| # anyway, not a workaround-of-convenience. | |
| runs-on: macos-latest | |
| needs: frontend | |
| continue-on-error: true # advisory only -- golang/govulncheck-action is | |
| # still self-described experimental (per ADR-0002's research); findings | |
| # are worth seeing, not worth blocking a merge on yet. | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: frontend-dist | |
| path: frontend/dist | |
| # Two separate steps, not one `go-package: ./internal/... .` -- the | |
| # action passes go-package through a quoted shell variable, so a | |
| # space-separated string becomes ONE malformed pattern | |
| # ("no packages matched the provided patterns"), not two. Real | |
| # failure caught on the first actual CI run, not assumed. | |
| - uses: golang/govulncheck-action@v1 | |
| with: | |
| go-version-input: '1.25' | |
| go-package: ./internal/... | |
| repo-checkout: false # already checked out above; the action's | |
| # own default checkout would wipe the frontend-dist artifact | |
| # just downloaded, which the root package needs (//go:embed). | |
| - uses: golang/govulncheck-action@v1 | |
| with: | |
| go-version-input: '1.25' | |
| go-package: . | |
| repo-checkout: false |