From 203aa9f661e8e4360775b40f13c1cf4725320744 Mon Sep 17 00:00:00 2001 From: Nabil-Fareed Alikhan Date: Sat, 5 Sep 2026 09:41:46 +0100 Subject: [PATCH] Run CI-equivalent checks before push --- .githooks/pre-push | 5 +++++ .github/workflows/ci.yml | 25 +++------------------- .npmrc | 1 + CONTRIBUTING.md | 36 ++++++++++++++++++++++++++------ package-lock.json | 6 +++--- package.json | 10 ++++++++- scripts/check-architecture.sh | 4 ++-- scripts/check-ci-portability.mjs | 24 +++++++++++++++++++++ scripts/check-runtime.mjs | 14 +++++++++++++ scripts/install-git-hooks.mjs | 14 +++++++++++++ 10 files changed, 105 insertions(+), 34 deletions(-) create mode 100755 .githooks/pre-push create mode 100644 scripts/check-ci-portability.mjs create mode 100644 scripts/check-runtime.mjs create mode 100644 scripts/install-git-hooks.mjs diff --git a/.githooks/pre-push b/.githooks/pre-push new file mode 100755 index 0000000..67a6104 --- /dev/null +++ b/.githooks/pre-push @@ -0,0 +1,5 @@ +#!/usr/bin/env sh +set -eu + +echo "Running BRIGX pre-CI checks before push..." +npm run verify:ci diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 28e007a..7587a36 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,6 @@ on: branches: - master paths-ignore: - - 'package.json' - '*.md' jobs: @@ -31,26 +30,8 @@ jobs: - name: Install npm dependencies run: npm ci - - name: Type-check - run: pixi run npx tsc --noEmit - - - name: Lint - run: pixi run npm run lint - - - name: Architecture guardrails - run: pixi run npm run quality:architecture - - - name: Licence policy - run: pixi run npm run quality:licenses - - - name: Runtime and build dependency audit - run: pixi run npm run quality:security - - - name: Unit tests - run: pixi run npm test - - - name: Production build - run: pixi run npm run build + - name: Run core CI checks + run: pixi run npm run verify:ci:core browser: name: Browser end-to-end tests @@ -70,4 +51,4 @@ jobs: run: npx playwright install --with-deps chromium - name: Browser tests - run: npm run test:e2e + run: npm run verify:ci:browser diff --git a/.npmrc b/.npmrc index 521a9f7..ea9d044 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,2 @@ legacy-peer-deps=true +engine-strict=true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 847eb8f..f514f18 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,9 +20,14 @@ Thank you for your interest in contributing to BRIGx — a browser-based tool fo 2. **Install dependencies** ```bash - npm install + nvm use + npm ci + npx playwright install chromium ``` + `npm ci` also installs the repository's pre-push hook. The hook runs the + same checks as GitHub CI and cancels the push if any of them fail. + 3. **Start the development server** ```bash @@ -31,6 +36,25 @@ Thank you for your interest in contributing to BRIGx — a browser-based tool fo The app will be available at [http://localhost:3000](http://localhost:3000). Changes to source files are reflected immediately via hot reload. +## Checking a Change Before CI + +Run the exact checks used by GitHub CI: + +```bash +npm run verify:ci +``` + +This includes type-checking, linting, architecture and licence policies, the +dependency security audit, unit tests, the production build, and production +browser tests. `npm run verify` additionally exercises the development server. + +The pre-push hook runs `npm run verify:ci` automatically. If hooks were disabled +or this checkout predates the hook, restore it with: + +```bash +npm run hooks:install +``` + ## Running Tests ```bash @@ -43,7 +67,7 @@ To run tests in watch mode (re-runs on file changes): npm run test:watch ``` -Tests live in `__tests__/` and use Jest with `jest-environment-jsdom`. +Tests live in `__tests__/` and use Vitest with jsdom. ## Linting @@ -51,7 +75,7 @@ Tests live in `__tests__/` and use Jest with `jest-environment-jsdom`. npm run lint ``` -Please ensure there are no new lint errors before opening a PR. Lint warnings for `@typescript-eslint/no-explicit-any` are acceptable in the short term but should be addressed progressively. +Please ensure there are no new lint errors before opening a PR. ## Building @@ -59,11 +83,11 @@ Please ensure there are no new lint errors before opening a PR. Lint warnings fo npm run build ``` -BRIGx uses `next build` with static export (`output: 'export'`). The built output is placed in `out/`. Always verify the build succeeds before submitting a PR. +BRIGX uses Vite. The built output is placed in `out/`. Always verify the build succeeds before submitting a PR. ## Pull Request Process -1. Create a feature branch from `main`: +1. Create a feature branch from `master`: ```bash git checkout -b feat/my-feature @@ -75,7 +99,7 @@ BRIGx uses `next build` with static export (`output: 'export'`). The built outpu 4. Verify the production build succeeds (`npm run build`). -5. Open a pull request against `main` on GitHub. Fill in the PR template with: +5. Open a pull request against `master` on GitHub. Fill in the PR template with: - A clear description of what changed and why - Any relevant issue numbers (e.g. `Closes #42`) - Notes on manual testing performed diff --git a/package-lock.json b/package-lock.json index e4cff33..2b13ddd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3554,9 +3554,9 @@ "dev": true }, "node_modules/nanoid": { - "version": "3.3.16", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", - "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", "dev": true, "funding": [ { diff --git a/package.json b/package.json index a21a425..d645cd6 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,11 @@ "dev": "vite", "build": "tsc -b && vite build", "start": "vite preview", + "typecheck": "tsc --noEmit", "lint": "eslint .", + "quality:runtime": "node scripts/check-runtime.mjs", "quality:architecture": "bash scripts/check-architecture.sh", + "quality:portability": "node scripts/check-ci-portability.mjs", "quality:licenses": "node scripts/check-licenses.mjs", "quality:security": "node scripts/check-security.mjs", "test": "vitest run", @@ -30,7 +33,12 @@ "test:coverage": "vitest run --coverage", "test:e2e": "playwright test", "test:e2e:dev": "playwright test --config playwright.dev.config.ts", - "verify": "npm run lint && npm run quality:architecture && npm run quality:licenses && npm run quality:security && npm test && npm run build && npm run test:e2e && npm run test:e2e:dev" + "verify:ci:core": "npm run quality:runtime && npm run typecheck && npm run lint && npm run quality:architecture && npm run quality:portability && npm run quality:licenses && npm run quality:security && npm test && npm run build", + "verify:ci:browser": "npm run test:e2e", + "verify:ci": "npm run verify:ci:core && npm run verify:ci:browser", + "verify": "npm run verify:ci && npm run test:e2e:dev", + "hooks:install": "node scripts/install-git-hooks.mjs", + "prepare": "npm run hooks:install" }, "dependencies": { "@genomicx/ui": "0.9.1", diff --git a/scripts/check-architecture.sh b/scripts/check-architecture.sh index 191e6e2..daeb81e 100644 --- a/scripts/check-architecture.sh +++ b/scripts/check-architecture.sh @@ -12,12 +12,12 @@ while IFS= read -r source_file; do fi done < <(find components hooks lib src workers -type f \( -name '*.ts' -o -name '*.tsx' \) -print | sort) -if rg -n "(from[[:space:]]+|import\()[\"'][^\"']*workers/" components hooks lib src; then +if grep -R -n -E "(from[[:space:]]+|import\()[\"'][^\"']*workers/" components hooks lib src; then echo "Architecture check: UI/domain modules must not import Web Worker entry modules." failed=1 fi -if rg -n "from[[:space:]]+[\"'][^\"']*renderer[\"']" lib/canvas-renderer.ts; then +if grep -n -E "from[[:space:]]+[\"'][^\"']*renderer[\"']" lib/canvas-renderer.ts; then echo "Architecture check: canvas rendering must use shared rendering contracts, not SVG renderer internals." failed=1 fi diff --git a/scripts/check-ci-portability.mjs b/scripts/check-ci-portability.mjs new file mode 100644 index 0000000..6a7f659 --- /dev/null +++ b/scripts/check-ci-portability.mjs @@ -0,0 +1,24 @@ +/* global console, process */ +import { delimiter } from 'node:path'; +import { execFileSync } from 'node:child_process'; + +if (process.platform === 'win32') { + console.log('CI portability check skipped on Windows; GitHub CI runs it on Linux.'); + process.exit(0); +} + +const systemPath = ['/usr/bin', '/bin']; + +try { + execFileSync('bash', ['scripts/check-architecture.sh'], { + env: { ...process.env, PATH: systemPath.join(delimiter) }, + stdio: 'inherit', + }); +} catch (error) { + console.error( + 'CI portability check failed. Quality scripts must use commands available on a clean Ubuntu runner.', + ); + process.exit(error.status || 1); +} + +console.log('CI portability check passed with system commands only.'); diff --git a/scripts/check-runtime.mjs b/scripts/check-runtime.mjs new file mode 100644 index 0000000..4a93212 --- /dev/null +++ b/scripts/check-runtime.mjs @@ -0,0 +1,14 @@ +/* global console, process */ +import { readFileSync } from 'node:fs'; + +const expectedMajor = Number.parseInt(readFileSync('.nvmrc', 'utf8').trim(), 10); +const actualMajor = Number.parseInt(process.versions.node.split('.')[0], 10); + +if (actualMajor !== expectedMajor) { + console.error( + `BRIGX requires Node.js ${expectedMajor}.x, but this shell is using ${process.version}. Run \`nvm use\` and try again.`, + ); + process.exit(1); +} + +console.log(`Node.js ${process.version} matches the BRIGX CI runtime.`); diff --git a/scripts/install-git-hooks.mjs b/scripts/install-git-hooks.mjs new file mode 100644 index 0000000..f887797 --- /dev/null +++ b/scripts/install-git-hooks.mjs @@ -0,0 +1,14 @@ +/* global console, process */ +import { execFileSync } from 'node:child_process'; + +try { + execFileSync('git', ['rev-parse', '--git-dir'], { stdio: 'ignore' }); +} catch { + console.log('Git hooks not installed: this checkout is not a Git worktree.'); + process.exit(0); +} + +execFileSync('git', ['config', '--local', 'core.hooksPath', '.githooks'], { + stdio: 'inherit', +}); +console.log('Installed BRIGX Git hooks from .githooks/.');