strip redundant doc comments from signed_core and signed_git
This commit is contained in:
@@ -4,42 +4,28 @@ use nostr::prelude::*;
|
||||
|
||||
use crate::RepoAddr;
|
||||
|
||||
/// Parsed NIP-34 repository announcement, plain data ready for the UI.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Announcement {
|
||||
/// ID of the announcement event itself.
|
||||
pub event_id: EventId,
|
||||
/// Repository ID, the `d` tag.
|
||||
pub id: String,
|
||||
/// Author of the announcement event.
|
||||
pub owner: PublicKey,
|
||||
/// When the announcement was published, used for latest-wins resolution.
|
||||
pub created_at: Timestamp,
|
||||
pub name: Option<String>,
|
||||
pub description: Option<String>,
|
||||
/// Webpage URLs for browsing.
|
||||
pub web: Vec<Url>,
|
||||
/// URLs for `git clone`.
|
||||
pub clone: Vec<Url>,
|
||||
/// Relays the repository monitors for patches and issues.
|
||||
pub relays: Vec<RelayUrl>,
|
||||
/// Earliest unique commit ID, the `r` tag with `euc` marker.
|
||||
pub euc: Option<String>,
|
||||
/// Other recognized maintainers.
|
||||
pub maintainers: Vec<PublicKey>,
|
||||
/// Marks the repository as a subordinate fork of the upstream, per NIP-34.
|
||||
pub upstream: Option<Upstream>,
|
||||
/// Hashtags labelling the repository, the `t` tags.
|
||||
pub hashtags: Vec<String>,
|
||||
}
|
||||
|
||||
/// The `u` tag of a fork announcement, per NIP-34.
|
||||
// The `u` tag of a fork announcement, per NIP-34.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Upstream {
|
||||
/// Raw first value of the `u` tag, a coordinate or git URL.
|
||||
pub raw: String,
|
||||
/// Upstream repository coordinate when the `u` tag names a NIP-34 repository.
|
||||
/// `None` for the git-URL form.
|
||||
// `None` for the git-URL form.
|
||||
pub addr: Option<RepoAddr>,
|
||||
}
|
||||
|
||||
@@ -65,27 +51,20 @@ impl Upstream {
|
||||
}
|
||||
}
|
||||
|
||||
/// Tag accessors for NIP-34 git collaboration events.
|
||||
pub trait GitEvent {
|
||||
/// Subject of an issue or pull request event.
|
||||
fn activity_subject(&self) -> String;
|
||||
|
||||
/// The `c` tag, the tip of the proposed branch, as hex.
|
||||
fn current_commit(&self) -> Option<String>;
|
||||
|
||||
/// The `merge-base` tag, the base commit a pull request diffs against.
|
||||
fn merge_base(&self) -> Option<String>;
|
||||
|
||||
/// The `clone` tag, URLs the tip commit can be fetched from.
|
||||
fn clone_urls(&self) -> Option<Vec<Url>>;
|
||||
|
||||
/// The `branch-name` tag, the proposed branch's name.
|
||||
fn branch_name(&self) -> Option<String>;
|
||||
|
||||
/// Whether the event is git activity worth showing in the activity list.
|
||||
fn is_git_activity(&self) -> bool;
|
||||
|
||||
/// Whether the event carries an `e`/`E` tag pointing at `root`.
|
||||
// Matches both NIP-10 lowercase `e` and NIP-22 uppercase `E` root pointers.
|
||||
fn references_root(&self, root: &EventId) -> bool;
|
||||
}
|
||||
|
||||
@@ -196,7 +175,6 @@ impl<T: GitEvent + ?Sized> GitEvent for &T {
|
||||
}
|
||||
}
|
||||
|
||||
/// A NIP-34 pull request root event, with its patch set and update history.
|
||||
pub struct PullRequest<'a>(pub &'a Event);
|
||||
|
||||
impl<'a> PullRequest<'a> {
|
||||
@@ -204,22 +182,17 @@ impl<'a> PullRequest<'a> {
|
||||
Self(event)
|
||||
}
|
||||
|
||||
/// The patch set of the pull request.
|
||||
///
|
||||
/// Returns an empty list when no patch event can be linked to the PR.
|
||||
// The PR references its root patch via an `e` tag.
|
||||
pub fn patches(&self, patches: impl IntoIterator<Item = &'a Event>) -> Vec<&'a Event> {
|
||||
let pr = self.0;
|
||||
let patches: Vec<&'a Event> = patches.into_iter().collect();
|
||||
|
||||
// The PR references its root patch via an `e` tag.
|
||||
if let Some(root_id) = pr.tags.event_ids().next()
|
||||
&& let Some(root) = patches.iter().find(|patch| patch.id == root_id)
|
||||
{
|
||||
return Self::forward_series(root, &patches);
|
||||
}
|
||||
|
||||
// The PR has no `e` tag.
|
||||
// The last patch of the set carries the tip commit in its `commit` or `r` tag.
|
||||
let Some(tip) = pr.current_commit() else {
|
||||
return Vec::new();
|
||||
};
|
||||
@@ -250,9 +223,7 @@ impl<'a> PullRequest<'a> {
|
||||
series
|
||||
}
|
||||
|
||||
/// The patch set of the pull request joined into one diff text.
|
||||
///
|
||||
/// Falls back to the root event's content when no patch set is found.
|
||||
// Falls back to the root event's content when no patch set is found.
|
||||
pub fn patch(&self, patches: impl IntoIterator<Item = &'a Event>) -> String {
|
||||
let pr = self.0;
|
||||
let patches: Vec<&'a Event> = patches.into_iter().collect();
|
||||
@@ -267,10 +238,8 @@ impl<'a> PullRequest<'a> {
|
||||
.join("\n")
|
||||
}
|
||||
|
||||
/// The newest `GitPullRequestUpdate` revising `root`, from the root's own author.
|
||||
///
|
||||
/// A pull request's tip is only mutable by its author per NIP-34, updates
|
||||
/// from anyone else are ignored even if they are newer.
|
||||
// A pull request's tip is only mutable by its author per NIP-34,
|
||||
// updates from anyone else are ignored even if they are newer.
|
||||
pub fn latest_update(
|
||||
events: impl Iterator<Item = &'a Event>,
|
||||
root: &Event,
|
||||
@@ -287,7 +256,6 @@ impl<'a> PullRequest<'a> {
|
||||
.max_by_key(|e| e.created_at)
|
||||
}
|
||||
|
||||
/// The chain of patches replying to `root` via NIP-10 `e` tags, oldest first.
|
||||
fn forward_series(root: &'a Event, patches: &[&'a Event]) -> Vec<&'a Event> {
|
||||
let mut series = vec![root];
|
||||
loop {
|
||||
@@ -309,9 +277,7 @@ impl<'a> PullRequest<'a> {
|
||||
series
|
||||
}
|
||||
|
||||
/// Whether `patch` produces `commit`, found via its `commit` or `r` tag.
|
||||
///
|
||||
/// It lets clients find existing patches for a specific commit.
|
||||
// Lets clients find existing patches for a specific commit.
|
||||
fn patch_produces_commit(patch: &Event, commit: &str) -> bool {
|
||||
patch
|
||||
.tags
|
||||
@@ -324,9 +290,7 @@ impl<'a> PullRequest<'a> {
|
||||
}
|
||||
|
||||
impl Announcement {
|
||||
/// The announced forks of `base` a new pull request compare can be built from.
|
||||
///
|
||||
/// The user's own forks are listed first.
|
||||
// The user's own forks are listed first.
|
||||
pub fn forks_in<'a>(
|
||||
announcements: &'a [Announcement],
|
||||
base: &RepoAddr,
|
||||
@@ -413,15 +377,11 @@ impl Announcement {
|
||||
RepoAddr::new(self.owner, self.id.clone())
|
||||
}
|
||||
|
||||
/// The name of the repository, or a default if none is provided.
|
||||
pub fn name(&self) -> String {
|
||||
self.name.clone().unwrap_or("Untitled".into())
|
||||
}
|
||||
|
||||
/// Whether this announcement is a fork of the repository at `base`.
|
||||
/// Its `u` tag points at `base`, which also covers permanent forks whose EUC diverged.
|
||||
///
|
||||
/// Or it shares `base`'s earliest unique commit and is not the base itself.
|
||||
// The `u` tag pointing at `base` also covers permanent forks whose EUC diverged.
|
||||
pub fn is_fork_of(&self, base: &RepoAddr, base_euc: Option<&str>) -> bool {
|
||||
if self.addr() == *base {
|
||||
return false;
|
||||
@@ -432,17 +392,14 @@ impl Announcement {
|
||||
base_euc.is_some_and(|euc| self.euc.as_deref() == Some(euc))
|
||||
}
|
||||
|
||||
/// The description of the repository, or a default if none is provided.
|
||||
pub fn description(&self) -> String {
|
||||
self.description
|
||||
.clone()
|
||||
.unwrap_or("No description".to_string())
|
||||
}
|
||||
|
||||
/// The effective maintainers of this repository,
|
||||
/// the announced `maintainers` plus the announcement author.
|
||||
///
|
||||
/// A `u` tag that marks the repository as a subordinate fork excludes them, per NIP-34.
|
||||
// A `u` tag marking the repository as a subordinate fork excludes the
|
||||
// announcement author from the maintainers, per NIP-34.
|
||||
pub fn effective_maintainers(&self) -> Vec<PublicKey> {
|
||||
let mut maintainers = self.maintainers.clone();
|
||||
if self.upstream.is_none() && !maintainers.contains(&self.owner) {
|
||||
@@ -451,7 +408,6 @@ impl Announcement {
|
||||
maintainers
|
||||
}
|
||||
|
||||
/// The `git clone` URLs for this repository, deduplicated.
|
||||
pub fn clone_urls(&self) -> Vec<String> {
|
||||
let mut seen = HashSet::new();
|
||||
self.clone
|
||||
@@ -545,7 +501,6 @@ mod tests {
|
||||
|
||||
let announcement = Announcement::from_event(&event).expect("parses");
|
||||
|
||||
// An invalid URL keeps the whole clone tag from being parsed.
|
||||
assert!(announcement.clone.is_empty());
|
||||
assert_eq!(
|
||||
announcement.relays,
|
||||
@@ -568,8 +523,6 @@ mod tests {
|
||||
let announcement = Announcement::from_event(&event).expect("parses");
|
||||
let upstream = announcement.upstream.expect("parses the u tag");
|
||||
|
||||
// The coordinate part resolves to a repository address.
|
||||
// The raw value keeps the `|git-url` suffix.
|
||||
assert_eq!(
|
||||
upstream.addr,
|
||||
Some(RepoAddr::new(
|
||||
@@ -589,7 +542,6 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn is_fork_of_matches_the_u_tag_coordinate() {
|
||||
// The base repository, announced by the `u` tag's owner.
|
||||
let base = RepoAddr::new(
|
||||
PublicKey::from_hex(MAINTAINER_HEX).expect("valid pubkey"),
|
||||
"upstream",
|
||||
@@ -597,26 +549,20 @@ mod tests {
|
||||
let event = announcement_event(&[&["d", "my-fork"], &["u", &base.to_string()]]);
|
||||
let fork = Announcement::from_event(&event).expect("parses");
|
||||
|
||||
// A `u` tag pointing at the base address marks a fork.
|
||||
// This holds even when neither side announces an EUC.
|
||||
assert!(fork.is_fork_of(&base, None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_fork_of_matches_a_shared_euc() {
|
||||
let euc = "aa231c4c6a5777dc89b42207b499891a344add5c";
|
||||
// The base repo has no `u` tag. It announces the family EUC.
|
||||
let base_event = announcement_event(&[&["d", "upstream"], &["r", euc, "euc"]]);
|
||||
let base = Announcement::from_event(&base_event).expect("parses");
|
||||
let base_addr = base.addr();
|
||||
|
||||
// A fork with no `u` tag, a pure mirror or cross-hosted clone, shares the EUC.
|
||||
// Clients of the family can then find it.
|
||||
let fork_event = announcement_event(&[&["d", "mirror"], &["r", euc, "euc"]]);
|
||||
let fork = Announcement::from_event(&fork_event).expect("parses");
|
||||
assert!(fork.is_fork_of(&base_addr, base.euc.as_deref()));
|
||||
|
||||
// An unrelated repository with a different EUC is not a fork.
|
||||
let other_event = announcement_event(&[
|
||||
&["d", "other"],
|
||||
&["r", "bb231c4c6a5777dc89b42207b499891a344add5c", "euc"],
|
||||
@@ -624,14 +570,11 @@ mod tests {
|
||||
let other = Announcement::from_event(&other_event).expect("parses");
|
||||
assert!(!other.is_fork_of(&base_addr, base.euc.as_deref()));
|
||||
|
||||
// Without a base EUC there is nothing to compare against.
|
||||
assert!(!fork.is_fork_of(&base_addr, None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_fork_of_matches_permanent_forks_with_a_diverged_euc() {
|
||||
// A permanent fork re-announces its EUC, the first commit after the fork.
|
||||
// Only the `u` tag still relates it to the base.
|
||||
let base = RepoAddr::new(
|
||||
PublicKey::from_hex(MAINTAINER_HEX).expect("valid pubkey"),
|
||||
"upstream",
|
||||
@@ -654,8 +597,6 @@ mod tests {
|
||||
let announcement = Announcement::from_event(&event).expect("parses");
|
||||
let maintainers = announcement.effective_maintainers();
|
||||
|
||||
// The owner asserts themselves as a maintainer of the primary project, per NIP-34.
|
||||
// Announced co-maintainers are included too.
|
||||
assert_eq!(maintainers.len(), 2);
|
||||
assert!(maintainers.contains(&announcement.owner));
|
||||
assert!(maintainers.contains(&PublicKey::from_hex(MAINTAINER_HEX).expect("valid pubkey")));
|
||||
@@ -672,8 +613,6 @@ mod tests {
|
||||
let announcement = Announcement::from_event(&event).expect("parses");
|
||||
let maintainers = announcement.effective_maintainers();
|
||||
|
||||
// A `u` tag marks the repository as a subordinate fork.
|
||||
// The author is then not a maintainer of the primary project, per NIP-34.
|
||||
assert!(!maintainers.contains(&announcement.owner));
|
||||
assert_eq!(
|
||||
maintainers,
|
||||
@@ -698,8 +637,6 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn pull_request_patch_joins_the_whole_patch_set() {
|
||||
// A PR references the root patch, per NIP-34.
|
||||
// Later patches of the set reply to the previous one via NIP-10 `e` tags.
|
||||
let root = patch_event("patch-one", vec![], 100);
|
||||
let second = patch_event("patch-two", vec![Tag::event(root.id)], 200);
|
||||
let pr = pr_event("description", vec![Tag::event(root.id)]);
|
||||
@@ -733,8 +670,6 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn pull_request_patches_finds_the_set_via_the_tip_commit() {
|
||||
// PRs without an `e` tag fall back to the patch producing the tip commit.
|
||||
// Walk the reply chain backward to the root.
|
||||
let root = patch_event("patch-one", vec![], 100);
|
||||
let tip = "1111111111111111111111111111111111111111";
|
||||
let last = patch_event(
|
||||
@@ -794,7 +729,6 @@ mod tests {
|
||||
created_at,
|
||||
)
|
||||
};
|
||||
// An update revising a different PR must be ignored even though it is newer.
|
||||
let unrelated = signed_at(
|
||||
Kind::GitPullRequestUpdate,
|
||||
vec![Tag::parse(["E", OTHER_ROOT_HEX]).expect("valid tag")],
|
||||
@@ -822,8 +756,6 @@ mod tests {
|
||||
.finalize(&other)
|
||||
.expect("signed event");
|
||||
|
||||
// The tip of a PR is only mutable by its author.
|
||||
// A newer update from anyone else must not win.
|
||||
assert!(PullRequest::latest_update([&stranger, &root].into_iter(), &root).is_none());
|
||||
}
|
||||
|
||||
@@ -861,8 +793,6 @@ mod tests {
|
||||
PublicKey::from_hex(OWNER_KEYS[0]).expect("pubkey"),
|
||||
"upstream",
|
||||
);
|
||||
// Newest first, as RepoListStore keeps them.
|
||||
// Unrelated repo, the user's fork with the shared EUC, another fork with a `u` tag.
|
||||
let all = vec![
|
||||
owned_announcements(
|
||||
2,
|
||||
@@ -936,7 +866,6 @@ mod tests {
|
||||
assert_eq!(forks.len(), 1);
|
||||
assert_eq!(forks[0].id, "mirror");
|
||||
|
||||
// Without a base EUC only `u`-tag forks match.
|
||||
all.push(
|
||||
owned_announcements(
|
||||
2,
|
||||
|
||||
Reference in New Issue
Block a user