add pull request panel

This commit is contained in:
2026-08-18 10:07:40 +07:00
parent 48357cfd88
commit 7912dd0a03
11 changed files with 569 additions and 24 deletions
+62
View File
@@ -297,6 +297,39 @@ impl RepoStore {
self.send(builder, cx);
}
/// Open a pull request on this repository: a root PR event whose content
/// is the `git format-patch` output of the proposed changes.
///
/// The branch metadata (branch name, clone URL, merge base, root patch)
/// isn't known to the UI yet and is left empty; the proposed commit is
/// parsed from the patch's `From <commit>` header, falling back to an
/// empty hash for hand-written content.
pub fn open_pull_request(
&mut self,
subject: Option<String>,
content: String,
cx: &mut Context<Self>,
) {
let current_commit = patch_current_commit(&content)
.and_then(|hex| hex.parse().ok())
.unwrap_or_else(|| bitcoin_hashes::Sha1::from_byte_array([0u8; 20]));
let builder = GitPullRequest {
repository: self.addr.clone(),
content,
subject,
labels: Vec::new(),
branch_name: None,
clone: Vec::new(),
current_commit,
root_patch_event: None,
merge_base: None,
}
.into_event_builder();
self.send(builder, cx);
}
/// Send a root patch (`git format-patch` output) to this repository.
pub fn send_root_patch(&mut self, patch: String, cx: &mut Context<Self>) {
let Ok(root_marker) = Tag::parse(["t", "root"]) else {
@@ -356,3 +389,32 @@ where
fn sort_newest_first(events: &mut [Event]) {
events.sort_by_key(|e| std::cmp::Reverse(e.created_at));
}
/// The proposed commit of a `git format-patch` output: the `From <commit>`
/// header on its 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)
}
#[cfg(test)]
mod tests {
use super::patch_current_commit;
#[test]
fn parses_format_patch_header() {
let patch = "From 1f6c0c5f3f1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a Mon Sep 17 00:00:00 2001\nFrom: A <a@b.c>\nSubject: [PATCH] fix\n\n---\n";
assert_eq!(
patch_current_commit(patch),
Some("1f6c0c5f3f1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a")
);
}
#[test]
fn no_commit_without_header() {
assert_eq!(patch_current_commit(""), None);
assert_eq!(patch_current_commit("Subject: [PATCH] x\n\n---\n"), None);
assert_eq!(patch_current_commit("From short\n"), None);
}
}