Skip to content

Documentation

Git Workflow & Automated Testing

Complete guide to branching strategy, commit conventions, automated testing with Vitest and Playwright, and tag-driven releases.

8/6/2026
10 min read Edit on GitHub

Introduction

SveltyCMS uses a comprehensive Git workflow with automated testing and semantic versioning to ensure code quality and streamline the release process. A mandatory Local Quality Gate is enforced via native Git hooks to ensure that only verified code reaches the repository.

Our CI/CD and Local pipeline uses:

  • Native Git Hooks: Zero-dependency quality gate (.githooks/pre-commit).
  • Vitest (jsdom): Unified unit testing for components, stores, services, and API handlers.
  • Unified Formatting: oxfmt-powered bun run format for lightning-fast cleanup.
  • Vitest Unit Suite: Fast unit testing (1,100+ tests in under 10 seconds for the full suite).
  • Playwright: Comprehensive E2E testing across multiple database backends.
  • Tag-Driven Releases: Push a v* tag to main to trigger npm publish + GitHub Release.
  • Standardized Network: Always use 127.0.0.1 for local consistency.

πŸ›‘οΈ Mandatory Local Quality Gate

Before any commit or push, SveltyCMS runs automated checks via native Git hooks. Activate them once per clone:

git config core.hooksPath .githooks

Git Hook Overview

SveltyCMS uses native Git hooks for local quality gates β€” no external precheck orchestrator script required.

Pre-commit (DB safety β†’ format+lint β†’ lint-staged β†’ risk:audit β†’ unit β†’ SBOM)

.githooks/pre-commit runs:

  1. Database safety β€” scripts/check-test-db-safety.ts blocks unsafe private.test.ts, live private.ts pointing at test DBs, and matching live/test DB names (user data protection).
  2. Format + lint β€” bun run check (oxfmt + oxlint).
  3. Lint-staged β€” bun run gate:fast.
  4. risk:audit β€” security-risk scan (all adapters) + secret misuse + slop + bun audit + OSV (skipped if only docs changed).
  5. Unit tests β€” vitest run (skipped if only docs changed).
  6. SBOM sync β€” when bun.lock / package.json changed.
Important

No double-run rule: the full unit suite (including hooks security tests) runs on pre-commit only. Pre-push runs build + post-build verifiers + tenant + SQLite integration β€” do not re-run the entire unit suite on push. Focused re-run: bun run test:security.

Live data rule: automated local runs never use config/private.ts or the user database β€” only private.test.ts + isolated DB names.

Pre-push (~5–8 min) β€” production build + verifiers + tenant + SQLite integration

.githooks/pre-push runs:

Check Command Est.
Production build (4 adapters) COMPILE_ALL_ADAPTERS=true bun run build ~45–120s
Prod backdoor verify scripts/verify-prod-build-backdoor.ts --mode=bench ~5–15s
Bundle size gate scripts/check-bundle-size.ts ~5–15s
Quality gate bun run check ~15–40s
Secret misuse scan scripts/scan-secret-misuse.ts --strict ~5–15s
Tenant isolation bun run test:tenant ~5–20s
SQLite integration tests bun test tests/integration/ ~60–180s

Full unit suite is not re-run on push. Multi-adapter DB matrix, E2E, and benchmarks are CI-only. Docs-only pushes skip build + integration.

bun run gate                               # pre-push gate (build + verifiers + tenant + SQLite)
bun run prepush                            # same as gate
bun test --timeout 300000 tests/integration/   # Integration only (needs build/)
bun run test:doctor                        # unit + SQLite integration + gate map
bun run risk:audit                         # same scanners as pre-commit step 4

Branching Strategy

We have two primary, long-lived branches: main and next.

main Branch (Production)

  • Purpose: Production-ready, stable code. This branch represents the latest official release.
  • Protection: Protected branch requiring pull request reviews.
  • Automated Actions:
    • Runs full Playwright + Vitest test suite.
    • Tag-driven releases: pushing a v* tag triggers npm publish + GitHub Release with auto-generated notes from commits.
  • Version source: Git tags, not package.json.

next Branch (Development)

  • Purpose: Development and staging. This is the primary branch for all new features.
  • Automated Actions:
    • βœ… Runs full test suite on every push.
    • βœ… Tests across multiple databases (MongoDB, PostgreSQL, MariaDB).
    • βœ… No automatic releases (tests only).

Commit Message Convention

Our automated release process depends on a strict commit message format. We use the Conventional Commits specification.

Commit Message Model (Conventional Commits + TQA)

We follow an enhanced Conventional Commits specification to maintain a clear Technical Ledger.

Format:

<type>(<scope>): <subject> [TQA-Verified]

Types:

  • tqa - Resilience & Integrity: Adding chaos tests, state-machine audits, or GDPR verification.
  • perf - Throughput & Latency: Memory leak fixes, JIT optimizations, and benchmark improvements.
  • feat - Feature: New functionality.
  • fix - Stability: Bug fixes.
  • refactor - Clean Code: Internal restructuring without behavior changes.

Mandatory Scopes:

  • resilience: For any changes to circuit breakers or failover logic.
  • temporal: For timezone/date normalization changes.
  • concurrency: For locking and atomic transaction changes.
  • ledger: For documentation and benchmark result updates.

Automated Testing Architecture

πŸ§ͺ Vitest Unit Tests

  • Speed: ⚑ Fast feedback on every commit (full suite via pre-commit).
  • Location: tests/unit/
  • Runner: Vitest with jsdom for components, stores, services, and API logic.
  • Command: bun run test:unit Β· focused security: bun run test:security

πŸ”— Contract Tests (Adapter Parity)

  • Purpose: Identical assertions run against all 4 databases (SQLite, MongoDB, PostgreSQL, MariaDB).
  • Location: tests/integration/databases/contract.test.ts
  • Contracts: Adapter, Auth, Permission, Setup Gating, Resilience.
  • Command: bun run test:integration

🎭 Playwright Tests (E2E)

  • Purpose: Browser automation for critical user journeys.
  • Standard: Always point to 127.0.0.1:4173 via TEST_MODE=true.
  • Location: tests/e2e/

🧠 Smart Test Orchestrator

  • Purpose: Reads git diff and selects required test suites. Unknown changes fail closed.
  • Command: bun run test:smart

πŸ” AI Slop Scanner

  • Purpose: Detects unsafe {@html}, legacy Svelte 4 patterns, missing ARIA, RTL violations, dead exports.
  • Command: bun run slop

Tiered Local Testing Strategy

SveltyCMS uses a three-tier testing strategy that balances developer velocity with full CI parity. Each tier corresponds to a different Git lifecycle event:

flowchart LR A["git commit"] -->|"~40–60s"| B["Pre-Commit
DB safety β†’ format+lint
β†’ lint-staged β†’ risk:audit β†’ unit"] C["git push"] -->|"~5–8 min"| D["Pre-Push
Build 4 adapters β†’ backdoor/bundle
β†’ check β†’ secrets β†’ tenant β†’ SQLite integ"]

Tier 1: Pre-Commit (.githooks/pre-commit) β€” Fast Feedback

Runs automatically on every git commit. Target: ~40–60 seconds (full unit suite + risk audit; skipped if only docs changed).

Check Tool
Test config safety check-test-db-safety.ts
Format + lint bun run check (oxfmt + oxlint)
Lint-staged bun run gate:fast
Risk audit bun run risk:audit
Unit tests bun run test:unit (Vitest)
SBOM sync audit:sbom (if lock changed)

Tier 2: Pre-Push (.githooks/pre-push) β€” Production Build + Integration

Runs automatically on every git push. Catches build and integration failures before they reach CI.

Check Command
Production build (4 adapters) COMPILE_ALL_ADAPTERS=true bun run build
Prod backdoor + bundle gates verify-prod-build-backdoor + check-bundle-size
Quality + secrets + tenant check + secret scan + test:tenant
SQLite integration tests bun test tests/integration/

Multi-adapter DB integration + E2E + benchmarks are CI-only.

Manual equivalent: bun run prepush / bun run gate (via hardened git wrapper).

Caution

--no-verify is blocked by scripts/git-safe.ts. Use bun run git push β€” bypassing requires the system git binary path deliberately.

Tier 3: Full CI Parity β€” CI Pipeline

CI runs the complete matrix automatically on every PR/push to next. Covers what local hooks skip:

  • Whitebox: format + lint + type check + secret scan + deploy backdoor probe
  • Build: COMPILE_ALL_ADAPTERS=true production build
  • DB tests: Full multi-adapter matrix (MongoDB, PostgreSQL, MariaDB, SQLite)
  • E2E: Playwright prep + 6 shards (chromium)
  • Benchmarks: Performance regression detection

All local test commands must use config/private.test.ts only β€” they must not rename, overwrite, or connect through the developer’s config/private.ts (live user data). Isolation is env + policy (private-config-policy.ts), not backup/restore of live config.

Prerequisites for local integration tests: Docker Desktop with MongoDB (27017), MariaDB (3306), and PostgreSQL (5432) on 127.0.0.1.


Scripts Audit

All scripts in scripts/ and their role in the testing pipeline:

Core Scripts (Testing Pipeline)

Script Role Called By
test-doctor.ts Gate map + unit + SQLite integration bun run test:doctor (manual)
test-smart.ts Git-diff-aware test selector bun run test:smart (manual)
security-audit.ts Security vulnerability scanner bun run security
run-e2e.ts Unified E2E runner (CI/dev modes) bun run test:e2e
check-test-db-safety.ts Blocks unsafe test config pre-commit
scan-secret-misuse.ts Secret exposure static analysis CI whitebox / manual
verify-prod-build-backdoor.ts Checks /api/testing stripped in deploy CI build / whitebox
verify-benchmark-local.ts Blocks local benchmarks on test DB names Manual
bundle-stats.ts Bundle size analysis bun run build:stats
check-bundle-size.ts CI bundle size gate CI build job
generate-sbom.ts Software bill of materials generation bun run audit:sbom

Utility Scripts

Script Role Command
security-audit.ts Security vulnerability scanner bun run security
generate-sbom.ts SBOM generation bun run audit:sbom
bundle-stats.ts Bundle size analysis bun run build:stats
upgrade.ts Automated core updates bun run upgrade
setup-system.ts System bootstrap Dev setup helper
generate-core-countries.js Country data generator Address widget data

Best Practices

Commit Workflow

  1. Stage changes: git add .
  2. Commit: git commit -m "feat(auth): add OAuth2 support" β€” pre-commit hook runs (DB safety β†’ format+lint β†’ lint-staged β†’ unit tests).
  3. Push: bun run git push origin feat/my-feature β€” pre-push hook runs (production build β†’ bun test tests/integration/).
  4. Before PR: Ensure CI passes β€” local hooks already guarantee the same gate.

Manual Verification

If you want to run checks outside the hook lifecycle:

# Pre-commit gate manually
bun run precommit

# Pre-push gate manually
bun run gate
# or: bun run prepush

# Unit + SQLite integration + gate map
bun run test:doctor

# Integration tests (SQLite; needs build/)
bun test --timeout 300000 tests/integration/

# Smart Test Orchestrator β€” auto-detects what to test from git diff
bun run test:smart

# AI Slop Scanner β€” detect code smells
bun run slop

Security & Slop Regression Check

For changes touching auth, middleware, or API routes, also run:

bun run test:security
bun run slop
Note

On Windows (PowerShell), always use ; to chain commands. Avoid && as it is not natively supported in PowerShell.


Troubleshooting

β€œPermission Denied” on Git Hook

If you are on Linux/macOS and the hook fails to execute:

chmod +x .githooks/pre-commit .githooks/pre-push

β€œDatabase connection failed” in Tests

Ensure you are using 127.0.0.1 in your config/private.test.ts and that the test database is accessible.

Bypassing Hooks

bun run git commit and bun run git push block --no-verify. Bypassing requires invoking the system Git binary directly β€” a deliberate act, not muscle memory. CI will reject the same failures the hooks catch.

Docker DB Not Reachable During Pre-Push

If the pre-push hook or local CI reports postgresql is not reachable at 127.0.0.1:5432:

docker compose -f tests/docker-compose.yml --profile postgresql up -d
docker compose -f tests/docker-compose.yml --profile mariadb up -d
docker compose -f tests/docker-compose.yml --profile mongodb up -d

Credentials must match src/utils/test-db-credentials.ts (image defaults: postgres/postgres, root/mariadb, mongo no-auth).


Related Documentation

gitworkflowtestingci-cdreleasedevelopment
Was this page helpful?