git-next-forge-github 0.14.1

GitHub support for git-next, the trunk-based development manager
Documentation
//
use crate::{self as github, GithubState};
use git_next_core::git::{self, forge::commit::Status};
use github::GithubStatus;

/// Checks the results of any (e.g. CI) status checks for the commit.
///
/// GitHub: <https://docs.github.com/en/rest/commits/statuses?apiVersion=2022-11-28#list-commit-statuses-for-a-reference>
pub async fn status(
    github: &github::Github,
    commit: &git::Commit,
) -> git::forge::webhook::Result<git::forge::commit::Status> {
    let repo_details = &github.repo_details;
    let hostname = repo_details.forge.hostname();
    let repo_path = &repo_details.repo_path;
    let url = format!("https://api.{hostname}/repos/{repo_path}/commits/{commit}/statuses");
    let Ok(response) = github
        .net
        .get(url)
        .headers(github::webhook::headers(repo_details.forge.token()))
        .body("")
        .send()
        .await
    else {
        return Ok(Status::Pending);
    };
    let statuses = response.json::<Vec<GithubStatus>>().await?;
    let result = statuses
        .into_iter()
        .map(|status| match status.state {
            GithubState::Success => Status::Pass,
            GithubState::Pending | GithubState::Blank => Status::Pending,
            GithubState::Failure | GithubState::Error => Status::Fail,
        })
        .reduce(|l, r| match (l, r) {
            (Status::Pass, Status::Pass) => Status::Pass,
            (_, Status::Fail) | (Status::Fail, _) => Status::Fail,
            (_, Status::Pending) | (Status::Pending, _) => Status::Pending,
            (Status::Error(e1), Status::Error(e2)) => Status::Error(format!("{e1} / {e2}")),
            (_, Status::Error(err)) | (Status::Error(err), _) => Status::Error(err),
        })
        .unwrap_or_else(|| {
            tracing::warn!("No status checks configured for 'next' branch",);
            Status::Pass
        });
    Ok(result)
}