Browse Source
- Documents the conditional Husky activation system for git hooks - Explains how hooks are committed but not automatically activated - Provides user workflows for enabling/disabling hooks - Includes troubleshooting guide and best practices - Covers three activation methods: environment variable, local file, global config - Supports team standards without forcing compliance System: Git hooks with optional activation Location: doc/husky-conditional-activation.mdpull/153/head
1 changed files with 381 additions and 0 deletions
@ -0,0 +1,381 @@ |
|||||
|
# Husky Conditional Activation System |
||||
|
|
||||
|
**Author**: Matthew Raymer |
||||
|
**Date**: 2025-08-21T09:40Z |
||||
|
**Status**: 🎯 **ACTIVE** - Git hooks with optional activation |
||||
|
|
||||
|
## Overview |
||||
|
|
||||
|
This document describes the **conditional Husky activation system** implemented |
||||
|
in the TimeSafari project. The system provides standardized git hooks that are |
||||
|
committed to version control but only activate when explicitly enabled by |
||||
|
individual developers. |
||||
|
|
||||
|
## Problem Statement |
||||
|
|
||||
|
Traditional Husky implementations face several challenges: |
||||
|
|
||||
|
1. **Automatic activation** on all systems can be disruptive |
||||
|
2. **Different environments** may have different requirements |
||||
|
3. **Team preferences** vary regarding git hook enforcement |
||||
|
4. **CI/CD systems** may not need or want git hooks |
||||
|
5. **New developers** may be surprised by unexpected hook behavior |
||||
|
|
||||
|
## Solution: Conditional Activation |
||||
|
|
||||
|
The conditional activation system solves these problems by: |
||||
|
|
||||
|
- **Committing hooks to git** for consistency and version control |
||||
|
- **Making hooks optional** by default |
||||
|
- **Providing multiple activation methods** for flexibility |
||||
|
- **Ensuring hooks exit gracefully** when disabled |
||||
|
- **Maintaining team standards** without forcing compliance |
||||
|
|
||||
|
## System Architecture |
||||
|
|
||||
|
### **Core Components** |
||||
|
|
||||
|
``` |
||||
|
.husky/ |
||||
|
├── _/husky.sh # Conditional activation logic |
||||
|
├── pre-commit # Pre-commit hook (linting) |
||||
|
├── commit-msg # Commit message validation |
||||
|
└── README.md # User activation instructions |
||||
|
``` |
||||
|
|
||||
|
### **Activation Methods** |
||||
|
|
||||
|
#### **Method 1: Environment Variable (Session Only)** |
||||
|
|
||||
|
```bash |
||||
|
export HUSKY_ENABLED=1 |
||||
|
``` |
||||
|
|
||||
|
- **Scope**: Current terminal session only |
||||
|
- **Use case**: Temporary activation for testing |
||||
|
- **Reset**: `unset HUSKY_ENABLED` |
||||
|
|
||||
|
#### **Method 2: Local File (Persistent)** |
||||
|
|
||||
|
```bash |
||||
|
touch .husky-enabled |
||||
|
``` |
||||
|
|
||||
|
- **Scope**: Current repository, persistent |
||||
|
- **Use case**: Long-term activation for development |
||||
|
- **Reset**: `rm .husky-enabled` |
||||
|
|
||||
|
#### **Method 3: Global Git Configuration** |
||||
|
|
||||
|
```bash |
||||
|
git config --global husky.enabled true |
||||
|
``` |
||||
|
|
||||
|
- **Scope**: All repositories for current user |
||||
|
- **Use case**: Developer preference across projects |
||||
|
- **Reset**: `git config --global --unset husky.enabled` |
||||
|
|
||||
|
## Implementation Details |
||||
|
|
||||
|
### **Conditional Activation Logic** |
||||
|
|
||||
|
The core logic in `.husky/_/husky.sh`: |
||||
|
|
||||
|
```bash |
||||
|
# Check if Husky is enabled for this user |
||||
|
if [ "$HUSKY_ENABLED" != "1" ] && [ ! -f .husky-enabled ]; then |
||||
|
echo "Husky is not enabled. To enable:" |
||||
|
echo " export HUSKY_ENABLED=1" |
||||
|
echo " or create .husky-enabled file" |
||||
|
exit 0 # Graceful exit, not an error |
||||
|
fi |
||||
|
``` |
||||
|
|
||||
|
### **Hook Behavior** |
||||
|
|
||||
|
When **disabled**: |
||||
|
|
||||
|
- Hooks display helpful activation instructions |
||||
|
- Exit with code 0 (success, not error) |
||||
|
- No git operations are blocked |
||||
|
- No performance impact |
||||
|
|
||||
|
When **enabled**: |
||||
|
|
||||
|
- Hooks run normally with full functionality |
||||
|
- Standard Husky behavior applies |
||||
|
- Git operations may be blocked if hooks fail |
||||
|
|
||||
|
## Available Hooks |
||||
|
|
||||
|
### **Pre-commit Hook** |
||||
|
|
||||
|
**File**: `.husky/pre-commit` |
||||
|
**Purpose**: Code quality enforcement before commits |
||||
|
**Action**: Runs `npm run lint-fix` |
||||
|
**When**: Before each commit |
||||
|
**Failure**: Prevents commit if linting fails |
||||
|
|
||||
|
**Activation Check**: |
||||
|
|
||||
|
```bash |
||||
|
if [ "$HUSKY_ENABLED" = "1" ] || [ -f .husky-enabled ]; then |
||||
|
echo "Running pre-commit hooks..." |
||||
|
npm run lint-fix |
||||
|
else |
||||
|
echo "Husky pre-commit hook skipped (not enabled)" |
||||
|
exit 0 |
||||
|
fi |
||||
|
``` |
||||
|
|
||||
|
### **Commit-msg Hook** |
||||
|
|
||||
|
**File**: `.husky/commit-msg` |
||||
|
**Purpose**: Commit message format validation |
||||
|
**Action**: Runs `npx commitlint --edit "$1"` |
||||
|
**When**: After commit message is written |
||||
|
**Failure**: Prevents commit if message format is invalid |
||||
|
|
||||
|
**Activation Check**: |
||||
|
|
||||
|
```bash |
||||
|
if [ "$HUSKY_ENABLED" = "1" ] || [ -f .husky-enabled ]; then |
||||
|
echo "Running commit-msg hooks..." |
||||
|
npx commitlint --edit "$1" |
||||
|
else |
||||
|
echo "Husky commit-msg hook skipped (not enabled)" |
||||
|
exit 0 |
||||
|
fi |
||||
|
``` |
||||
|
|
||||
|
## User Workflows |
||||
|
|
||||
|
### **New Developer Setup** |
||||
|
|
||||
|
1. **Clone repository** |
||||
|
|
||||
|
```bash |
||||
|
git clone <repository-url> |
||||
|
cd <repository-name> |
||||
|
``` |
||||
|
|
||||
|
2. **Hooks are present but inactive** |
||||
|
- Pre-commit and commit-msg hooks exist |
||||
|
- No automatic activation |
||||
|
- Git operations work normally |
||||
|
|
||||
|
3. **Optional: Enable hooks** |
||||
|
|
||||
|
```bash |
||||
|
# For current session only |
||||
|
export HUSKY_ENABLED=1 |
||||
|
|
||||
|
# For persistent activation |
||||
|
touch .husky-enabled |
||||
|
``` |
||||
|
|
||||
|
### **Daily Development** |
||||
|
|
||||
|
#### **With Hooks Disabled** |
||||
|
|
||||
|
```bash |
||||
|
git add . |
||||
|
git commit -m "feat: add new feature" |
||||
|
# Hooks are skipped, commit proceeds normally |
||||
|
``` |
||||
|
|
||||
|
#### **With Hooks Enabled** |
||||
|
|
||||
|
```bash |
||||
|
git add . |
||||
|
git commit -m "feat: add new feature" |
||||
|
# Pre-commit hook runs linting |
||||
|
# Commit-msg hook validates message format |
||||
|
# Commit only proceeds if all hooks pass |
||||
|
``` |
||||
|
|
||||
|
### **Troubleshooting** |
||||
|
|
||||
|
#### **Hooks Not Running** |
||||
|
|
||||
|
```bash |
||||
|
# Check if hooks are enabled |
||||
|
echo $HUSKY_ENABLED |
||||
|
ls -la .husky-enabled |
||||
|
|
||||
|
# Enable hooks |
||||
|
export HUSKY_ENABLED=1 |
||||
|
# or |
||||
|
touch .husky-enabled |
||||
|
``` |
||||
|
|
||||
|
#### **Hooks Running Unexpectedly** |
||||
|
|
||||
|
```bash |
||||
|
# Disable hooks |
||||
|
unset HUSKY_ENABLED |
||||
|
rm -f .husky-enabled |
||||
|
|
||||
|
# Check global configuration |
||||
|
git config --global --get husky.enabled |
||||
|
``` |
||||
|
|
||||
|
## Configuration Files |
||||
|
|
||||
|
### **`.gitignore` Entry** |
||||
|
|
||||
|
```gitignore |
||||
|
# Husky activation file (user-specific) |
||||
|
.husky-enabled |
||||
|
``` |
||||
|
|
||||
|
This ensures that: |
||||
|
|
||||
|
- Hooks are committed to git (team standard) |
||||
|
- Activation files are not committed (user preference) |
||||
|
- Each developer can control their own activation |
||||
|
|
||||
|
### **Package.json Dependencies** |
||||
|
|
||||
|
```json |
||||
|
{ |
||||
|
"devDependencies": { |
||||
|
"husky": "^9.0.11", |
||||
|
"@commitlint/cli": "^18.6.1", |
||||
|
"@commitlint/config-conventional": "^18.6.2" |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
## Benefits |
||||
|
|
||||
|
### **For Development Teams** |
||||
|
|
||||
|
1. **Consistency**: All developers have the same hook configuration |
||||
|
2. **Flexibility**: Individual developers can choose activation |
||||
|
3. **Standards**: Team coding standards are enforced when enabled |
||||
|
4. **Version Control**: Hook configuration is tracked and versioned |
||||
|
5. **Onboarding**: New developers get standardized setup |
||||
|
|
||||
|
### **For Individual Developers** |
||||
|
|
||||
|
1. **Choice**: Control over when hooks are active |
||||
|
2. **Performance**: No unnecessary hook execution when disabled |
||||
|
3. **Learning**: Gradual adoption of git hook practices |
||||
|
4. **Debugging**: Easy to disable hooks for troubleshooting |
||||
|
5. **Environment**: Works across different development environments |
||||
|
|
||||
|
### **For CI/CD Systems** |
||||
|
|
||||
|
1. **No Interference**: Hooks don't run in automated environments |
||||
|
2. **Consistency**: Same hook logic available if needed |
||||
|
3. **Flexibility**: Can enable hooks in specific CI scenarios |
||||
|
4. **Reliability**: No unexpected hook failures in automation |
||||
|
|
||||
|
## Best Practices |
||||
|
|
||||
|
### **Team Adoption** |
||||
|
|
||||
|
1. **Start with disabled hooks** for new team members |
||||
|
2. **Encourage gradual adoption** of hook activation |
||||
|
3. **Document hook benefits** and usage patterns |
||||
|
4. **Provide training** on hook configuration |
||||
|
5. **Support troubleshooting** when hooks cause issues |
||||
|
|
||||
|
### **Hook Development** |
||||
|
|
||||
|
1. **Keep hooks lightweight** and fast |
||||
|
2. **Provide clear error messages** when hooks fail |
||||
|
3. **Include helpful activation instructions** in disabled state |
||||
|
4. **Test hooks in both enabled and disabled states** |
||||
|
5. **Document hook requirements** and dependencies |
||||
|
|
||||
|
### **Configuration Management** |
||||
|
|
||||
|
1. **Commit hook files** to version control |
||||
|
2. **Ignore activation files** in .gitignore |
||||
|
3. **Document activation methods** clearly |
||||
|
4. **Provide examples** for common use cases |
||||
|
5. **Maintain backward compatibility** when updating hooks |
||||
|
|
||||
|
## Troubleshooting Guide |
||||
|
|
||||
|
### **Common Issues** |
||||
|
|
||||
|
#### **Hooks Running When Not Expected** |
||||
|
|
||||
|
```bash |
||||
|
# Check all activation methods |
||||
|
echo "Environment variable: $HUSKY_ENABLED" |
||||
|
echo "Local file exists: $([ -f .husky-enabled ] && echo "yes" || echo "no")" |
||||
|
echo "Global config: $(git config --global --get husky.enabled)" |
||||
|
``` |
||||
|
|
||||
|
#### **Hooks Not Running When Expected** |
||||
|
|
||||
|
```bash |
||||
|
# Verify hook files exist and are executable |
||||
|
ls -la .husky/ |
||||
|
chmod +x .husky/pre-commit |
||||
|
chmod +x .husky/commit-msg |
||||
|
``` |
||||
|
|
||||
|
#### **Permission Denied Errors** |
||||
|
|
||||
|
```bash |
||||
|
# Fix file permissions |
||||
|
chmod +x .husky/_/husky.sh |
||||
|
chmod +x .husky/pre-commit |
||||
|
chmod +x .husky/commit-msg |
||||
|
``` |
||||
|
|
||||
|
### **Debug Mode** |
||||
|
|
||||
|
Enable debug output to troubleshoot hook issues: |
||||
|
|
||||
|
```bash |
||||
|
export HUSKY_DEBUG=1 |
||||
|
export HUSKY_ENABLED=1 |
||||
|
git commit -m "test: debug commit" |
||||
|
``` |
||||
|
|
||||
|
## Future Enhancements |
||||
|
|
||||
|
### **Planned Improvements** |
||||
|
|
||||
|
1. **Hook Configuration File**: YAML/JSON configuration for hook behavior |
||||
|
2. **Selective Hook Activation**: Enable/disable specific hooks individually |
||||
|
3. **Hook Performance Metrics**: Track execution time and success rates |
||||
|
4. **Integration with IDEs**: IDE-specific activation methods |
||||
|
5. **Remote Configuration**: Team-wide hook settings via configuration |
||||
|
|
||||
|
### **Extension Points** |
||||
|
|
||||
|
1. **Custom Hook Scripts**: Easy addition of project-specific hooks |
||||
|
2. **Hook Templates**: Reusable hook patterns for common tasks |
||||
|
3. **Conditional Logic**: Complex activation rules based on context |
||||
|
4. **Notification System**: Hook status reporting and alerts |
||||
|
5. **Analytics**: Hook usage and effectiveness tracking |
||||
|
|
||||
|
## Conclusion |
||||
|
|
||||
|
The conditional Husky activation system provides an elegant solution to the |
||||
|
challenges of git hook management in team environments. By committing |
||||
|
standardized hooks while making activation optional, it balances consistency |
||||
|
with flexibility, enabling teams to maintain coding standards without forcing compliance. |
||||
|
|
||||
|
This approach supports gradual adoption, respects individual preferences, and |
||||
|
provides a solid foundation for git hook practices that can evolve with team needs |
||||
|
and project requirements. |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
**Related Documents**: |
||||
|
|
||||
|
- [Git Hooks Best Practices](./git-hooks-best-practices.md) |
||||
|
- [Code Quality Standards](./code-quality-standards.md) |
||||
|
- [Development Workflow](./development-workflow.md) |
||||
|
|
||||
|
**Maintainer**: Development Team |
||||
|
**Review Schedule**: Quarterly |
||||
|
**Next Review**: 2025-11-21 |
Loading…
Reference in new issue