The existing 380-test backend suite runs entirely against the in-memory
datastore provider, which treats every partition-key value as equivalent.
This hid one entire class of bug — partition-key mismatches — until
production. D7 closes that gap.
Implementation:
- backend/src/test-helpers.ts adds useCosmosDatastore() that swaps the
active provider for CosmosDatastoreProvider using COSMOS_ENDPOINT /
COSMOS_KEY / COSMOS_DATABASE. Throws synchronously when env is missing
so a misconfigured run fails loudly instead of silently falling back
to in-memory.
- backend/vitest.config.ts now excludes src/**/*.cosmos.test.ts so the
default 'pnpm test' run stays green for contributors without Docker.
- backend/vitest.cosmos.config.ts (new) includes ONLY *.cosmos.test.ts,
bumps testTimeout to 30s / hookTimeout to 60s for the real client
round-trips, and locks DB_PROVIDER=cosmos in test env.
- backend/src/cosmos.smoke.cosmos.test.ts (new) covers the four most
important partition-key contracts in NoteLett:
workspaces /userId
notes /workspaceId
note_tasks /workspaceId
note_shares /workspaceId (full create → resolve → delete → null)
Each test also asserts that a wrong-partition-key lookup returns null,
which is the failure mode the in-memory provider cannot simulate.
- backend/package.json adds 'test:cosmos' script.
- .github/workflows/ci.yml gains a backend-cosmos job that boots the
official mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator
container as a service, waits for it to be ready (60 × 5s polls of
/_explorer/emulator.pem), then runs pnpm test:cosmos against it.
The job depends on the existing backend job so the emulator only
spins up after unit tests pass.
Verified locally:
- pnpm --filter @notelett/backend test: 380/380 (cosmos suite excluded)
- vitest list --config vitest.cosmos.config.ts: 4 tests under the cosmos
smoke suite, as designed
- pnpm run verify: end-to-end green (backend 380/380, web 96/96,
mobile 97/97)
- ci.yml passes Python yaml.safe_load
CI verification: the new job will execute on the next push. Local
verification against the emulator requires Docker on the dev host.
384 lines
12 KiB
YAML
384 lines
12 KiB
YAML
name: CI — NoteLett
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
pull_request:
|
|
branches: [main]
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
release-guards:
|
|
name: Release guards — secrets + token/color drift
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Checkout common-plat guard scripts
|
|
uses: actions/checkout@v4
|
|
with:
|
|
repository: saravanakumardb1/learning_ai_common_plat
|
|
path: learning_ai_common_plat
|
|
token: ${{ secrets.GH_PAT }}
|
|
|
|
- name: Link common-platform workspace path
|
|
run: |
|
|
ln -sfn "$GITHUB_WORKSPACE/learning_ai_common_plat" ../learning_ai_common_plat
|
|
|
|
- name: Install audit tools
|
|
run: sudo apt-get update && sudo apt-get install -y ripgrep
|
|
|
|
- name: Run release guard audit
|
|
run: COMMON_PLAT="$GITHUB_WORKSPACE/learning_ai_common_plat" bash scripts/release-guard-audit.sh
|
|
|
|
- name: Run UI drift ratchet (one-way gate vs scripts/ui-drift-baseline.json)
|
|
run: bash scripts/ui-drift-ratchet.sh
|
|
|
|
- name: Run UI drift audit (report mode, informational)
|
|
run: bash scripts/ui-drift-audit.sh || true
|
|
|
|
backend:
|
|
name: Backend — typecheck + test + build
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Checkout common-plat (for @bytelyst/* packages)
|
|
uses: actions/checkout@v4
|
|
with:
|
|
repository: saravanakumardb1/learning_ai_common_plat
|
|
path: learning_ai_common_plat
|
|
token: ${{ secrets.GH_PAT }}
|
|
|
|
- name: Link common-platform workspace path
|
|
run: |
|
|
ln -sfn "$GITHUB_WORKSPACE/learning_ai_common_plat" ../learning_ai_common_plat
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 22
|
|
cache: pnpm
|
|
cache-dependency-path: pnpm-lock.yaml
|
|
|
|
- name: Enable pnpm
|
|
run: corepack enable
|
|
|
|
- name: Build @bytelyst/* packages
|
|
working-directory: learning_ai_common_plat
|
|
run: |
|
|
pnpm install --frozen-lockfile
|
|
pnpm build
|
|
|
|
- name: Install workspace dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Backend lint
|
|
run: pnpm --filter @notelett/backend run lint
|
|
|
|
- name: Backend typecheck
|
|
run: pnpm --filter @notelett/backend run typecheck
|
|
|
|
- name: Backend tests
|
|
run: pnpm --filter @notelett/backend run test
|
|
env:
|
|
DB_PROVIDER: memory
|
|
JWT_SECRET: ci-test-secret-at-least-32-characters-long
|
|
|
|
- name: Backend build
|
|
run: pnpm --filter @notelett/backend run build
|
|
|
|
backend-cosmos:
|
|
# Cosmos-emulator smoke — exercises partition-key paths that the
|
|
# in-memory provider cannot detect. Runs only the *.cosmos.test.ts
|
|
# suite via vitest.cosmos.config.ts. See backend/src/cosmos.smoke.cosmos.test.ts
|
|
# for the contract.
|
|
name: Backend — Cosmos emulator smoke (partition keys)
|
|
runs-on: ubuntu-latest
|
|
needs: backend
|
|
services:
|
|
cosmos:
|
|
image: mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:latest
|
|
ports:
|
|
- 8081:8081
|
|
- 10251:10251
|
|
- 10252:10252
|
|
- 10253:10253
|
|
- 10254:10254
|
|
env:
|
|
AZURE_COSMOS_EMULATOR_PARTITION_COUNT: 4
|
|
AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE: false
|
|
options: >-
|
|
--memory 3g
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Checkout common-plat (for @bytelyst/* packages)
|
|
uses: actions/checkout@v4
|
|
with:
|
|
repository: saravanakumardb1/learning_ai_common_plat
|
|
path: learning_ai_common_plat
|
|
token: ${{ secrets.GH_PAT }}
|
|
|
|
- name: Link common-platform workspace path
|
|
run: |
|
|
ln -sfn "$GITHUB_WORKSPACE/learning_ai_common_plat" ../learning_ai_common_plat
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 22
|
|
cache: pnpm
|
|
cache-dependency-path: pnpm-lock.yaml
|
|
|
|
- name: Enable pnpm
|
|
run: corepack enable
|
|
|
|
- name: Build @bytelyst/* packages
|
|
working-directory: learning_ai_common_plat
|
|
run: |
|
|
pnpm install --frozen-lockfile
|
|
pnpm build
|
|
|
|
- name: Install workspace dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Wait for Cosmos emulator to be ready
|
|
run: |
|
|
for i in {1..60}; do
|
|
if curl -ks --max-time 5 https://localhost:8081/_explorer/emulator.pem >/dev/null 2>&1; then
|
|
echo "Cosmos emulator is ready (after ${i}s)"
|
|
exit 0
|
|
fi
|
|
echo "Waiting for Cosmos emulator... ($i/60)"
|
|
sleep 5
|
|
done
|
|
echo "Cosmos emulator failed to become ready in 5 minutes" >&2
|
|
exit 1
|
|
|
|
- name: Run Cosmos smoke suite
|
|
run: pnpm --filter @notelett/backend run test:cosmos
|
|
env:
|
|
DB_PROVIDER: cosmos
|
|
COSMOS_ENDPOINT: https://localhost:8081
|
|
# Well-known emulator dev key. NOT a secret.
|
|
# https://learn.microsoft.com/en-us/azure/cosmos-db/local-emulator
|
|
COSMOS_KEY: C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==
|
|
COSMOS_DATABASE: notelett_test
|
|
NODE_TLS_REJECT_UNAUTHORIZED: 0
|
|
JWT_SECRET: ci-test-secret-at-least-32-characters-long
|
|
|
|
web:
|
|
name: Web — typecheck + test + build
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Checkout common-plat (for @bytelyst/* packages)
|
|
uses: actions/checkout@v4
|
|
with:
|
|
repository: saravanakumardb1/learning_ai_common_plat
|
|
path: learning_ai_common_plat
|
|
token: ${{ secrets.GH_PAT }}
|
|
|
|
- name: Link common-platform workspace path
|
|
run: |
|
|
ln -sfn "$GITHUB_WORKSPACE/learning_ai_common_plat" ../learning_ai_common_plat
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 22
|
|
cache: pnpm
|
|
cache-dependency-path: pnpm-lock.yaml
|
|
|
|
- name: Enable pnpm
|
|
run: corepack enable
|
|
|
|
- name: Build @bytelyst/* packages
|
|
working-directory: learning_ai_common_plat
|
|
run: |
|
|
pnpm install --frozen-lockfile
|
|
pnpm build
|
|
|
|
- name: Install workspace dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Web lint
|
|
run: pnpm --filter @notelett/web run lint
|
|
|
|
- name: Web typecheck
|
|
run: pnpm --filter @notelett/web run typecheck
|
|
|
|
- name: Web tests
|
|
run: pnpm --filter @notelett/web run test
|
|
|
|
- name: Web build
|
|
run: pnpm --filter @notelett/web run build
|
|
|
|
web-e2e:
|
|
name: Web E2E — Playwright
|
|
runs-on: ubuntu-latest
|
|
needs: web
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Checkout common-plat (for @bytelyst/* packages)
|
|
uses: actions/checkout@v4
|
|
with:
|
|
repository: saravanakumardb1/learning_ai_common_plat
|
|
path: learning_ai_common_plat
|
|
token: ${{ secrets.GH_PAT }}
|
|
|
|
- name: Link common-platform workspace path
|
|
run: |
|
|
ln -sfn "$GITHUB_WORKSPACE/learning_ai_common_plat" ../learning_ai_common_plat
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 22
|
|
cache: pnpm
|
|
cache-dependency-path: pnpm-lock.yaml
|
|
|
|
- name: Enable pnpm
|
|
run: corepack enable
|
|
|
|
- name: Build @bytelyst/* packages
|
|
working-directory: learning_ai_common_plat
|
|
run: |
|
|
pnpm install --frozen-lockfile
|
|
pnpm build
|
|
|
|
- name: Install workspace dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Cache Playwright browsers
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: ~/.cache/ms-playwright
|
|
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-playwright-
|
|
|
|
- name: Install Playwright Chromium
|
|
run: pnpm --filter @notelett/web exec playwright install --with-deps chromium
|
|
|
|
- name: Web Playwright E2E
|
|
run: pnpm --filter @notelett/web run test:e2e -- --reporter=list
|
|
|
|
- name: Upload Playwright report
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: web-playwright-report
|
|
path: |
|
|
web/playwright-report
|
|
web/test-results
|
|
if-no-files-found: ignore
|
|
|
|
docker-build:
|
|
name: Docker — backend + web images
|
|
runs-on: ubuntu-latest
|
|
needs: [backend, web]
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Checkout common-plat (for @bytelyst/* packages)
|
|
uses: actions/checkout@v4
|
|
with:
|
|
repository: saravanakumardb1/learning_ai_common_plat
|
|
path: learning_ai_common_plat
|
|
token: ${{ secrets.GH_PAT }}
|
|
|
|
- name: Link common-platform workspace path
|
|
run: |
|
|
ln -sfn "$GITHUB_WORKSPACE/learning_ai_common_plat" ../learning_ai_common_plat
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 22
|
|
cache: pnpm
|
|
cache-dependency-path: pnpm-lock.yaml
|
|
|
|
- name: Enable pnpm
|
|
run: corepack enable
|
|
|
|
- name: Install common-platform dependencies
|
|
working-directory: learning_ai_common_plat
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Prepare Docker tarball dependencies
|
|
run: COMMON_PLAT="$GITHUB_WORKSPACE/learning_ai_common_plat" bash scripts/docker-prep.sh
|
|
|
|
- name: Build backend image
|
|
env:
|
|
GITEA_NPM_TOKEN: ${{ secrets.GITEA_NPM_TOKEN }}
|
|
run: |
|
|
printf '%s' "${GITEA_NPM_TOKEN:-}" > /tmp/gitea_npm_token
|
|
DOCKER_BUILDKIT=1 docker build \
|
|
--secret id=gitea_npm_token,src=/tmp/gitea_npm_token \
|
|
-f backend/Dockerfile \
|
|
-t notelett-backend:ci \
|
|
.
|
|
|
|
- name: Build web image
|
|
env:
|
|
GITEA_NPM_TOKEN: ${{ secrets.GITEA_NPM_TOKEN }}
|
|
run: |
|
|
printf '%s' "${GITEA_NPM_TOKEN:-}" > /tmp/gitea_npm_token
|
|
DOCKER_BUILDKIT=1 docker build \
|
|
--secret id=gitea_npm_token,src=/tmp/gitea_npm_token \
|
|
--build-arg NEXT_PUBLIC_NOTES_API_URL=http://localhost:4016/api \
|
|
--build-arg NEXT_PUBLIC_PLATFORM_SERVICE_URL=http://localhost:4003/api \
|
|
-f web/Dockerfile \
|
|
-t notelett-web:ci \
|
|
.
|
|
|
|
- name: Restore Docker prep changes
|
|
if: always()
|
|
run: bash scripts/docker-prep.sh --restore
|
|
|
|
mobile:
|
|
name: Mobile — lint + typecheck + test
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Checkout common-plat (for @bytelyst/* packages)
|
|
uses: actions/checkout@v4
|
|
with:
|
|
repository: saravanakumardb1/learning_ai_common_plat
|
|
path: learning_ai_common_plat
|
|
token: ${{ secrets.GH_PAT }}
|
|
|
|
- name: Link common-platform workspace path
|
|
run: |
|
|
ln -sfn "$GITHUB_WORKSPACE/learning_ai_common_plat" ../learning_ai_common_plat
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 22
|
|
cache: pnpm
|
|
cache-dependency-path: pnpm-lock.yaml
|
|
|
|
- name: Enable pnpm
|
|
run: corepack enable
|
|
|
|
- name: Build @bytelyst/* packages
|
|
working-directory: learning_ai_common_plat
|
|
run: |
|
|
pnpm install --frozen-lockfile
|
|
pnpm build
|
|
|
|
- name: Install workspace dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Mobile lint
|
|
run: pnpm --filter @notelett/mobile run lint
|
|
|
|
- name: Mobile typecheck
|
|
run: pnpm --filter @notelett/mobile run typecheck
|
|
|
|
- name: Mobile tests
|
|
run: pnpm --filter @notelett/mobile run test
|