send-email: teach git send-email option to translate aliases

git send-email has support for converting shorthand alias names to canonical email addresses via the alias file. It supports a wide variety of alias file formats based on popular email program file formats. Other programs, such as b4, would like the ability to convert aliases in the same way as git send-email without needing to re-implement the logic for understanding the many file formats. Teach git send-email a new option, --translate-aliases, which will enable this functionality. Similar to --dump-aliases, this option works like a new mode of operation for git send-email. When run with --translate-aliases, git send-email reads from standard input and converts any provided alias into its canonical name and email according to the alias file. Each expanded name and address is printed to standard output, one per line. Signed-off-by: Jacob Keller <jacob.keller@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jacob Keller committed Aug 13, 2024 at 17:05 UTC c038a6f1d748dd1062ffa91f7a8453c73f5bcf9f
3 files changed +131 -1
Documentation/git-send-email.txt
+7
@@ -12,6 +12,7 @@ SYNOPSIS
12 'git send-email' [<options>] (<file>|<directory>)...
13 'git send-email' [<options>] <format-patch-options>
14 'git send-email' --dump-aliases
15 +'git send-email' --translate-aliases
16
17
18 DESCRIPTION
@@ -475,6 +476,12 @@ Information
476 that this only includes the alias name and not its expanded email addresses.
477 See 'sendemail.aliasesFile' for more information about aliases.
478
479 +--translate-aliases::
480 + Instead of the normal operation, read from standard input and
481 + interpret each line as an email alias. Translate it according to the
482 + configured alias file(s). Output each translated name and email
483 + address to standard output, one per line. See 'sendemail.aliasFile'
484 + for more information about aliases.
485
486 CONFIGURATION
487 -------------
git-send-email.perl
+20 -1
@@ -31,6 +31,7 @@ sub usage {
31 git send-email [<options>] <file|directory>
32 git send-email [<options>] <format-patch options>
33 git send-email --dump-aliases
34 +git send-email --translate-aliases
35
36 Composing:
37 --from <str> * Email From:
@@ -99,6 +100,10 @@ git send-email --dump-aliases
100
101 Information:
102 --dump-aliases * Dump configured aliases and exit.
103 + --translate-aliases * Translate aliases read from standard
104 + input according to the configured email
105 + alias file(s), outputting the result to
106 + standard output.
107
108 EOT
109 exit(1);
@@ -212,6 +217,7 @@ my $format_patch;
217 my $compose_filename;
218 my $force = 0;
219 my $dump_aliases = 0;
220 +my $translate_aliases = 0;
221
222 # Variables to prevent short format-patch options from being captured
223 # as abbreviated send-email options
@@ -476,11 +482,14 @@ my $git_completion_helper;
482 my %dump_aliases_options = (
483 "h" => \$help,
484 "dump-aliases" => \$dump_aliases,
485 + "translate-aliases" => \$translate_aliases,
486 );
487 $rc = GetOptions(%dump_aliases_options);
488 usage() unless $rc;
489 die __("--dump-aliases incompatible with other options\n")
483 - if !$help and $dump_aliases and @ARGV;
490 + if !$help and ($dump_aliases or $translate_aliases) and @ARGV;
491 +die __("--dump-aliases and --translate-aliases are mutually exclusive\n")
492 + if !$help and $dump_aliases and $translate_aliases;
493 my %options = (
494 "sender|from=s" => \$sender,
495 "in-reply-to=s" => \$initial_in_reply_to,
@@ -724,6 +733,16 @@ if ($dump_aliases) {
733 exit(0);
734 }
735
736 +if ($translate_aliases) {
737 + while (<STDIN>) {
738 + my @addr_list = parse_address_line($_);
739 + @addr_list = expand_aliases(@addr_list);
740 + @addr_list = sanitize_address_list(@addr_list);
741 + print "$_\n" for @addr_list;
742 + }
743 + exit(0);
744 +}
745 +
746 # is_format_patch_arg($f) returns 0 if $f names a patch, or 1 if
747 # $f is a revision list specification to be passed to format-patch.
748 sub is_format_patch_arg {
t/t9001-send-email.sh
+104
@@ -2120,6 +2120,110 @@ test_expect_success '--dump-aliases must be used alone' '
2120 test_must_fail git send-email --dump-aliases --to=janice@example.com -1 refs/heads/accounting
2121 '
2122
2123 +test_translate_aliases () {
2124 + msg="$1" && shift &&
2125 + filetype="$1" && shift &&
2126 + aliases="$1" && shift &&
2127 + printf '%s\n' "$@" >expect &&
2128 + cat >.tmp-email-aliases &&
2129 + printf '%s\n' "$aliases" >aliases &&
2130 +
2131 + test_expect_success $PREREQ "$msg" '
2132 + clean_fake_sendmail && rm -fr outdir &&
2133 + git config --replace-all sendemail.aliasesfile \
2134 + "$(pwd)/.tmp-email-aliases" &&
2135 + git config sendemail.aliasfiletype "$filetype" &&
2136 + git send-email --translate-aliases <aliases 2>errors >actual &&
2137 + test_cmp expect actual
2138 + '
2139 +}
2140 +
2141 +test_translate_aliases '--translate-aliases sendmail format' \
2142 + 'sendmail' \
2143 + 'alice bcgrp' \
2144 + 'Alice W Land <awol@example.com>' \
2145 + 'Robert Bobbyton <bob@example.com>' \
2146 + 'chloe@example.com' \
2147 + 'Other <o@example.com>' <<-\EOF
2148 + alice: Alice W Land <awol@example.com>
2149 + bob: Robert Bobbyton <bob@example.com>
2150 + chloe: chloe@example.com
2151 + abgroup: alice, bob
2152 + bcgrp: bob, chloe, Other <o@example.com>
2153 + EOF
2154 +
2155 +test_translate_aliases '--translate-aliases mutt format' \
2156 + 'mutt' \
2157 + 'donald bob' \
2158 + 'Donald C Carlton <donc@example.com>' \
2159 + 'Robert Bobbyton <bob@example.com>' <<-\EOF
2160 + alias alice Alice W Land <awol@example.com>
2161 + alias donald Donald C Carlton <donc@example.com>
2162 + alias bob Robert Bobbyton <bob@example.com>
2163 + alias chloe chloe@example.com
2164 + EOF
2165 +
2166 +test_translate_aliases '--translate-aliases mailrc format' \
2167 + 'mailrc' \
2168 + 'chloe eve alice' \
2169 + 'chloe@example.com' \
2170 + 'Eve <eve@example.com>' \
2171 + 'Alice W Land <awol@example.com>' <<-\EOF
2172 + alias alice "Alice W Land <awol@example.com>"
2173 + alias eve "Eve <eve@example.com>"
2174 + alias bob "Robert Bobbyton <bob@example.com>"
2175 + alias chloe chloe@example.com
2176 + EOF
2177 +
2178 +test_translate_aliases '--translate-aliases pine format' \
2179 + 'pine' \
2180 + 'eve bob bcgrp' \
2181 + 'eve@example.com' \
2182 + 'bob@example.com' \
2183 + 'bob@example.com' \
2184 + 'chloe@example.com' \
2185 + 'Other <o@example.com>' <<-\EOF
2186 + alice Alice W Land awol@example.com Friend
2187 + eve Eve eve@example.com
2188 + bob Robert Bobbyton bob@example.com
2189 + chloe chloe@example.com
2190 + bcgrp (bob, chloe, Other <o@example.com>)
2191 + EOF
2192 +
2193 +test_translate_aliases '--translate-aliases gnus format' \
2194 + 'gnus' \
2195 + 'alice chloe eve' \
2196 + 'awol@example.com' \
2197 + 'chloe@example.com' \
2198 + 'eve@example.com' <<-\EOF
2199 + (define-mail-alias "alice" "awol@example.com")
2200 + (define-mail-alias "eve" "eve@example.com")
2201 + (define-mail-alias "bob" "bob@example.com")
2202 + (define-mail-alias "chloe" "chloe@example.com")
2203 + EOF
2204 +
2205 +test_expect_success $PREREQ '--translate-aliases passes valid addresses through' '
2206 + cat >expect <<-\EOF &&
2207 + Other <o@example.com>
2208 + EOF
2209 + cat >aliases <<-\EOF &&
2210 + Other <o@example.com>
2211 + EOF
2212 + git send-email --translate-aliases <aliases >actual &&
2213 + test_cmp expect actual
2214 +'
2215 +
2216 +test_expect_success $PREREQ '--translate-aliases passes unknown aliases through' '
2217 + cat >expect <<-\EOF &&
2218 + blargh
2219 + EOF
2220 + cat >aliases <<-\EOF &&
2221 + blargh
2222 + EOF
2223 + git send-email --translate-aliases <aliases >actual &&
2224 + test_cmp expect actual
2225 +'
2226 +
2227 test_expect_success $PREREQ 'aliases and sendemail.identity' '
2228 test_must_fail git \
2229 -c sendemail.identity=cloud \