Git Workflow & Automated Testing
Complete guide to branching strategy, commit conventions, automated testing with Vitest and Playwright, and tag-driven releases.
On this page
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 formatfor 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 tomainto trigger npm publish + GitHub Release. - Standardized Network: Always use
127.0.0.1for 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:
- Database safety β
scripts/check-test-db-safety.tsblocks unsafeprivate.test.ts, liveprivate.tspointing at test DBs, and matching live/test DB names (user data protection). - Format + lint β
bun run check(oxfmt + oxlint). - Lint-staged β
bun run gate:fast. risk:auditβ security-risk scan (all adapters) + secret misuse + slop +bun audit+ OSV (skipped if only docs changed).- Unit tests β
vitest run(skipped if only docs changed). - SBOM sync β when
bun.lock/package.jsonchanged.
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:4173viaTEST_MODE=true. - Location:
tests/e2e/
π§ Smart Test Orchestrator
- Purpose: Reads
git diffand 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:
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).
--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=trueproduction 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
- Stage changes:
git add . - Commit:
git commit -m "feat(auth): add OAuth2 support"β pre-commit hook runs (DB safety β format+lint β lint-staged β unit tests). - Push:
bun run git push origin feat/my-featureβ pre-push hook runs (production build βbun test tests/integration/). - 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
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).