hive-forge: surface issues an issue/pr blocks in list/issue/pr

This commit is contained in:
damocles 2026-08-19 15:03:15 +02:00
commit a3f14f5126
4 changed files with 88 additions and 18 deletions

View file

@ -382,6 +382,50 @@ pub(crate) fn dependency_summaries(
.collect())
}
/// One entry in a `GET .../blocks` response — same `number`/`title`/
/// `state` shape [`dependency_summaries`] maps down to, but only those
/// fields: this struct exists to be lenient (see
/// [`Client::get_api_json`]'s doc comment), not to model the full Issue
/// response body.
#[derive(Deserialize)]
struct BlockingIssue {
#[serde(default)]
number: u64,
#[serde(default)]
title: String,
#[serde(default)]
state: String,
}
/// The issues *blocked by* `number` — the reverse of
/// [`dependency_summaries`]. Forgejo's dependency API is one-directional
/// in `forgejo-api`'s generated client (only the forward `GET
/// .../dependencies` is wrapped), but the reverse route is real — `GET
/// .../blocks`, confirmed against Forgejo/Gitea's actual API surface, just
/// not covered by the crate — so this goes through
/// [`Client::get_api_json`] instead, same escape hatch [`issue_reactions`]
/// already uses for an uncovered route.
///
/// # Errors
///
/// Propagates the forge API errors from listing blocking issues.
pub(crate) fn blocking_summaries(
client: &Client,
owner: &str,
name: &str,
number: u64,
) -> Result<Vec<Value>> {
let blocking: NullableVec<BlockingIssue> = client.get_api_json(
&format!("/repos/{owner}/{name}/issues/{number}/blocks"),
&[],
)?;
Ok(blocking
.0
.into_iter()
.map(|b| json!({ "number": b.number, "title": b.title, "state": b.state }))
.collect())
}
/// Deserialize a possibly-null JSON array as an empty `Vec`.
///
/// Several Forgejo list endpoints return an explicit `null` body instead of