Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .husky/pre-commit
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1 +1,32 @@
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"

FAIL=0

# Run a check; capture output; print details only on failure
check() {
local name="$1"; shift
local out
out=$("$@" 2>&1)
local status=$?
if [ $status -eq 0 ]; then
printf '✅ %s\n' "$name"
else
printf '❌ %s\n' "$name"
printf '%s\n' "$out"
FAIL=$((FAIL + 1))
fi
}

# 1. Format + safe lint fixes on staged files — lint-staged auto-restages changes
npx lint-staged

# 2. Type safety — catches broken types before they reach CI
check 'TypeScript (api)' npm run typecheck --workspace=apps/api
check 'TypeScript (web)' npm run typecheck --workspace=apps/web

# 3. Tests — each workspace runs its own vitest config
check 'Tests (api)' npm run test --workspace=apps/api
check 'Tests (web)' npm run test --workspace=apps/web

[ $FAIL -eq 0 ]
2 changes: 1 addition & 1 deletion apps/web/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default defineConfig({
plugins: [sveltekit()],
resolve: {
alias: {
'$env/dynamic/public': resolve('./src/tests/env.ts'),
'$env/dynamic/public': resolve(import.meta.dirname, './src/tests/env.ts'),
},
conditions: ['browser'],
},
Expand Down
3 changes: 2 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
"dev:local": "concurrently -n api,web -c cyan,magenta \"npm run dev -w apps/api\" \"npm run dev -w apps/web\"",
"build": "docker compose build",
"check": "bash scripts/check.sh",
"lint": "biome check .",
"test": "npm run test -w apps/api && npm run test -w apps/web",
"prepare": "node -e \"require('fs').existsSync('.git') && require('child_process').execSync('husky', {stdio:'inherit'})\"",
"storybook": "npm run storybook --workspace=apps/web"
},
Expand All @@ -15,7 +17,11 @@
"@sveltejs/vite-plugin-svelte": "^4.0.0",
"concurrently": "^9.2.1",
"husky": "^9.1.7",
"lint-staged": "^16.3.2"
"lint-staged": "^16.3.2",
"vitest": "^2.1.9"
},
"lint-staged": {
"*.{ts,js,svelte,json,css}": "biome check --write --no-errors-on-unmatched"
},
"msw": {
"workerDirectory": ["apps/web/static"]
Expand Down
99 changes: 47 additions & 52 deletions scripts/check.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
set -euo pipefail
set -uo pipefail

ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"
Expand All @@ -12,80 +12,75 @@ fi
PASS=0
FAIL=0
WARN=0
declare -a FAIL_LABELS=()
declare -a FAIL_OUTPUTS=()
declare -a WARN_LABELS=()
declare -a WARN_OUTPUTS=()

run_step() {
local label="$1"
shift
echo ""
echo "▶ $label"
if "$@"; then
echo " ✅ $label"
local label="$1"; shift
local out
if out=$("$@" 2>&1); then
echo "✅ $label"
PASS=$((PASS + 1))
else
echo " ❌ $label"
echo "❌ $label"
FAIL=$((FAIL + 1))
FAIL_LABELS+=("$label")
FAIL_OUTPUTS+=("$out")
fi
}

# run_warn: same as run_step but failure is non-blocking — increments WARN, not FAIL.
run_warn() {
local label="$1"
shift
echo ""
echo "▶ $label (warning)"
if "$@"; then
echo " ✅ $label"
local label="$1"; shift
local out
if out=$("$@" 2>&1); then
echo "✅ $label"
PASS=$((PASS + 1))
else
echo " ⚠️ $label non-blocking"
echo "⚠️ $label (non-blocking)"
WARN=$((WARN + 1))
WARN_LABELS+=("$label")
WARN_OUTPUTS+=("$out")
fi
}

echo "════════════════════════════════════"
echo " Minime quality checks"
echo "════════════════════════════════════"

# Biome: lint + format check (read-only — no auto-mutate; biome ci exits non-zero on any violation)
run_step "Biome lint + format" npx biome ci .

# TypeScript: typecheck per app
if [ -f "apps/api/tsconfig.json" ]; then
run_step "TypeScript (api)" bash -c "cd apps/api && npx tsc --noEmit"
fi

if [ -f "apps/web/tsconfig.json" ]; then
run_step "TypeScript (web)" bash -c "cd apps/web && npx svelte-kit sync && npx tsc --noEmit"
fi
run_step "Biome lint + format" npx biome ci .
run_step "TypeScript (api)" npm run typecheck --workspace=apps/api
run_step "TypeScript (web)" npm run typecheck --workspace=apps/web
run_step "Svelte check" npm run check --workspace=apps/web
run_step "Tests (api)" npm run test --workspace=apps/api
run_step "Tests (web)" npm run test --workspace=apps/web
run_step "Web build" npm run build --workspace=apps/web
run_warn "Storybook build" npm run build-storybook --workspace=apps/web

# Svelte: sync + check
if [ -f "apps/web/package.json" ]; then
run_step "Svelte check" bash -c "cd apps/web && npx svelte-kit sync && npx svelte-check --tsconfig ./tsconfig.json"
fi

# Tests: per app
if [ -f "apps/api/package.json" ] && grep -q '"test"' apps/api/package.json; then
run_step "Tests (api)" bash -c "cd apps/api && npx vitest run --passWithNoTests"
fi

if [ -f "apps/web/package.json" ] && grep -q '"test"' apps/web/package.json; then
run_step "Tests (web)" bash -c "cd apps/web && npx vitest run --passWithNoTests"
fi
echo ""
echo "════════════════════════════════════"
printf " %d passed" "$PASS"
[ "$FAIL" -gt 0 ] && printf ", %d failed" "$FAIL"
[ "$WARN" -gt 0 ] && printf ", %d warnings" "$WARN"
echo ""
echo "════════════════════════════════════"

# Web build: catches Svelte compile errors that svelte-check misses
if [ -f "apps/web/package.json" ]; then
run_step "Web build" bash -c "cd apps/web && npx vite build"
# Print failure details — only the output for steps that failed
if [ "${#FAIL_LABELS[@]}" -gt 0 ]; then
echo ""
for i in "${!FAIL_LABELS[@]}"; do
echo "── ❌ ${FAIL_LABELS[$i]} ──────────────────────────"
echo "${FAIL_OUTPUTS[$i]}"
done
fi

# Storybook build: verifies addon-a11y registers and all stories compile — non-blocking.
# a11y violations surface in the browser panel at dev time, not as CI exit codes.
if [ -f "apps/web/package.json" ] && grep -q '"storybook"' apps/web/package.json; then
run_warn "Storybook build (a11y addon smoke)" bash -c "cd apps/web && npx storybook build --quiet"
if [ "${#WARN_LABELS[@]}" -gt 0 ]; then
echo ""
for i in "${!WARN_LABELS[@]}"; do
echo "── ⚠️ ${WARN_LABELS[$i]} ──────────────────────────"
echo "${WARN_OUTPUTS[$i]}"
done
fi

echo ""
echo "════════════════════════════════════"
echo " Results: $PASS passed, $FAIL failed, $WARN warnings"
echo "════════════════════════════════════"

[ "$FAIL" -eq 0 ]