strip redundant doc comments from signed_core and signed_git
This commit is contained in:
+35
-147
@@ -21,74 +21,41 @@ use crate::checkouts::CheckoutsStore;
|
||||
use crate::push::{GraspPush, PushOutcome, grasp_base_url, grasp06_prs_url, pr_clone_urls};
|
||||
use crate::repos::RepoListStore;
|
||||
|
||||
/// Maximum size of one patch event.
|
||||
///
|
||||
/// NIP-34 suggests patches when each event is under 60kb.
|
||||
// NIP-34 suggests patches when each event is under 60kb.
|
||||
const MAX_PATCH_EVENT_BYTES: usize = 60 * 1024;
|
||||
|
||||
/// Per-repository store.
|
||||
///
|
||||
/// Holds the announcement, state, issues, patches, PRs, comments and resolved statuses.
|
||||
pub struct RepoStore {
|
||||
/// NIP-34 address. `None` while the repository is local-only.
|
||||
addr: Option<RepoAddr>,
|
||||
/// Latest announcement. Seeded from the open-time hint, replaced by the
|
||||
/// database's latest on the first pass. `None` while local-only.
|
||||
// Seeded from the open-time hint, replaced by the database's latest on the
|
||||
// first pass. `None` while local-only.
|
||||
pub announcement: Option<Announcement>,
|
||||
/// Local working copy. The scan path for a local repository, kept when it is
|
||||
/// later announced so the panel keeps its worktree.
|
||||
// The scan path for a local repository, kept when it is later announced so
|
||||
// the panel keeps its worktree.
|
||||
pub path: Option<PathBuf>,
|
||||
/// NIP-34 state detected on disk for a local repository, if any.
|
||||
pub nip34: Option<Nip34Binding>,
|
||||
/// The first local pass has been applied.
|
||||
///
|
||||
/// Views distinguish "no data yet" from a genuinely empty repository with it.
|
||||
// Views distinguish "no data yet" from a genuinely empty repository with it.
|
||||
pub loaded: bool,
|
||||
/// Branch pointed to by `HEAD` in the latest state announcement.
|
||||
pub head: Option<String>,
|
||||
pub issues: Vec<Event>,
|
||||
pub patches: Vec<Event>,
|
||||
pub pull_requests: Vec<Event>,
|
||||
/// Comments on issues / PRs, oldest first.
|
||||
pub comments: Vec<Event>,
|
||||
/// Resolved status per root event, issue, patch or PR.
|
||||
status_by_root: HashMap<EventId, RepoStatus>,
|
||||
/// Open issue and root PR counts.
|
||||
/// Computed with [`Self::status_by_root`] on every refresh.
|
||||
open_issue_count: usize,
|
||||
open_pr_count: usize,
|
||||
pub last_error: Option<String>,
|
||||
/// Non-fatal warning of the last action, if any.
|
||||
///
|
||||
/// Example, a PR published without its commit reaching a grasp server.
|
||||
pub last_warning: Option<String>,
|
||||
/// Warning of the last push that only some grasp servers accepted.
|
||||
///
|
||||
/// The repository is out of sync on the rejected servers until it is republished.
|
||||
// The repository is out of sync on the rejected servers until republished.
|
||||
pub last_push_warning: Option<String>,
|
||||
/// A republish or a checkout push is in flight.
|
||||
///
|
||||
/// Views show a spinner and disable their push triggers while it is set.
|
||||
pub pushing: bool,
|
||||
/// A clone-into-a-folder operation is in flight.
|
||||
///
|
||||
/// Views show a spinner and disable the clone trigger while it is set.
|
||||
pub cloning: bool,
|
||||
/// Relays already asked to connect to, from this repository's NIP-34 `relays` tag.
|
||||
///
|
||||
/// Avoids re-subscribing and re-fetching on every refresh.
|
||||
// Avoids re-subscribing and re-fetching on every refresh.
|
||||
repo_relays: HashSet<RelayUrl>,
|
||||
/// Root events, issues, patches and PRs, already fetched per root.
|
||||
///
|
||||
/// The per-root fetches cover NIP-22 comments and statuses without an `a` tag.
|
||||
// Covers NIP-22 comments and statuses without an `a` tag.
|
||||
root_fetches: HashSet<EventId>,
|
||||
/// Maintainers already synced through gossip in Uncensored mode.
|
||||
///
|
||||
/// Avoids re-running the maintainer Auto sync on every refresh.
|
||||
synced_maintainers: HashSet<PublicKey>,
|
||||
/// In-flight tasks, cancelled when the store drops.
|
||||
// In-flight tasks, cancelled when the store drops.
|
||||
tasks: Vec<Task<Result<(), Error>>>,
|
||||
/// Backend subscription of an announced repository. `None` while local-only.
|
||||
_subscription: Option<Subscription>,
|
||||
}
|
||||
|
||||
@@ -141,7 +108,6 @@ impl RepoStore {
|
||||
}
|
||||
}
|
||||
|
||||
/// Local repository discovered by the scan, not announced to NIP-34 yet.
|
||||
pub fn new_local(path: PathBuf, nip34: Option<Nip34Binding>) -> Self {
|
||||
Self {
|
||||
addr: None,
|
||||
@@ -170,7 +136,6 @@ impl RepoStore {
|
||||
}
|
||||
}
|
||||
|
||||
/// An announced repository whose working copy is already on disk.
|
||||
pub fn from_worktree(
|
||||
addr: RepoAddr,
|
||||
announcement: Announcement,
|
||||
@@ -182,7 +147,6 @@ impl RepoStore {
|
||||
store
|
||||
}
|
||||
|
||||
/// Switch a local repository to its NIP-34 mode, keeping its path.
|
||||
pub fn announce(&mut self, announcement: Announcement, cx: &mut Context<Self>) {
|
||||
self.addr = Some(announcement.addr());
|
||||
self.announcement = Some(announcement.clone());
|
||||
@@ -235,7 +199,6 @@ impl RepoStore {
|
||||
self.addr.as_ref()
|
||||
}
|
||||
|
||||
/// Returns the repository's name, or `Unknown` when not known.
|
||||
pub fn name(&self) -> SharedString {
|
||||
self.announcement
|
||||
.as_ref()
|
||||
@@ -244,9 +207,6 @@ impl RepoStore {
|
||||
})
|
||||
}
|
||||
|
||||
/// Filters that make up a repository.
|
||||
///
|
||||
/// Announcement, state, activity and deletions targeting it.
|
||||
fn repo_filters(addr: &RepoAddr) -> Vec<Filter> {
|
||||
let mut filters = vec![
|
||||
Filter::new()
|
||||
@@ -255,12 +215,11 @@ impl RepoStore {
|
||||
.identifier(addr.identifier()),
|
||||
addr.activity_filter(),
|
||||
];
|
||||
// Deletion requests, NIP-09/62, must be known before any event is shown.
|
||||
// Deletion requests must be known before any event is shown.
|
||||
filters.extend(addr.deletion_filters());
|
||||
filters
|
||||
}
|
||||
|
||||
/// Fetch this repository's events from the relays in its NIP-34 `relays` tag.
|
||||
fn connect_announced_relays(&mut self, relays: &[RelayUrl], cx: &mut Context<Self>) {
|
||||
let Some(addr) = self.addr.clone() else {
|
||||
return;
|
||||
@@ -285,39 +244,33 @@ impl RepoStore {
|
||||
});
|
||||
}
|
||||
|
||||
/// Filters the SDK resolves through NIP-65 gossip in Uncensored mode.
|
||||
// NIP-34 events tag the announcement author, which may not be a
|
||||
// maintainer for subordinate forks.
|
||||
fn maintainer_filters(addr: &RepoAddr, maintainers: &[PublicKey]) -> Vec<Filter> {
|
||||
let mut pubkeys = maintainers.to_vec();
|
||||
// NIP-34 events tag the announcement author,
|
||||
// which may not be a maintainer for subordinate forks.
|
||||
if !pubkeys.contains(&addr.public_key()) {
|
||||
pubkeys.push(addr.public_key());
|
||||
}
|
||||
|
||||
vec![
|
||||
// Announcement and state events, including co-maintainer states.
|
||||
Filter::new()
|
||||
.kinds([Kind::GitRepoAnnouncement, Kind::RepoState])
|
||||
.authors(pubkeys.clone())
|
||||
.identifier(addr.identifier()),
|
||||
// Activity tagging a maintainer, resolved to their read relays.
|
||||
Filter::new()
|
||||
.kinds(filters::ACTIVITY_KINDS)
|
||||
.coordinate(addr.coordinate())
|
||||
.pubkeys(pubkeys.clone()),
|
||||
// Activity authored by a maintainer, resolved to their write relays.
|
||||
Filter::new()
|
||||
.kinds(filters::ACTIVITY_KINDS)
|
||||
.coordinate(addr.coordinate())
|
||||
.authors(pubkeys.clone()),
|
||||
// Deletions authored by a maintainer.
|
||||
Filter::new()
|
||||
.kinds([Kind::EventDeletion, Kind::RequestToVanish])
|
||||
.authors(pubkeys),
|
||||
]
|
||||
}
|
||||
|
||||
/// In Uncensored mode, sync the maintainer-shaped filters through the SDK's NIP-65 gossip targeting
|
||||
fn sync_maintainer_relays(&mut self, maintainers: &[PublicKey], cx: &mut Context<Self>) {
|
||||
let strategy = SettingsStore::try_global(cx)
|
||||
.map(|store| store.read(cx).settings().event_fetching)
|
||||
@@ -358,7 +311,6 @@ impl RepoStore {
|
||||
});
|
||||
}
|
||||
|
||||
/// Re-query the local database and update all fields.
|
||||
pub fn refresh(&mut self, cx: &mut Context<Self>) {
|
||||
if self.addr.is_none() {
|
||||
return;
|
||||
@@ -531,7 +483,6 @@ impl RepoStore {
|
||||
this.announcement = announcement;
|
||||
}
|
||||
|
||||
// The announcement may list relays for this repository's activity.
|
||||
let relays = this
|
||||
.announcement
|
||||
.as_ref()
|
||||
@@ -540,7 +491,6 @@ impl RepoStore {
|
||||
|
||||
this.connect_announced_relays(&relays, cx);
|
||||
|
||||
// Uncensored mode also covers the maintainers' NIP-65 relays.
|
||||
let maintainers = this
|
||||
.announcement
|
||||
.as_ref()
|
||||
@@ -602,22 +552,18 @@ impl RepoStore {
|
||||
self.tasks.push(task);
|
||||
}
|
||||
|
||||
/// Resolve the status of a root event, an issue, patch or PR, per NIP-34.
|
||||
pub fn status_of(&self, root: &Event) -> RepoStatus {
|
||||
status_of(&self.status_by_root, root)
|
||||
}
|
||||
|
||||
/// Number of open issues.
|
||||
pub fn issue_count(&self) -> usize {
|
||||
self.open_issue_count
|
||||
}
|
||||
|
||||
/// Number of open pull requests.
|
||||
pub fn pull_request_count(&self) -> usize {
|
||||
self.open_pr_count
|
||||
}
|
||||
|
||||
/// Whether `user` is the author or owner of this repository.
|
||||
pub fn is_author(&self, user: &PublicKey) -> bool {
|
||||
self.addr
|
||||
.as_ref()
|
||||
@@ -647,14 +593,10 @@ impl RepoStore {
|
||||
.filter(move |e| e.references_root(root))
|
||||
}
|
||||
|
||||
/// Comment on a root event, an issue or PR, per NIP-34, kind 1111.
|
||||
pub fn comment(&mut self, root: &Event, content: String, cx: &mut Context<Self>) {
|
||||
self.reply(root, None, content, cx);
|
||||
}
|
||||
|
||||
/// Reply to `parent`, a comment on `root`, with a NIP-22 threaded comment.
|
||||
///
|
||||
/// `None` publishes a top-level comment on the root itself.
|
||||
fn reply(
|
||||
&mut self,
|
||||
root: &Event,
|
||||
@@ -710,8 +652,8 @@ impl RepoStore {
|
||||
return;
|
||||
}
|
||||
|
||||
// The tip of the series is its last commit.
|
||||
// `git format-patch` orders patches oldest first.
|
||||
// The tip of the series is its last commit; `git format-patch` orders
|
||||
// patches oldest first.
|
||||
let Some(current_commit) = series.tip_commit() else {
|
||||
self.last_error = Some(
|
||||
"Patch must be `git format-patch` output with a `From <commit-id>` header".into(),
|
||||
@@ -731,7 +673,6 @@ impl RepoStore {
|
||||
cx.notify();
|
||||
return;
|
||||
};
|
||||
// The author's npub names their GRASP-06 namespace, `/prs/...`.
|
||||
let author_npub = user.to_bech32().unwrap();
|
||||
|
||||
let owner = addr.public_key();
|
||||
@@ -762,8 +703,6 @@ impl RepoStore {
|
||||
};
|
||||
|
||||
let task: Task<Result<(), Error>> = cx.spawn(async move |this, cx| {
|
||||
// The PR references the root patch,
|
||||
// viewers can then find the patch without carrying it inline.
|
||||
let root_patch = match publish_patch_series(
|
||||
&client,
|
||||
&signer,
|
||||
@@ -785,11 +724,10 @@ impl RepoStore {
|
||||
}
|
||||
};
|
||||
|
||||
// GRASP-06 pushes the tip to the author's own grasp servers.
|
||||
// The path is `/prs/<author-npub>/<repo-id>.git`.
|
||||
// Contributing to another project never depends on that project's servers.
|
||||
// Resolve the servers from the author's latest kind-10317 grasp list.
|
||||
// The settings defaults stand in when no list is published or the query fails.
|
||||
// GRASP-06 pushes the tip to the author's own grasp servers at
|
||||
// `/prs/<author-npub>/<repo-id>.git`; contributing to another
|
||||
// project never depends on that project's servers. Resolve the
|
||||
// servers from the author's latest kind-10317 grasp list.
|
||||
let author_servers = {
|
||||
let query_client = client.clone();
|
||||
let published = cx
|
||||
@@ -866,7 +804,6 @@ impl RepoStore {
|
||||
}
|
||||
})?;
|
||||
|
||||
// Sign before publishing.
|
||||
let event = cx
|
||||
.background_spawn({
|
||||
let signer = signer.clone();
|
||||
@@ -883,7 +820,6 @@ impl RepoStore {
|
||||
let path = path.clone();
|
||||
let tip = tip.clone();
|
||||
let reference = reference.clone();
|
||||
// Author servers first, then the announced base grasp servers.
|
||||
let targets: Vec<(String, String)> = author_targets
|
||||
.into_iter()
|
||||
.chain(base_targets)
|
||||
@@ -933,8 +869,6 @@ impl RepoStore {
|
||||
}
|
||||
};
|
||||
|
||||
// A draft PR carries a kind-1633 status event, NIP-34.
|
||||
// Publish it right after the PR event so viewers never show it open.
|
||||
if draft {
|
||||
this.update(cx, |this, cx| {
|
||||
this.set_status(&pr_event, RepoStatus::Draft, cx);
|
||||
@@ -946,12 +880,6 @@ impl RepoStore {
|
||||
self.tasks.push(task);
|
||||
}
|
||||
|
||||
/// Generate the patch between `merge_base` and `compare_ref` in `repo_path`,
|
||||
/// then open a pull request from it.
|
||||
///
|
||||
/// Fails descriptively when there are no commits to propose or the patch
|
||||
/// could not be generated; otherwise publishes exactly like
|
||||
/// [`Self::open_pull_request`].
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn open_pull_request_from_refs(
|
||||
&mut self,
|
||||
@@ -965,8 +893,8 @@ impl RepoStore {
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<(), Error>> {
|
||||
cx.spawn(async move |this, cx| {
|
||||
// Regenerate the series at submit time.
|
||||
// The published patch covers the current tip of the compare branch.
|
||||
// Regenerate at submit time so the published patch covers the
|
||||
// current tip of the compare branch.
|
||||
let patch = cx
|
||||
.background_spawn({
|
||||
let repo_path = repo_path.clone();
|
||||
@@ -999,9 +927,6 @@ impl RepoStore {
|
||||
})
|
||||
}
|
||||
|
||||
/// Update a pull request.
|
||||
///
|
||||
/// Other authors must open a new PR.
|
||||
pub fn update_pull_request(&mut self, root: &Event, patch: String, cx: &mut Context<Self>) {
|
||||
self.last_error = None;
|
||||
self.last_warning = None;
|
||||
@@ -1034,7 +959,7 @@ impl RepoStore {
|
||||
return;
|
||||
}
|
||||
|
||||
// The new tip of the PR is the last commit of the series.
|
||||
// The tip of the updated PR is the last commit of the series.
|
||||
let Some(current_commit) = series.tip_commit() else {
|
||||
self.last_error = Some(
|
||||
"Patch must be `git format-patch` output with a `From <commit-id>` header".into(),
|
||||
@@ -1043,8 +968,8 @@ impl RepoStore {
|
||||
return;
|
||||
};
|
||||
|
||||
// The first revision patch replies to the original root patch, NIP-34.
|
||||
// Use the PR's `e` tag, or the oldest patch of the linked set if the PR has none.
|
||||
// The first revision patch replies to the original root patch, NIP-34:
|
||||
// use the PR's `e` tag, or the oldest patch of the linked set.
|
||||
let root_patch_id = root.tags.event_ids().next().or_else(|| {
|
||||
PullRequest::new(root)
|
||||
.patches(self.patches.iter())
|
||||
@@ -1097,8 +1022,8 @@ impl RepoStore {
|
||||
}
|
||||
.into_event_builder();
|
||||
|
||||
// The `r` EUC tag lets clients subscribe to all PR updates.
|
||||
// The SDK builder omits it.
|
||||
// The `r` EUC tag lets clients subscribe to all PR updates; the
|
||||
// SDK builder omits it.
|
||||
match euc.as_deref() {
|
||||
Some(euc) => builder.tag(Tag::parse(["r", euc]).expect("valid r tag")),
|
||||
None => builder,
|
||||
@@ -1122,9 +1047,6 @@ impl RepoStore {
|
||||
self.tasks.push(task);
|
||||
}
|
||||
|
||||
/// Set the status of a root event.
|
||||
///
|
||||
/// Only the root author or a maintainer may set it, per NIP-34.
|
||||
fn set_status(&mut self, root: &Event, status: RepoStatus, cx: &mut Context<Self>) {
|
||||
self.last_error = None;
|
||||
|
||||
@@ -1166,8 +1088,6 @@ impl RepoStore {
|
||||
self.publish(builder, cx);
|
||||
}
|
||||
|
||||
/// The latest announcement of this repository,
|
||||
/// for operations that need its clone URLs and relays.
|
||||
fn action_announcement(&self, cx: &App) -> Option<Announcement> {
|
||||
let addr = self.addr.as_ref()?;
|
||||
self.announcement.clone().or_else(|| {
|
||||
@@ -1227,11 +1147,6 @@ impl RepoStore {
|
||||
self.run_push(push, Some((addr, path)), cx)
|
||||
}
|
||||
|
||||
/// Run a backend push task, tracking progress in [`Self::pushing`] and
|
||||
/// the outcome in [`Self::last_error`] and [`Self::last_push_warning`].
|
||||
///
|
||||
/// `pushed_checkout` names the checkout whose ready-to-push statuses
|
||||
/// should be recomputed after the remote moved.
|
||||
fn run_push(
|
||||
&mut self,
|
||||
push: Task<Result<PushOutcome, Error>>,
|
||||
@@ -1252,11 +1167,8 @@ impl RepoStore {
|
||||
match &result {
|
||||
Ok(outcome) => {
|
||||
this.last_error = None;
|
||||
// A push only some grasp servers accepted is a warning:
|
||||
// the repo is out of sync on the rest until it is republished.
|
||||
this.last_push_warning = outcome.partial_warning();
|
||||
if let Some((addr, path)) = &pushed_checkout {
|
||||
// The remote moved, so recompute the ready-to-push statuses.
|
||||
CheckoutsStore::global(cx).update(cx, |store, cx| {
|
||||
store.checkout_pushed(addr, path, cx);
|
||||
});
|
||||
@@ -1275,10 +1187,6 @@ impl RepoStore {
|
||||
})
|
||||
}
|
||||
|
||||
/// Delete the repository from nostr, announcement, state and activity.
|
||||
///
|
||||
/// Only the repository owner may delete it. The lists update when the
|
||||
/// deletion events arrive.
|
||||
pub fn delete_repository(&mut self, cx: &mut Context<Self>) -> Task<Result<(), Error>> {
|
||||
let Some(addr) = self.addr.clone() else {
|
||||
return self.action_error("This repository is not published to Nostr yet", cx);
|
||||
@@ -1300,8 +1208,7 @@ impl RepoStore {
|
||||
})
|
||||
}
|
||||
|
||||
/// Clone the repository into `destination`, a user-chosen folder outside
|
||||
/// the cache, and remember the clone as a checkout of this repository.
|
||||
// A user-chosen folder outside the cache; remembered as a checkout.
|
||||
pub fn clone_to_folder(
|
||||
&mut self,
|
||||
destination: PathBuf,
|
||||
@@ -1329,8 +1236,7 @@ impl RepoStore {
|
||||
|
||||
let clone = {
|
||||
let destination = destination.clone();
|
||||
// The clone's repository handle is dropped in the task: gix handles
|
||||
// are not `Send`, they must not cross the spawn boundary.
|
||||
// gix handles are not `Send` and must not cross the spawn boundary.
|
||||
cx.background_spawn(async move { Repo::clone(&clone_urls, &destination).map(|_| ()) })
|
||||
};
|
||||
|
||||
@@ -1376,12 +1282,8 @@ impl RepoStore {
|
||||
Task::ready(Err(anyhow::anyhow!("{message}")))
|
||||
}
|
||||
|
||||
/// Sign `builder`, broadcast it and track the outcome in [`Self::last_error`].
|
||||
///
|
||||
/// Every one-shot repository event (issue, comment, status) goes through
|
||||
/// this. Multi-step flows (opening or updating a pull request, a patch
|
||||
/// series) call the SDK directly instead, since their error handling and
|
||||
/// post-conditions differ per step.
|
||||
// Every one-shot repository event (issue, comment, status) goes through
|
||||
// this; multi-step flows call the SDK directly instead.
|
||||
fn publish(&mut self, builder: EventBuilder, cx: &mut Context<Self>) {
|
||||
self.last_error = None;
|
||||
|
||||
@@ -1446,15 +1348,13 @@ fn resolve_statuses(
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// The proposed commit of a `git format-patch` output.
|
||||
/// It is the `From <commit>` header on the first line.
|
||||
// The `From <commit>` header on the first line.
|
||||
fn patch_current_commit(patch: &str) -> Option<&str> {
|
||||
let line = patch.lines().next()?;
|
||||
let hex = line.strip_prefix("From ")?;
|
||||
hex.split_whitespace().next().filter(|hex| hex.len() == 40)
|
||||
}
|
||||
|
||||
/// A `git format-patch` series with the facts derived from its parts.
|
||||
struct PatchSeries {
|
||||
parts: Vec<String>,
|
||||
}
|
||||
@@ -1469,7 +1369,7 @@ impl PatchSeries {
|
||||
}
|
||||
}
|
||||
|
||||
/// The byte length of the first part over the NIP-34 size suggestion.
|
||||
// The byte length of the first part over the NIP-34 size suggestion.
|
||||
fn oversized_length(&self) -> Option<usize> {
|
||||
self.parts
|
||||
.iter()
|
||||
@@ -1477,8 +1377,8 @@ impl PatchSeries {
|
||||
.find(|length| *length > MAX_PATCH_EVENT_BYTES)
|
||||
}
|
||||
|
||||
/// The tip of the series is its last commit;
|
||||
/// `git format-patch` orders patches oldest first.
|
||||
// The tip of the series is its last commit; `git format-patch` orders
|
||||
// patches oldest first.
|
||||
fn tip_commit(&self) -> Option<Sha1Hash> {
|
||||
self.parts
|
||||
.last()
|
||||
@@ -1494,9 +1394,7 @@ impl PatchSeries {
|
||||
}
|
||||
}
|
||||
|
||||
/// Publish a `git format-patch` series as chained kind-1617 events.
|
||||
///
|
||||
/// Returns the root event, the one a PR references.
|
||||
// Returns the root event, the one a PR references.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn publish_patch_series(
|
||||
client: &Client,
|
||||
@@ -1566,7 +1464,6 @@ async fn publish_patch_series(
|
||||
root.ok_or_else(|| anyhow::anyhow!("patch series is empty"))
|
||||
}
|
||||
|
||||
/// Build a NIP-22 kind-1111 comment.
|
||||
fn comment_builder(
|
||||
root: &Event,
|
||||
parent: Option<&Event>,
|
||||
@@ -1630,19 +1527,15 @@ mod tests {
|
||||
assert!(kinds.contains(&expected), "missing {expected} tag");
|
||||
}
|
||||
|
||||
// The uppercase `E` tag scopes the root, with its id, relay hint and author.
|
||||
let e = event.tags.iter().find(|t| t.kind() == "E").expect("E tag");
|
||||
let slice = e.as_slice();
|
||||
assert_eq!(slice[1], root.id.to_hex());
|
||||
assert_eq!(slice[2], relay.as_str());
|
||||
assert_eq!(slice[3], root.pubkey.to_hex());
|
||||
|
||||
// The lowercase `e` tag references the parent.
|
||||
// For a top-level comment the parent is the root itself.
|
||||
let e = event.tags.iter().find(|t| t.kind() == "e").expect("e tag");
|
||||
assert_eq!(e.as_slice()[1], root.id.to_hex());
|
||||
|
||||
// Signed's own `references_root` must keep matching the comment.
|
||||
assert!(event.references_root(&root.id));
|
||||
}
|
||||
|
||||
@@ -1652,13 +1545,11 @@ mod tests {
|
||||
let maintainer = Keys::generate().public_key();
|
||||
let addr = signed_core::RepoAddr::new(owner, "my-repo");
|
||||
|
||||
// The owner is not among the maintainers, as on a subordinate fork.
|
||||
let filters = RepoStore::maintainer_filters(&addr, &[maintainer]);
|
||||
assert_eq!(filters.len(), 4);
|
||||
|
||||
let expected = HashSet::from([owner, maintainer]);
|
||||
|
||||
// Gossip only resolves pubkeys from `authors` and the lowercase `#p` tag.
|
||||
let named = |filter: &Filter| -> HashSet<PublicKey> {
|
||||
let authors = filter.authors.iter().flatten().copied();
|
||||
let p_tag = filter
|
||||
@@ -1670,7 +1561,6 @@ mod tests {
|
||||
authors.chain(p_tag).collect()
|
||||
};
|
||||
|
||||
// Announcement and state events, scoped to the repository identifier.
|
||||
let announcement = &filters[0];
|
||||
assert_eq!(named(announcement), expected);
|
||||
assert!(
|
||||
@@ -1679,7 +1569,6 @@ mod tests {
|
||||
.contains_key(&SingleLetterTag::LOWERCASE_D)
|
||||
);
|
||||
|
||||
// Activity filters, scoped to the repository coordinate.
|
||||
for filter in &filters[1..3] {
|
||||
assert_eq!(named(filter), expected);
|
||||
assert!(
|
||||
@@ -1689,7 +1578,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
// Deletions, named by author only.
|
||||
let deletions = &filters[3];
|
||||
assert_eq!(
|
||||
deletions
|
||||
|
||||
Reference in New Issue
Block a user