From: Paul Gortmaker <paul.gortmaker@windriver.com>
To: Jay Soffian <jaysoffian@gmail.com>
Cc: git@vger.kernel.org, Nanako Shiraishi <nanako3@lavabit.com>,
Junio C Hamano <gitster@pobox.com>
Subject: Re: [PATCH v2] send-email: add --confirm option
Date: Sun, 1 Mar 2009 12:09:17 -0500 [thread overview]
Message-ID: <7d1d9c250903010909h7d92f165oc703a05e819671a4@mail.gmail.com> (raw)
In-Reply-To: <1235924234-16923-1-git-send-email-jaysoffian@gmail.com>
On Sun, Mar 1, 2009 at 11:17 AM, Jay Soffian <jaysoffian@gmail.com> wrote:
> send-email violates the principle of least surprise by automatically
> cc'ing additional recipients without confirming this with the user.
>
> This patch teaches send-email a --confirm option. It takes the
> following values:
>
> --confirm=always always confirm before sending
> --confirm=never never confirm before sending
> --confirm=cc confirm before sending when send-email has
> automatically added addresses from the patch to
> the Cc list
> --confirm=compose confirm before sending the first message when
> using --compose. (Needed to maintain backwards
> compatibility with existing behavior.)
> --confirm=auto 'cc' + 'compose'
>
> The option defaults to 'compose' if any suppress Cc related options have
> been used, otherwise it defaults to 'auto'.
>
> Unfortunately, it is impossible to introduce this patch such that it
> helps new users without potentially upsetting some existing users. We
> attempt to mitigate the latter by:
>
> * Allowing the user to "git config sendemail.config never"
I think it should be sendemail.confirm in the above. Thanks for
taking this seriously -- I think lots of new git users (who probably
will never make it to this list) will benefit from it without ever
even knowing.
Paul.
> * Allowing the user to say "all" after the first prompt to not be
> prompted on remaining emails during the same invocation.
> * Telling the user about the "sendemail.confirm" setting whenever they
> use "all"
> * Only prompting if no --suppress related options have been passed, as
> using such an option is likely to indicate an experienced send-email
> user.
>
> Signed-off-by: Jay Soffian <jaysoffian@gmail.com>
> ---
> Changes from v1:
>
> - Added no-confirm tests, and put them early to prevent the rest of
> the tests from potentially hanging. Note if one of these tests
> fails then we exit t9001-send-email.sh immediately.
>
> - Added verification of the --confirm setting. (I had done this
> previously but somehow failed to stage it.)
>
> - Added additional language to the commit messsage in an attempt to
> provide justification for the change in default behavior.
>
> - When the user specifies "all" in response to a confirm prompt, we
> hint them about how to use "sendemail.confirm" config setting.
>
> Documentation/git-send-email.txt | 16 ++++++
> git-send-email.perl | 72 +++++++++++++++++--------
> t/t9001-send-email.sh | 108 ++++++++++++++++++++++++++++++++------
> 3 files changed, 157 insertions(+), 39 deletions(-)
>
> diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
> index 164d149..bcf7ff1 100644
> --- a/Documentation/git-send-email.txt
> +++ b/Documentation/git-send-email.txt
> @@ -199,6 +199,22 @@ specified, as well as 'body' if --no-signed-off-cc is specified.
> Administering
> ~~~~~~~~~~~~~
>
> +--confirm::
> + Confirm just before sending:
> ++
> +--
> +- 'always' will always confirm before sending
> +- 'never' will never confirm before sending
> +- 'cc' will confirm before sending when send-email has automatically
> + added addresses from the patch to the Cc list
> +- 'compose' will confirm before sending the first message when using --compose.
> +- 'auto' is equivalent to 'cc' + 'compose'
> +--
> ++
> +Default is the value of 'sendemail.confirm' configuration value; if that
> +is unspecified, default to 'auto' unless any of the suppress options
> +have been specified, in which case default to 'compose'.
> +
> --dry-run::
> Do everything except actually send the emails.
>
> diff --git a/git-send-email.perl b/git-send-email.perl
> index adf7ecb..439b70b 100755
> --- a/git-send-email.perl
> +++ b/git-send-email.perl
> @@ -75,6 +75,8 @@ git send-email [options] <file | directory | rev-list options >
> --[no-]thread * Use In-Reply-To: field. Default on.
>
> Administering:
> + --confirm <str> * Confirm recipients before sending;
> + auto, cc, compose, always, or never.
> --quiet * Output one line of info per email.
> --dry-run * Don't actually send the emails.
> --[no-]validate * Perform patch sanity checks. Default on.
> @@ -181,7 +183,7 @@ sub do_edit {
> my ($thread, $chain_reply_to, $suppress_from, $signed_off_by_cc, $cc_cmd);
> my ($smtp_server, $smtp_server_port, $smtp_authuser, $smtp_encryption);
> my ($identity, $aliasfiletype, @alias_files, @smtp_host_parts);
> -my ($validate);
> +my ($validate, $confirm);
> my (@suppress_cc);
>
> my %config_bool_settings = (
> @@ -207,6 +209,7 @@ my %config_settings = (
> "suppresscc" => \@suppress_cc,
> "envelopesender" => \$envelope_sender,
> "multiedit" => \$multiedit,
> + "confirm" => \$confirm,
> );
>
> # Handle Uncouth Termination
> @@ -258,6 +261,7 @@ my $rc = GetOptions("sender|from=s" => \$sender,
> "suppress-from!" => \$suppress_from,
> "suppress-cc=s" => \@suppress_cc,
> "signed-off-cc|signed-off-by-cc!" => \$signed_off_by_cc,
> + "confirm=s" => \$confirm,
> "dry-run" => \$dry_run,
> "envelope-sender=s" => \$envelope_sender,
> "thread!" => \$thread,
> @@ -346,6 +350,13 @@ if ($suppress_cc{'body'}) {
> delete $suppress_cc{'body'};
> }
>
> +# Set confirm
> +if (!defined $confirm) {
> + $confirm = scalar %suppress_cc ? 'compose' : 'auto';
> +};
> +die "Unknown --confirm setting: '$confirm'\n"
> + unless $confirm =~ /^(?:auto|cc|compose|always|never)/;
> +
> # Debugging, print out the suppressions.
> if (0) {
> print "suppressions:\n";
> @@ -663,25 +674,13 @@ if (!defined $smtp_server) {
> $smtp_server ||= 'localhost'; # could be 127.0.0.1, too... *shrug*
> }
>
> -if ($compose) {
> - while (1) {
> - $_ = $term->readline("Send this email? (y|n) ");
> - last if defined $_;
> - print "\n";
> - }
> -
> - if (uc substr($_,0,1) ne 'Y') {
> - cleanup_compose_files();
> - exit(0);
> - }
> -
> - if ($compose > 0) {
> - @files = ($compose_filename . ".final", @files);
> - }
> +if ($compose && $compose > 0) {
> + @files = ($compose_filename . ".final", @files);
> }
>
> # Variables we set as part of the loop over files
> -our ($message_id, %mail, $subject, $reply_to, $references, $message);
> +our ($message_id, %mail, $subject, $reply_to, $references, $message,
> + $needs_confirm, $message_num);
>
> sub extract_valid_address {
> my $address = shift;
> @@ -837,6 +836,27 @@ X-Mailer: git-send-email $gitversion
> unshift (@sendmail_parameters,
> '-f', $raw_from) if(defined $envelope_sender);
>
> + if ($needs_confirm && !$dry_run) {
> + print "\n$header\n";
> + while (1) {
> + chomp ($_ = $term->readline(
> + "Send this email? ([y]es|[n]o|[q]uit|[a]ll): "
> + ));
> + last if /^(?:yes|y|no|n|quit|q|all|a)/i;
> + print "\n";
> + }
> + if (/^n/i) {
> + return;
> + } elsif (/^q/i) {
> + cleanup_compose_files();
> + exit(0);
> + } elsif (/^a/i) {
> + $confirm = 'never';
> + print "You may disable all future prompting via sendemail.confirm;\n";
> + print "Run 'git send-email --help' for details.\n";
> + }
> + }
> +
> if ($dry_run) {
> # We don't want to send the email.
> } elsif ($smtp_server =~ m#^/#) {
> @@ -935,6 +955,7 @@ X-Mailer: git-send-email $gitversion
> $reply_to = $initial_reply_to;
> $references = $initial_reply_to || '';
> $subject = $initial_subject;
> +$message_num = 0;
>
> foreach my $t (@files) {
> open(F,"<",$t) or die "can't open file $t";
> @@ -943,11 +964,12 @@ foreach my $t (@files) {
> my $author_encoding;
> my $has_content_type;
> my $body_encoding;
> - @cc = @initial_cc;
> + @cc = ();
> @xh = ();
> my $input_format = undef;
> my @header = ();
> $message = "";
> + $message_num++;
> # First unfold multiline header fields
> while(<F>) {
> last if /^\s*$/;
> @@ -1080,6 +1102,13 @@ foreach my $t (@files) {
> }
> }
>
> + $needs_confirm = (
> + $confirm eq "always" or
> + ($confirm =~ /^(?:auto|cc)$/ && @cc) or
> + ($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1));
> +
> + @cc = (@initial_cc, @cc);
> +
> send_message();
>
> # set up for the next message
> @@ -1094,13 +1123,10 @@ foreach my $t (@files) {
> $message_id = undef;
> }
>
> -if ($compose) {
> - cleanup_compose_files();
> -}
> +cleanup_compose_files();
>
> sub cleanup_compose_files() {
> - unlink($compose_filename, $compose_filename . ".final");
> -
> + unlink($compose_filename, $compose_filename . ".final") if $compose;
> }
>
> $smtp->quit if $smtp;
> diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
> index 4df4f96..08d5b91 100755
> --- a/t/t9001-send-email.sh
> +++ b/t/t9001-send-email.sh
> @@ -35,6 +35,47 @@ test_expect_success 'Extract patches' '
> patches=`git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1`
> '
>
> +# Test no confirm early to ensure remaining tests will not hang
> +test_no_confirm () {
> + rm -f no_confirm_okay
> + echo n | \
> + GIT_SEND_EMAIL_NOTTY=1 \
> + git send-email \
> + --from="Example <from@example.com>" \
> + --to=nobody@example.com \
> + --smtp-server="$(pwd)/fake.sendmail" \
> + $@ \
> + $patches > stdout &&
> + test_must_fail grep "Send this email" stdout &&
> + > no_confirm_okay
> +}
> +
> +# Exit immediately to prevent hang if a no-confirm test fails
> +check_no_confirm () {
> + test -f no_confirm_okay || {
> + say 'No confirm test failed; skipping remaining tests to prevent hanging'
> + test_done
> + }
> +}
> +
> +test_expect_success 'No confirm with --suppress-cc' '
> + test_no_confirm --suppress-cc=sob
> +'
> +check_no_confirm
> +
> +test_expect_success 'No confirm with --confirm=never' '
> + test_no_confirm --confirm=never
> +'
> +check_no_confirm
> +
> +# leave sendemail.confirm set to never after this so that none of the
> +# remaining tests prompt unintentionally.
> +test_expect_success 'No confirm with sendemail.confirm=never' '
> + git config sendemail.confirm never &&
> + test_no_confirm --compose --subject=foo
> +'
> +check_no_confirm
> +
> test_expect_success 'Send patches' '
> git send-email --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
> '
> @@ -175,15 +216,13 @@ test_set_editor "$(pwd)/fake-editor"
>
> test_expect_success '--compose works' '
> clean_fake_sendmail &&
> - echo y | \
> - GIT_SEND_EMAIL_NOTTY=1 \
> - git send-email \
> - --compose --subject foo \
> - --from="Example <nobody@example.com>" \
> - --to=nobody@example.com \
> - --smtp-server="$(pwd)/fake.sendmail" \
> - $patches \
> - 2>errors
> + git send-email \
> + --compose --subject foo \
> + --from="Example <nobody@example.com>" \
> + --to=nobody@example.com \
> + --smtp-server="$(pwd)/fake.sendmail" \
> + $patches \
> + 2>errors
> '
>
> test_expect_success 'first message is compose text' '
> @@ -375,15 +414,56 @@ test_expect_success '--suppress-cc=cc' '
> test_suppression cc
> '
>
> +test_confirm () {
> + echo y | \
> + GIT_SEND_EMAIL_NOTTY=1 \
> + git send-email \
> + --from="Example <nobody@example.com>" \
> + --to=nobody@example.com \
> + --smtp-server="$(pwd)/fake.sendmail" \
> + $@ \
> + $patches | grep "Send this email"
> +}
> +
> +test_expect_success '--confirm=always' '
> + test_confirm --confirm=always --suppress-cc=all
> +'
> +
> +test_expect_success '--confirm=auto' '
> + test_confirm --confirm=auto
> +'
> +
> +test_expect_success '--confirm=cc' '
> + test_confirm --confirm=cc
> +'
> +
> +test_expect_success '--confirm=compose' '
> + test_confirm --confirm=compose --compose
> +'
> +
> +test_expect_success 'confirm by default (due to cc)' '
> + CONFIRM=$(git config --get sendemail.confirm) &&
> + git config --unset sendemail.confirm &&
> + test_confirm &&
> + git config sendemail.confirm $CONFIRM
> +'
> +
> +test_expect_success 'confirm by default (due to --compose)' '
> + CONFIRM=$(git config --get sendemail.confirm) &&
> + git config --unset sendemail.confirm &&
> + test_confirm --suppress-cc=all --compose
> + ret="$?"
> + git config sendemail.confirm ${CONFIRM:-never}
> + test $ret = "0"
> +'
> +
> test_expect_success '--compose adds MIME for utf8 body' '
> clean_fake_sendmail &&
> (echo "#!$SHELL_PATH" &&
> echo "echo utf8 body: àéìöú >>\"\$1\""
> ) >fake-editor-utf8 &&
> chmod +x fake-editor-utf8 &&
> - echo y | \
> GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
> - GIT_SEND_EMAIL_NOTTY=1 \
> git send-email \
> --compose --subject foo \
> --from="Example <nobody@example.com>" \
> @@ -405,9 +485,7 @@ test_expect_success '--compose respects user mime type' '
> echo " echo utf8 body: àéìöú) >\"\$1\""
> ) >fake-editor-utf8-mime &&
> chmod +x fake-editor-utf8-mime &&
> - echo y | \
> GIT_EDITOR="\"$(pwd)/fake-editor-utf8-mime\"" \
> - GIT_SEND_EMAIL_NOTTY=1 \
> git send-email \
> --compose --subject foo \
> --from="Example <nobody@example.com>" \
> @@ -421,9 +499,7 @@ test_expect_success '--compose respects user mime type' '
>
> test_expect_success '--compose adds MIME for utf8 subject' '
> clean_fake_sendmail &&
> - echo y | \
> GIT_EDITOR="\"$(pwd)/fake-editor\"" \
> - GIT_SEND_EMAIL_NOTTY=1 \
> git send-email \
> --compose --subject utf8-sübjëct \
> --from="Example <nobody@example.com>" \
> @@ -445,7 +521,7 @@ test_expect_success 'detects ambiguous reference/file conflict' '
> test_expect_success 'feed two files' '
> rm -fr outdir &&
> git format-patch -2 -o outdir &&
> - GIT_SEND_EMAIL_NOTTY=1 git send-email \
> + git send-email \
> --dry-run \
> --from="Example <nobody@example.com>" \
> --to=nobody@example.com \
> --
> 1.6.2.rc1.309.g5f417
>
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
next prev parent reply other threads:[~2009-03-01 17:10 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-03-01 8:23 [PATCH] send-email: add --confirm option Jay Soffian
2009-03-01 9:03 ` Junio C Hamano
2009-03-01 14:05 ` Jay Soffian
2009-03-01 16:17 ` [PATCH v2] " Jay Soffian
2009-03-01 17:09 ` Paul Gortmaker [this message]
2009-03-01 17:49 ` Jay Soffian
2009-03-02 8:24 ` Nanako Shiraishi
2009-03-02 9:01 ` Junio C Hamano
2009-03-02 9:23 ` Nanako Shiraishi
2009-03-02 10:35 ` Felipe Contreras
2009-03-02 12:33 ` Jay Soffian
2009-03-02 7:34 ` Junio C Hamano
2009-03-02 12:35 ` Jay Soffian
2009-03-03 2:47 ` Junio C Hamano
2009-03-03 4:52 ` [PATCH v3] send-email: add --confirm option and configuration setting Jay Soffian
2009-03-03 6:53 ` Junio C Hamano
2009-03-03 10:11 ` Nanako Shiraishi
2009-03-03 11:54 ` Bert Wesarg
2009-03-03 16:22 ` Jay Soffian
2009-03-03 16:48 ` Junio C Hamano
2009-03-03 18:05 ` Bert Wesarg
2009-03-03 18:18 ` Jay Soffian
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=7d1d9c250903010909h7d92f165oc703a05e819671a4@mail.gmail.com \
--to=paul.gortmaker@windriver.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=jaysoffian@gmail.com \
--cc=nanako3@lavabit.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).