Pre-commit Setup and Optimization
"Quality is not an act, it's a habit." โ Aristotle
This document describes Speakr's pre-commit hook configuration, optimization strategies, and future improvement opportunities.
๐ Table of Contents
- Overview
- Current Setup
- Optimizations
- Usage Guide
- Performance Metrics
- Future Improvements
- Troubleshooting
Overview
Pre-commit hooks ensure code quality by running automated checks before each commit. This prevents broken code from entering the repository and maintains consistent coding standards across the team.
Why Pre-commit?
- Early Detection: Catch issues before they reach CI/CD
- Consistent Quality: Enforce formatting and linting standards
- Fast Feedback: Immediate results during development
- Team Alignment: Same standards for all contributors
Current Setup
Our optimized pre-commit configuration targets affected packages only, reducing execution time by ~70% for typical changes.
Configuration Files
.pre-commit-config.yaml
: Main configurationscripts/selective-tests.sh
: Advanced selective testing script
Hook Categories
1. Package-Specific Rust Hooks
speakr-core (triggered by ^speakr-core/.*\.rs$
):
cargo-fmt-core
: Code formatting checkcargo-clippy-core
: Linting with all warnings as errorscargo-test-core
: Unit and integration tests
speakr-tauri (triggered by ^speakr-tauri/.*\.rs$
):
cargo-fmt-tauri
: Code formatting checkcargo-clippy-tauri
: Linting with all warnings as errorscargo-test-tauri
: Unit and integration tests
speakr-ui (triggered by ^speakr-ui/.*\.rs$
):
cargo-fmt-ui
: Code formatting checkcargo-clippy-ui
: Linting with all warnings as errorscargo-test-ui
: Unit and integration tests
2. Workspace-Level Hooks
Workspace Changes (triggered by ^(Cargo\.(toml|lock)|\.cargo/.*)$
):
cargo-fmt-workspace
: Format all packagescargo-clippy-workspace
: Lint entire workspace
3. Smart Integration Hooks
Dependency Awareness:
cargo-test-integration
: Whenspeakr-core
changes, also testspeakr-tauri
(dependency relationship)
4. General Quality Hooks
- Trailing whitespace: Remove unnecessary whitespace
- YAML/JSON/TOML validation: Syntax checking
- Large file detection: Prevent accidental commits of large files
- Merge conflict detection: Catch unresolved conflicts
- Markdown linting: Documentation quality
Optimizations
๐ฏ Selective Package Testing
Problem: Previous setup ran all checks on all packages for any Rust file change.
Solution: File pattern matching to target only affected packages.
# Before: Always runs on ANY .rs file
files: \.rs$
entry: cargo test --all
# After: Only runs on speakr-core files
files: ^speakr-core/.*\.rs$
entry: cargo test --package speakr-core
๐ง Dependency-Aware Testing
Problem: Changes to speakr-core
could break speakr-tauri
without running its tests.
Solution: Smart integration testing when dependencies change.
# Integration test: core changes affect tauri
- id: cargo-test-integration
name: Cargo Test (integration - core affects tauri)
entry: cargo test --package speakr-tauri
files: ^speakr-core/.*\.rs$ # Triggered by core changes
โก Performance Optimizations
- Parallel Execution: Each package's hooks can run in parallel
- Targeted Scoping: Only affected code gets checked
- Smart Caching: Cargo's incremental compilation benefits
- Early Exit: Hooks fail fast on first error
Usage Guide
Installation
# Install pre-commit (if not already installed)
pip install pre-commit
# Install hooks in repository
pre-commit install
# Optional: Install for push events too
pre-commit install -t pre-push
Daily Workflow
Automatic (Recommended):
git add .
git commit -m "feat: add new feature"
# Hooks run automatically, commit proceeds if all pass
Manual Testing:
# Run all hooks on all files
pre-commit run --all-files
# Run specific hook
pre-commit run cargo-fmt-core
# Run on specific files
pre-commit run --files speakr-core/src/lib.rs
Advanced Selective Testing
For maximum control, use our custom script:
# Test only packages affected by changes since last commit
./scripts/selective-tests.sh
# Compare against specific commit/branch
./scripts/selective-tests.sh main
./scripts/selective-tests.sh abc123def
# Get help
./scripts/selective-tests.sh --help
Bypassing Hooks (Emergency Only)
# Skip all hooks (use sparingly!)
git commit -m "hotfix: urgent fix" --no-verify
# Skip specific hook
SKIP=cargo-test-core git commit -m "fix: skip tests temporarily"
Performance Metrics
Before Optimization
- Total packages checked: 3/3 (100%)
- Average execution time: ~45 seconds
- Parallel efficiency: Low (redundant work)
After Optimization
- Typical single-package change: 1/3 packages (33%)
- Average execution time: ~15 seconds (70% improvement)
- Parallel efficiency: High (targeted work)
- Smart dependencies: Core changes โ Core + Tauri tests
Real-world Example
Scenario: Modify speakr-ui/src/app.rs
Before: โ Tests all 3 packages (~45s)
After: โ Tests only speakr-ui
package (~12s)
Speedup: 3.75x faster ๐
Future Improvements
๐ Performance Enhancements
1. Incremental Testing with Coverage
Goal: Only run tests affected by specific code changes, not entire packages.
Implementation:
# Future: Ultra-granular testing
cargo test --package speakr-core -- --test-affected-by src/audio.rs
Tools to explore:
cargo-difftests
: Selective re-testing framework- LLVM coverage analysis for affected test discovery
determinator
: Facebook's affected package detection
2. Caching and Memoization
Goal: Skip checks if code hasn't changed since last successful run.
Implementation:
# Cache test results based on content hash
- id: cargo-test-cached
entry: cache-wrapper cargo test --package speakr-core
cache_key: "hash:speakr-core/**/*.rs"
Benefits:
- Near-instant results for unchanged code
- Perfect for repeated CI runs on same commit
3. Parallel Package Testing
Goal: Run different package tests truly in parallel.
Current: Sequential package testing Future: Matrix-style parallel execution
# Run in parallel using job control
cargo test --package speakr-core &
cargo test --package speakr-tauri &
cargo test --package speakr-ui &
wait # Wait for all to complete
๐ Enhanced Feedback
1. Rich Diff Display
Goal: Show exactly what code caused failures.
Implementation:
# Future: Rich failure reporting
cargo clippy --message-format json | jq -r '.spans[] | .file_name + ":" + .line_start'
Features:
- Syntax-highlighted diffs
- Click-to-fix suggestions
- Context-aware error messages
2. Performance Profiling
Goal: Track and optimize hook execution time.
Metrics to collect:
- Per-hook execution time
- Cache hit/miss ratios
- Package-level timing breakdown
- Historical performance trends
3. Smart Notifications
Goal: Contextual feedback based on change type.
Examples:
# API changes detected
โ ๏ธ Public API modified in speakr-core - consider semver impact
# Performance impact detected
๐ Tests are 20% slower - check for performance regressions
# Security sensitive changes
๐ Cryptographic code modified - extra security review recommended
๐งช Test Quality Improvements
1. Mutation Testing Integration
Goal: Ensure tests actually catch bugs.
Implementation:
# Run mutation tests on changed code
cargo mutants --package speakr-core --in-diff HEAD~1..HEAD
2. Dependency Impact Analysis
Goal: Understand full impact of changes across the dependency graph.
Visualization:
speakr-core change impact:
โโโ speakr-core (direct) โ
โโโ speakr-tauri (depends on core) โ
โโโ speakr-ui (independent) โญ๏ธ skipped
3. Flaky Test Detection
Goal: Identify and fix unreliable tests.
Implementation:
- Run tests multiple times in CI
- Track test success/failure rates
- Auto-quarantine flaky tests
- Generate flakiness reports
๐ง Developer Experience
1. IDE Integration
Goal: Show pre-commit status in development environment.
Features:
- Real-time hook status in VS Code/Cursor
- Inline error highlighting
- One-click fix suggestions
2. Hook Customization
Goal: Allow per-developer customization.
Implementation:
# .pre-commit-config.local.yaml (git-ignored)
hooks:
- id: cargo-clippy-core
args: ["--", "-A", "clippy::pedantic"] # Less strict for local dev
3. Quick Fix Tools
Goal: Automated fixing of common issues.
Examples:
# Auto-fix formatting
pre-commit run cargo-fmt-core --hook-stage manual
# Auto-fix common clippy warnings
cargo clippy --fix --allow-dirty
# Auto-update dependencies
cargo update && pre-commit run cargo-test-all
Troubleshooting
Common Issues
Hook Fails with "Package not found"
Cause: Package name mismatch in hook configuration.
Solution: Verify package names match Cargo.toml
files:
cargo metadata --format-version 1 | jq '.packages[].name'
Tests Pass Locally but Fail in CI
Cause: Different dependency versions or environment.
Solution: Use Cargo.lock
and consistent Rust versions:
# CI configuration
rust-toolchain: "1.88.0" # Pin exact version
Hooks Run on Wrong Files
Cause: Incorrect regex patterns in files:
configuration.
Solution: Test patterns with realistic file paths:
# Test regex pattern
echo "speakr-core/src/lib.rs" | grep -E "^speakr-core/.*\.rs$"
Performance Issues
Slow Hook Execution
- Check package scoping: Ensure hooks target specific packages
- Review test suite: Look for slow integration tests
- Enable caching: Use
--cache-dir
for cargo operations
Memory Issues
- Limit parallel jobs: Set
CARGO_BUILD_JOBS=2
- Increase memory limits: Configure system swap
- Use release mode for tests:
cargo test --release
(if appropriate)
Getting Help
- Check configuration: Validate with
pre-commit validate-config
- Debug mode: Run with
pre-commit run --verbose
- Clean cache: Use
pre-commit clean
to reset - Manual testing: Test individual hooks in isolation