1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-05-07 05:46:08 +02:00

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
This commit is contained in:
Junio C Hamano 2023-05-10 10:23:28 -07:00
commit b6e9521956
3 changed files with 108 additions and 43 deletions

View File

@ -595,10 +595,29 @@ processed by rebase.
sendemail-validate
~~~~~~~~~~~~~~~~~~
This hook is invoked by linkgit:git-send-email[1]. It takes a single parameter,
the name of the file that holds the e-mail to be sent. Exiting with a
non-zero status causes `git send-email` to abort before sending any
e-mails.
This hook is invoked by linkgit:git-send-email[1].
It takes these command line arguments. They are,
1. the name of the file which holds the contents of the email to be sent.
2. The name of the file which holds the SMTP headers of the email.
The SMTP headers are passed in the exact same way as they are passed to the
user's Mail Transport Agent (MTA). In effect, the email given to the user's
MTA, is the contents of $2 followed by the contents of $1.
An example of a few common headers is shown below. Take notice of the
capitalization and multi-line tab structure.
From: Example <from@example.com>
To: to@example.com
Cc: cc@example.com,
A <author@example.com>,
One <one@example.com>,
two@example.com
Subject: PATCH-STRING
Exiting with a non-zero status causes `git send-email` to abort
before sending any e-mails.
The following environment variables are set when executing the hook.

View File

@ -792,7 +792,19 @@ sub is_format_patch_arg {
@rev_list_opts);
}
@files = handle_backup_files(@files);
if (defined $sender) {
$sender =~ s/^\s+|\s+$//g;
($sender) = expand_aliases($sender);
} else {
$sender = $repoauthor->() || $repocommitter->() || '';
}
# $sender could be an already sanitized address
# (e.g. sendemail.from could be manually sanitized by user).
# But it's a no-op to run sanitize_address on an already sanitized address.
$sender = sanitize_address($sender);
$time = time - scalar $#files;
if ($validate) {
# FIFOs can only be read once, exclude them from validation.
@ -810,6 +822,7 @@ sub is_format_patch_arg {
$ENV{GIT_SENDEMAIL_FILE_TOTAL} = "$num_files";
foreach my $r (@real_files) {
$ENV{GIT_SENDEMAIL_FILE_COUNTER} = "$num";
pre_process_file($r, 1);
validate_patch($r, $target_xfer_encoding);
$num += 1;
}
@ -817,6 +830,8 @@ sub is_format_patch_arg {
delete $ENV{GIT_SENDEMAIL_FILE_TOTAL};
}
@files = handle_backup_files(@files);
if (@files) {
unless ($quiet) {
print $_,"\n" for (@files);
@ -1065,18 +1080,6 @@ sub file_declares_8bit_cte {
}
}
if (defined $sender) {
$sender =~ s/^\s+|\s+$//g;
($sender) = expand_aliases($sender);
} else {
$sender = $repoauthor->() || $repocommitter->() || '';
}
# $sender could be an already sanitized address
# (e.g. sendemail.from could be manually sanitized by user).
# But it's a no-op to run sanitize_address on an already sanitized address.
$sender = sanitize_address($sender);
my $to_whom = __("To whom should the emails be sent (if anyone)?");
my $prompting = 0;
if (!@initial_to && !defined $to_cmd) {
@ -1236,10 +1239,6 @@ sub make_message_id {
#print "new message id = $message_id\n"; # Was useful for debugging
}
$time = time - scalar $#files;
sub unquote_rfc2047 {
local ($_) = @_;
my $charset;
@ -1517,16 +1516,7 @@ sub file_name_is_absolute {
return File::Spec::Functions::file_name_is_absolute($path);
}
# Prepares the email, then asks the user what to do.
#
# If the user chooses to send the email, it's sent and 1 is returned.
# If the user chooses not to send the email, 0 is returned.
# If the user decides they want to make further edits, -1 is returned and the
# caller is expected to call send_message again after the edits are performed.
#
# If an error occurs sending the email, this just dies.
sub send_message {
sub gen_header {
my @recipients = unique_email_list(@to);
@cc = (grep { my $cc = extract_valid_address_or_die($_);
not grep { $cc eq $_ || $_ =~ /<\Q${cc}\E>$/ } @recipients
@ -1568,6 +1558,22 @@ sub send_message {
if (@xh) {
$header .= join("\n", @xh) . "\n";
}
my $recipients_ref = \@recipients;
return ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header);
}
# Prepares the email, then asks the user what to do.
#
# If the user chooses to send the email, it's sent and 1 is returned.
# If the user chooses not to send the email, 0 is returned.
# If the user decides they want to make further edits, -1 is returned and the
# caller is expected to call send_message again after the edits are performed.
#
# If an error occurs sending the email, this just dies.
sub send_message {
my ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header) = gen_header();
my @recipients = @$recipients_ref;
my @sendmail_parameters = ('-i', @recipients);
my $raw_from = $sender;
@ -1757,11 +1763,8 @@ sub send_message {
$references = $initial_in_reply_to || '';
$message_num = 0;
# Prepares the email, prompts the user, sends it out
# Returns 0 if an edit was done and the function should be called again, or 1
# otherwise.
sub process_file {
my ($t) = @_;
sub pre_process_file {
my ($t, $quiet) = @_;
open my $fh, "<", $t or die sprintf(__("can't open file %s"), $t);
@ -1915,9 +1918,9 @@ sub process_file {
}
close $fh;
push @to, recipients_cmd("to-cmd", "to", $to_cmd, $t)
push @to, recipients_cmd("to-cmd", "to", $to_cmd, $t, $quiet)
if defined $to_cmd;
push @cc, recipients_cmd("cc-cmd", "cc", $cc_cmd, $t)
push @cc, recipients_cmd("cc-cmd", "cc", $cc_cmd, $t, $quiet)
if defined $cc_cmd && !$suppress_cc{'cccmd'};
if ($broken_encoding{$t} && !$has_content_type) {
@ -1976,6 +1979,15 @@ sub process_file {
@initial_to = @to;
}
}
}
# Prepares the email, prompts the user, and sends it out
# Returns 0 if an edit was done and the function should be called again, or 1
# on the email being successfully sent out.
sub process_file {
my ($t) = @_;
pre_process_file($t, $quiet);
my $message_was_sent = send_message();
if ($message_was_sent == -1) {
@ -2024,7 +2036,7 @@ sub process_file {
# Execute a command (e.g. $to_cmd) to get a list of email addresses
# and return a results array
sub recipients_cmd {
my ($prefix, $what, $cmd, $file) = @_;
my ($prefix, $what, $cmd, $file, $quiet) = @_;
my @addresses = ();
open my $fh, "-|", "$cmd \Q$file\E"
@ -2110,10 +2122,21 @@ sub validate_patch {
chdir($repo->wc_path() or $repo->repo_path())
or die("chdir: $!");
local $ENV{"GIT_DIR"} = $repo->repo_path();
my ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header) = gen_header();
require File::Temp;
my ($header_filehandle, $header_filename) = File::Temp::tempfile(
TEMPLATE => ".gitsendemail.header.XXXXXX",
DIR => $repo->repo_path(),
UNLINK => 1,
);
print $header_filehandle $header;
my @cmd = ("git", "hook", "run", "--ignore-missing",
$hook_name, "--");
my @cmd_msg = (@cmd, "<patch>");
my @cmd_run = (@cmd, $target);
my @cmd_msg = (@cmd, "<patch>", "<header>");
my @cmd_run = (@cmd, $target, $header_filename);
$hook_error = system_or_msg(\@cmd_run, undef, "@cmd_msg");
chdir($cwd_save) or die("chdir: $!");
}

View File

@ -540,7 +540,7 @@ test_expect_success $PREREQ "--validate respects relative core.hooksPath path" '
test_path_is_file my-hooks.ran &&
cat >expect <<-EOF &&
fatal: longline.patch: rejected by sendemail-validate hook
fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1
fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch> <header>'"'"' died with exit code 1
warning: no patches were sent
EOF
test_cmp expect actual
@ -559,12 +559,35 @@ test_expect_success $PREREQ "--validate respects absolute core.hooksPath path" '
test_path_is_file my-hooks.ran &&
cat >expect <<-EOF &&
fatal: longline.patch: rejected by sendemail-validate hook
fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch>'"'"' died with exit code 1
fatal: command '"'"'git hook run --ignore-missing sendemail-validate -- <patch> <header>'"'"' died with exit code 1
warning: no patches were sent
EOF
test_cmp expect actual
'
test_expect_success $PREREQ "--validate hook supports header argument" '
write_script my-hooks/sendemail-validate <<-\EOF &&
if test "$#" -ge 2
then
grep "X-test-header: v1.0" "$2"
else
echo "No header arg passed"
exit 1
fi
EOF
test_config core.hooksPath "my-hooks" &&
rm -fr outdir &&
git format-patch \
--add-header="X-test-header: v1.0" \
-n HEAD^1 -o outdir &&
git send-email \
--dry-run \
--to=nobody@example.com \
--smtp-server="$(pwd)/fake.sendmail" \
--validate \
outdir/000?-*.patch
'
for enc in 7bit 8bit quoted-printable base64
do
test_expect_success $PREREQ "--transfer-encoding=$enc produces correct header" '