Skip to content

fix: Linux CI e2e green — 14 failures triaged, 2 real product bugs fo… #13

fix: Linux CI e2e green — 14 failures triaged, 2 real product bugs fo…

fix: Linux CI e2e green — 14 failures triaged, 2 real product bugs fo… #13

Workflow file for this run

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
# macos-latest, not ubuntu-latest -- resolved a real contradiction the
# dormant-pipeline period shipped unverified (caught by the first
# catch-up run after ADR-0034): on ubuntu, CGO_ENABLED=0 is
# load-bearing (Wails3's GTK-gated packages, see build-go's server
# entry) but `go test -race` REQUIRES cgo -- mutually exclusive on
# that runner for the root package. macOS is the platform Mill
# actually ships for (release is macOS-only, SPEC §1.3), cgo works
# there by default, and running WITHOUT the server tag makes this job
# the exact mirror of lefthook's local go-test -- which also means
# desktop-tagged code (hotkey_desktop.go etc.) finally COMPILES in CI,
# closing part of SPEC §9.5's named "CI never compiles desktop build
# tags" debt. Server-tagged code still compiles in CI via build-go's
# ubuntu entry and runs via the e2e job's server binary.
runs-on: macos-latest
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
# The root package (`.`) is included alongside ./internal/... --
# previously excluded, leaving the root-level service tests running
# in neither CI nor Lefthook. Needs frontend/dist: 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 . ./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