diff options
author | Oswald Buddenhagen <oswald.buddenhagen@qt.io> | 2017-08-25 20:16:13 +0200 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@gmx.de> | 2020-02-28 16:53:27 +0000 |
commit | 24b9194c656ace9a11d121863f13ca7d9eb0302b (patch) | |
tree | 4ef7913467c4da7c35ea3b67246bad70b5f32718 /bin | |
parent | 77d2922357ebbbf598a8fa9b3d90fef9d7f78f39 (diff) | |
download | qtrepotools-24b9194c656ace9a11d121863f13ca7d9eb0302b.tar.gz |
gpush: add target branch validation
complain when attempting to push a Change for a branch it hasn't been
pushed for before while it has been pushed for other branches.
add the --force-branch option to override the check.
we specifically ignore merged Changes, to avoid complaining about
cherry-picks. this introduces the risk of creating duplicates for
Changes that were temporarily cherry-picked locally and forgotten about.
this loophole will be addressed by a different mechanism later.
Change-Id: Ifac640a8163ec0f099c53de845fb2c5a372e917a
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
Diffstat (limited to 'bin')
-rwxr-xr-x | bin/git-gpush | 60 | ||||
-rw-r--r-- | bin/git_gpush.pm | 18 |
2 files changed, 72 insertions, 6 deletions
diff --git a/bin/git-gpush b/bin/git-gpush index 75e0cfd..e38eb28 100755 --- a/bin/git-gpush +++ b/bin/git-gpush @@ -57,6 +57,10 @@ Options: upstream branch for 'ref-from' is used as the target branch. This setting persists for the series, even when it grows. + -fb, --force-branch + Push for specified branch despite the pushed Changes having + been pushed previously, but only for different branches. + -l, --list Report all Changes that would be pushed, then quit. This is a purely off-line operation. @@ -123,6 +127,7 @@ EOM my $ref_from; my $ref_to; +my $force_branch = 0; my $list_only = 0; my @reviewers; @@ -148,6 +153,8 @@ sub parse_arguments(@) } elsif ($arg eq "-b" || $arg eq "--branch") { fail("--branch needs an argument.\n") if (!@_ || ($_[0] =~ /^-/)); $ref_to = shift @_; + } elsif ($arg eq "-fb" || $arg eq "--force-branch") { + $force_branch = 1; } elsif ($arg eq "-l" || $arg eq "--list") { $list_only = 1; } elsif ($arg eq "--aliases") { @@ -192,7 +199,7 @@ sub parse_arguments(@) } my $push_specific = - @reviewers || @CCs + @reviewers || @CCs || $force_branch || defined($remote) || defined($ref_to); if ($list_only) { @@ -400,6 +407,48 @@ sub get_changes() return $group; } +# Assign each local Change to a matching remote Change if possible, +# on the way complaining about creating duplicates. +sub map_remote_changes($) +{ + my ($group) = @_; + + my $changes = $$group{changes}; + my $br = $$group{branch}; + my (@bad_chg, %bad_br); + foreach my $change (@$changes) { + my $gis = $gerrit_infos_by_id{$$change{id}}; + next if (!$gis); + my ($good, @bad); + foreach my $gi (@$gis) { + if ($$gi{branch} eq $br) { + $good = $gi; + } elsif ($$gi{status} ne "MERGED") { + # MERGED Changes are ignored, to avoid false positives for cherry-picks. + push @bad, $gi; + } + } + if ($good) { + $$change{gerrit} = $good; + } elsif (@bad && !$force_branch) { + my @bbr = map { $$_{branch} } @bad; + $$change{annotation} = ' ['.join(" ", sort @bbr).']'; + push @bad_chg, $change; + $bad_br{$_} = 1 foreach (@bbr); + } + } + if (@bad_chg) { + my $reports = report_pushed_changes($group); + my $tpfx = (@bad_chg == @$changes) ? "The" : "Some of the"; + my $tsfx = (keys(%bad_br) == 1) ? "a different branch" : "different branches"; + report_fixed($reports, + "$tpfx Change(s) were previously pushed only for $tsfx.\n", + "Please move them server-side, push for a matching branch,\n", + "or use --force-branch to continue nonetheless.\n"); + fail_formatted($reports); + } +} + use constant { NEW => 'NEW', MODIFIED => 'MODIFIED', @@ -507,14 +556,13 @@ sub execute_pushing() my $group = get_changes(); my $pushed_changes = $$group{changes}; if ($online) { - my @queries; - foreach my $change (@$pushed_changes) { - my $commit = $$change{pushed}; - push @queries, "commit:".$commit if (defined($commit)); - } + my @queries = map { "change:".$$_{id} } @$pushed_changes; query_gerrit(\@queries); } determine_remote_branch($group); + if ($online) { + map_remote_changes($group); + } classify_changes_offline($group); if ($list_only) { show_changes($group); diff --git a/bin/git_gpush.pm b/bin/git_gpush.pm index a9e2553..6c3d69c 100644 --- a/bin/git_gpush.pm +++ b/bin/git_gpush.pm @@ -478,6 +478,7 @@ sub changes_from_commits($) ######################## our %gerrit_info_by_key; +our %gerrit_infos_by_id; ################## # state handling # @@ -762,6 +763,8 @@ sub format_reports($) my $type = $$report{type} // ""; if ($type eq "flowed") { $output .= wrap("", "", $_)."\n" foreach (@{$$report{texts}}); + } elsif ($type eq "fixed") { + $output .= join("", @{$$report{texts}}); } elsif ($type eq "change") { _unpack_report($report, my ($id, $subject, $prefix, $suffix, $annot, $fixlen)); my $w = $width - $fixlen; @@ -802,6 +805,16 @@ sub report_flowed($@) }; } +sub report_fixed($@) +{ + my ($reports, @texts) = @_; + + push @$reports, { + type => "fixed", + texts => \@texts + }; +} + sub report_local_changes($$) { my ($reports, $changes) = @_; @@ -1025,6 +1038,9 @@ sub query_gerrit($;$) my ($key, $changeid) = ($$review{'number'}, $$review{'id'}); next if (!defined($key) || !defined($changeid)); my $ginfo = \%{$gerrit_info_by_key{$key}}; + push @{$gerrit_infos_by_id{$changeid}}, $ginfo; + my $status = $$review{'status'}; + defined($status) or fail("Huh?! $changeid has no status?\n"); my $branch = $$review{'branch'}; defined($branch) or fail("Huh?! $changeid has no branch?\n"); my $pss = $$review{'patchSets'}; @@ -1039,6 +1055,8 @@ sub query_gerrit($;$) ); $revs[$number] = \%rev; } + $$ginfo{id} = $changeid; + $$ginfo{status} = $status; $$ginfo{branch} = $branch; $$ginfo{revs} = [ grep { $_ } @revs ]; # Drop deleted ones. push @ginfos, $ginfo; |