Skip to content

Commit 6dcb2db

Browse files
committed
Merge branch 'jk/send-email-mailmap'
"git send-email" learned "--mailmap" option to allow rewriting the recipient addresses. * jk/send-email-mailmap: send-email: add mailmap support via sendemail.mailmap and --mailmap check-mailmap: add options for additional mailmap sources check-mailmap: accept "user@host" contacts
2 parents 2e7b89e + 241499a commit 6dcb2db

File tree

7 files changed

+222
-21
lines changed

7 files changed

+222
-21
lines changed

Documentation/git-check-mailmap.txt

+14-4
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ SYNOPSIS
1515
DESCRIPTION
1616
-----------
1717

18-
For each ``Name $$<user@host>$$'' or ``$$<user@host>$$'' from the command-line
19-
or standard input (when using `--stdin`), look up the person's canonical name
20-
and email address (see "Mapping Authors" below). If found, print them;
21-
otherwise print the input as-is.
18+
For each ``Name $$<user@host>$$'', ``$$<user@host>$$'', or ``$$user@host$$''
19+
from the command-line or standard input (when using `--stdin`), look up the
20+
person's canonical name and email address (see "Mapping Authors" below). If
21+
found, print them; otherwise print the input as-is.
2222

2323

2424
OPTIONS
@@ -27,6 +27,16 @@ OPTIONS
2727
Read contacts, one per line, from the standard input after exhausting
2828
contacts provided on the command-line.
2929

30+
--mailmap-file=<file>::
31+
In addition to any configured mailmap files, read the specified
32+
mailmap file. Entries in this file take precedence over entries in
33+
either the default mailmap file or any configured mailmap file.
34+
35+
--mailmap-blob=<blob>::
36+
Like `--mailmap-file`, but consider the value as a reference to a
37+
blob in the repository. If both `--mailmap-file` and
38+
`--mailmap-blob` are specified, entries in `--mailmap-file` will
39+
take precedence.
3040

3141
OUTPUT
3242
------

builtin/check-mailmap.c

+18-7
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@
99
#include "write-or-die.h"
1010

1111
static int use_stdin;
12+
static const char *mailmap_file, *mailmap_blob;
1213
static const char * const check_mailmap_usage[] = {
1314
N_("git check-mailmap [<options>] <contact>..."),
1415
NULL
1516
};
1617

1718
static const struct option check_mailmap_options[] = {
1819
OPT_BOOL(0, "stdin", &use_stdin, N_("also read contacts from stdin")),
20+
OPT_FILENAME(0, "mailmap-file", &mailmap_file, N_("read additional mailmap entries from file")),
21+
OPT_STRING(0, "mailmap-blob", &mailmap_blob, N_("blob"), N_("read additional mailmap entries from blob")),
1922
OPT_END()
2023
};
2124

@@ -25,13 +28,17 @@ static void check_mailmap(struct string_list *mailmap, const char *contact)
2528
size_t namelen, maillen;
2629
struct ident_split ident;
2730

28-
if (split_ident_line(&ident, contact, strlen(contact)))
29-
die(_("unable to parse contact: %s"), contact);
30-
31-
name = ident.name_begin;
32-
namelen = ident.name_end - ident.name_begin;
33-
mail = ident.mail_begin;
34-
maillen = ident.mail_end - ident.mail_begin;
31+
if (!split_ident_line(&ident, contact, strlen(contact))) {
32+
name = ident.name_begin;
33+
namelen = ident.name_end - ident.name_begin;
34+
mail = ident.mail_begin;
35+
maillen = ident.mail_end - ident.mail_begin;
36+
} else {
37+
name = NULL;
38+
namelen = 0;
39+
mail = contact;
40+
maillen = strlen(contact);
41+
}
3542

3643
map_user(mailmap, &mail, &maillen, &name, &namelen);
3744

@@ -52,6 +59,10 @@ int cmd_check_mailmap(int argc, const char **argv, const char *prefix)
5259
die(_("no contacts specified"));
5360

5461
read_mailmap(&mailmap);
62+
if (mailmap_blob)
63+
read_mailmap_blob(&mailmap, mailmap_blob);
64+
if (mailmap_file)
65+
read_mailmap_file(&mailmap, mailmap_file, 0);
5566

5667
for (i = 0; i < argc; ++i)
5768
check_mailmap(&mailmap, argv[i]);

git-send-email.perl

+20
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ sub usage {
4747
--compose-encoding <str> * Encoding to assume for introduction.
4848
--8bit-encoding <str> * Encoding to assume 8bit mails if undeclared
4949
--transfer-encoding <str> * Transfer encoding to use (quoted-printable, 8bit, base64)
50+
--[no-]mailmap * Use mailmap file to map all email addresses to canonical
51+
real names and email addresses.
5052
5153
Sending:
5254
--envelope-sender <str> * Email envelope sender.
@@ -278,12 +280,14 @@ sub do_edit {
278280
my ($auto_8bit_encoding);
279281
my ($compose_encoding);
280282
my ($sendmail_cmd);
283+
my ($mailmap_file, $mailmap_blob);
281284
# Variables with corresponding config settings & hardcoded defaults
282285
my ($debug_net_smtp) = 0; # Net::SMTP, see send_message()
283286
my $thread = 1;
284287
my $chain_reply_to = 0;
285288
my $use_xmailer = 1;
286289
my $validate = 1;
290+
my $mailmap = 0;
287291
my $target_xfer_encoding = 'auto';
288292
my $forbid_sendmail_variables = 1;
289293

@@ -300,6 +304,7 @@ sub do_edit {
300304
"annotate" => \$annotate,
301305
"xmailer" => \$use_xmailer,
302306
"forbidsendmailvariables" => \$forbid_sendmail_variables,
307+
"mailmap" => \$mailmap,
303308
);
304309

305310
my %config_settings = (
@@ -333,6 +338,8 @@ sub do_edit {
333338
my %config_path_settings = (
334339
"aliasesfile" => \@alias_files,
335340
"smtpsslcertpath" => \$smtp_ssl_cert_path,
341+
"mailmap.file" => \$mailmap_file,
342+
"mailmap.blob" => \$mailmap_blob,
336343
);
337344

338345
# Handle Uncouth Termination
@@ -533,6 +540,8 @@ sub config_regexp {
533540
"thread!" => \$thread,
534541
"validate!" => \$validate,
535542
"transfer-encoding=s" => \$target_xfer_encoding,
543+
"mailmap!" => \$mailmap,
544+
"use-mailmap!" => \$mailmap,
536545
"format-patch!" => \$format_patch,
537546
"8bit-encoding=s" => \$auto_8bit_encoding,
538547
"compose-encoding=s" => \$compose_encoding,
@@ -1104,6 +1113,16 @@ sub expand_one_alias {
11041113
our ($message_id, %mail, $subject, $in_reply_to, $references, $message,
11051114
$needs_confirm, $message_num, $ask_default);
11061115
1116+
sub mailmap_address_list {
1117+
return @_ unless @_ and $mailmap;
1118+
my @options = ();
1119+
push(@options, "--mailmap-file=$mailmap_file") if $mailmap_file;
1120+
push(@options, "--mailmap-blob=$mailmap_blob") if $mailmap_blob;
1121+
my @addr_list = Git::command('check-mailmap', @options, @_);
1122+
s/^<(.*)>$/$1/ for @addr_list;
1123+
return @addr_list;
1124+
}
1125+
11071126
sub extract_valid_address {
11081127
my $address = shift;
11091128
my $local_part_regexp = qr/[^<>"\s@]+/;
@@ -1313,6 +1332,7 @@ sub process_address_list {
13131332
@addr_list = expand_aliases(@addr_list);
13141333
@addr_list = sanitize_address_list(@addr_list);
13151334
@addr_list = validate_address_list(@addr_list);
1335+
@addr_list = mailmap_address_list(@addr_list);
13161336
return @addr_list;
13171337
}
13181338

mailmap.c

+3-6
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,8 @@ static void read_mailmap_line(struct string_list *map, char *buffer)
142142
add_mapping(map, name1, email1, name2, email2);
143143
}
144144

145-
/* Flags for read_mailmap_file() */
146-
#define MAILMAP_NOFOLLOW (1<<0)
147-
148-
static int read_mailmap_file(struct string_list *map, const char *filename,
149-
unsigned flags)
145+
int read_mailmap_file(struct string_list *map, const char *filename,
146+
unsigned flags)
150147
{
151148
char buffer[1024];
152149
FILE *f;
@@ -186,7 +183,7 @@ static void read_mailmap_string(struct string_list *map, char *buf)
186183
}
187184
}
188185

189-
static int read_mailmap_blob(struct string_list *map, const char *name)
186+
int read_mailmap_blob(struct string_list *map, const char *name)
190187
{
191188
struct object_id oid;
192189
char *buf;

mailmap.h

+7
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ struct string_list;
66
extern char *git_mailmap_file;
77
extern char *git_mailmap_blob;
88

9+
/* Flags for read_mailmap_file() */
10+
#define MAILMAP_NOFOLLOW (1<<0)
11+
12+
int read_mailmap_file(struct string_list *map, const char *filename,
13+
unsigned flags);
14+
int read_mailmap_blob(struct string_list *map, const char *name);
15+
916
int read_mailmap(struct string_list *map);
1017
void clear_mailmap(struct string_list *map);
1118

t/t4203-mailmap.sh

+38-4
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,46 @@ test_expect_success 'check-mailmap --stdin arguments: mapping' '
7272
test_cmp expect actual
7373
'
7474

75-
test_expect_success 'check-mailmap bogus contact' '
76-
test_must_fail git check-mailmap bogus
75+
test_expect_success 'check-mailmap simple address: mapping' '
76+
test_when_finished "rm .mailmap" &&
77+
cat >.mailmap <<-EOF &&
78+
New Name <$GIT_AUTHOR_EMAIL>
79+
EOF
80+
cat .mailmap >expect &&
81+
git check-mailmap "$GIT_AUTHOR_EMAIL" >actual &&
82+
test_cmp expect actual
83+
'
84+
85+
test_expect_success 'check-mailmap --stdin simple address: mapping' '
86+
test_when_finished "rm .mailmap" &&
87+
cat >.mailmap <<-EOF &&
88+
New Name <$GIT_AUTHOR_EMAIL>
89+
EOF
90+
cat >stdin <<-EOF &&
91+
$GIT_AUTHOR_EMAIL
92+
EOF
93+
cat .mailmap >expect &&
94+
git check-mailmap --stdin <stdin >actual &&
95+
test_cmp expect actual
96+
'
97+
98+
test_expect_success 'check-mailmap simple address: no mapping' '
99+
cat >expect <<-EOF &&
100+
101+
EOF
102+
git check-mailmap "[email protected]" >actual &&
103+
test_cmp expect actual
77104
'
78105

79-
test_expect_success 'check-mailmap bogus contact --stdin' '
80-
test_must_fail git check-mailmap --stdin bogus </dev/null
106+
test_expect_success 'check-mailmap --stdin simple address: no mapping' '
107+
cat >expect <<-EOF &&
108+
109+
EOF
110+
cat >stdin <<-EOF &&
111+
112+
EOF
113+
git check-mailmap --stdin <stdin >actual &&
114+
test_cmp expect actual
81115
'
82116

83117
test_expect_success 'No mailmap' '

t/t9001-send-email.sh

+122
Original file line numberDiff line numberDiff line change
@@ -2485,6 +2485,128 @@ test_expect_success $PREREQ 'leading and trailing whitespaces are removed' '
24852485
test_cmp expected-list actual-list
24862486
'
24872487

2488+
test_expect_success $PREREQ 'mailmap support with --to' '
2489+
clean_fake_sendmail &&
2490+
test_config mailmap.file "mailmap.test" &&
2491+
cat >mailmap.test <<-EOF &&
2492+
2493+
EOF
2494+
git format-patch --stdout -1 >a.patch &&
2495+
git send-email \
2496+
--from="Example <[email protected]>" \
2497+
--smtp-server="$(pwd)/fake.sendmail" \
2498+
2499+
--mailmap \
2500+
a.patch \
2501+
2>errors >out &&
2502+
grep "^!someone@example\.com!$" commandline1
2503+
'
2504+
2505+
test_expect_success $PREREQ 'sendemail.mailmap configuration' '
2506+
clean_fake_sendmail &&
2507+
test_config mailmap.file "mailmap.test" &&
2508+
test_config sendemail.mailmap "true" &&
2509+
cat >mailmap.test <<-EOF &&
2510+
2511+
EOF
2512+
git format-patch --stdout -1 >a.patch &&
2513+
git send-email \
2514+
--from="Example <[email protected]>" \
2515+
--smtp-server="$(pwd)/fake.sendmail" \
2516+
2517+
a.patch \
2518+
2>errors >out &&
2519+
grep "^!someone@example\.com!$" commandline1
2520+
'
2521+
2522+
test_expect_success $PREREQ 'sendemail.mailmap.file configuration' '
2523+
clean_fake_sendmail &&
2524+
test_config sendemail.mailmap.file "mailmap.test" &&
2525+
test_config sendemail.mailmap "true" &&
2526+
cat >mailmap.test <<-EOF &&
2527+
2528+
EOF
2529+
git format-patch --stdout -1 >a.patch &&
2530+
git send-email \
2531+
--from="Example <[email protected]>" \
2532+
--smtp-server="$(pwd)/fake.sendmail" \
2533+
2534+
a.patch \
2535+
2>errors >out &&
2536+
grep "^!someone@example\.com!$" commandline1
2537+
'
2538+
2539+
test_expect_success $PREREQ 'sendemail.mailmap identity overrides configuration' '
2540+
clean_fake_sendmail &&
2541+
test_config sendemail.cloud.mailmap.file "mailmap.test" &&
2542+
test_config sendemail.mailmap "false" &&
2543+
test_config sendemail.cloud.mailmap "true" &&
2544+
cat >mailmap.test <<-EOF &&
2545+
2546+
EOF
2547+
git format-patch --stdout -1 >a.patch &&
2548+
git send-email \
2549+
--from="Example <[email protected]>" \
2550+
--smtp-server="$(pwd)/fake.sendmail" \
2551+
--identity=cloud \
2552+
2553+
a.patch \
2554+
2>errors >out &&
2555+
grep "^!someone@example\.com!$" commandline1
2556+
'
2557+
2558+
test_expect_success $PREREQ '--no-mailmap overrides configuration' '
2559+
clean_fake_sendmail &&
2560+
test_config sendemail.cloud.mailmap.file "mailmap.test" &&
2561+
test_config sendemail.mailmap "false" &&
2562+
test_config sendemail.cloud.mailmap "true" &&
2563+
cat >mailmap.test <<-EOF &&
2564+
2565+
EOF
2566+
git format-patch --stdout -1 >a.patch &&
2567+
git send-email \
2568+
--from="Example <[email protected]>" \
2569+
--smtp-server="$(pwd)/fake.sendmail" \
2570+
--identity=cloud \
2571+
2572+
--no-mailmap \
2573+
a.patch \
2574+
2>errors >out &&
2575+
grep "^!someone@example\.org!$" commandline1
2576+
'
2577+
2578+
test_expect_success $PREREQ 'mailmap support in To header' '
2579+
clean_fake_sendmail &&
2580+
test_config mailmap.file "mailmap.test" &&
2581+
cat >mailmap.test <<-EOF &&
2582+
2583+
EOF
2584+
git format-patch --stdout -1 [email protected] >a.patch &&
2585+
git send-email \
2586+
--from="Example <[email protected]>" \
2587+
--smtp-server="$(pwd)/fake.sendmail" \
2588+
--mailmap \
2589+
a.patch \
2590+
2>errors >out &&
2591+
grep "^!someone@example\.com!$" commandline1
2592+
'
2593+
2594+
test_expect_success $PREREQ 'mailmap support in Cc header' '
2595+
clean_fake_sendmail &&
2596+
test_config mailmap.file "mailmap.test" &&
2597+
cat >mailmap.test <<-EOF &&
2598+
2599+
EOF
2600+
git format-patch --stdout -1 [email protected] >a.patch &&
2601+
git send-email \
2602+
--from="Example <[email protected]>" \
2603+
--smtp-server="$(pwd)/fake.sendmail" \
2604+
--mailmap \
2605+
a.patch \
2606+
2>errors >out &&
2607+
grep "^!someone@example\.com!$" commandline1
2608+
'
2609+
24882610
test_expect_success $PREREQ 'test using command name with --sendmail-cmd' '
24892611
clean_fake_sendmail &&
24902612
PATH="$PWD:$PATH" \

0 commit comments

Comments
 (0)