Skip to content

Commit c4c9d55

Browse files
committed
Merge branch 'rj/send-email-validate-hook-count-messages'
The sendemail-validate validate hook learned to pass the total number of input files and where in the sequence each invocation is via environment variables. * rj/send-email-validate-hook-count-messages: send-email: export patch counters in validate environment
2 parents 80d268f + 3c8d3ad commit c4c9d55

File tree

4 files changed

+146
-1
lines changed

4 files changed

+146
-1
lines changed

Documentation/githooks.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,28 @@ the name of the file that holds the e-mail to be sent. Exiting with a
600600
non-zero status causes `git send-email` to abort before sending any
601601
e-mails.
602602

603+
The following environment variables are set when executing the hook.
604+
605+
`GIT_SENDEMAIL_FILE_COUNTER`::
606+
A 1-based counter incremented by one for every file holding an e-mail
607+
to be sent (excluding any FIFOs). This counter does not follow the
608+
patch series counter scheme. It will always start at 1 and will end at
609+
GIT_SENDEMAIL_FILE_TOTAL.
610+
611+
`GIT_SENDEMAIL_FILE_TOTAL`::
612+
The total number of files that will be sent (excluding any FIFOs). This
613+
counter does not follow the patch series counter scheme. It will always
614+
be equal to the number of files being sent, whether there is a cover
615+
letter or not.
616+
617+
These variables may for instance be used to validate patch series.
618+
619+
The sample `sendemail-validate` hook that comes with Git checks that all sent
620+
patches (excluding the cover letter) can be applied on top of the upstream
621+
repository default branch without conflicts. Some placeholders are left for
622+
additional validation steps to be performed after all patches of a given series
623+
have been applied.
624+
603625
fsmonitor-watchman
604626
~~~~~~~~~~~~~~~~~~
605627

git-send-email.perl

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -795,11 +795,26 @@ sub is_format_patch_arg {
795795
@files = handle_backup_files(@files);
796796

797797
if ($validate) {
798+
# FIFOs can only be read once, exclude them from validation.
799+
my @real_files = ();
798800
foreach my $f (@files) {
799801
unless (-p $f) {
800-
validate_patch($f, $target_xfer_encoding);
802+
push(@real_files, $f);
801803
}
802804
}
805+
806+
# Run the loop once again to avoid gaps in the counter due to FIFO
807+
# arguments provided by the user.
808+
my $num = 1;
809+
my $num_files = scalar @real_files;
810+
$ENV{GIT_SENDEMAIL_FILE_TOTAL} = "$num_files";
811+
foreach my $r (@real_files) {
812+
$ENV{GIT_SENDEMAIL_FILE_COUNTER} = "$num";
813+
validate_patch($r, $target_xfer_encoding);
814+
$num += 1;
815+
}
816+
delete $ENV{GIT_SENDEMAIL_FILE_COUNTER};
817+
delete $ENV{GIT_SENDEMAIL_FILE_TOTAL};
803818
}
804819

805820
if (@files) {

t/t9001-send-email.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2326,6 +2326,37 @@ test_expect_success $PREREQ 'invoke hook' '
23262326
)
23272327
'
23282328

2329+
expected_file_counter_output () {
2330+
total=$1
2331+
count=0
2332+
while test $count -ne $total
2333+
do
2334+
count=$((count + 1)) &&
2335+
echo "$count/$total" || return
2336+
done
2337+
}
2338+
2339+
test_expect_success $PREREQ '--validate hook allows counting of messages' '
2340+
test_when_finished "rm -rf my-hooks.log" &&
2341+
test_config core.hooksPath "my-hooks" &&
2342+
mkdir -p my-hooks &&
2343+
2344+
write_script my-hooks/sendemail-validate <<-\EOF &&
2345+
num=$GIT_SENDEMAIL_FILE_COUNTER &&
2346+
tot=$GIT_SENDEMAIL_FILE_TOTAL &&
2347+
echo "$num/$tot" >>my-hooks.log || exit 1
2348+
EOF
2349+
2350+
>my-hooks.log &&
2351+
expected_file_counter_output 4 >expect &&
2352+
git send-email \
2353+
--from="Example <[email protected]>" \
2354+
2355+
--smtp-server="$(pwd)/fake.sendmail" \
2356+
--validate -3 --cover-letter --force &&
2357+
test_cmp expect my-hooks.log
2358+
'
2359+
23292360
test_expect_success $PREREQ 'test that send-email works outside a repo' '
23302361
nongit git send-email \
23312362
--from="Example <[email protected]>" \
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#!/bin/sh
2+
3+
# An example hook script to validate a patch (and/or patch series) before
4+
# sending it via email.
5+
#
6+
# The hook should exit with non-zero status after issuing an appropriate
7+
# message if it wants to prevent the email(s) from being sent.
8+
#
9+
# To enable this hook, rename this file to "sendemail-validate".
10+
#
11+
# By default, it will only check that the patch(es) can be applied on top of
12+
# the default upstream branch without conflicts in a secondary worktree. After
13+
# validation (successful or not) of the last patch of a series, the worktree
14+
# will be deleted.
15+
#
16+
# The following config variables can be set to change the default remote and
17+
# remote ref that are used to apply the patches against:
18+
#
19+
# sendemail.validateRemote (default: origin)
20+
# sendemail.validateRemoteRef (default: HEAD)
21+
#
22+
# Replace the TODO placeholders with appropriate checks according to your
23+
# needs.
24+
25+
validate_cover_letter () {
26+
file="$1"
27+
# TODO: Replace with appropriate checks (e.g. spell checking).
28+
true
29+
}
30+
31+
validate_patch () {
32+
file="$1"
33+
# Ensure that the patch applies without conflicts.
34+
git am -3 "$file" || return
35+
# TODO: Replace with appropriate checks for this patch
36+
# (e.g. checkpatch.pl).
37+
true
38+
}
39+
40+
validate_series () {
41+
# TODO: Replace with appropriate checks for the whole series
42+
# (e.g. quick build, coding style checks, etc.).
43+
true
44+
}
45+
46+
# main -------------------------------------------------------------------------
47+
48+
if test "$GIT_SENDEMAIL_FILE_COUNTER" = 1
49+
then
50+
remote=$(git config --default origin --get sendemail.validateRemote) &&
51+
ref=$(git config --default HEAD --get sendemail.validateRemoteRef) &&
52+
worktree=$(mktemp --tmpdir -d sendemail-validate.XXXXXXX) &&
53+
git worktree add -fd --checkout "$worktree" "refs/remotes/$remote/$ref" &&
54+
git config --replace-all sendemail.validateWorktree "$worktree"
55+
else
56+
worktree=$(git config --get sendemail.validateWorktree)
57+
fi || {
58+
echo "sendemail-validate: error: failed to prepare worktree" >&2
59+
exit 1
60+
}
61+
62+
unset GIT_DIR GIT_WORK_TREE
63+
cd "$worktree" &&
64+
65+
if grep -q "^diff --git " "$1"
66+
then
67+
validate_patch "$1"
68+
else
69+
validate_cover_letter "$1"
70+
fi &&
71+
72+
if test "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL"
73+
then
74+
git config --unset-all sendemail.validateWorktree &&
75+
trap 'git worktree remove -ff "$worktree"' EXIT &&
76+
validate_series
77+
fi

0 commit comments

Comments
 (0)