mirror of
https://codeberg.org/Cyborus/forgejo-cli.git
synced 2024-11-10 03:59:31 +01:00
Merge pull request 'fix pr detection' (#89) from pr-guess-fix-2 into main
Reviewed-on: https://codeberg.org/Cyborus/forgejo-cli/pulls/89
This commit is contained in:
commit
0edf5efff4
1 changed files with 158 additions and 17 deletions
175
src/prs.rs
175
src/prs.rs
|
@ -1285,24 +1285,165 @@ async fn guess_pr(
|
||||||
api: &Forgejo,
|
api: &Forgejo,
|
||||||
) -> eyre::Result<forgejo_api::structs::PullRequest> {
|
) -> eyre::Result<forgejo_api::structs::PullRequest> {
|
||||||
let local_repo = git2::Repository::open(".")?;
|
let local_repo = git2::Repository::open(".")?;
|
||||||
let head_id = local_repo.head()?.peel_to_commit()?.id();
|
let head = local_repo.head()?;
|
||||||
let sha = oid_to_string(head_id);
|
eyre::ensure!(head.is_branch(), "head is not on branch");
|
||||||
let pr = api
|
let local_branch = git2::Branch::wrap(head);
|
||||||
.repo_get_commit_pull_request(repo.owner(), repo.name(), &sha)
|
let remote_branch = local_branch.upstream()?;
|
||||||
.await?;
|
let remote_head_name = remote_branch
|
||||||
Ok(pr)
|
.get()
|
||||||
|
.name()
|
||||||
|
.ok_or_eyre("remote branch does not have valid name")?;
|
||||||
|
let remote_head_short = remote_head_name
|
||||||
|
.rsplit_once("/")
|
||||||
|
.map(|(_, b)| b)
|
||||||
|
.unwrap_or(remote_head_name);
|
||||||
|
let this_repo = api.repo_get(repo.owner(), repo.name()).await?;
|
||||||
|
|
||||||
|
// check for PRs on the main branch first
|
||||||
|
let base = this_repo
|
||||||
|
.default_branch
|
||||||
|
.as_deref()
|
||||||
|
.ok_or_eyre("repo does not have default branch")?;
|
||||||
|
if let Ok(pr) = api
|
||||||
|
.repo_get_pull_request_by_base_head(repo.owner(), repo.name(), base, remote_head_short)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return Ok(pr);
|
||||||
|
}
|
||||||
|
|
||||||
|
let this_full_name = this_repo
|
||||||
|
.full_name
|
||||||
|
.as_deref()
|
||||||
|
.ok_or_eyre("repo does not have full name")?;
|
||||||
|
let parent_remote_head_name = format!("{this_full_name}:{remote_head_short}");
|
||||||
|
|
||||||
|
if let Some(parent) = this_repo.parent.as_deref() {
|
||||||
|
let (parent_owner, parent_name) = repo_name_from_repo(parent)?;
|
||||||
|
let parent_base = this_repo
|
||||||
|
.default_branch
|
||||||
|
.as_deref()
|
||||||
|
.ok_or_eyre("repo does not have default branch")?;
|
||||||
|
if let Ok(pr) = api
|
||||||
|
.repo_get_pull_request_by_base_head(
|
||||||
|
parent_owner,
|
||||||
|
parent_name,
|
||||||
|
parent_base,
|
||||||
|
&parent_remote_head_name,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return Ok(pr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// then iterate all branches
|
||||||
|
if let Some(pr) = find_pr_from_branch(repo.owner(), repo.name(), api, remote_head_short).await?
|
||||||
|
{
|
||||||
|
return Ok(pr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(parent) = this_repo.parent.as_deref() {
|
||||||
|
let (parent_owner, parent_name) = repo_name_from_repo(parent)?;
|
||||||
|
|
||||||
|
if let Some(pr) =
|
||||||
|
find_pr_from_branch(parent_owner, parent_name, api, &parent_remote_head_name).await?
|
||||||
|
{
|
||||||
|
return Ok(pr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eyre::bail!("could not find PR");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn oid_to_string(oid: git2::Oid) -> String {
|
async fn find_pr_from_branch(
|
||||||
let mut s = String::with_capacity(40);
|
repo_owner: &str,
|
||||||
for byte in oid.as_bytes() {
|
repo_name: &str,
|
||||||
s.push(
|
api: &Forgejo,
|
||||||
char::from_digit((byte & 0xF) as u32, 16).expect("every nibble is a valid hex digit"),
|
head: &str,
|
||||||
);
|
) -> eyre::Result<Option<forgejo_api::structs::PullRequest>> {
|
||||||
s.push(
|
for page in 1.. {
|
||||||
char::from_digit(((byte >> 4) & 0xF) as u32, 16)
|
let branch_query = forgejo_api::structs::RepoListBranchesQuery {
|
||||||
.expect("every nibble is a valid hex digit"),
|
page: Some(page),
|
||||||
);
|
limit: Some(30),
|
||||||
|
};
|
||||||
|
let remote_branches = match api
|
||||||
|
.repo_list_branches(repo_owner, repo_name, branch_query)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(x) if !x.is_empty() => x,
|
||||||
|
_ => break,
|
||||||
|
};
|
||||||
|
|
||||||
|
let prs = futures::future::try_join_all(
|
||||||
|
remote_branches
|
||||||
|
.into_iter()
|
||||||
|
.map(|branch| check_branch_pair(repo_owner, repo_name, api, branch, head)),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
for pr in prs {
|
||||||
|
if pr.is_some() {
|
||||||
|
return Ok(pr);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn check_branch_pair(
|
||||||
|
repo_owner: &str,
|
||||||
|
repo_name: &str,
|
||||||
|
api: &Forgejo,
|
||||||
|
base: forgejo_api::structs::Branch,
|
||||||
|
head: &str,
|
||||||
|
) -> eyre::Result<Option<forgejo_api::structs::PullRequest>> {
|
||||||
|
let base_name = base
|
||||||
|
.name
|
||||||
|
.as_deref()
|
||||||
|
.ok_or_eyre("remote branch does not have name")?;
|
||||||
|
match api
|
||||||
|
.repo_get_pull_request_by_base_head(repo_owner, repo_name, base_name, head)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(pr) => Ok(Some(pr)),
|
||||||
|
Err(_) => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn repo_name_from_repo(repo: &forgejo_api::structs::Repository) -> eyre::Result<(&str, &str)> {
|
||||||
|
let owner = repo
|
||||||
|
.owner
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_eyre("repo does not have owner")?
|
||||||
|
.login
|
||||||
|
.as_deref()
|
||||||
|
.ok_or_eyre("repo owner does not have name")?;
|
||||||
|
let name = repo.name.as_deref().ok_or_eyre("repo does not have name")?;
|
||||||
|
Ok((owner, name))
|
||||||
|
}
|
||||||
|
|
||||||
|
//async fn guess_pr(
|
||||||
|
// repo: &RepoName,
|
||||||
|
// api: &Forgejo,
|
||||||
|
//) -> eyre::Result<forgejo_api::structs::PullRequest> {
|
||||||
|
// let local_repo = git2::Repository::open(".")?;
|
||||||
|
// let head_id = local_repo.head()?.peel_to_commit()?.id();
|
||||||
|
// let sha = oid_to_string(head_id);
|
||||||
|
// let pr = api
|
||||||
|
// .repo_get_commit_pull_request(repo.owner(), repo.name(), &sha)
|
||||||
|
// .await?;
|
||||||
|
// Ok(pr)
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//fn oid_to_string(oid: git2::Oid) -> String {
|
||||||
|
// let mut s = String::with_capacity(40);
|
||||||
|
// for byte in oid.as_bytes() {
|
||||||
|
// s.push(
|
||||||
|
// char::from_digit((byte & 0xF) as u32, 16).expect("every nibble is a valid hex digit"),
|
||||||
|
// );
|
||||||
|
// s.push(
|
||||||
|
// char::from_digit(((byte >> 4) & 0xF) as u32, 16)
|
||||||
|
// .expect("every nibble is a valid hex digit"),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// s
|
||||||
|
//}
|
||||||
|
|
Loading…
Reference in a new issue