Skip to content

Commit 4733623

Browse files
committed
CU-86b7kybxx - feat: add file filtering options for pre-commit and pre-push hooks in configuration
1 parent 6b2de87 commit 4733623

File tree

4 files changed

+142
-34
lines changed

4 files changed

+142
-34
lines changed

.dev-hooks.example.yml

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ pre-commit:
88
# Enable/disable pre-commit checks (default: true)
99
enabled: true
1010

11+
# Only run if changes include these file patterns (optional)
12+
# Supports multiple patterns: "*.py, *.js"
13+
# only_for_files: "*.py"
14+
1115
# Commands to run before commit
1216
commands:
1317
# Example: Run linter
@@ -32,9 +36,14 @@ pre-push:
3236
# Skip branch name validation (default: false)
3337
skip_branch_validation: false
3438

39+
# Only run commands if changes include these file patterns (optional)
40+
# If no matching files are changed, commands are skipped
41+
# Supports multiple patterns separated by comma: "*.py, *.js"
42+
only_for_files: "*.py"
43+
3544
# Commands to run before push
3645
commands:
37-
# Example: Run tests
46+
# Example: Run tests (only if .py files changed)
3847
- name: "Run Tests"
3948
run: "pytest"
4049

@@ -59,56 +68,58 @@ docker:
5968

6069
# --- Python Project ---
6170
# pre-commit:
71+
# only_for_files: "*.py"
6272
# commands:
6373
# - name: "Lint"
6474
# run: "ruff check ."
6575
# - name: "Types"
6676
# run: "mypy src/"
67-
# - name: "Format"
68-
# run: "ruff format --check ."
6977
# pre-push:
78+
# only_for_files: "*.py"
7079
# commands:
7180
# - name: "Tests"
7281
# run: "pytest -v"
7382

7483
# --- Node.js Project ---
7584
# pre-commit:
85+
# only_for_files: "*.js, *.ts, *.tsx"
7686
# commands:
7787
# - name: "Lint"
7888
# run: "npm run lint"
7989
# - name: "Types"
8090
# run: "npm run typecheck"
8191
# pre-push:
92+
# only_for_files: "*.js, *.ts, *.tsx"
8293
# commands:
8394
# - name: "Tests"
8495
# run: "npm test"
85-
# - name: "Build"
86-
# run: "npm run build"
8796

8897
# --- PHP/Drupal Project (Dockerized) ---
8998
# docker:
9099
# enabled: true
91100
# compose: true
92101
# container: "php"
93102
# pre-commit:
103+
# only_for_files: "*.php, *.module, *.inc"
94104
# commands:
95105
# - name: "PHPCS"
96106
# run: "vendor/bin/phpcs --standard=Drupal web/modules/custom"
97107
# pre-push:
108+
# only_for_files: "*.php"
98109
# commands:
99110
# - name: "PHPUnit"
100111
# run: "vendor/bin/phpunit"
101112

102113
# --- Go Project ---
103114
# pre-commit:
115+
# only_for_files: "*.go"
104116
# commands:
105117
# - name: "Vet"
106118
# run: "go vet ./..."
107119
# - name: "Fmt"
108120
# run: "test -z $(gofmt -l .)"
109121
# pre-push:
122+
# only_for_files: "*.go"
110123
# commands:
111124
# - name: "Tests"
112125
# run: "go test ./..."
113-
# - name: "Build"
114-
# run: "go build ./..."

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Git hooks for development workflow automation.
77
- **commit-msg**: Validates commit messages follow [Conventional Commits](https://www.conventionalcommits.org/) format (with optional ClickUp ID)
88
- **pre-commit**: Runs custom commands (lint, type check, format) from config file
99
- **pre-push**: Validates branch naming + runs custom commands (tests) from config file
10+
- **File filtering**: Only run commands when specific file types are changed
1011

1112
## Installation
1213

@@ -105,6 +106,7 @@ cp .dev-hooks.example.yml .dev-hooks.yml
105106
# Pre-commit commands (run on every commit)
106107
pre-commit:
107108
enabled: true
109+
only_for_files: "*.py" # Only run if .py files are staged
108110
commands:
109111
- name: "Lint Check"
110112
run: "ruff check src/"
@@ -115,6 +117,7 @@ pre-commit:
115117
pre-push:
116118
enabled: true
117119
skip_branch_validation: false
120+
only_for_files: "*.py" # Only run tests if .py files changed
118121
commands:
119122
- name: "Run Tests"
120123
run: "pytest"
@@ -127,6 +130,23 @@ docker:
127130
compose_file: "docker-compose.yml"
128131
```
129132
133+
### File Filtering
134+
135+
Use `only_for_files` to run commands only when specific file types are changed:
136+
137+
```yaml
138+
pre-commit:
139+
only_for_files: "*.py" # Single pattern
140+
141+
pre-push:
142+
only_for_files: "*.py, *.js" # Multiple patterns (comma-separated)
143+
```
144+
145+
If no matching files are found, commands are skipped with a message:
146+
```
147+
Skipping pre-push commands (no matching files: *.py)
148+
```
149+
130150
### Docker Support
131151

132152
For dockerized projects, enable docker execution:

src/dev_tools_hooks/hooks/pre-commit

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
# Pre-commit hook for code quality checks
44
# Runs custom commands from .dev-hooks.yml (lint, type check, format, etc.)
5+
# Optionally filtered by file types
56

67
# Colors optimized for macOS Terminal
78
RED='\x1b[31m'
@@ -91,22 +92,61 @@ yaml_get_commands() {
9192
' "$file"
9293
}
9394

95+
# ============================================================================
96+
# File Filter Check
97+
# ============================================================================
98+
99+
has_matching_staged_files() {
100+
local filter="$1"
101+
102+
if [ -z "$filter" ]; then
103+
return 0
104+
fi
105+
106+
# Get staged files
107+
local staged_files=$(git diff --cached --name-only --diff-filter=ACMR)
108+
109+
if [ -z "$staged_files" ]; then
110+
return 1
111+
fi
112+
113+
# Check if any file matches the filter pattern
114+
IFS=',' read -ra patterns <<< "$filter"
115+
for pattern in "${patterns[@]}"; do
116+
pattern=$(echo "$pattern" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
117+
local regex=$(echo "$pattern" | sed 's/\./\\./g; s/\*/.*/g')
118+
119+
if echo "$staged_files" | grep -qE "$regex"; then
120+
return 0
121+
fi
122+
done
123+
124+
return 1
125+
}
126+
94127
# ============================================================================
95128
# Run Commands from .dev-hooks.yml
96129
# ============================================================================
97130

98131
run_commands() {
99132
if [ ! -f "$CONFIG_FILE" ]; then
100-
# No config file, nothing to do
101133
exit 0
102134
fi
103135

104-
# Check if pre-commit is enabled
105136
local enabled=$(yaml_get "pre-commit.enabled" "$CONFIG_FILE")
106137
if [ "$enabled" = "false" ]; then
107138
exit 0
108139
fi
109140

141+
# Check file filter
142+
local only_for_files=$(yaml_get "pre-commit.only_for_files" "$CONFIG_FILE")
143+
if [ -n "$only_for_files" ]; then
144+
if ! has_matching_staged_files "$only_for_files"; then
145+
echo -e "${DIM}Skipping pre-commit commands (no matching files: ${only_for_files})${NC}"
146+
exit 0
147+
fi
148+
fi
149+
110150
# Check docker settings
111151
local docker_enabled=$(yaml_get "docker.enabled" "$CONFIG_FILE")
112152
local docker_compose=$(yaml_get "docker.compose" "$CONFIG_FILE")
@@ -115,7 +155,6 @@ run_commands() {
115155

116156
[ -z "$compose_file" ] && compose_file="docker-compose.yml"
117157

118-
# Get commands
119158
local commands=$(yaml_get_commands "pre-commit" "$CONFIG_FILE")
120159

121160
if [ -z "$commands" ]; then
@@ -139,7 +178,6 @@ run_commands() {
139178
echo -e "${BLUE}${NC} ${WHITE}${BOLD}${name}${NC}"
140179
echo -e " ${DIM}${cmd}${NC}"
141180

142-
# Build the actual command
143181
local full_cmd="$cmd"
144182

145183
if [ "$docker_enabled" = "true" ]; then
@@ -150,7 +188,6 @@ run_commands() {
150188
fi
151189
fi
152190

153-
# Run command
154191
cd "$PROJECT_ROOT" || exit 1
155192

156193
if eval "$full_cmd"; then

0 commit comments

Comments
 (0)