diff --git a/Documentation/git-check-mailmap.txt b/Documentation/git-check-mailmap.txt index 02f4418323..966c91c46a 100644 --- a/Documentation/git-check-mailmap.txt +++ b/Documentation/git-check-mailmap.txt @@ -15,10 +15,10 @@ SYNOPSIS DESCRIPTION ----------- -For each ``Name $$$$'' or ``$$$$'' from the command-line -or standard input (when using `--stdin`), look up the person's canonical name -and email address (see "Mapping Authors" below). If found, print them; -otherwise print the input as-is. +For each ``Name $$$$'', ``$$$$'', or ``$$user@host$$'' +from the command-line or standard input (when using `--stdin`), look up the +person's canonical name and email address (see "Mapping Authors" below). If +found, print them; otherwise print the input as-is. OPTIONS @@ -27,6 +27,16 @@ OPTIONS Read contacts, one per line, from the standard input after exhausting contacts provided on the command-line. +--mailmap-file=:: + In addition to any configured mailmap files, read the specified + mailmap file. Entries in this file take precedence over entries in + either the default mailmap file or any configured mailmap file. + +--mailmap-blob=:: + Like `--mailmap-file`, but consider the value as a reference to a + blob in the repository. If both `--mailmap-file` and + `--mailmap-blob` are specified, entries in `--mailmap-file` will + take precedence. OUTPUT ------ diff --git a/builtin/check-mailmap.c b/builtin/check-mailmap.c index b8a05b8e07..2334b57222 100644 --- a/builtin/check-mailmap.c +++ b/builtin/check-mailmap.c @@ -9,6 +9,7 @@ #include "write-or-die.h" static int use_stdin; +static const char *mailmap_file, *mailmap_blob; static const char * const check_mailmap_usage[] = { N_("git check-mailmap [] ..."), NULL @@ -16,6 +17,8 @@ NULL static const struct option check_mailmap_options[] = { OPT_BOOL(0, "stdin", &use_stdin, N_("also read contacts from stdin")), + OPT_FILENAME(0, "mailmap-file", &mailmap_file, N_("read additional mailmap entries from file")), + OPT_STRING(0, "mailmap-blob", &mailmap_blob, N_("blob"), N_("read additional mailmap entries from blob")), OPT_END() }; @@ -25,13 +28,17 @@ static void check_mailmap(struct string_list *mailmap, const char *contact) size_t namelen, maillen; struct ident_split ident; - if (split_ident_line(&ident, contact, strlen(contact))) - die(_("unable to parse contact: %s"), contact); - - name = ident.name_begin; - namelen = ident.name_end - ident.name_begin; - mail = ident.mail_begin; - maillen = ident.mail_end - ident.mail_begin; + if (!split_ident_line(&ident, contact, strlen(contact))) { + name = ident.name_begin; + namelen = ident.name_end - ident.name_begin; + mail = ident.mail_begin; + maillen = ident.mail_end - ident.mail_begin; + } else { + name = NULL; + namelen = 0; + mail = contact; + maillen = strlen(contact); + } map_user(mailmap, &mail, &maillen, &name, &namelen); @@ -52,6 +59,10 @@ int cmd_check_mailmap(int argc, const char **argv, const char *prefix) die(_("no contacts specified")); read_mailmap(&mailmap); + if (mailmap_blob) + read_mailmap_blob(&mailmap, mailmap_blob); + if (mailmap_file) + read_mailmap_file(&mailmap, mailmap_file, 0); for (i = 0; i < argc; ++i) check_mailmap(&mailmap, argv[i]); diff --git a/git-send-email.perl b/git-send-email.perl index cdcee1d0cf..c835d4c11a 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -47,6 +47,8 @@ git send-email --translate-aliases --compose-encoding * Encoding to assume for introduction. --8bit-encoding * Encoding to assume 8bit mails if undeclared --transfer-encoding * Transfer encoding to use (quoted-printable, 8bit, base64) + --[no-]mailmap * Use mailmap file to map all email addresses to canonical + real names and email addresses. Sending: --envelope-sender * Email envelope sender. @@ -278,12 +280,14 @@ my (@suppress_cc); my ($auto_8bit_encoding); my ($compose_encoding); my ($sendmail_cmd); +my ($mailmap_file, $mailmap_blob); # Variables with corresponding config settings & hardcoded defaults my ($debug_net_smtp) = 0; # Net::SMTP, see send_message() my $thread = 1; my $chain_reply_to = 0; my $use_xmailer = 1; my $validate = 1; +my $mailmap = 0; my $target_xfer_encoding = 'auto'; my $forbid_sendmail_variables = 1; @@ -300,6 +304,7 @@ my %config_bool_settings = ( "annotate" => \$annotate, "xmailer" => \$use_xmailer, "forbidsendmailvariables" => \$forbid_sendmail_variables, + "mailmap" => \$mailmap, ); my %config_settings = ( @@ -333,6 +338,8 @@ my %config_settings = ( my %config_path_settings = ( "aliasesfile" => \@alias_files, "smtpsslcertpath" => \$smtp_ssl_cert_path, + "mailmap.file" => \$mailmap_file, + "mailmap.blob" => \$mailmap_blob, ); # Handle Uncouth Termination @@ -533,6 +540,8 @@ my %options = ( "thread!" => \$thread, "validate!" => \$validate, "transfer-encoding=s" => \$target_xfer_encoding, + "mailmap!" => \$mailmap, + "use-mailmap!" => \$mailmap, "format-patch!" => \$format_patch, "8bit-encoding=s" => \$auto_8bit_encoding, "compose-encoding=s" => \$compose_encoding, @@ -1104,6 +1113,16 @@ if ($compose && $compose > 0) { our ($message_id, %mail, $subject, $in_reply_to, $references, $message, $needs_confirm, $message_num, $ask_default); +sub mailmap_address_list { + return @_ unless @_ and $mailmap; + my @options = (); + push(@options, "--mailmap-file=$mailmap_file") if $mailmap_file; + push(@options, "--mailmap-blob=$mailmap_blob") if $mailmap_blob; + my @addr_list = Git::command('check-mailmap', @options, @_); + s/^<(.*)>$/$1/ for @addr_list; + return @addr_list; +} + sub extract_valid_address { my $address = shift; my $local_part_regexp = qr/[^<>"\s@]+/; @@ -1313,6 +1332,7 @@ sub process_address_list { @addr_list = expand_aliases(@addr_list); @addr_list = sanitize_address_list(@addr_list); @addr_list = validate_address_list(@addr_list); + @addr_list = mailmap_address_list(@addr_list); return @addr_list; } diff --git a/mailmap.c b/mailmap.c index 2acf97f307..9f9fa3199a 100644 --- a/mailmap.c +++ b/mailmap.c @@ -142,11 +142,8 @@ static void read_mailmap_line(struct string_list *map, char *buffer) add_mapping(map, name1, email1, name2, email2); } -/* Flags for read_mailmap_file() */ -#define MAILMAP_NOFOLLOW (1<<0) - -static int read_mailmap_file(struct string_list *map, const char *filename, - unsigned flags) +int read_mailmap_file(struct string_list *map, const char *filename, + unsigned flags) { char buffer[1024]; FILE *f; @@ -186,7 +183,7 @@ static void read_mailmap_string(struct string_list *map, char *buf) } } -static int read_mailmap_blob(struct string_list *map, const char *name) +int read_mailmap_blob(struct string_list *map, const char *name) { struct object_id oid; char *buf; diff --git a/mailmap.h b/mailmap.h index cbda9bc5e0..908365e1bf 100644 --- a/mailmap.h +++ b/mailmap.h @@ -6,6 +6,13 @@ struct string_list; extern char *git_mailmap_file; extern char *git_mailmap_blob; +/* Flags for read_mailmap_file() */ +#define MAILMAP_NOFOLLOW (1<<0) + +int read_mailmap_file(struct string_list *map, const char *filename, + unsigned flags); +int read_mailmap_blob(struct string_list *map, const char *name); + int read_mailmap(struct string_list *map); void clear_mailmap(struct string_list *map); diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh index 79e5f42760..2265ff8872 100755 --- a/t/t4203-mailmap.sh +++ b/t/t4203-mailmap.sh @@ -72,12 +72,46 @@ test_expect_success 'check-mailmap --stdin arguments: mapping' ' test_cmp expect actual ' -test_expect_success 'check-mailmap bogus contact' ' - test_must_fail git check-mailmap bogus +test_expect_success 'check-mailmap simple address: mapping' ' + test_when_finished "rm .mailmap" && + cat >.mailmap <<-EOF && + New Name <$GIT_AUTHOR_EMAIL> + EOF + cat .mailmap >expect && + git check-mailmap "$GIT_AUTHOR_EMAIL" >actual && + test_cmp expect actual ' -test_expect_success 'check-mailmap bogus contact --stdin' ' - test_must_fail git check-mailmap --stdin bogus .mailmap <<-EOF && + New Name <$GIT_AUTHOR_EMAIL> + EOF + cat >stdin <<-EOF && + $GIT_AUTHOR_EMAIL + EOF + cat .mailmap >expect && + git check-mailmap --stdin actual && + test_cmp expect actual +' + +test_expect_success 'check-mailmap simple address: no mapping' ' + cat >expect <<-EOF && + + EOF + git check-mailmap "bugs@company.xx" >actual && + test_cmp expect actual +' + +test_expect_success 'check-mailmap --stdin simple address: no mapping' ' + cat >expect <<-EOF && + + EOF + cat >stdin <<-EOF && + bugs@company.xx + EOF + git check-mailmap --stdin actual && + test_cmp expect actual ' test_expect_success 'No mailmap' ' diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index c5e862694e..df5336bb7e 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -2485,6 +2485,128 @@ test_expect_success $PREREQ 'leading and trailing whitespaces are removed' ' test_cmp expected-list actual-list ' +test_expect_success $PREREQ 'mailmap support with --to' ' + clean_fake_sendmail && + test_config mailmap.file "mailmap.test" && + cat >mailmap.test <<-EOF && + Some Body + EOF + git format-patch --stdout -1 >a.patch && + git send-email \ + --from="Example " \ + --smtp-server="$(pwd)/fake.sendmail" \ + --to=someone@example.org \ + --mailmap \ + a.patch \ + 2>errors >out && + grep "^!someone@example\.com!$" commandline1 +' + +test_expect_success $PREREQ 'sendemail.mailmap configuration' ' + clean_fake_sendmail && + test_config mailmap.file "mailmap.test" && + test_config sendemail.mailmap "true" && + cat >mailmap.test <<-EOF && + Some Body + EOF + git format-patch --stdout -1 >a.patch && + git send-email \ + --from="Example " \ + --smtp-server="$(pwd)/fake.sendmail" \ + --to=someone@example.org \ + a.patch \ + 2>errors >out && + grep "^!someone@example\.com!$" commandline1 +' + +test_expect_success $PREREQ 'sendemail.mailmap.file configuration' ' + clean_fake_sendmail && + test_config sendemail.mailmap.file "mailmap.test" && + test_config sendemail.mailmap "true" && + cat >mailmap.test <<-EOF && + Some Body + EOF + git format-patch --stdout -1 >a.patch && + git send-email \ + --from="Example " \ + --smtp-server="$(pwd)/fake.sendmail" \ + --to=someone@example.org \ + a.patch \ + 2>errors >out && + grep "^!someone@example\.com!$" commandline1 +' + +test_expect_success $PREREQ 'sendemail.mailmap identity overrides configuration' ' + clean_fake_sendmail && + test_config sendemail.cloud.mailmap.file "mailmap.test" && + test_config sendemail.mailmap "false" && + test_config sendemail.cloud.mailmap "true" && + cat >mailmap.test <<-EOF && + Some Body + EOF + git format-patch --stdout -1 >a.patch && + git send-email \ + --from="Example " \ + --smtp-server="$(pwd)/fake.sendmail" \ + --identity=cloud \ + --to=someone@example.org \ + a.patch \ + 2>errors >out && + grep "^!someone@example\.com!$" commandline1 +' + +test_expect_success $PREREQ '--no-mailmap overrides configuration' ' + clean_fake_sendmail && + test_config sendemail.cloud.mailmap.file "mailmap.test" && + test_config sendemail.mailmap "false" && + test_config sendemail.cloud.mailmap "true" && + cat >mailmap.test <<-EOF && + Some Body + EOF + git format-patch --stdout -1 >a.patch && + git send-email \ + --from="Example " \ + --smtp-server="$(pwd)/fake.sendmail" \ + --identity=cloud \ + --to=someone@example.org \ + --no-mailmap \ + a.patch \ + 2>errors >out && + grep "^!someone@example\.org!$" commandline1 +' + +test_expect_success $PREREQ 'mailmap support in To header' ' + clean_fake_sendmail && + test_config mailmap.file "mailmap.test" && + cat >mailmap.test <<-EOF && + + EOF + git format-patch --stdout -1 --to=someone@example.org >a.patch && + git send-email \ + --from="Example " \ + --smtp-server="$(pwd)/fake.sendmail" \ + --mailmap \ + a.patch \ + 2>errors >out && + grep "^!someone@example\.com!$" commandline1 +' + +test_expect_success $PREREQ 'mailmap support in Cc header' ' + clean_fake_sendmail && + test_config mailmap.file "mailmap.test" && + cat >mailmap.test <<-EOF && + + EOF + git format-patch --stdout -1 --cc=someone@example.org >a.patch && + git send-email \ + --from="Example " \ + --smtp-server="$(pwd)/fake.sendmail" \ + --mailmap \ + a.patch \ + 2>errors >out && + grep "^!someone@example\.com!$" commandline1 +' + test_expect_success $PREREQ 'test using command name with --sendmail-cmd' ' clean_fake_sendmail && PATH="$PWD:$PATH" \