cob: mandatory `Oid` in `CodeLocation`

To make `CodeLocation` reusable across different components, require
that a commit's `Oid` is part of the struct.

An `Oid` is necessary since the `path` can refer to a path at any
point in time throughout the history of the repository. By pinning the
commit that is being referred to, the path will refer to the path
within the associated tree [of the commit].

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
This commit is contained in:
Fintan Halpenny 2023-12-18 13:28:17 +00:00 committed by cloudhead
parent 1f36879aa2
commit 2dea54c6ee
No known key found for this signature in database
5 changed files with 66 additions and 59 deletions

View File

@ -4,7 +4,7 @@ use std::path::Path;
use std::str; use std::str;
use base64::prelude::{Engine, BASE64_STANDARD}; use base64::prelude::{Engine, BASE64_STANDARD};
use radicle::patch::CodeLocation; use radicle::cob::CodeLocation;
use serde_json::{json, Value}; use serde_json::{json, Value};
use radicle::cob::issue::{Issue, IssueId}; use radicle::cob::issue::{Issue, IssueId};

View File

@ -3111,6 +3111,7 @@ mod routes {
} }
], ],
"location": { "location": {
"commit": HEAD,
"path": "README.md", "path": "README.md",
"new": { "new": {
"type": "lines", "type": "lines",
@ -3224,7 +3225,7 @@ mod routes {
"summary": "A small review", "summary": "A small review",
"comments": [ "comments": [
{ {
"id": "b108acfd2117480fd87012a5ab7cb69a0651d933", "id": "2ed1c517997d3f1a83c6830ebab069c6e2ee967e",
"author": { "author": {
"id": "did:key:z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8", "id": "did:key:z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8",
}, },
@ -3272,6 +3273,7 @@ mod routes {
"timestamp": 1671125284, "timestamp": 1671125284,
"replyTo": null, "replyTo": null,
"location": { "location": {
"commit": HEAD,
"path": "README.md", "path": "README.md",
"old": null, "old": null,
"new": { "new": {

View File

@ -1,12 +1,13 @@
use std::fmt; use std::fmt;
use std::fmt::Display; use std::fmt::Display;
use std::ops::Deref; use std::ops::{Deref, Range};
use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
use localtime::LocalTime; use localtime::LocalTime;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::git_ext::Oid; use crate::git::Oid;
use crate::prelude::{Did, PublicKey}; use crate::prelude::{Did, PublicKey};
/// Timestamp used for COB operations. /// Timestamp used for COB operations.
@ -385,3 +386,57 @@ mod test {
Color::from_str("#abc").unwrap_err(); Color::from_str("#abc").unwrap_err();
} }
} }
/// Describes a code location that can be used for comments on
/// patches, issues, and diffs.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CodeLocation {
/// [`Oid`] of the Git commit.
pub commit: Oid,
/// Path of file.
pub path: PathBuf,
/// Line range on old file. `None` for added files.
pub old: Option<CodeRange>,
/// Line range on new file. `None` for deleted files.
pub new: Option<CodeRange>,
}
/// Code range.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", tag = "type")]
pub enum CodeRange {
/// One or more lines.
Lines { range: Range<usize> },
/// Character range within a line.
Chars { line: usize, range: Range<usize> },
}
impl std::cmp::PartialOrd for CodeRange {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl std::cmp::Ord for CodeRange {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match (self, other) {
(CodeRange::Lines { .. }, CodeRange::Chars { .. }) => std::cmp::Ordering::Less,
(CodeRange::Chars { .. }, CodeRange::Lines { .. }) => std::cmp::Ordering::Greater,
(CodeRange::Lines { range: a }, CodeRange::Lines { range: b }) => {
a.clone().cmp(b.clone())
}
(
CodeRange::Chars {
line: l1,
range: r1,
},
CodeRange::Chars {
line: l2,
range: r2,
},
) => l1.cmp(l2).then(r1.clone().cmp(r2.clone())),
}
}
}

View File

@ -2,8 +2,6 @@
use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::collections::{BTreeMap, BTreeSet, HashMap};
use std::fmt; use std::fmt;
use std::ops::Deref; use std::ops::Deref;
use std::ops::Range;
use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
use amplify::Wrapper; use amplify::Wrapper;
@ -14,7 +12,7 @@ use storage::RepositoryError;
use thiserror::Error; use thiserror::Error;
use crate::cob; use crate::cob;
use crate::cob::common::{Author, Authorization, Label, Reaction, Timestamp}; use crate::cob::common::{Author, Authorization, CodeLocation, Label, Reaction, Timestamp};
use crate::cob::store::Transaction; use crate::cob::store::Transaction;
use crate::cob::store::{Cob, CobAction}; use crate::cob::store::{Cob, CobAction};
use crate::cob::thread; use crate::cob::thread;
@ -1408,57 +1406,6 @@ impl fmt::Display for Verdict {
} }
} }
/// Code range.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", tag = "type")]
pub enum CodeRange {
/// One or more lines.
Lines { range: Range<usize> },
/// Character range within a line.
Chars { line: usize, range: Range<usize> },
}
impl std::cmp::PartialOrd for CodeRange {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl std::cmp::Ord for CodeRange {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match (self, other) {
(CodeRange::Lines { .. }, CodeRange::Chars { .. }) => std::cmp::Ordering::Less,
(CodeRange::Chars { .. }, CodeRange::Lines { .. }) => std::cmp::Ordering::Greater,
(CodeRange::Lines { range: a }, CodeRange::Lines { range: b }) => {
a.clone().cmp(b.clone())
}
(
CodeRange::Chars {
line: l1,
range: r1,
},
CodeRange::Chars {
line: l2,
range: r2,
},
) => l1.cmp(l2).then(r1.clone().cmp(r2.clone())),
}
}
}
/// Code location, used for attaching comments to diffs.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CodeLocation {
/// Path of file.
pub path: PathBuf,
/// Line range on old file. `None` for added files.
pub old: Option<CodeRange>,
/// Line range on new file. `None` for deleted files.
pub new: Option<CodeRange>,
}
/// A patch review on a revision. /// A patch review on a revision.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct Review { pub struct Review {
@ -2351,12 +2298,14 @@ where
#[cfg(test)] #[cfg(test)]
#[allow(clippy::unwrap_used)] #[allow(clippy::unwrap_used)]
mod test { mod test {
use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
use std::vec; use std::vec;
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use super::*; use super::*;
use crate::cob::common::CodeRange;
use crate::cob::test::Actor; use crate::cob::test::Actor;
use crate::crypto::test::signer::MockSigner; use crate::crypto::test::signer::MockSigner;
use crate::identity; use crate::identity;
@ -2784,6 +2733,7 @@ mod test {
let (rid, _) = patch.latest(); let (rid, _) = patch.latest();
let location = CodeLocation { let location = CodeLocation {
commit: branch.oid,
path: PathBuf::from_str("README").unwrap(), path: PathBuf::from_str("README").unwrap(),
old: None, old: None,
new: Some(CodeRange::Lines { range: 5..8 }), new: Some(CodeRange::Lines { range: 5..8 }),

View File

@ -1,6 +1,6 @@
//! Logging module. //! Logging module.
//! //!
//! For test logging see [`test`]. //! For test logging see [`mod@test`].
#[cfg(feature = "test")] #[cfg(feature = "test")]
pub mod test; pub mod test;