cobs: Fix COB drafts to work correctly

This commit is contained in:
Alexis Sellier 2024-09-30 13:57:09 +02:00 committed by cloudhead
parent e130b4dc06
commit 729a6e057e
No known key found for this signature in database
5 changed files with 51 additions and 68 deletions

View File

@ -635,11 +635,7 @@ impl<'a, G: Signer> ReviewBuilder<'a, G> {
Brain::new(self.patch_id, signer.public_key(), base, repo)?
};
let diff = self.diff(&brain.accepted, &tree, repo, opts)?;
let drafts = DraftStore::new(*signer.public_key(), self.repo).with(
signer.public_key(),
&cob::patch::TYPENAME,
&patch_id,
)?;
let drafts = DraftStore::new(self.repo, *signer.public_key());
let mut patches = cob::patch::Cache::no_cache(&drafts)?;
let mut patch = patches.get_mut(&patch_id)?;
let mut queue = ReviewQueue::from(diff);

View File

@ -10,7 +10,7 @@ pub enum Create {
Evaluate(Box<dyn std::error::Error + Send + Sync + 'static>),
#[error(transparent)]
CreateChange(#[from] git::change::error::Create),
#[error("failed to updated references for during object creation")]
#[error("failed to updated references for during object creation: {err}")]
Refs {
#[source]
err: Box<dyn std::error::Error + Send + Sync + 'static>,
@ -40,7 +40,7 @@ pub enum Retrieve {
Evaluate(Box<dyn std::error::Error + Send + Sync + 'static>),
#[error(transparent)]
Git(#[from] git2::Error),
#[error("failed to get references during object retrieval")]
#[error("failed to get references during object retrieval: {err}")]
Refs {
#[source]
err: Box<dyn std::error::Error + Send + Sync + 'static>,
@ -63,7 +63,7 @@ pub enum Update {
NoSuchObject,
#[error(transparent)]
CreateChange(#[from] git::change::error::Create),
#[error("failed to get references during object update")]
#[error("failed to get references during object update: {err}")]
Refs {
#[source]
err: Box<dyn std::error::Error + Send + Sync + 'static>,

View File

@ -3208,7 +3208,12 @@ mod test {
let alice = test::setup::NodeWithRepo::default();
let checkout = alice.repo.checkout();
let branch = checkout.branch_with([("README", b"Hello World!")]);
let mut patches = Cache::no_cache(&*alice.repo).unwrap();
let mut patches = {
let path = alice.tmp.path().join("cobs.db");
let db = cob::cache::Store::open(path).unwrap();
let store = cob::patch::Patches::open(&*alice.repo).unwrap();
cob::patch::Cache::open(store, db)
};
let mut patch = patches
.create(
"My first patch",

View File

@ -324,18 +324,15 @@ pub mod refs {
.with_namespace(remote.into())
}
/// Draft collaborative objects of a type.
/// All draft collaborative object, identified by `typename` and `object_id`, for all remotes.
///
/// `refs/namespaces/<remote>/refs/drafts/cobs/<typename>/*`
/// `refs/namespaces/*/refs/drafts/cobs/<typename>/<object_id>`
///
pub fn cobs(remote: &RemoteId, typename: &cob::TypeName) -> PatternString {
Qualified::from_components(
component!("drafts"),
component!("cobs"),
Some(Component::from(typename)),
)
.with_namespace(remote.into())
.to_pattern(refspec::pattern!("*"))
pub fn cobs(typename: &cob::TypeName, object_id: &cob::ObjectId) -> PatternString {
refspec::pattern!("refs/namespaces/*")
.join(refname!("refs/drafts/cobs"))
.join(Component::from(typename))
.join(Component::from(object_id))
}
}

View File

@ -32,6 +32,8 @@ pub enum ObjectsError {
Convert(#[from] cob::object::storage::convert::Error),
#[error(transparent)]
Git(#[from] git2::Error),
#[error(transparent)]
GitExt(#[from] git_ext::Error),
}
#[derive(Error, Debug)]
@ -178,38 +180,13 @@ impl cob::object::Storage for Repository {
// which allows for some of the features needed for code review. For
// example, users can draft comments and later decide to publish them.
pub struct DraftStore<'a, R> {
remote: RemoteId,
repo: &'a R,
}
impl<'a, R: storage::WriteRepository> DraftStore<'a, R> {
/// Create this draft store with an existing COB from storage, so that changes applied
/// to this COB can evaluate properly. This creates a symbolic reference to the COB
/// pointing to the public COB reference.
pub fn with(
self,
remote: &RemoteId,
typename: &cob::TypeName,
id: &ObjectId,
) -> Result<Self, git::Error> {
let target = git::refs::storage::cob(remote, typename, id);
let name = git::refs::storage::draft::cob(remote, typename, id);
let repo = self.repo.raw();
repo.reference_symbolic(
name.as_str(),
target.as_str(),
true, // The reference may already exist, overwrite it if so.
format!("Link to COB {id} of type {typename}").as_str(),
)?;
Ok(self)
}
remote: RemoteId,
}
impl<'a, R> DraftStore<'a, R> {
pub fn new(remote: RemoteId, repo: &'a R) -> Self {
Self { remote, repo }
pub fn new(repo: &'a R, remote: RemoteId) -> Self {
Self { repo, remote }
}
}
@ -398,33 +375,41 @@ impl<'a, R: storage::WriteRepository> cob::object::Storage for DraftStore<'a, R>
typename: &cob::TypeName,
object_id: &cob::ObjectId,
) -> Result<cob::object::Objects, Self::ObjectsError> {
// Nb. There can only be one draft per COB, per remote.
let Ok(r) = self.repo.raw().find_reference(
git::refs::storage::draft::cob(&self.remote, typename, object_id).as_str(),
) else {
return Ok(Objects::default());
};
let r = cob::object::Reference::try_from(r).map_err(Self::ObjectsError::from)?;
let mut objs = Objects::default();
Ok(Objects::new(r))
// First get the signed COB tips of all remotes for this object.
let signed = self
.repo
.references_glob(&git::refs::storage::cobs(typename, object_id))?;
for (r, id) in signed {
let r = cob::object::Reference {
name: r.to_ref_string(),
target: cob::object::Commit { id },
};
objs.push(r);
}
// Then get the draft COB tip that belongs to us only, if any.
let draft_ref = &git::refs::storage::draft::cob(&self.remote, typename, object_id);
if let Ok(draft_oid) = self
.repo
.reference_oid(&self.remote, &draft_ref.strip_namespace())
{
objs.push(cob::object::Reference {
name: draft_ref.to_ref_string(),
target: cob::object::Commit { id: draft_oid },
})
}
Ok(objs)
}
fn types(
&self,
typename: &cob::TypeName,
_typename: &cob::TypeName,
) -> Result<BTreeMap<cob::ObjectId, cob::object::Objects>, Self::TypesError> {
let glob = git::refs::storage::draft::cobs(&self.remote, typename);
let references = self.repo.references_glob(&glob)?;
let mut objs = BTreeMap::new();
for (name, id) in references {
let r = cob::object::Reference {
name: name.into_refstring(),
target: cob::object::Commit { id },
};
objs.insert(id.into(), Objects::new(r));
}
Ok(objs)
unimplemented!()
}
fn update(