Skip to content

Commit 4d3d80e

Browse files
committed
Add production-grade QA infrastructure
Adopted from recallnet/tradecore QA system: TypeScript: - Maximum strict mode (noUncheckedIndexedAccess, exactOptionalPropertyTypes, noPropertyAccessFromIndexSignature, noUnusedLocals/Parameters) - Fixed all source files for new strict flags ESLint (7 plugins): - typescript-eslint strictTypeChecked + stylisticTypeChecked - eslint-plugin-unicorn (node protocol, filename-case) - eslint-plugin-sonarjs (cognitive complexity max 15) - eslint-plugin-security (unsafe regex, eval, object injection) - eslint-plugin-promise (always-return, catch-or-return) - eslint-plugin-no-secrets (tolerance 4.5) - eslint-plugin-import-x (ordering, no-duplicates, no-self-import) - eslint-config-prettier (formatting rules disabled) - Test files relaxed (no-explicit-any, no-non-null-assertion off) Prettier: - .prettierrc + .prettierignore, format/format:check scripts Husky hooks: - Pre-commit: 9 stages (lint-staged, lockfile sync, typecheck, lint, build, test, secrets check, console.log warnings, changeset check) - Pre-push: 5 checks (uncommitted changes, build, lint, typecheck, tests) CI pipeline (4 jobs): - lint-and-typecheck (with format:check) - test with coverage thresholds - build-verify (entry point + export smoke tests) - changeset-check (PR only) Testing: - vitest.config.ts with v8 coverage (80/80/70/80 thresholds) - @vitest/coverage-v8 in parser package Also: Updated README install instructions for GitHub Packages registry.
1 parent 91d7d01 commit 4d3d80e

49 files changed

Lines changed: 2794 additions & 697 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
1-
# CI — runs on every push to main and every PR targeting main.
2-
#
3-
# Jobs:
4-
# build — Full monorepo build to catch compile errors
5-
# test — Unit tests across all packages
6-
# typecheck — TypeScript type checking
7-
81
name: CI
92

103
on:
@@ -14,7 +7,7 @@ on:
147
branches: [main]
158

169
jobs:
17-
build:
10+
lint-and-typecheck:
1811
runs-on: ubuntu-latest
1912
steps:
2013
- uses: actions/checkout@v4
@@ -27,10 +20,16 @@ jobs:
2720
cache: "pnpm"
2821
- run: pnpm install --frozen-lockfile
2922
- run: pnpm build
23+
- name: Lint
24+
run: pnpm lint
25+
- name: Type-check
26+
run: pnpm typecheck
27+
- name: Format check
28+
run: pnpm format:check
3029

3130
test:
3231
runs-on: ubuntu-latest
33-
needs: build
32+
needs: [lint-and-typecheck]
3433
steps:
3534
- uses: actions/checkout@v4
3635
- uses: pnpm/action-setup@v2
@@ -42,9 +41,10 @@ jobs:
4241
cache: "pnpm"
4342
- run: pnpm install --frozen-lockfile
4443
- run: pnpm build
45-
- run: pnpm test
44+
- name: Run tests with coverage
45+
run: pnpm test:coverage
4646

47-
typecheck:
47+
build-verify:
4848
runs-on: ubuntu-latest
4949
steps:
5050
- uses: actions/checkout@v4
@@ -56,5 +56,36 @@ jobs:
5656
node-version: 22
5757
cache: "pnpm"
5858
- run: pnpm install --frozen-lockfile
59-
- run: pnpm build
60-
- run: pnpm typecheck
59+
- name: Build all packages
60+
run: pnpm build
61+
- name: Verify CLI entry point
62+
run: node packages/cli/dist/index.js --help
63+
- name: Verify parser exports
64+
run: node -e "import('@recallnet/codecontext-parser').then(m => { if (!m.parseContextTags) throw new Error('Missing export'); console.log('Parser exports OK'); })"
65+
- name: Verify ESLint plugin exports
66+
run: node -e "import('@recallnet/codecontext-eslint-plugin').then(m => { if (!m.default?.rules) throw new Error('Missing rules'); console.log('ESLint plugin exports OK'); })"
67+
68+
changeset-check:
69+
runs-on: ubuntu-latest
70+
if: github.event_name == 'pull_request'
71+
steps:
72+
- uses: actions/checkout@v4
73+
with:
74+
fetch-depth: 0
75+
- uses: pnpm/action-setup@v2
76+
with:
77+
version: 10
78+
- uses: actions/setup-node@v4
79+
with:
80+
node-version: 22
81+
cache: "pnpm"
82+
- run: pnpm install --frozen-lockfile
83+
- name: Check for changesets
84+
run: |
85+
CHANGED=$(git diff --name-only origin/main...HEAD | grep -E '^packages/(parser|cli|eslint-plugin)/src/' || true)
86+
if [ -n "$CHANGED" ]; then
87+
CHANGESETS=$(git diff --name-only origin/main...HEAD | grep -E '^\.changeset/.*\.md$' || true)
88+
if [ -z "$CHANGESETS" ]; then
89+
echo "::warning::Source files changed in publishable packages but no changeset found. Run 'pnpm changeset' before merging."
90+
fi
91+
fi

.husky/pre-commit

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
echo "=== Pre-commit checks ==="
5+
6+
# ── Stage 0: lint-staged (format staged files) ──────────────────────
7+
echo "[0/8] Formatting staged files..."
8+
npx lint-staged
9+
10+
# ── Stage 1: Lockfile sync ──────────────────────────────────────────
11+
echo "[1/8] Checking lockfile sync..."
12+
pnpm install --frozen-lockfile --ignore-scripts 2>/dev/null || {
13+
echo "❌ pnpm-lock.yaml is out of sync. Run 'pnpm install' and stage the lockfile."
14+
exit 1
15+
}
16+
17+
# ── Stage 2: Type-check (affected packages) ─────────────────────────
18+
echo "[2/8] Type-checking..."
19+
npx turbo typecheck
20+
21+
# ── Stage 3: Lint (affected packages) ───────────────────────────────
22+
echo "[3/8] Linting..."
23+
npx turbo lint
24+
25+
# ── Stage 4: Build ──────────────────────────────────────────────────
26+
echo "[4/8] Building..."
27+
npx turbo build
28+
29+
# ── Stage 5: Tests ──────────────────────────────────────────────────
30+
echo "[5/8] Running tests..."
31+
npx turbo test
32+
33+
# ── Stage 6: Hardcoded secrets check ────────────────────────────────
34+
echo "[6/8] Checking for hardcoded secrets..."
35+
SECRETS_FOUND=0
36+
git diff --cached --name-only --diff-filter=d | while read -r file; do
37+
if [[ "$file" =~ \.(ts|tsx|js|jsx|mjs|cjs)$ ]]; then
38+
if git show ":$file" 2>/dev/null | grep -inE '(api[_-]?key|secret[_-]?key|password|token)\s*[:=]\s*["\x27][A-Za-z0-9+/=]{8,}' | grep -v '// eslint-disable' | grep -v 'process\.env' | grep -v 'import' >/dev/null 2>&1; then
39+
echo "⚠️ Possible hardcoded secret in: $file"
40+
SECRETS_FOUND=1
41+
fi
42+
fi
43+
done
44+
if [ "$SECRETS_FOUND" -eq 1 ]; then
45+
echo "❌ Potential secrets detected. Use environment variables instead."
46+
exit 1
47+
fi
48+
49+
# ── Stage 7: Console.log warnings ───────────────────────────────────
50+
echo "[7/8] Checking for console.log statements..."
51+
CONSOLE_FOUND=0
52+
git diff --cached --name-only --diff-filter=d | while read -r file; do
53+
if [[ "$file" =~ \.(ts|tsx)$ ]] && [[ ! "$file" =~ \.test\. ]] && [[ ! "$file" =~ \.spec\. ]]; then
54+
if git show ":$file" 2>/dev/null | grep -n 'console\.log\b' >/dev/null 2>&1; then
55+
echo "⚠️ console.log found in: $file"
56+
CONSOLE_FOUND=1
57+
fi
58+
fi
59+
done
60+
if [ "$CONSOLE_FOUND" -eq 1 ]; then
61+
echo "⚠️ Warning: console.log statements found (non-blocking)"
62+
fi
63+
64+
# ── Stage 8: Changeset requirement ──────────────────────────────────
65+
# Check if any publishable package files changed without a changeset
66+
CHANGED_PACKAGES=$(git diff --cached --name-only | grep -E '^packages/(parser|cli|eslint-plugin)/src/' || true)
67+
if [ -n "$CHANGED_PACKAGES" ]; then
68+
CHANGESETS=$(git diff --cached --name-only | grep -E '^\.changeset/.*\.md$' || true)
69+
if [ -z "$CHANGESETS" ]; then
70+
echo "⚠️ Warning: Source files changed in publishable packages but no changeset found."
71+
echo " Run 'pnpm changeset' to create one before merging to main."
72+
fi
73+
fi
74+
75+
echo "✅ All pre-commit checks passed"

.husky/pre-push

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
echo "=== Pre-push checks ==="
5+
6+
# ── Check 1: No uncommitted changes ─────────────────────────────────
7+
echo "[1/5] Checking for uncommitted changes..."
8+
if ! git diff --quiet || ! git diff --cached --quiet; then
9+
echo "❌ Uncommitted changes detected. Commit or stash before pushing."
10+
exit 1
11+
fi
12+
13+
# ── Check 2: Full build ─────────────────────────────────────────────
14+
echo "[2/5] Building all packages..."
15+
npx turbo build
16+
17+
# ── Check 3: Full lint ──────────────────────────────────────────────
18+
echo "[3/5] Linting..."
19+
npx turbo lint
20+
21+
# ── Check 4: Full type-check ────────────────────────────────────────
22+
echo "[4/5] Type-checking..."
23+
npx turbo typecheck
24+
25+
# ── Check 5: Full test suite ────────────────────────────────────────
26+
echo "[5/5] Running all tests..."
27+
npx turbo test
28+
29+
echo "✅ All pre-push checks passed"

.node-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
22

.prettierignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
node_modules/
2+
dist/
3+
.turbo/
4+
*.tsbuildinfo
5+
pnpm-lock.yaml
6+
.codecontext-cache.json

.prettierrc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"semi": true,
3+
"singleQuote": false,
4+
"trailingComma": "es5",
5+
"tabWidth": 2,
6+
"printWidth": 100
7+
}

0 commit comments

Comments
 (0)