apiserver: implement SourceControlService repo_resolve_bookmark

Summary:
Implement the `repo_resolve_bookmark` call, which resolves a bookmark in a repo
to the commits that the bookmark points to.

Reviewed By: krallin

Differential Revision: D17157498

fbshipit-source-id: e7e53df2cb9e3efaddcd22a8d0db344a8d279f08
This commit is contained in:
Mark Thomas 2019-09-09 04:20:51 -07:00 committed by Facebook Github Bot
parent 121a66da8b
commit 879c6d9900
3 changed files with 110 additions and 1 deletions

View File

@ -4,10 +4,11 @@
// This software may be used and distributed according to the terms of the
// GNU General Public License version 2 or any later version.
use std::collections::{BTreeMap, BTreeSet};
use std::sync::Arc;
use async_trait::async_trait;
use mononoke_api::{CoreContext, Mononoke};
use mononoke_api::{ChangesetContext, CoreContext, Mononoke, MononokeError};
use scuba_ext::ScubaSampleBuilder;
use slog::Logger;
use source_control::server::SourceControlService;
@ -29,6 +30,12 @@ trait ScubaInfoProvider {
}
}
impl ScubaInfoProvider for thrift::RepoSpecifier {
fn scuba_reponame(&self) -> Option<String> {
Some(self.name.clone())
}
}
#[derive(Clone)]
pub struct SourceControlServiceImpl {
mononoke: Arc<Mononoke>,
@ -74,6 +81,39 @@ impl SourceControlServiceImpl {
}
}
/// Generate a mapping for a commit's identity into the requested identity
/// schemes.
async fn map_commit_identity(
changeset_ctx: &ChangesetContext,
schemes: &BTreeSet<thrift::CommitIdentityScheme>,
) -> Result<BTreeMap<thrift::CommitIdentityScheme, thrift::CommitId>, MononokeError> {
let mut ids = BTreeMap::new();
ids.insert(
thrift::CommitIdentityScheme::BONSAI,
thrift::CommitId::bonsai(changeset_ctx.id().as_ref().into()),
);
if schemes.contains(&thrift::CommitIdentityScheme::HG) {
if let Some(hg_cs_id) = changeset_ctx.hg_id().await? {
ids.insert(
thrift::CommitIdentityScheme::HG,
thrift::CommitId::hg(hg_cs_id.as_ref().into()),
);
}
}
Ok(ids)
}
mod errors {
use super::thrift;
pub(super) fn repo_not_found(reponame: impl AsRef<str>) -> thrift::RequestError {
thrift::RequestError {
kind: thrift::RequestErrorKind::REPO_NOT_FOUND,
reason: format!("repo not found ({})", reponame.as_ref()),
}
}
}
#[async_trait]
impl SourceControlService for SourceControlServiceImpl {
async fn list_repos(
@ -90,4 +130,33 @@ impl SourceControlService for SourceControlServiceImpl {
.collect();
Ok(rsp)
}
/// Resolve a bookmark to a changeset.
///
/// Returns whether the bookmark exists, and the IDs of the changeset in
/// the requested indentity schemes.
async fn repo_resolve_bookmark(
&self,
repo: thrift::RepoSpecifier,
params: thrift::RepoResolveBookmarkParams,
) -> Result<thrift::RepoResolveBookmarkResponse, service::RepoResolveBookmarkExn> {
let ctx = self.create_ctx(Some(&repo));
let repo = self
.mononoke
.repo(ctx, &repo.name)?
.ok_or_else(|| errors::repo_not_found(&repo.name))?;
match repo.resolve_bookmark(params.bookmark_name).await? {
Some(cs) => {
let ids = map_commit_identity(&cs, &params.identity_schemes).await?;
Ok(thrift::RepoResolveBookmarkResponse {
exists: true,
ids: Some(ids),
})
}
None => Ok(thrift::RepoResolveBookmarkResponse {
exists: false,
ids: None,
}),
}
}
}

View File

@ -9,6 +9,7 @@ use std::sync::Arc;
use blobrepo::BlobRepo;
use blobrepo_factory::{open_blobrepo, Caching};
use blobstore::Blobstore;
use bookmarks::BookmarkName;
use context::CoreContext;
use derive_unode_manifest::derived_data_unodes::RootUnodeManifestMapping;
use failure::Error;
@ -131,6 +132,21 @@ impl RepoContext {
Ok(id)
}
/// Resolve a bookmark to a changeset.
pub async fn resolve_bookmark(
&self,
bookmark: impl ToString,
) -> Result<Option<ChangesetContext>, MononokeError> {
let bookmark = BookmarkName::new(bookmark.to_string())?;
let cs_id = self
.repo
.blob_repo
.get_bonsai_bookmark(self.ctx.clone(), &bookmark)
.compat()
.await?;
Ok(cs_id.map(|cs_id| ChangesetContext::new(self.clone(), cs_id)))
}
/// Look up a changeset by specifier.
pub async fn changeset(
&self,

View File

@ -58,3 +58,27 @@ async fn commit_info_by_hg_hash() -> Result<(), Error> {
Ok(())
}
#[tokio::test]
async fn commit_info_by_bookmark() -> Result<(), Error> {
let mononoke = Mononoke::new_test(vec![("test".to_string(), linear::getrepo())]);
let ctx = CoreContext::test_mock();
let repo = mononoke.repo(ctx, "test")?.expect("repo exists");
let cs = repo
.resolve_bookmark("master")
.await?
.expect("bookmark exists");
let hash = "7785606eb1f26ff5722c831de402350cf97052dc44bc175da6ac0d715a3dbbf6";
assert_eq!(cs.id(), ChangesetId::from_str(hash)?);
let hg_hash = "79a13814c5ce7330173ec04d279bf95ab3f652fb";
assert_eq!(cs.hg_id().await?, Some(HgChangesetId::from_str(hg_hash)?));
assert_eq!(cs.message().await?, "modified 10");
assert_eq!(cs.author().await?, "Jeremy Fitzhardinge <jsgf@fb.com>");
assert_eq!(
cs.author_date().await?,
FixedOffset::west(7 * 3600).timestamp(1504041761, 0)
);
Ok(())
}