feat: stream newest pull requests by category
This commit is contained in:
+80
-27
@@ -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 { .. } => {
|
||||
|
||||
Reference in New Issue
Block a user