send-email: expose header information to git-send-email's sendemail-validate hook
To allow further flexibility in the Git hook, the SMTP header information of the email which git-send-email intends to send, is now passed as the 2nd argument to the sendemail-validate hook. As an example, this can be useful for acting upon keywords in the subject or specific email addresses. Cc: Luben Tuikov <luben.tuikov@amd.com> Cc: Junio C Hamano <gitster@pobox.com> Cc: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Acked-by: Luben Tuikov <luben.tuikov@amd.com> Signed-off-by: Michael Strawbridge <michael.strawbridge@amd.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Michael Strawbridge committed
Apr 19, 2023 at 16:27 UTC
a8022c5f7b678189135b6caa3fadb3d8ec0c0d48
3 files changed
+77
-25
Documentation/githooks.txt
+23
-4
@@ -595,10 +595,29 @@ processed by rebase.
595
sendemail-validate
596
~~~~~~~~~~~~~~~~~~
597
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 <from@example.com>
612
+ To: to@example.com
613
+ Cc: cc@example.com,
614
+ A <author@example.com>,
615
+ One <one@example.com>,
616
+ two@example.com
617
+ Subject: PATCH-STRING
618
+
619
+Exiting with a non-zero status causes `git send-email` to abort
620
+before sending any e-mails.
621
622
fsmonitor-watchman
623
~~~~~~~~~~~~~~~~~~
git-send-email.perl
+29
-19
@@ -792,16 +792,31 @@ if (@rev_list_opts) {
792
@rev_list_opts);
793
}
794
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;
808
809
if ($validate) {
810
foreach my $f (@files) {
811
unless (-p $f) {
812
+ pre_process_file($f, 1);
813
validate_patch($f, $target_xfer_encoding);
814
}
815
}
816
}
817
818
+@files = handle_backup_files(@files);
819
+
820
if (@files) {
821
unless ($quiet) {
822
print $_,"\n" for (@files);
@@ -1050,18 +1065,6 @@ if (!$force) {
1065
}
1066
}
1067
1053
-if (defined $sender) {
1054
- $sender =~ s/^\s+|\s+$//g;
1055
- ($sender) = expand_aliases($sender);
1056
-} else {
1057
- $sender = $repoauthor->() || $repocommitter->() || '';
1058
-}
1059
-
1060
-# $sender could be an already sanitized address
1061
-# (e.g. sendemail.from could be manually sanitized by user).
1062
-# But it's a no-op to run sanitize_address on an already sanitized address.
1063
-$sender = sanitize_address($sender);
1064
-
1068
my $to_whom = __("To whom should the emails be sent (if anyone)?");
1069
my $prompting = 0;
1070
if (!@initial_to && !defined $to_cmd) {
@@ -1221,10 +1224,6 @@ sub make_message_id {
1224
#print "new message id = $message_id\n"; # Was useful for debugging
1225
}
1226
1224
-
1225
-
1226
-$time = time - scalar $#files;
1227
-
1227
sub unquote_rfc2047 {
1228
local ($_) = @_;
1229
my $charset;
@@ -2108,10 +2107,21 @@ sub validate_patch {
2107
chdir($repo->wc_path() or $repo->repo_path())
2108
or die("chdir: $!");
2109
local $ENV{"GIT_DIR"} = $repo->repo_path();
2110
+
2111
+ my ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header) = gen_header();
2112
+
2113
+ require File::Temp;
2114
+ my ($header_filehandle, $header_filename) = File::Temp::tempfile(
2115
+ TEMPLATE => ".gitsendemail.header.XXXXXX",
2116
+ DIR => $repo->repo_path(),
2117
+ UNLINK => 1,
2118
+ );
2119
+ print $header_filehandle $header;
2120
+
2121
my @cmd = ("git", "hook", "run", "--ignore-missing",
2122
$hook_name, "--");
2113
- my @cmd_msg = (@cmd, "<patch>");
2114
- my @cmd_run = (@cmd, $target);
2123
+ my @cmd_msg = (@cmd, "<patch>", "<header>");
2124
+ my @cmd_run = (@cmd, $target, $header_filename);
2125
$hook_error = system_or_msg(\@cmd_run, undef, "@cmd_msg");
2126
chdir($cwd_save) or die("chdir: $!");
2127
}
t/t9001-send-email.sh
+25
-2
@@ -540,7 +540,7 @@ test_expect_success $PREREQ "--validate respects relative core.hooksPath path" '
540
test_path_is_file my-hooks.ran &&
541
cat >expect <<-EOF &&
542
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
544
warning: no patches were sent
545
EOF
546
test_cmp expect actual
@@ -559,12 +559,35 @@ test_expect_success $PREREQ "--validate respects absolute core.hooksPath path" '
559
test_path_is_file my-hooks.ran &&
560
cat >expect <<-EOF &&
561
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
563
warning: no patches were sent
564
EOF
565
test_cmp expect actual
566
'
567
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
+ --to=nobody@example.com \
586
+ --smtp-server="$(pwd)/fake.sendmail" \
587
+ --validate \
588
+ outdir/000?-*.patch
589
+'
590
+
591
for enc in 7bit 8bit quoted-printable base64
592
do
593
test_expect_success $PREREQ "--transfer-encoding=$enc produces correct header" '