swarm-controller: start a review try-out on a PR and read its result
POST /api/review-classifier/try-out validates the run (owner/name repo,
a PR number, one to ten classifications with distinct names, thresholds
up to 100), reads the PR's head commit, commits and diff with the
controller's forge token, sends one request to the review classifier on
the queue and answers 202 with an id. GET .../try-out/{id} reports the
run as running, done (rows and overall verdict) or failed (the error).
Results live in memory for an hour after the reply; there is no run
store. POST then GET because a run can outlast the gateway's 60-second
proxy read timeout. Both routes are utoipa-annotated, so they show on
/api/docs/.
This commit is contained in:
parent
88a55f136e
commit
d70ed41537
9 changed files with 824 additions and 3 deletions
|
|
@ -24,8 +24,9 @@ use forgejo_api::structs::{
|
|||
ChangeFileOperationOperation, ChangeFilesOptions, CreateBranchProtectionOption,
|
||||
CreateHookOption, CreateHookOptionConfig, CreateHookOptionType, CreateRepoOption,
|
||||
CreateUserOption, EditUserOption, IssueListIssuesQuery, IssueListIssuesQueryState,
|
||||
IssueListIssuesQueryType, RepoGetContentsQuery, RepoListPullRequestsQuery,
|
||||
RepoListPullRequestsQueryState, RepoSearchQuery, StateType,
|
||||
IssueListIssuesQueryType, RepoDownloadPullDiffOrPatchQuery, RepoGetContentsQuery,
|
||||
RepoGetPullRequestCommitsQuery, RepoListPullRequestsQuery, RepoListPullRequestsQueryState,
|
||||
RepoSearchQuery, StateType,
|
||||
};
|
||||
use forgejo_api::{ApiErrorKind, Auth, Forgejo, ForgejoError};
|
||||
use futures_util::{StreamExt as _, TryStreamExt as _};
|
||||
|
|
@ -36,6 +37,7 @@ use std::sync::{Arc, OnceLock};
|
|||
use utoipa::ToSchema;
|
||||
|
||||
use crate::webhook::DeliveryKind;
|
||||
use swarm_queue_client::review_classifier::Commit;
|
||||
|
||||
pub mod agent_token;
|
||||
pub mod docs_grant;
|
||||
|
|
@ -55,6 +57,14 @@ pub struct ConfigPrStatus {
|
|||
pub html_url: Option<String>,
|
||||
}
|
||||
|
||||
/// A PR as [`Client::pull_for_review`] reads it for the review classifier.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct PullForReview {
|
||||
pub head_sha: String,
|
||||
pub commits: Vec<Commit>,
|
||||
pub diff: String,
|
||||
}
|
||||
|
||||
/// One row of [`Client::issue_report`] — an open issue plus the two facts
|
||||
/// derived from its dependency graph that swarm-ui's issue-report page
|
||||
/// sorts/filters on. See that function's doc comment for how both are
|
||||
|
|
@ -1031,6 +1041,67 @@ impl Client {
|
|||
Ok(rows.into_iter().flatten().collect())
|
||||
}
|
||||
|
||||
/// What the review classifier reads of `owner/repo`'s PR `number`: its
|
||||
/// head commit, its commits oldest first with their full messages, and
|
||||
/// its unified diff.
|
||||
///
|
||||
/// # Errors
|
||||
/// A forge failure, with the [`ForgejoError`] underneath; a 404 on the
|
||||
/// first call means the repo or the PR does not exist
|
||||
/// ([`is_repo_not_found`]).
|
||||
pub async fn pull_for_review(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
number: i64,
|
||||
) -> Result<PullForReview> {
|
||||
let pull = self
|
||||
.api
|
||||
.repo_get_pull_request(owner, repo, number)
|
||||
.await
|
||||
.with_context(|| format!("read PR {number} of {owner}/{repo}"))?;
|
||||
let head_sha = pull
|
||||
.head
|
||||
.and_then(|h| h.sha)
|
||||
.with_context(|| format!("PR {number} of {owner}/{repo} names no head commit"))?;
|
||||
let commits = self
|
||||
.api
|
||||
.repo_get_pull_request_commits(
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
RepoGetPullRequestCommitsQuery {
|
||||
verification: Some(false),
|
||||
files: Some(false),
|
||||
},
|
||||
)
|
||||
.all()
|
||||
.await
|
||||
.with_context(|| format!("list the commits of PR {number} of {owner}/{repo}"))?
|
||||
.into_iter()
|
||||
.map(|c| Commit {
|
||||
sha: c.sha.unwrap_or_default(),
|
||||
message: c.commit.and_then(|m| m.message).unwrap_or_default(),
|
||||
})
|
||||
.collect();
|
||||
let diff = self
|
||||
.api
|
||||
.repo_download_pull_diff_or_patch(
|
||||
owner,
|
||||
repo,
|
||||
number,
|
||||
"diff",
|
||||
RepoDownloadPullDiffOrPatchQuery::default(),
|
||||
)
|
||||
.await
|
||||
.with_context(|| format!("read the diff of PR {number} of {owner}/{repo}"))?;
|
||||
Ok(PullForReview {
|
||||
head_sha,
|
||||
commits,
|
||||
diff,
|
||||
})
|
||||
}
|
||||
|
||||
/// Register the swarm-wide hooks against this controller, so a real
|
||||
/// forge event reaches [`crate::webhook`] instead of the endpoint only
|
||||
/// being reachable by hand.
|
||||
|
|
|
|||
Loading…
Reference in a new issue