ci: run typecheck, build & tests on PRs and main (#6)

* ci: run typecheck, build & tests on PRs and main

Add a GitHub Actions workflow (.github/workflows/ci.yml) that installs on
Node 20 (the pinned runtime), builds shared/server/web, typechecks desktop,
and runs the full vitest suite across all packages on every pull request and
push to main. The repo already had 500+ tests but only ever ran them locally.

Also wires up the missing test/typecheck plumbing this exposed:
- web package had 55 test files but no test script — add test/test:watch/typecheck
- add root-level test and typecheck aggregate scripts
- fix a latent web type error the new typecheck surfaced: reference
  vite-plugin-pwa/react types so virtual:pwa-register/react is typed
  (useRegisterSW callback params were implicit any; the tsc half of the web
  build script has been failing, masked by vite build ignoring type errors)

* test: fix two latent failures surfaced by CI on Node 20

- server: exclude dist/** from vitest. Vitest 4's default exclude dropped
  dist/, so after `pnpm build` emits compiled .test.js files, vitest ran those
  stale copies alongside src/*.test.ts and they failed (compiled vi.mock paths
  resolve differently).
- web: polyfill Blob.prototype.stream in the jsdom test setup. jsdom's Blob has
  no .stream() on Node 20 (Node 25 provided one, masking this locally); undici's
  Response constructor calls blob.stream(), so new Response(blob) threw
  'object.stream is not a function'.
This commit is contained in:
TheZwiss
2026-07-10 00:15:41 +02:00
committed by GitHub
parent 0727d5a3b3
commit 628e4dec3e
6 changed files with 99 additions and 1 deletions
+67
View File
@@ -0,0 +1,67 @@
name: CI
# Runs the workspace's typecheck, production build, and full test suite on every
# pull request and on pushes to main. Purpose: catch compile errors and test
# regressions before merge instead of relying on each contributor running tests
# locally. Once this check is green on a PR, enable branch protection on `main`
# ("Require status checks to pass" → select "Build & test") to make it blocking.
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
# A newer commit on the same branch/PR supersedes in-flight runs — cancel the
# stale one so a rapid push sequence doesn't queue redundant CI.
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
build-and-test:
name: Build & test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.34.3
# Node 20 is the project's supported runtime (package.json engines pins
# >=20 <21, .nvmrc says 20). Running the matrix on 20 also means the fresh
# install below pulls better-sqlite3's prebuilt binary for the correct ABI,
# which is what makes the server suite runnable in CI.
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
# The desktop postinstall tries to rebuild the native uiohook-napi module.
# It fails gracefully (|| warn) without X11 dev headers, and nothing in CI
# needs the native binary — the desktop tests and TS compile are pure JS —
# so we intentionally skip installing those headers to keep CI fast.
- name: Install dependencies
run: pnpm install --frozen-lockfile
# Compiles shared → server → web (each runs tsc; web also runs the Vite
# production build). This is the typecheck + build gate for those three.
- name: Build shared, server & web
run: pnpm build
# Desktop is not part of `pnpm build` (that produces an Electron installer,
# which release.yml owns). Type-check its source here so desktop TS errors
# surface on PRs rather than only at release-tag time.
- name: Typecheck desktop
run: pnpm --filter @backspace/desktop build:ts
# Runs every package's `test` script (server, web, desktop) via vitest.
- name: Test
run: pnpm -r test