feat: stream newest pull requests by category

This commit is contained in:
Valdemar Lorenzen
2026-10-14 14:08:21 +02:00
parent 5243de66fe
commit 0000089f42
8 changed files with 1465 additions and 377 deletions
+80 -27
View File
@@ -1,7 +1,7 @@
//! Read-only active-repository discovery and isolated revision comparison.
use crate::diff::{
Catalog, Category, ChangedFile, Comparison, ComparisonMode, FileStatus, RepoKind, Revision,
RevisionTarget, line_hunks,
Catalog, Category, ChangedFile, Comparison, ComparisonMode, FileStatus, PullRequestPage,
RepoKind, Revision, RevisionTarget, line_hunks,
};
use std::{
collections::{BTreeMap, BTreeSet},
@@ -1535,7 +1535,10 @@ impl Repository {
self.load_remote(remote, None)?;
self.catalog()
}
pub fn pull_requests(&mut self, name: &str) -> Result<Catalog, String> {
fn pull_request_remote(
&mut self,
name: &str,
) -> Result<(String, String, Option<String>), String> {
self.discover_remotes()?;
let remote = if name.is_empty() {
self.remotes
@@ -1561,40 +1564,91 @@ impl Repository {
} else {
Some(text(checked(output)?)?.trim().to_owned())
};
let pulls = crate::forge::list(
&remote.url,
Ok((remote.name.clone(), remote.url.clone(), provider))
}
pub fn pull_request_page(
&mut self,
name: &str,
closed: bool,
page: u32,
) -> Result<PullRequestPage, String> {
let (remote, url, provider) = self.pull_request_remote(name)?;
let page = crate::forge::page(
&url,
provider.as_deref(),
closed,
page,
&self.root,
&self.cancelled,
)
.map_err(|error| error.replace("remote.<name>", &format!("remote.{}", remote.name)))?;
Ok(Catalog {
.map_err(|error| error.replace("remote.<name>", &format!("remote.{remote}")))?;
Ok(PullRequestPage {
kind: self.kind,
notice: Some(format!("Pull requests from {}", remote.name)),
entries: pulls
remote: remote.clone(),
has_more: page.has_more,
entries: page
.entries
.into_iter()
.map(|pull| Revision {
target: match pull.revisions {
Ok(revisions) => RevisionTarget::PullRequest {
remote: remote.name.clone(),
base_ref: revisions.base_ref,
base_sha: revisions.base_sha,
head_ref: revisions.head_ref,
head_sha: revisions.head_sha,
.map(|pull| {
(
Revision {
target: RevisionTarget::PullRequest {
remote: remote.clone(),
number: pull.number,
},
label: format!("#{} {}", pull.number, pull.title),
description: pull.description,
category: if pull.closed {
Category::Closed
} else {
Category::Open
},
},
Err(error) => RevisionTarget::UnavailablePullRequest(error),
},
label: format!("#{} {}", pull.number, pull.title),
description: pull.description,
category: if pull.closed {
Category::Closed
} else {
Category::Open
},
pull.created_at,
)
})
.collect(),
})
}
pub fn resolve_pull_request(
&mut self,
revision: Revision,
) -> Result<(Revision, Revision), String> {
let RevisionTarget::PullRequest { remote, number } = &revision.target else {
return Err("Select a pull request".into());
};
let (remote, url, provider) = self.pull_request_remote(remote)?;
let pull = crate::forge::resolve(
&url,
provider.as_deref(),
*number,
&self.root,
&self.cancelled,
)
.map_err(|error| error.replace("remote.<name>", &format!("remote.{remote}")))?;
let revisions = pull.revisions?;
let before = Revision {
target: RevisionTarget::RemoteCommit {
remote: remote.clone(),
reference: revisions.base_ref.clone(),
id: revisions.base_sha,
},
label: revisions.base_ref,
description: String::new(),
category: revision.category,
};
let after = Revision {
target: RevisionTarget::RemoteCommit {
remote,
reference: revisions.head_ref,
id: revisions.head_sha,
},
..revision
};
Ok((before, after))
}
fn resolve(&mut self, target: &RevisionTarget) -> Result<(PathBuf, String), String> {
let id = match target {
RevisionTarget::Commit(id) | RevisionTarget::RemoteCommit { id, .. } => {
@@ -1620,7 +1674,6 @@ impl Repository {
})?
.clone(),
RevisionTarget::Working => return Err("Working checkout is not a commit".into()),
RevisionTarget::UnavailablePullRequest(error) => return Err(error.clone()),
RevisionTarget::FetchRemote(_)
| RevisionTarget::ListRemote(_)
| RevisionTarget::PullRequest { .. } => {