mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
317 lines
9.9 KiB
YAML
317 lines
9.9 KiB
YAML
name: Tests
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
on:
|
|
pull_request:
|
|
branches: [main, dev]
|
|
paths:
|
|
- 'server/**'
|
|
- 'client/**'
|
|
- 'shared/**'
|
|
- 'plugin-sdk/**'
|
|
# npm workspaces hoist every dependency into the single root lockfile, so
|
|
# a dependency bump touches none of the four directories above — and a
|
|
# native binding like better-sqlite3 is exactly what needs the suite.
|
|
- 'package.json'
|
|
- 'package-lock.json'
|
|
- 'Dockerfile'
|
|
- 'docker-compose.yml'
|
|
- '.github/workflows/test.yml'
|
|
|
|
jobs:
|
|
plugin-facts:
|
|
name: Plugin Permission Facts
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 22
|
|
cache: npm
|
|
|
|
- name: Install dependencies
|
|
run: npm ci --workspace server
|
|
|
|
# The plugin permission facts live once, in
|
|
# server/src/nest/plugins/protocol/envelope.ts. Every other copy - the SDK's
|
|
# generated/host-facts.ts and shared's plugin-permissions.ts - is generated from it
|
|
# and checked in, because publish-plugin-sdk builds from a standalone checkout with
|
|
# no server present. This fails the PR if a copy drifts, if a new permission has no
|
|
# admin.plugins.perm.* translation, or if the CLI has no hint for it.
|
|
- name: Check the generated plugin facts are in sync
|
|
run: cd server && npm run check:plugin-facts
|
|
|
|
i18n-parity:
|
|
name: i18n Key Parity
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: 24
|
|
|
|
- name: Check i18n key parity
|
|
run: node shared/scripts/i18n-parity.mjs --strict
|
|
|
|
shared-contracts:
|
|
name: Shared Contracts (Zod)
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: 24
|
|
cache: npm
|
|
cache-dependency-path: package-lock.json
|
|
|
|
- name: Install dependencies
|
|
run: npm ci --workspace shared
|
|
|
|
- name: Typecheck
|
|
run: cd shared && npm run typecheck
|
|
|
|
- name: Run tests
|
|
run: cd shared && npm run test:coverage
|
|
|
|
- name: Upload coverage
|
|
if: success()
|
|
uses: actions/upload-artifact@v6
|
|
with:
|
|
name: shared-coverage
|
|
path: shared/coverage/
|
|
retention-days: 7
|
|
|
|
plugin-sdk-tests:
|
|
name: Plugin SDK Tests
|
|
runs-on: ubuntu-latest
|
|
defaults:
|
|
run:
|
|
working-directory: plugin-sdk
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
# 22 matches the TREK server runtime and has node:sqlite, which the
|
|
# dev-server tests exercise (same choice as publish-plugin-sdk.yml).
|
|
node-version: 22
|
|
|
|
# plugin-sdk is standalone (own lockfile, not a root workspace), so it
|
|
# installs from its own directory.
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Typecheck
|
|
run: npm run typecheck
|
|
|
|
- name: Run tests
|
|
run: npm run test:coverage
|
|
|
|
- name: Upload coverage
|
|
if: success()
|
|
uses: actions/upload-artifact@v6
|
|
with:
|
|
name: plugin-sdk-coverage
|
|
path: plugin-sdk/coverage/
|
|
retention-days: 7
|
|
|
|
server-tests:
|
|
name: Server Tests
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: 24
|
|
cache: npm
|
|
cache-dependency-path: package-lock.json
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Ensure @swc/core's Linux binary for unplugin-swc
|
|
# The lockfile was generated on Windows and omits @swc/core's Linux
|
|
# optional native binary, so npm ci/install skips it on the runner.
|
|
# Install the matching version explicitly so the server's SWC transform
|
|
# (server/vitest.config.ts) can load.
|
|
run: |
|
|
SWC_VERSION=$(node -p "require('@swc/core/package.json').version")
|
|
npm install --no-save --legacy-peer-deps "@swc/core-linux-x64-gnu@$SWC_VERSION"
|
|
|
|
- name: Build shared
|
|
run: npm run build --workspace=shared
|
|
|
|
- name: Build server (tsc -> dist)
|
|
run: cd server && npm run build
|
|
|
|
- name: Smoke production require chain
|
|
# Vitest aliases the MCP SDK deep imports, so only this exercises what
|
|
# production runs: the built dist resolving the MCP SDK's subpath
|
|
# exports through the tsconfig-paths/register runtime hook.
|
|
run: cd server && node --require tsconfig-paths/register -e "require('./dist/nest-mcp')"
|
|
|
|
- name: Typecheck
|
|
run: cd server && npm run typecheck
|
|
|
|
- name: Typecheck tests
|
|
# tests/ is outside the build tsconfig, so a service that grows a
|
|
# constructor parameter does not break its hand-wired call sites at
|
|
# compile time: the argument arrives as undefined and throws at runtime,
|
|
# if anything reads it at all. This is the step that catches it.
|
|
run: cd server && npm run typecheck:tests
|
|
|
|
- name: Lint
|
|
run: cd server && npm run lint:check
|
|
|
|
- name: Run tests
|
|
run: cd server && npm run test:coverage
|
|
|
|
- name: Upload coverage
|
|
if: success()
|
|
uses: actions/upload-artifact@v6
|
|
with:
|
|
name: backend-coverage
|
|
path: server/coverage/
|
|
retention-days: 7
|
|
|
|
s3-contract:
|
|
name: S3 Driver Contract (MinIO)
|
|
runs-on: ubuntu-latest
|
|
# Fork PRs don't get repo secrets, so MINIO_LICENSE_KEY would be empty
|
|
# and the AIStor container would fail to boot.
|
|
if: github.event.pull_request.head.repo.full_name == github.repository
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: 24
|
|
cache: npm
|
|
cache-dependency-path: package-lock.json
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Ensure @swc/core's Linux binary for unplugin-swc
|
|
# The lockfile was generated on Windows and omits @swc/core's Linux
|
|
# optional native binary, so npm ci/install skips it on the runner.
|
|
# Install the matching version explicitly so the server's SWC transform
|
|
# (server/vitest.config.ts) can load.
|
|
run: |
|
|
SWC_VERSION=$(node -p "require('@swc/core/package.json').version")
|
|
npm install --no-save --legacy-peer-deps "@swc/core-linux-x64-gnu@$SWC_VERSION"
|
|
|
|
- name: Build shared
|
|
run: npm run build --workspace=shared
|
|
|
|
- name: Write MinIO license
|
|
run: printf '%s' "${{ secrets.MINIO_LICENSE_KEY }}" > minio-licence.key
|
|
|
|
- name: Start MinIO
|
|
# `services:` can't pass the `server /data --license ...` command to
|
|
# the AIStor image, so it starts via docker run. 127.0.0.1 endpoint is
|
|
# load-bearing: aws-lite picks path-style only for IP/localhost hosts,
|
|
# which is all stock MinIO/AIStor speaks.
|
|
run: |
|
|
docker run -d --name minio -p 127.0.0.1:9000:9000 \
|
|
-v "$PWD/minio-licence.key:/minio.license:ro" \
|
|
-e MINIO_ROOT_USER=trekci -e MINIO_ROOT_PASSWORD=trekci-secret \
|
|
quay.io/minio/aistor/minio:RELEASE.2026-08-07T18-34-35Z server /data --license /minio.license
|
|
|
|
- name: Wait for MinIO
|
|
# curl was removed from the AIStor image — poll from the runner instead.
|
|
# 60 x 2s gives a wider margin on cold runners than the 30 x 1s the
|
|
# pre-6fbff835 job used.
|
|
run: |
|
|
for i in $(seq 1 60); do
|
|
curl -sf http://127.0.0.1:9000/minio/health/live && exit 0
|
|
sleep 2
|
|
done
|
|
echo "MinIO never became healthy" >&2
|
|
docker logs minio >&2
|
|
exit 1
|
|
|
|
- name: Run the S3 driver contract suite
|
|
# No --coverage: the src/nest/storage/** 94/84/97/94 pin must keep
|
|
# holding from hermetic tests alone. The suite's beforeAll creates
|
|
# the trek-test bucket idempotently — no separate bucket-init step.
|
|
env:
|
|
TREK_TEST_S3_ENDPOINT: http://127.0.0.1:9000
|
|
TREK_TEST_S3_BUCKET: trek-test
|
|
TREK_TEST_S3_ACCESS_KEY_ID: trekci
|
|
TREK_TEST_S3_SECRET_ACCESS_KEY: trekci-secret
|
|
run: cd server && npx vitest run tests/unit/nest/storage/s3.driver.contract.test.ts
|
|
|
|
client-quality:
|
|
# Split out of client-tests: the suite takes ~11 minutes, and having the
|
|
# gates in front of it meant a single lint finding threw away the whole test
|
|
# signal for that run. Both jobs pay the install/build, which is cheap next
|
|
# to running the two in series.
|
|
name: Client Types & Lint
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: 24
|
|
cache: npm
|
|
cache-dependency-path: package-lock.json
|
|
|
|
- name: Install dependencies
|
|
run: npm ci --workspace shared && npm ci --workspace client
|
|
|
|
- name: Build shared
|
|
run: npm run build --workspace=shared
|
|
|
|
- name: Typecheck
|
|
run: cd client && npm run typecheck
|
|
|
|
- name: Lint
|
|
run: cd client && npm run lint:check
|
|
|
|
- name: Page pattern check
|
|
run: cd client && npm run lint:pages
|
|
|
|
client-tests:
|
|
name: Client Tests
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: 24
|
|
cache: npm
|
|
cache-dependency-path: package-lock.json
|
|
|
|
- name: Install dependencies
|
|
run: npm ci --workspace shared && npm ci --workspace client
|
|
|
|
- name: Build shared
|
|
run: npm run build --workspace=shared
|
|
|
|
- name: Run tests
|
|
run: cd client && npm run test:coverage
|
|
|
|
- name: Upload coverage
|
|
if: success()
|
|
uses: actions/upload-artifact@v6
|
|
with:
|
|
name: frontend-coverage
|
|
path: client/coverage/
|
|
retention-days: 7
|