mononoke: correct handling of non-pushrebase pushes in push redirector

Summary: One notable change - non-pushrebase pushes on shared bookmarks will now fail.

Reviewed By: ikostia

Differential Revision: D18425394

fbshipit-source-id: 4983789a15caa1ceec044d379e3a4748b2821dea
This commit is contained in:
Stanislau Hlebik 2019-11-11 08:50:49 -08:00 committed by Facebook Github Bot
parent 09d9a5bed9
commit db61f6da5a
4 changed files with 240 additions and 31 deletions

View File

@ -32,6 +32,7 @@ use futures::Future;
use futures_preview::compat::Future01CompatExt;
use futures_preview::future::try_join_all;
use futures_util::{future::FutureExt, try_future::TryFutureExt, try_join};
use metaconfig_types::CommitSyncConfig;
use mononoke_types::ChangesetId;
use pushrebase::PushrebaseChangesetPair;
use std::collections::{HashMap, HashSet};
@ -52,6 +53,8 @@ pub struct RepoSyncTarget {
pub large_to_small_commit_syncer: CommitSyncer<Arc<dyn SyncedCommitMapping>>,
// A struct, needed to backsync commits
pub target_repo_dbs: TargetRepoDbs,
// Config for commit sync functionality
pub commit_sync_config: CommitSyncConfig,
}
impl RepoSyncTarget {
@ -503,6 +506,17 @@ impl RepoSyncTarget {
new: maybe_new,
} = orig;
if self
.commit_sync_config
.common_pushrebase_bookmarks
.contains(&name)
{
return Err(format_err!(
"cannot force pushrebase to shared bookmark {}",
name
));
}
let (old, new) = try_join!(
async {
match maybe_old {

View File

@ -195,6 +195,7 @@ fn create_repo_sync_target(
small_to_large_commit_syncer,
large_to_small_commit_syncer,
target_repo_dbs,
commit_sync_config,
})
.boxify()
}

View File

@ -0,0 +1,214 @@
$ . "${TEST_FIXTURES}/library.sh"
setup configuration
$ REPOTYPE="blob:files"
$ REPOID=0 REPONAME=large-mon setup_common_config $REPOTYPE
$ REPOID=1 REPONAME=small-mon-1 setup_common_config $REPOTYPE
$ REPOID=2 REPONAME=small-mon-2 setup_common_config $REPOTYPE
$ cat >> "$TESTTMP/mononoke-config/common/commitsyncmap.toml" <<EOF
> [megarepo_test]
> large_repo_id = 0
> common_pushrebase_bookmarks = ["master_bookmark"]
> [[megarepo_test.small_repos]]
> repoid = 1
> bookmark_prefix = "bookprefix1/"
> default_action = "prepend_prefix"
> default_prefix = "smallrepofolder1"
> direction = "large_to_small"
> [megarepo_test.small_repos.map]
> "special"="specialsmallrepofolder1"
> [[megarepo_test.small_repos]]
> repoid = 2
> bookmark_prefix = "bookprefix2/"
> default_action = "prepend_prefix"
> default_prefix = "smallrepofolder2"
> direction = "small_to_large"
> [megarepo_test.small_repos.map]
> "special"="specialsmallrepofolder2"
> EOF
Verification function
$ function verify_wc() {
> local large_repo_commit
> large_repo_commit="$1"
> "$MONONOKE_ADMIN" "${CACHING_ARGS[@]}" --log-level ERROR --mononoke-config-path "$TESTTMP"/mononoke-config --source-repo-id="$REPOIDLARGE" --target-repo-id="$REPOIDSMALL1" crossrepo verify-wc $large_repo_commit
> }
setup hg server repos
$ function createfile { mkdir -p "$(dirname $1)" && echo "$1" > "$1" && hg add -q "$1"; }
$ function create_first_post_move_commit {
> echo 1 > "$1/filetoremove" && hg add "$1/filetoremove" && hg ci -m 'first post-move commit'
> hg revert -r .^ "$1/filetoremove"
> }
$ cd $TESTTMP
$ hginit_treemanifest small-hg-srv-1
$ hginit_treemanifest small-hg-srv-2
$ cd "$TESTTMP/small-hg-srv-1"
$ echo 1 > file.txt
$ hg addremove -q && hg ci -q -m 'pre-move commit 1'
$ cd "$TESTTMP/small-hg-srv-2"
$ echo 2 > file.txt
$ hg addremove -q && hg ci -q -m 'pre-move commit 2'
$ cd "$TESTTMP"
$ cp -r small-hg-srv-1 large-hg-srv
$ cd large-hg-srv
$ mkdir smallrepofolder1
$ hg mv file.txt smallrepofolder1/file.txt
$ hg ci -m 'move commit'
$ mkdir smallrepofolder2
$ echo 2 > smallrepofolder2/file.txt
$ hg addremove -q
$ hg ci -m "move commit for repo 2"
$ create_first_post_move_commit smallrepofolder1
$ hg book -r . master_bookmark
$ cd "$TESTTMP/small-hg-srv-1"
$ create_first_post_move_commit .
$ hg book -r . master_bookmark
$ cd "$TESTTMP/small-hg-srv-2"
$ hg book -r . master_bookmark
blobimport hg servers repos into Mononoke repos
$ cd $TESTTMP
$ REPOIDLARGE=0
$ REPOIDSMALL1=1
$ REPOIDSMALL2=2
$ REPOID="$REPOIDLARGE" blobimport large-hg-srv/.hg large-mon
$ REPOID="$REPOIDSMALL1" blobimport small-hg-srv-1/.hg small-mon-1
$ REPOID="$REPOIDSMALL2" blobimport small-hg-srv-2/.hg small-mon-2
setup hg client repos
$ function init_client() {
> cd "$TESTTMP"
> hgclone_treemanifest ssh://user@dummy/"$1" "$2" --noupdate --config extensions.remotenames=
> cd "$TESTTMP/$2"
> cat >> .hg/hgrc <<EOF
> [extensions]
> pushrebase =
> remotenames =
> EOF
> }
$ init_client small-hg-srv-1 small-hg-client-1
$ init_client small-hg-srv-2 small-hg-client-2
$ cd "$TESTTMP"
$ init_client large-hg-srv large-hg-client
Setup helpers
$ log() {
> hg log -G -T "{desc} [{phase};rev={rev};{node|short}] {remotenames}" "$@"
> }
$ LARGE_MASTER_BONSAI=$(get_bonsai_bookmark $REPOIDLARGE master_bookmark)
$ SMALL1_MASTER_BONSAI=$(get_bonsai_bookmark $REPOIDSMALL1 master_bookmark)
$ SMALL2_MASTER_BONSAI=$(get_bonsai_bookmark $REPOIDSMALL2 master_bookmark)
start mononoke server
$ mononoke
$ wait_for_mononoke
Make sure mapping is set up and we know what we don't have to sync initial entries
$ add_synced_commit_mapping_entry $REPOIDSMALL1 $SMALL1_MASTER_BONSAI $REPOIDLARGE $LARGE_MASTER_BONSAI
$ add_synced_commit_mapping_entry $REPOIDSMALL2 $SMALL2_MASTER_BONSAI $REPOIDLARGE $LARGE_MASTER_BONSAI
$ sqlite3 "$TESTTMP/monsql/sqlite_dbs" "INSERT INTO mutable_counters (repo_id, name, value) VALUES ($REPOIDSMALL1, 'backsync_from_$REPOIDLARGE', 2)";
Normal pushrebase with one commit
$ cd "$TESTTMP/small-hg-client-1"
$ REPONAME=small-mon-1 hgmn up -q master_bookmark
$ echo 2 > 2 && hg addremove -q && hg ci -q -m newcommit
$ REPONAME=small-mon-1 hgmn push -r . --to master_bookmark | grep updating
updating bookmark master_bookmark
-- newcommit was correctly pushed to master_bookmark
$ log -r master_bookmark
@ newcommit [public;rev=2;6989db12d1e5] default/master_bookmark
|
~
-- newcommit is also present in the large repo (after a pull)
$ cd "$TESTTMP"/large-hg-client
$ log -r master_bookmark
o first post-move commit [public;rev=3;bca7e9574548] default/master_bookmark
|
~
$ REPONAME=large-mon hgmn pull -q
$ log -r master_bookmark
o newcommit [public;rev=4;7c9a729ceb57] default/master_bookmark
|
~
- compare the working copies
$ verify_wc master_bookmark
At the same time, the tailed repo gets new commits
$ cd "$TESTTMP/small-hg-client-2"
$ REPONAME=small-mon-2 hgmn up -q master_bookmark
$ createfile file2_1
$ hg ci -qm "Post-merge commit 1"
$ REPONAME=small-mon-2 hgmn push --to master_bookmark -q
-- tailer puts this commit into a large repo
$ mononoke_x_repo_sync_once $REPOIDSMALL2 $REPOIDLARGE master_bookmark once --commit master_bookmark 2>&1 | grep "synced as"
* public changeset 46d7f49c05a72a305692183a11274a0fbbdc4f8a4b53ca759fb3d257ba54184e synced as 3a9ffb4771519f86b79729a543da084c6a70ff385933aed540e2112a049a0697 * (glob)
Force pushrebase should fail, because it pushes to a shared bookmark
$ cd "$TESTTMP/small-hg-client-1"
$ REPONAME=small-mon-1 hgmn up -q master_bookmark^
$ echo 3 > 3 && hg add 3 && hg ci -q -m "non-forward move"
$ REPONAME=small-mon-1 hgmn push --to master_bookmark --force --pushvar NON_FAST_FORWARD=true | grep updating
remote: Command failed
remote: Error:
remote: cannot force pushrebase to shared bookmark master_bookmark
remote: Root cause:
remote: ErrorMessage {
remote: msg: "cannot force pushrebase to shared bookmark master_bookmark",
remote: }
abort: stream ended unexpectedly (got 0 bytes, expected 4)
[1]
Non-shared bookmark should work
$ REPONAME=small-mon-1 hgmn push --to master_bookmark_non_fast_forward --force --create -q
-- it should also be present in a large repo
$ cd "$TESTTMP/large-hg-client"
$ REPONAME=large-mon hgmn pull -q
$ log -r bookprefix1/master_bookmark_non_fast_forward
o non-forward move [public;rev=5;6b6a308437bb] default/bookprefix1/master_bookmark_non_fast_forward
|
~
Bookmark-only pushrebase (Create a new bookmark, do not push commits)
$ cd "$TESTTMP/small-hg-client-1"
$ REPONAME=small-mon-1 hgmn push -r master_bookmark^ --to master_bookmark_2 --create | grep exporting
exporting bookmark master_bookmark_2
$ hg book --all
no bookmarks set
default/master_bookmark 2:6989db12d1e5
default/master_bookmark_2 1:680aaf36d7a2
default/master_bookmark_non_fast_forward 3:161addaa86c7
-- this is not a `common_pushrebase_bookmark`, so should be prefixed
$ cd "$TESTTMP/large-hg-client"
$ REPONAME=large-mon hgmn pull -q
devel-warn: applied empty changegroup at: * (glob)
$ hg book --all
no bookmarks set
default/bookprefix1/master_bookmark_2 3:bca7e9574548
default/bookprefix1/master_bookmark_non_fast_forward 5:6b6a308437bb
default/master_bookmark 6:bf8e8d65212d
- compare the working copies
$ verify_wc bookprefix1/master_bookmark_2
Delete a bookmark
$ cd "$TESTTMP/small-hg-client-1"
$ REPONAME=small-mon-1 hgmn push -d master_bookmark_2 | grep deleting
deleting remote bookmark master_bookmark_2
$ hg book --all
no bookmarks set
default/master_bookmark 2:6989db12d1e5
default/master_bookmark_non_fast_forward 3:161addaa86c7
$ cd "$TESTTMP/large-hg-client"
$ REPONAME=large-mon hgmn pull -q
devel-warn: applied empty changegroup at: * (glob)
$ hg book --all
no bookmarks set
default/bookprefix1/master_bookmark_non_fast_forward 5:6b6a308437bb
default/master_bookmark 6:bf8e8d65212d

View File

@ -116,33 +116,13 @@ Normal pushrebase with one commit
- compare the working copies
$ verify_wc master_bookmark
Force pushrebase
$ cd "$TESTTMP/small-hg-client"
$ REPONAME=small-mon hgmn up -q master_bookmark^
$ echo 3 > 3 && hg add 3 && hg ci -q -m "Master after non-forward move"
$ REPONAME=small-mon hgmn push --to master_bookmark --force --pushvar NON_FAST_FORWARD=true | grep updating
updating bookmark master_bookmark
$ log -r master_bookmark
@ Master after non-forward move [public;rev=3;e5ca36a3d680] default/master_bookmark
|
~
-- it should also be present in a large repo
$ cd "$TESTTMP/large-hg-client"
$ REPONAME=large-mon hgmn pull -q
$ log -r master_bookmark
o Master after non-forward move [public;rev=4;373fa4f55174] default/master_bookmark
|
~
- compare the working copies
$ verify_wc master_bookmark
Bookmark-only pushrebase (Create a new bookmark, do not push commits)
$ cd "$TESTTMP/small-hg-client"
$ REPONAME=small-mon hgmn push -r master_bookmark^ --to master_bookmark_2 --create | grep exporting
exporting bookmark master_bookmark_2
$ hg book --all
no bookmarks set
default/master_bookmark 3:e5ca36a3d680
default/master_bookmark 2:ce81c7d38286
default/master_bookmark_2 1:11f848659bfc
-- this is not a `common_pushrebase_bookmark`, so should be prefixed
$ cd "$TESTTMP/large-hg-client"
@ -151,7 +131,7 @@ Bookmark-only pushrebase (Create a new bookmark, do not push commits)
$ hg book --all
no bookmarks set
default/bookprefix/master_bookmark_2 2:bfcfb674663c
default/master_bookmark 4:373fa4f55174
default/master_bookmark 3:819e91b238b7
- compare the working copies
$ verify_wc bookprefix/master_bookmark_2
@ -161,13 +141,13 @@ Delete a bookmark
deleting remote bookmark master_bookmark_2
$ hg book --all
no bookmarks set
default/master_bookmark 3:e5ca36a3d680
default/master_bookmark 2:ce81c7d38286
$ cd "$TESTTMP/large-hg-client"
$ REPONAME=large-mon hgmn pull -q
devel-warn: applied empty changegroup at: * (glob)
$ hg book --all
no bookmarks set
default/master_bookmark 4:373fa4f55174
default/master_bookmark 3:819e91b238b7
Normal pushrebase with many commits
$ cd "$TESTTMP/small-hg-client"
@ -178,7 +158,7 @@ Normal pushrebase with many commits
$ createfile 7 && hg ci -qm "The staunchest tramp to ply his trade"
$ REPONAME=small-mon hgmn push --to master_bookmark
pushing rev 5448ef1ede9d to destination ssh://user@dummy/small-mon bookmark master_bookmark
pushing rev beb30dc3a35c to destination ssh://user@dummy/small-mon bookmark master_bookmark
searching for changes
adding changesets
adding manifests
@ -186,14 +166,14 @@ Normal pushrebase with many commits
added 0 changesets with 0 changes to 0 files
updating bookmark master_bookmark
$ log -r master_bookmark
@ The staunchest tramp to ply his trade [public;rev=7;5448ef1ede9d] default/master_bookmark
@ The staunchest tramp to ply his trade [public;rev=6;beb30dc3a35c] default/master_bookmark
|
~
-- this should also be present in a large repo, once we pull:
$ cd "$TESTTMP/large-hg-client"
$ REPONAME=large-mon hgmn pull -q
$ log -r master_bookmark
o The staunchest tramp to ply his trade [public;rev=8;73bd0869f142] default/master_bookmark
o The staunchest tramp to ply his trade [public;rev=7;34c34be6efde] default/master_bookmark
|
~
$ verify_wc master_bookmark
@ -208,14 +188,14 @@ Pushrebase, which deletes and removes files
$ REPONAME=small-mon hgmn push --to master_bookmark | grep updating
updating bookmark master_bookmark
$ log -r master_bookmark
@ Moves, renames and copies [public;rev=8;ed440ae481ea] default/master_bookmark
@ Moves, renames and copies [public;rev=7;b888ee4f19b5] default/master_bookmark
|
~
-- this should also be present in a large repo, once we pull:
$ cd "$TESTTMP/large-hg-client"
$ REPONAME=large-mon hgmn pull -q
$ log -r master_bookmark
o Moves, renames and copies [public;rev=9;ba47ebe8e77d] default/master_bookmark
o Moves, renames and copies [public;rev=8;b4e3e504160c] default/master_bookmark
|
~
$ verify_wc master_bookmark
@ -229,14 +209,14 @@ Pushrebase, which replaces a directory with a file
$ REPONAME=small-mon hgmn push --to master_bookmark | grep updating
updating bookmark master_bookmark
$ log -r master_bookmark
@ Replace a directory with a file [public;rev=9;e8e60f4bf53e] default/master_bookmark
@ Replace a directory with a file [public;rev=8;e72ee383159a] default/master_bookmark
|
~
-- this should also be present in a large repo, once we pull
$ cd "$TESTTMP/large-hg-client"
$ REPONAME=large-mon hgmn pull -q
$ log -r master_bookmark
o Replace a directory with a file [public;rev=10;63366cd3030b] default/master_bookmark
o Replace a directory with a file [public;rev=9;6ac00e7afd93] default/master_bookmark
|
~
$ verify_wc master_bookmark