Skip to content

Commit 608e4ac

Browse files
committed
feat: Support for Batch-Size in File Hooks
feat: Adds --hook:batch-size=N arguments to enable file batching Default = 1; 0 = All Files docs: Updates README.md and sample-config.yaml for batch support docs: Small update to Useful Hook Parameters docs: Better placement of "--hook args can appear anywhere" messaging chore: Run pre-commit hooks and fix shellcheck/shfmt warnings
1 parent a38ec6c commit 608e4ac

4 files changed

Lines changed: 66 additions & 10 deletions

File tree

README.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ You can copy/paste the following snippet into your `.pre-commit-config.yaml` fil
3131
#
3232
# --hook:env:NAME=VALUE
3333
#
34+
# NOTE: You can set the number of files to process in a single command
35+
# invocation for file-based hooks using the following format:
36+
#
37+
# --hook:batch-size=N
38+
#
39+
# (N=0 will process all files in a single invocation)
40+
#
3441
# NOTE: You can invoke hooks via 'go tool' using:
3542
#
3643
# --hook:go-tool
@@ -211,6 +218,8 @@ See the [my-cmd](#my-cmd) hooks for more information.
211218

212219
--------------------------
213220
### Useful Hook Parameters
221+
Here are a few pre-commit parameters that may be useful when configuring hooks:
222+
214223
```
215224
- id: hook-id
216225
args: [arg1, arg2, ..., '--'] # Pass options ('--' is optional)
@@ -245,7 +254,22 @@ The hook script will detect this argument and set the variable `NAME` to the val
245254

246255
You can pass multiple `--hook:env:` arguments.
247256

248-
The arguments can appear anywhere in the `args:` list.
257+
#### Passing Batch Size To Hooks
258+
For file-based hooks, you can specify the number of files to include in a single command invocation.
259+
260+
**NOTE:** By default, file-based hooks execute the command once for each staged file.
261+
262+
This feature is enabled via support for a specially-formatted argument:
263+
264+
* `--hook:batch-size=N`
265+
266+
The hook script will detect this argument and use `N` as the batch size.
267+
268+
* `N` must be an integer >= 0.
269+
* A value of `1` (the default) executes the command once for each file.
270+
* A value of `0` executes the command once for all files.
271+
* A value of `N > 1` executes the command once for every `N` files.
272+
(note: the last execution may have < N files)
249273

250274
#### Invoking Hooks Via go tool
251275
You can invoke hooks via `go tool` to ensure that a specific version of a tool is used (requires Go 1.24+).
@@ -388,6 +412,9 @@ By default, hooks ONLY run when matching file types (usually `*.go`) are staged.
388412

389413
When configured to `"always_run"`, a hook is executed as if EVERY matching file were staged.
390414

415+
#### Placement of --Hook: Arguments
416+
The special `--hook:` arguments listed above can appear anywhere in the `args:` list.
417+
391418
#### Aliases / Names
392419

393420
pre-commit supports the ability to assign both an `alias` and a `name` to a configured hook:

lib/cmd-files.bash

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,24 @@
99
prepare_file_hook_cmd "$@"
1010

1111
error_code=0
12-
for file in "${FILES[@]}"; do
13-
if [ "${error_on_output:-}" -eq 1 ]; then
14-
output=$(/usr/bin/env "${ENV_VARS[@]}" "${cmd[@]}" "${OPTIONS[@]}" "${file}" 2>&1)
15-
if [ -n "${output}" ]; then
16-
printf "%s\n" "${output}"
12+
# If batch_size=0, process all files in one go
13+
if [ "${batch_size}" -eq 0 ]; then
14+
batch_size=${#FILES[@]}
15+
fi
16+
17+
# Handle empty FILES to avoid infinite loop if batch_size is also 0
18+
if [ ${#FILES[@]} -gt 0 ]; then
19+
for ((i = 0; i < ${#FILES[@]}; i += batch_size)); do
20+
batch=("${FILES[@]:i:batch_size}")
21+
if [ "${error_on_output:-}" -eq 1 ]; then
22+
output=$(/usr/bin/env "${ENV_VARS[@]}" "${cmd[@]}" "${OPTIONS[@]}" "${batch[@]}" 2>&1)
23+
if [ -n "${output}" ]; then
24+
printf "%s\n" "${output}"
25+
error_code=1
26+
fi
27+
elif ! /usr/bin/env "${ENV_VARS[@]}" "${cmd[@]}" "${OPTIONS[@]}" "${batch[@]}"; then
1728
error_code=1
1829
fi
19-
elif ! /usr/bin/env "${ENV_VARS[@]}" "${cmd[@]}" "${OPTIONS[@]}" "${file}"; then
20-
error_code=1
21-
fi
22-
done
30+
done
31+
fi
2332
exit $error_code

lib/common.bash

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
: "${ignore_pattern_array:=}"
88
: "${ignore_file_pattern_array:=}"
99
: "${ignore_dir_pattern_array:=}"
10+
: "${batch_size:=1}"
1011
ignore_dir_pattern_array+=("vendor")
1112

1213
##
@@ -214,6 +215,7 @@ function parse_file_hook_args {
214215
# Positional order of saved arguments is preserved
215216
#
216217
local ENV_REGEX='^[a-zA-Z_][a-zA-Z0-9_]*=.*$'
218+
local BATCH_SIZE_REGEX='^(0|[1-9][0-9]*)$'
217219
ENV_VARS=()
218220
local __ARGS=()
219221
while [ $# -gt 0 ] && [ "$1" != "--" ]; do
@@ -228,6 +230,16 @@ function parse_file_hook_args {
228230
fi
229231
shift
230232
;;
233+
--hook:batch-size=*)
234+
local batch_size_arg="${1#--hook:batch-size=}"
235+
if [[ "${batch_size_arg}" =~ ${BATCH_SIZE_REGEX} ]]; then
236+
batch_size="${batch_size_arg}"
237+
else
238+
printf "ERROR: Invalid hook:batch-size value: '%s'\n" "${batch_size_arg}" >&2
239+
exit 1
240+
fi
241+
shift
242+
;;
231243
--hook:ignore-pattern=*)
232244
local ignore_pattern="${1#--hook:ignore-pattern=}"
233245
if [[ -n "${ignore_pattern}" ]]; then

sample-config.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,14 @@ repos:
7474
#
7575
# --hook:env:NAME=VALUE
7676
#
77+
# Passing Batch Size to Hooks:
78+
# You can set the number of files to process in a single command
79+
# invocation for file-based hooks using the following format:
80+
#
81+
# --hook:batch-size=N
82+
#
83+
# (N=0 will process all files in a single invocation)
84+
#
7785
# NOTE: You can invoke hooks via 'go tool' using:
7886
#
7987
# --hook:go-tool

0 commit comments

Comments
 (0)