Skip to content

Commit c3149cd

Browse files
RajivTSfacebook-github-bot
authored andcommitted
Refactor git bookmark mover logic
Summary: Lot of code in a single function. Let's clean it up. Differential Revision: D78090943 fbshipit-source-id: 6ed398bc3cefb5d111f2b7245efabc4a7828cd6c
1 parent 96b1a30 commit c3149cd

2 files changed

Lines changed: 83 additions & 47 deletions

File tree

eden/mononoke/git/import_tools/src/bookmark.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,14 @@ impl BookmarkOperationType {
104104
_ => false,
105105
}
106106
}
107+
108+
pub fn old_changeset(&self) -> Option<ChangesetId> {
109+
match self {
110+
Self::Move(old, _) => Some(*old),
111+
Self::Delete(old) => Some(*old),
112+
_ => None,
113+
}
114+
}
107115
}
108116

109117
/// Method responsible for either creating, moving or deleting a bookmark in gitimport and gitserver.

eden/mononoke/git_server/src/service/bookmark_mover.rs

Lines changed: 75 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use anyhow::Result;
1313
use bonsai_tag_mapping::BonsaiTagMappingRef;
1414
use bookmarks::BookmarkPrefix;
1515
use cloned::cloned;
16+
use context::CoreContext;
1617
use futures::StreamExt;
1718
use futures::TryStreamExt;
1819
use futures::stream;
@@ -25,6 +26,7 @@ use import_tools::git_reader::GitReader;
2526
use import_tools::set_bookmark;
2627
use mononoke_api::BookmarkKey;
2728
use mononoke_api::MononokeError;
29+
use mononoke_api::Repo;
2830
use mononoke_api::repo::RepoContextBuilder;
2931
use mononoke_api::repo::git::bookmark_exists_with_prefix;
3032
use mononoke_api::repo::git::get_bookmark_state;
@@ -165,14 +167,6 @@ async fn set_ref_inner(
165167
if ref_update.ref_name.starts_with(COMMIT_CLOUD_REF_PREFIX) {
166168
return Ok(());
167169
}
168-
169-
// Check if push redirector is enabled, if it is then reject the push
170-
if push_redirector_enabled(&ctx, repo.clone()).await? {
171-
return Err(anyhow::anyhow!(
172-
"Pushes to repo {0} are disallowed because its source of truth has been moved. Use `git pushrebase` or make changes directly in the repo where the source of truth was moved.",
173-
repo.repo_identity().name()
174-
));
175-
}
176170
// If the ref is a content ref, then we have already processed it in the uploader. There is no
177171
// bookmark to move in this case
178172
if ref_update.is_content() {
@@ -186,6 +180,15 @@ async fn set_ref_inner(
186180
}
187181
return Ok(());
188182
}
183+
// Create the bookmark operation representing the ref update if its allowed
184+
let bookmark_operation = bookmark_operation(
185+
&ctx,
186+
repo.clone(),
187+
mappings_store.clone(),
188+
object_store.clone(),
189+
&ref_update,
190+
)
191+
.await?;
189192
// Create the repo context which is the pre-requisite for moving bookmarks
190193
let repo_context = RepoContextBuilder::new(ctx.clone(), repo.clone(), repos)
191194
.await
@@ -194,6 +197,67 @@ async fn set_ref_inner(
194197
.build()
195198
.await
196199
.context("Failure in creating RepoContext for git push")?;
200+
201+
// Do one final check of SoT to ensure that we don't update the bookmark if the repo is locked or sourced in Metagit
202+
if !mononoke_source_of_truth(&ctx, repo.clone()).await? {
203+
return Err(anyhow::anyhow!(
204+
"Mononoke is not the source of truth for this repo"
205+
));
206+
}
207+
208+
// Flag for client side expectation of allow non fast forward updates. Git clients by default
209+
// prevent users from pushing non-ffwd updates. If the request reaches the server, then that
210+
// means the client has explicitly requested for a non-ffwd update and the final result will be
211+
// governed by the server side config (ofcourse subject to bypass)
212+
let allow_non_fast_forward = true;
213+
// Actually perform the ref update
214+
let result = set_bookmark(
215+
&ctx,
216+
&repo_context,
217+
&bookmark_operation,
218+
Some(request_context.pushvars.as_ref()),
219+
allow_non_fast_forward,
220+
BookmarkOperationErrorReporting::Plain,
221+
)
222+
.await;
223+
if let Err(err) = result {
224+
anyhow::bail!(update_error(&mappings_store, err).await);
225+
}
226+
// If the bookmark is a tag and the operation is a delete, then we need to remove the tag entry
227+
// from bonsai_tag_mapping table in addition to removing the bookmark entry from bookmarks table
228+
let bookmark_key = &bookmark_operation.bookmark_key;
229+
if bookmark_key.is_tag() && bookmark_operation.is_delete() {
230+
repo.bonsai_tag_mapping()
231+
.delete_mappings_by_name(vec![bookmark_key.name().to_string()])
232+
.await?;
233+
}
234+
// If requested, let's wait for the bookmark move to get reflected in WBC
235+
if request_context.pushvars.wait_for_wbc_update() {
236+
wait_for_bookmark_move(
237+
&ctx,
238+
&repo,
239+
bookmark_key,
240+
bookmark_operation.operation_type.old_changeset(),
241+
)
242+
.await?;
243+
}
244+
Ok(())
245+
}
246+
247+
async fn bookmark_operation(
248+
ctx: &CoreContext,
249+
repo: Arc<Repo>,
250+
mappings_store: Arc<GitMappingsStore>,
251+
object_store: Arc<GitObjectStore>,
252+
ref_update: &RefUpdate,
253+
) -> Result<BookmarkOperation> {
254+
// Check if push redirector is enabled, if it is then reject the push
255+
if push_redirector_enabled(ctx, repo.clone()).await? {
256+
return Err(anyhow::anyhow!(
257+
"Pushes to repo {0} are disallowed because its source of truth has been moved. Use `git pushrebase` or make changes directly in the repo where the source of truth was moved.",
258+
repo.repo_identity().name()
259+
));
260+
}
197261
// Get the bonsai changeset id of the old and the new git commits
198262
let old_changeset = get_bonsai(&mappings_store, &object_store, &ref_update.from).await?;
199263
let new_changeset = get_bonsai(&mappings_store, &object_store, &ref_update.to).await?;
@@ -206,20 +270,14 @@ async fn set_ref_inner(
206270
)?;
207271
let bookmark_operation =
208272
BookmarkOperation::new(bookmark_key.clone(), old_changeset, new_changeset)?;
209-
// Do one final check of SoT to ensure that we don't update the bookmark if the repo is locked or sourced in Metagit
210-
if !mononoke_source_of_truth(&ctx, repo.clone()).await? {
211-
return Err(anyhow::anyhow!(
212-
"Mononoke is not the source of truth for this repo"
213-
));
214-
}
215273
if bookmark_operation.is_create() {
216274
let bookmark_prefix_str = if !bookmark_key.as_str().ends_with("/") {
217275
format!("{bookmark_key}/")
218276
} else {
219277
bookmark_key.to_string()
220278
};
221279
let bookmark_prefix = BookmarkPrefix::from_str(bookmark_prefix_str.as_str())?;
222-
if bookmark_exists_with_prefix(&ctx, &request_context.repo, &bookmark_prefix).await? {
280+
if bookmark_exists_with_prefix(ctx, &repo, &bookmark_prefix).await? {
223281
// reject push
224282
return Err(anyhow::anyhow!(
225283
"Creation of bookmark \"{bookmark_key}\" was blocked because it exists as a path prefix of an existing bookmark",
@@ -229,7 +287,7 @@ async fn set_ref_inner(
229287
let bookmark_prefix_path =
230288
BookmarkKey::from_str(std::str::from_utf8(&bookmark_prefix_path.to_vec())?)?;
231289
// Check if the path ancestors of this bookmark already exist as bookmark in the repo
232-
if get_bookmark_state(&ctx, &request_context.repo, &bookmark_prefix_path)
290+
if get_bookmark_state(ctx, &repo, &bookmark_prefix_path)
233291
.await?
234292
.is_existing()
235293
{
@@ -239,37 +297,7 @@ async fn set_ref_inner(
239297
}
240298
}
241299
}
242-
243-
// Flag for client side expectation of allow non fast forward updates. Git clients by default
244-
// prevent users from pushing non-ffwd updates. If the request reaches the server, then that
245-
// means the client has explicitly requested for a non-ffwd update and the final result will be
246-
// governed by the server side config (ofcourse subject to bypass)
247-
let allow_non_fast_forward = true;
248-
// Actually perform the ref update
249-
let result = set_bookmark(
250-
&ctx,
251-
&repo_context,
252-
&bookmark_operation,
253-
Some(request_context.pushvars.as_ref()),
254-
allow_non_fast_forward,
255-
BookmarkOperationErrorReporting::Plain,
256-
)
257-
.await;
258-
if let Err(err) = result {
259-
anyhow::bail!(update_error(&mappings_store, err).await);
260-
}
261-
// If the bookmark is a tag and the operation is a delete, then we need to remove the tag entry
262-
// from bonsai_tag_mapping table in addition to removing the bookmark entry from bookmarks table
263-
if bookmark_key.is_tag() && bookmark_operation.is_delete() {
264-
repo.bonsai_tag_mapping()
265-
.delete_mappings_by_name(vec![bookmark_key.name().to_string()])
266-
.await?;
267-
}
268-
// If requested, let's wait for the bookmark move to get reflected in WBC
269-
if request_context.pushvars.wait_for_wbc_update() {
270-
wait_for_bookmark_move(&ctx, &repo, &bookmark_key, old_changeset).await?;
271-
}
272-
Ok(())
300+
Ok(bookmark_operation)
273301
}
274302

275303
async fn get_bonsai(

0 commit comments

Comments
 (0)