diff options
author | Oswald Buddenhagen <oswald.buddenhagen@gmx.de> | 2023-03-31 12:42:16 +0200 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@gmx.de> | 2024-01-09 16:36:55 +0000 |
commit | e7e89bb0f0c25533eac252c19590101122b35637 (patch) | |
tree | 0baef9a27eee867b8cb6730cfd32b562b9e99e8c /bin | |
parent | bc2eaa3ec88eef320345aed8dc8d9be4b6c2b119 (diff) |
gpush: make it possible to set a description on each series
this can be much more verbose than a topic name, and is aimed at
authoring cover letters in mail mode.
Change-Id: I65f769ee0c018e840a7561065f6da0da3bb94417
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Diffstat (limited to 'bin')
-rwxr-xr-x | bin/git-gpush | 79 | ||||
-rw-r--r-- | bin/git_gpush.pm | 58 |
2 files changed, 131 insertions, 6 deletions
diff --git a/bin/git-gpush b/bin/git-gpush index 288f763..18639a7 100755 --- a/bin/git-gpush +++ b/bin/git-gpush @@ -167,6 +167,14 @@ Options: This setting persists for the series, even when it grows. Use an empty topic to delete a previously set one. + -D, --edit-description + Edit the series' description. In mail mode, a non-empty description + causes a cover letter to be created; the first paragraph becomes + the subject, while the rest becomes the body. In Gerrit mode, the + description is not processed, and may be used for local notes. The + commit listing includes only the first line, except in verbose mode. + This option implies --group. + -- <git option>... In mail mode, set additional options for git format-patch and git send-email for the specified series. All subsequent arguments @@ -382,6 +390,7 @@ my $ref_base; my $ref_to; my $force_branch = 0; my $topic; +my $edit_desc = 0; my $force = 0; my $push_all = 0; my $group_only = 0; @@ -432,6 +441,10 @@ sub parse_arguments(@) } elsif ($arg eq "-R" || $arg eq "--reset-props") { $group_only = 1; $reset_props = 1; + } elsif ($arg eq "-D" || $arg eq "--edit-description") { + $group_only = 1; + $edit_desc = 1; + $quiet = 1; # Suppress listing of Changes } elsif ($arg eq "--keep-version") { $keep_version = 1; } elsif ($arg eq "--reset-version") { @@ -542,7 +555,7 @@ sub parse_arguments(@) my $series_modifying = $series_specifying || defined($ref_to) || defined($topic) || $keep_version || $reset_version - || $format_opts; + || $format_opts || $edit_desc; my $gerrit_specific = @reviewers || @CCs || defined($remote) || $force_branch; my $push_specific = @@ -965,6 +978,40 @@ sub determine_format_options($) $$group{fmt_opt_text} = $fmt_opt_text; } +sub determine_description($) +{ + my ($group) = @_; + + my $dsc = aggregate_indirect_property( + $group, sub { $$_{dsc} }, + sub { "has inconsistent descriptions." + ." Use --edit-description to rectify.\n" }); + my $dsc_text = defined($dsc) ? unquote_text_prop($prop_by_key{$dsc}) : undef; + $$group{desc} = $dsc; + $$group{desc_text} = $dsc_text; +} + +sub edit_description($) +{ + my ($group) = @_; + + my $changes = $$group{changes}; + my %desc_hash = map { unquote_text_prop($prop_by_key{$_}) => 1 } + grep { defined($_) } map { $$_{dsc} } @$changes; + my $desc = join("\n=============================\n\n", keys %desc_hash); + + my @reports; + report_text(\@reports, 'fixed', "Series of ".int(@$changes)." Change(s):\n"); + report_local_changes(\@reports, $changes); + my $comment = format_reports(\@reports); + $comment =~ s/^/# /smg; + $desc .= "\n".$comment; + + $desc = edit_textfile($desc); + $desc =~ s/(^|\n)(?:(?:#[^\n]*)?\n)+$/$1/g; + return new_prop(quote_text_prop($desc)); +} + sub scan_pushed_group($$) { my ($group, $commits) = @_; @@ -2041,6 +2088,19 @@ sub annotate_group($$) my $fmt_opt = $$group{fmt_opt_text}; push @annot, "> Format options: ".format_cmd(@$fmt_opt)."\n" if ($fmt_opt); + + my $dsc = $$group{desc_text}; + if (defined($dsc)) { + if ($verbose) { + push @annot, ",----- Description ------\n"; + push @annot, ($dsc =~ s/^/| /mgr); + push @annot, "\`-----------------------\n"; + } else { + $dsc =~ s/^([^\n]*+)\n?+(.*)/$1/sm; + $dsc .= " [...]" if (length($2)); + push @annot, "> Description: ".$dsc."\n"; + } + } } $$group{annotation} = \@annot if (@annot); } @@ -2265,10 +2325,14 @@ sub format_patches($) my $base = $$group{base}; my $tpc = $$group{topic}; my $ver = $$group{version}; + my $dsc = $$group{desc_text}; my $fmt_opt = $$group{fmt_opt_text}; my @gitopt = ('--binary'); push @gitopt, '--reroll-count', $ver if ($ver > 1); + push @gitopt, '--cover-letter', '--cover-from-description=subject', + '--description-file='.write_textfile($dsc) + if (defined($dsc)); push @gitopt, @$fmt_opt if ($fmt_opt); # Can't use the -<n> <tip> notation, as -8 is misunderstood # by git send-email. @@ -2288,6 +2352,10 @@ sub format_patches($) push @gitcmd, @gitopt; run_process(SOFT_FAIL | FWD_OUTPUT | DRY_RUN, @gitcmd); } + + cleanup_textfile(); + + # Note: no other processes must be invoked in between. return !$?; } @@ -2299,6 +2367,7 @@ sub update_state_grouping($) my ($group) = @_; my $gid = $$group{gid}; + my $dsc = $edit_desc && edit_description($group); my $fmt = $format_opts && new_fmt_opt(); foreach my $change (@{$$group{changes}}) { $$change{grp} = $gid; @@ -2312,6 +2381,8 @@ sub update_state_grouping($) if (defined($ref_base) || $reset_props); $$change{ver} = 0 if ($reset_version); + $$change{dsc} = $dsc + if ($edit_desc); $$change{fmt} = $fmt if ($format_opts); $$change{exclude} = $exclude ? 1 : undef @@ -2323,9 +2394,9 @@ sub update_state($) { my ($group) = @_; - my ($gid, $branch, $tpc, $ver, $fmt, $base) = + my ($gid, $branch, $tpc, $ver, $dsc, $fmt, $base) = ($$group{gid}, $$group{branch}, $$group{topic}, - $$group{version}, + $$group{version}, $$group{desc}, $$group{fmt_opt}, $$group{base}); # Setting an empty topic clears the previous topic from the server. $tpc = undef if (defined($tpc) && !length($tpc)); @@ -2336,6 +2407,7 @@ sub update_state($) $$change{topic} = $tpc; $$change{ntopic} = undef; $$change{ver} = $ver; + $$change{dsc} = $dsc; $$change{fmt} = $fmt; $$change{tgt} = $branch; $$change{ntgt} = undef; @@ -2439,6 +2511,7 @@ sub execute_pushing() foreach my $group (@$annot_groups) { determine_topic($group); if ($mail_mode) { + determine_description($group); determine_format_options($group); } } diff --git a/bin/git_gpush.pm b/bin/git_gpush.pm index 06cf21a..9d6b44b 100644 --- a/bin/git_gpush.pm +++ b/bin/git_gpush.pm @@ -19,7 +19,7 @@ $SIG{__DIE__} = \&Carp::confess; use List::Util qw(min max pairmap); use File::Spec; -use File::Temp qw(mktemp); +use File::Temp qw(mktemp tempfile); use IPC::Open3 qw(open3); use Symbol qw(gensym); use Term::ReadKey; @@ -749,6 +749,57 @@ sub unquote_list_prop($) return map { unquote_text_prop($_) } split(/ /, $in); } +our $_textfile; + +sub cleanup_textfile() +{ + if (defined($_textfile)) { + unlink($_textfile); + $_textfile = undef; + } +} + +END { cleanup_textfile(); } + +sub write_textfile($) +{ + my ($text) = @_; + + die("Only one textfile may be active at a time.\n") + if (defined($_textfile)); + + my $fh; + ($fh, $_textfile) = + tempfile("git-gpush.XXXXXX", SUFFIX => ".txt", TMPDIR => 1); + print $fh $text; + close($fh) or fail("Cannot write temporary file.\n"); + return $_textfile; +} + +sub read_textfile() +{ + open(my $fh, $_textfile) or fail("Cannot open temporary file.\n"); + local $/; + my $text = <$fh>; + close($fh); + + cleanup_textfile(); + + return $text; +} + +sub edit_textfile($) +{ + my ($text) = @_; + + write_textfile($text); + + state $editor = read_cmd_line(0, 'git', 'var', 'GIT_EDITOR'); + run_process(FWD_STDIN | FWD_OUTPUT, $editor, $_textfile); + + return read_textfile(); +} + ################## # state handling # ################## @@ -763,6 +814,7 @@ sub unquote_list_prop($) # - tgt: Target branch name. # - topic: Gerrit topic. Persisted only as a cache. # - fmt: format-patch/send-email options (indirect). +# - dsc: verbose series description / notes (indirect). # - pushed: SHA1 of the commit this Change was pushed as last time # from this repository. # - rebased: prospective value for 'pushed'. @@ -849,9 +901,9 @@ sub save_state(;$$) print "Saving ".($new ? "new " : "")."state".($dry ? " [DRY]" : "")." ...\n" if ($debug); my %prop_hash; my (@lines, @updates); - my %ikeys = map { $_ => 1 } ('fmt'); + my %ikeys = map { $_ => 1 } ('fmt', 'dsc'); my @fkeys = ('key', 'grp', 'id', 'base', 'src', 'tgt', - 'topic', 'ver', 'fmt', + 'topic', 'ver', 'fmt', 'dsc', 'nbase', 'ntgt', 'ntopic', 'exclude', 'hide'); my @rkeys = ('pushed', 'rebased', 'orig', 'rorig'); if ($new) { |