Skip to content

Commit b6e9521

Browse files
committed
Merge branch 'ms/send-email-feed-header-to-validate-hook'
"git send-email" learned to give the e-mail headers to the validate hook by passing an extra argument from the command line. * ms/send-email-feed-header-to-validate-hook: send-email: expose header information to git-send-email's sendemail-validate hook send-email: refactor header generation functions
2 parents e2abfa7 + a8022c5 commit b6e9521

File tree

3 files changed

+108
-43
lines changed

3 files changed

+108
-43
lines changed

Documentation/githooks.txt

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -595,10 +595,29 @@ processed by rebase.
595595
sendemail-validate
596596
~~~~~~~~~~~~~~~~~~
597597

598-
This hook is invoked by linkgit:git-send-email[1]. It takes a single parameter,
599-
the name of the file that holds the e-mail to be sent. Exiting with a
600-
non-zero status causes `git send-email` to abort before sending any
601-
e-mails.
598+
This hook is invoked by linkgit:git-send-email[1].
599+
600+
It takes these command line arguments. They are,
601+
1. the name of the file which holds the contents of the email to be sent.
602+
2. The name of the file which holds the SMTP headers of the email.
603+
604+
The SMTP headers are passed in the exact same way as they are passed to the
605+
user's Mail Transport Agent (MTA). In effect, the email given to the user's
606+
MTA, is the contents of $2 followed by the contents of $1.
607+
608+
An example of a few common headers is shown below. Take notice of the
609+
capitalization and multi-line tab structure.
610+
611+
From: Example <[email protected]>
612+
613+
614+
615+
616+
617+
Subject: PATCH-STRING
618+
619+
Exiting with a non-zero status causes `git send-email` to abort
620+
before sending any e-mails.
602621

603622
The following environment variables are set when executing the hook.
604623

git-send-email.perl

Lines changed: 60 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,19 @@ sub is_format_patch_arg {
792792
@rev_list_opts);
793793
}
794794

795-
@files = handle_backup_files(@files);
795+
if (defined $sender) {
796+
$sender =~ s/^\s+|\s+$//g;
797+
($sender) = expand_aliases($sender);
798+
} else {
799+
$sender = $repoauthor->() || $repocommitter->() || '';
800+
}
801+
802+
# $sender could be an already sanitized address
803+
# (e.g. sendemail.from could be manually sanitized by user).
804+
# But it's a no-op to run sanitize_address on an already sanitized address.
805+
$sender = sanitize_address($sender);
806+
807+
$time = time - scalar $#files;
796808

797809
if ($validate) {
798810
# FIFOs can only be read once, exclude them from validation.
@@ -810,13 +822,16 @@ sub is_format_patch_arg {
810822
$ENV{GIT_SENDEMAIL_FILE_TOTAL} = "$num_files";
811823
foreach my $r (@real_files) {
812824
$ENV{GIT_SENDEMAIL_FILE_COUNTER} = "$num";
825+
pre_process_file($r, 1);
813826
validate_patch($r, $target_xfer_encoding);
814827
$num += 1;
815828
}
816829
delete $ENV{GIT_SENDEMAIL_FILE_COUNTER};
817830
delete $ENV{GIT_SENDEMAIL_FILE_TOTAL};
818831
}
819832

833+
@files = handle_backup_files(@files);
834+
820835
if (@files) {
821836
unless ($quiet) {
822837
print $_,"\n" for (@files);
@@ -1065,18 +1080,6 @@ sub file_declares_8bit_cte {
10651080
}
10661081
}
10671082
1068-
if (defined $sender) {
1069-
$sender =~ s/^\s+|\s+$//g;
1070-
($sender) = expand_aliases($sender);
1071-
} else {
1072-
$sender = $repoauthor->() || $repocommitter->() || '';
1073-
}
1074-
1075-
# $sender could be an already sanitized address
1076-
# (e.g. sendemail.from could be manually sanitized by user).
1077-
# But it's a no-op to run sanitize_address on an already sanitized address.
1078-
$sender = sanitize_address($sender);
1079-
10801083
my $to_whom = __("To whom should the emails be sent (if anyone)?");
10811084
my $prompting = 0;
10821085
if (!@initial_to && !defined $to_cmd) {
@@ -1236,10 +1239,6 @@ sub make_message_id {
12361239
#print "new message id = $message_id\n"; # Was useful for debugging
12371240
}
12381241

1239-
1240-
1241-
$time = time - scalar $#files;
1242-
12431242
sub unquote_rfc2047 {
12441243
local ($_) = @_;
12451244
my $charset;
@@ -1517,16 +1516,7 @@ sub file_name_is_absolute {
15171516
return File::Spec::Functions::file_name_is_absolute($path);
15181517
}
15191518

1520-
# Prepares the email, then asks the user what to do.
1521-
#
1522-
# If the user chooses to send the email, it's sent and 1 is returned.
1523-
# If the user chooses not to send the email, 0 is returned.
1524-
# If the user decides they want to make further edits, -1 is returned and the
1525-
# caller is expected to call send_message again after the edits are performed.
1526-
#
1527-
# If an error occurs sending the email, this just dies.
1528-
1529-
sub send_message {
1519+
sub gen_header {
15301520
my @recipients = unique_email_list(@to);
15311521
@cc = (grep { my $cc = extract_valid_address_or_die($_);
15321522
not grep { $cc eq $_ || $_ =~ /<\Q${cc}\E>$/ } @recipients
@@ -1568,6 +1558,22 @@ sub send_message {
15681558
if (@xh) {
15691559
$header .= join("\n", @xh) . "\n";
15701560
}
1561+
my $recipients_ref = \@recipients;
1562+
return ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header);
1563+
}
1564+
1565+
# Prepares the email, then asks the user what to do.
1566+
#
1567+
# If the user chooses to send the email, it's sent and 1 is returned.
1568+
# If the user chooses not to send the email, 0 is returned.
1569+
# If the user decides they want to make further edits, -1 is returned and the
1570+
# caller is expected to call send_message again after the edits are performed.
1571+
#
1572+
# If an error occurs sending the email, this just dies.
1573+
1574+
sub send_message {
1575+
my ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header) = gen_header();
1576+
my @recipients = @$recipients_ref;
15711577

15721578
my @sendmail_parameters = ('-i', @recipients);
15731579
my $raw_from = $sender;
@@ -1757,11 +1763,8 @@ sub send_message {
17571763
$references = $initial_in_reply_to || '';
17581764
$message_num = 0;
17591765

1760-
# Prepares the email, prompts the user, sends it out
1761-
# Returns 0 if an edit was done and the function should be called again, or 1
1762-
# otherwise.
1763-
sub process_file {
1764-
my ($t) = @_;
1766+
sub pre_process_file {
1767+
my ($t, $quiet) = @_;
17651768

17661769
open my $fh, "<", $t or die sprintf(__("can't open file %s"), $t);
17671770

@@ -1915,9 +1918,9 @@ sub process_file {
19151918
}
19161919
close $fh;
19171920

1918-
push @to, recipients_cmd("to-cmd", "to", $to_cmd, $t)
1921+
push @to, recipients_cmd("to-cmd", "to", $to_cmd, $t, $quiet)
19191922
if defined $to_cmd;
1920-
push @cc, recipients_cmd("cc-cmd", "cc", $cc_cmd, $t)
1923+
push @cc, recipients_cmd("cc-cmd", "cc", $cc_cmd, $t, $quiet)
19211924
if defined $cc_cmd && !$suppress_cc{'cccmd'};
19221925

19231926
if ($broken_encoding{$t} && !$has_content_type) {
@@ -1976,6 +1979,15 @@ sub process_file {
19761979
@initial_to = @to;
19771980
}
19781981
}
1982+
}
1983+
1984+
# Prepares the email, prompts the user, and sends it out
1985+
# Returns 0 if an edit was done and the function should be called again, or 1
1986+
# on the email being successfully sent out.
1987+
sub process_file {
1988+
my ($t) = @_;
1989+
1990+
pre_process_file($t, $quiet);
19791991

19801992
my $message_was_sent = send_message();
19811993
if ($message_was_sent == -1) {
@@ -2024,7 +2036,7 @@ sub process_file {
20242036
# Execute a command (e.g. $to_cmd) to get a list of email addresses
20252037
# and return a results array
20262038
sub recipients_cmd {
2027-
my ($prefix, $what, $cmd, $file) = @_;
2039+
my ($prefix, $what, $cmd, $file, $quiet) = @_;
20282040

20292041
my @addresses = ();
20302042
open my $fh, "-|", "$cmd \Q$file\E"
@@ -2110,10 +2122,21 @@ sub validate_patch {
21102122
chdir($repo->wc_path() or $repo->repo_path())
21112123
or die("chdir: $!");
21122124
local $ENV{"GIT_DIR"} = $repo->repo_path();
2125+
2126+
my ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header) = gen_header();
2127+
2128+
require File::Temp;
2129+
my ($header_filehandle, $header_filename) = File::Temp::tempfile(
2130+
TEMPLATE => ".gitsendemail.header.XXXXXX",
2131+
DIR => $repo->repo_path(),
2132+
UNLINK => 1,
2133+
);
2134+
print $header_filehandle $header;
2135+
21132136
my @cmd = ("git", "hook", "run", "--ignore-missing",
21142137
$hook_name, "--");
2115-
my @cmd_msg = (@cmd, "<patch>");
2116-
my @cmd_run = (@cmd, $target);
2138+
my @cmd_msg = (@cmd, "<patch>", "<header>");
2139+
my @cmd_run = (@cmd, $target, $header_filename);
21172140
$hook_error = system_or_msg(\@cmd_run, undef, "@cmd_msg");
21182141
chdir($cwd_save) or die("chdir: $!");
21192142
}

t/t9001-send-email.sh

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ test_expect_success $PREREQ "--validate respects relative core.hooksPath path" '
540540
test_path_is_file my-hooks.ran &&
541541
cat >expect <<-EOF &&
542542
fatal: longline.patch: rejected by sendemail-validate hook
543-
fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1
543+
fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch> <header>'"'"' died with exit code 1
544544
warning: no patches were sent
545545
EOF
546546
test_cmp expect actual
@@ -559,12 +559,35 @@ test_expect_success $PREREQ "--validate respects absolute core.hooksPath path" '
559559
test_path_is_file my-hooks.ran &&
560560
cat >expect <<-EOF &&
561561
fatal: longline.patch: rejected by sendemail-validate hook
562-
fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1
562+
fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch> <header>'"'"' died with exit code 1
563563
warning: no patches were sent
564564
EOF
565565
test_cmp expect actual
566566
'
567567

568+
test_expect_success $PREREQ "--validate hook supports header argument" '
569+
write_script my-hooks/sendemail-validate <<-\EOF &&
570+
if test "$#" -ge 2
571+
then
572+
grep "X-test-header: v1.0" "$2"
573+
else
574+
echo "No header arg passed"
575+
exit 1
576+
fi
577+
EOF
578+
test_config core.hooksPath "my-hooks" &&
579+
rm -fr outdir &&
580+
git format-patch \
581+
--add-header="X-test-header: v1.0" \
582+
-n HEAD^1 -o outdir &&
583+
git send-email \
584+
--dry-run \
585+
586+
--smtp-server="$(pwd)/fake.sendmail" \
587+
--validate \
588+
outdir/000?-*.patch
589+
'
590+
568591
for enc in 7bit 8bit quoted-printable base64
569592
do
570593
test_expect_success $PREREQ "--transfer-encoding=$enc produces correct header" '

0 commit comments

Comments
 (0)