diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 729856587..174deb371 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -32,7 +32,21 @@ jobs: node-version-file: '.node-version' cache: npm + # Cache the installed tree keyed on the lockfile + Node version. On a hit + # (lockfile unchanged) `npm ci` — extraction + the postinstall folds patch — + # is skipped entirely and node_modules is just restored (the patch is baked + # into the cached tree). setup-node's `cache: npm` still warms the download + # cache for the miss path. Save runs only on a miss AND only if install + # succeeded (`success()`), so a failed `npm ci` can never poison the cache. + - name: Restore node_modules + id: node-modules + uses: actions/cache/restore@v4 + with: + path: node_modules + key: node-modules-${{ runner.os }}-${{ hashFiles('package-lock.json', '.node-version') }} + - name: Install dependencies + if: steps.node-modules.outputs.cache-hit != 'true' # Harden against transient registry network failures (ECONNRESET etc.): # raise npm's built-in fetch retries/timeouts and retry `npm ci` up to # 3 times with backoff before failing the build. @@ -52,37 +66,43 @@ jobs: sleep $((attempt * 15)) done - # ── Critical gate — if this fails, nothing deploys ────────────────── + - name: Save node_modules + if: steps.node-modules.outputs.cache-hit != 'true' && success() + uses: actions/cache/save@v4 + with: + path: node_modules + key: node-modules-${{ runner.os }}-${{ hashFiles('package-lock.json', '.node-version') }} + + # ── Quality gates run BEFORE the slow build so a format/lint/type/test + # error fails in seconds instead of after the ~minutes-long build. All are + # hard gates — any failure fails the job and blocks the deploy. The tree is + # held clean (prettier formatted, eslint 0 errors, typecheck 0), so these + # gate real regressions. NOTE: the lotus-build.sh upstream-merge path can + # deploy without CI; a later normal push surfaces any introduced issue here + # — fix forward (or briefly re-soften a gate) rather than deploy broken. + # eslint gates on errors only (existing no-explicit-any warnings stay + # informational — check:eslint has no --max-warnings). + - name: Prettier + run: npm run check:prettier + + - name: ESLint + run: npm run check:eslint + + - name: TypeScript + run: npm run typecheck + + # Deterministic pure-logic tests on Node's built-in runner via tsx (no + # vitest — Vite 8 is ahead of vitest's range). A failure blocks the deploy. + - name: Unit tests + run: npm test + + # ── Critical gate — if this fails, nothing deploys. Produces dist/. ── - name: Build run: npm run build env: NODE_OPTIONS: '--max_old_space_size=4096' VITE_APP_VERSION: ${{ github.sha }} - # Unit tests are a hard gate too — deterministic pure-logic tests on Node's - # built-in runner via tsx (no vitest — Vite 8 is ahead of vitest's range). - # A failure blocks the deploy. - - name: Unit tests - run: npm test - - # ── Quality gates (hard — a failure fails the job and blocks deploy) ── - # The tree is held clean (typecheck 0, eslint 0 errors, prettier - # formatted), so these gate real regressions instead of relying on local - # runs. NOTE: an upstream-stable merge (the lotus-build.sh path) could - # introduce upstream type/lint/format issues; that path deploys without - # CI, but a subsequent normal push would surface the failure here — fix - # forward (or briefly re-soften a gate) rather than let it deploy broken. - # eslint gates on errors only (existing `no-explicit-any` warnings stay - # informational — `check:eslint` has no --max-warnings). - - name: TypeScript - run: npm run typecheck - - - name: ESLint - run: npm run check:eslint - - - name: Prettier - run: npm run check:prettier - # ── Security (informational — findings shouldn't block a deploy) ───── - name: Audit (high/critical) run: npm audit --audit-level=high --omit=dev diff --git a/.husky/pre-commit b/.husky/pre-commit index 7aea7a8da..2312dc587 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,3 +1 @@ -# These are commented until we enable lint and typecheck -# npx tsc -p tsconfig.json --noEmit -# npx lint-staged \ No newline at end of file +npx lint-staged