diff --git a/repo_client/src/push_redirector/mod.rs b/repo_client/src/push_redirector/mod.rs index 25034b381f..286648e051 100644 --- a/repo_client/src/push_redirector/mod.rs +++ b/repo_client/src/push_redirector/mod.rs @@ -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>, // 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 { diff --git a/server/repo_listener/src/repo_handlers.rs b/server/repo_listener/src/repo_handlers.rs index 16f9cdf9dd..e40edae484 100644 --- a/server/repo_listener/src/repo_handlers.rs +++ b/server/repo_listener/src/repo_handlers.rs @@ -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() } diff --git a/tests/integration/test-push-redirector-pushrebase-onesided.t b/tests/integration/test-push-redirector-pushrebase-onesided.t new file mode 100644 index 0000000000..043ee186df --- /dev/null +++ b/tests/integration/test-push-redirector-pushrebase-onesided.t @@ -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" < [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 < [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 diff --git a/tests/integration/test-push-redirector-pushrebase.t b/tests/integration/test-push-redirector-pushrebase.t index ee44c13c4d..487e046c5f 100644 --- a/tests/integration/test-push-redirector-pushrebase.t +++ b/tests/integration/test-push-redirector-pushrebase.t @@ -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