update
This commit is contained in:
@@ -6,6 +6,7 @@ use nostr_sdk::prelude::*;
|
||||
use signed_core::{Announcement, Deletions, RepoAddr, RepoStatus, filters, parse_state};
|
||||
|
||||
use crate::backend::{Backend, BackendEvent};
|
||||
use crate::git_store::GitStore;
|
||||
|
||||
/// Delay between a refresh request and the actual re-query, so bursts of
|
||||
/// events (e.g. per-event `NostrUpdate`s) collapse into one query.
|
||||
@@ -293,6 +294,13 @@ impl RepoStore {
|
||||
.count()
|
||||
}
|
||||
|
||||
/// Whether `user` is the author (owner) of this repository: the public
|
||||
/// key of the repository address. Only the author may manage the
|
||||
/// repository's pull requests (close / reopen / merge).
|
||||
pub fn is_author(&self, user: &PublicKey) -> bool {
|
||||
&self.addr.public_key == user
|
||||
}
|
||||
|
||||
/// Open an issue on this repository.
|
||||
pub fn open_issue(&mut self, subject: Option<String>, content: String, cx: &mut Context<Self>) {
|
||||
let builder = GitIssue {
|
||||
@@ -392,6 +400,62 @@ impl RepoStore {
|
||||
self.send(builder, cx);
|
||||
}
|
||||
|
||||
/// Merge a pull request: apply its patch (`git format-patch` output) to
|
||||
/// the local clone of this repository, then publish the merged status.
|
||||
///
|
||||
/// Only the repository author may merge. The clone is created on demand
|
||||
/// from the announcement's clone URLs when the repository hasn't been
|
||||
/// mirrored locally yet. Patch application runs on a background thread
|
||||
/// (`git am`); failures (e.g. a patch that no longer applies) surface in
|
||||
/// [`Self::last_error`] and no status is sent.
|
||||
pub fn merge_pull_request(&mut self, root: &Event, cx: &mut Context<Self>) {
|
||||
self.last_error = None;
|
||||
|
||||
let is_author = Backend::global(cx)
|
||||
.read(cx)
|
||||
.current_user()
|
||||
.is_some_and(|user| self.is_author(&user));
|
||||
if !is_author {
|
||||
self.last_error = Some("Only the repository author can merge pull requests".into());
|
||||
return;
|
||||
}
|
||||
|
||||
let cache = GitStore::global(cx).cache().clone();
|
||||
let addr = self.addr.clone();
|
||||
let clone_urls: Vec<String> = self
|
||||
.announcement
|
||||
.as_ref()
|
||||
.map(|a| a.clone.iter().map(ToString::to_string).collect())
|
||||
.unwrap_or_default();
|
||||
let patch = root.content.clone();
|
||||
let root = root.clone();
|
||||
|
||||
let apply = cx.background_spawn(async move {
|
||||
let repo = cache.ensure_clone(&addr, &clone_urls)?;
|
||||
let workdir = repo
|
||||
.workdir()
|
||||
.ok_or_else(|| anyhow::anyhow!("repository has no worktree"))?;
|
||||
signed_git::apply_patch(workdir, &patch)
|
||||
});
|
||||
|
||||
self.tasks.push(cx.spawn(async move |this, cx| {
|
||||
match apply.await {
|
||||
Ok(()) => {
|
||||
this.update(cx, |this, cx| {
|
||||
this.set_status(&root, RepoStatus::Applied, cx);
|
||||
})?;
|
||||
}
|
||||
Err(e) => {
|
||||
this.update(cx, |this, cx| {
|
||||
this.last_error = Some(e.to_string());
|
||||
cx.notify();
|
||||
})?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}));
|
||||
}
|
||||
|
||||
fn send(&mut self, builder: EventBuilder, cx: &mut Context<Self>) {
|
||||
self.last_error = None;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user