From fcdcaa9f3fab747fb11572d279dbf31235e2c694 Mon Sep 17 00:00:00 2001 From: Francois Kritzinger Date: Tue, 29 Oct 2024 17:02:51 +0200 Subject: Implement build_unloaded_pre_check() --- mod/mod-ci-github.cxx | 122 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 119 insertions(+), 3 deletions(-) diff --git a/mod/mod-ci-github.cxx b/mod/mod-ci-github.cxx index 820d62c..0a9b68a 100644 --- a/mod/mod-ci-github.cxx +++ b/mod/mod-ci-github.cxx @@ -836,13 +836,13 @@ namespace brep } function (const tenant_service&)> ci_github:: - build_unloaded_pre_check (tenant_service&&, - service_data&&, + build_unloaded_pre_check (tenant_service&& ts, + service_data&& sd, const diag_epilogue& log_writer) const noexcept { NOTIFICATION_DIAG (log_writer); - // Note: PR only (but both local and remove). + // Note: PR only (but both local and remote). // // - Ask for test merge commit. // - If not ready, get called again. @@ -858,6 +858,122 @@ namespace brep // started the CI job). // + // Request PR pre-check info (triggering the generation of the test merge + // commit on GitHub's side). + // + optional pc ( // Pre-check information. + gq_pull_request_pre_check_info (error, + sd.installation_access.token, + sd.event_node_id)); + + if (!pc) + { + // Test merge commit not available yet: get called again to retry. + // + return nullptr; + } + + // Create the CI request if nothing is wrong, otherwise issue diagnostics. + // + if (pc->behind) + { + l3 ([&]{trace << "ignoring pull request " << sd.event_node_id + << ": head is behind base";}); + } + else if (pc->merge_commit_sha.empty ()) + { + l3 ([&]{trace << "ignoring pull request " << sd.event_node_id + << ": not auto-mergeable";}); + } + else if (pc->head_sha != sd.report_sha) + { + l3 ([&]{trace << "ignoring pull request " << sd.event_node_id + << ": head commit has changed";}); + } + else + { + // Create the CI request. + + // Update service data's check_sha if this is a remote PR. + // + if (sd.kind == service_data::remote) + sd.check_sha = pc->merge_commit_sha; + + // Service id that will uniquely identify the CI request. + // + string sid (sd.repository_node_id + ":" + sd.report_sha); + + // Create an unloaded CI request, doing nothing if one already exists + // (which could've been created by a head branch push or another PR + // sharing the same head commit). + // + // Note: use no delay since we need to (re)create the synthetic conclusion + // check run as soon as possible. + // + // Note that we use the create() API instead of start() since duplicate + // management is not available in start(). + // + // After this call we will start getting the build_unloaded() + // notifications until (1) we load the request, (2) we cancel it, or (3) + // it gets archived after some timeout. + // + if (auto pr = create (error, warn, verb_ ? &trace : nullptr, + *build_db_, + tenant_service (sid, "ci-github", sd.json ()), + chrono::seconds (30) /* interval */, + chrono::seconds (0) /* delay */, + duplicate_tenant_mode::ignore)) + { + if (pr->second == duplicate_tenant_result::ignored) + { + // This PR is sharing a head commit with something else. + // + // If this is a local PR then it's probably the branch push, which + // is expected, so do nothing. + // + // If this is a remote PR then it could be anything (branch push, + // local PR, or another remote PR), so we can't recover. This PR + // could go green despite its test merge commit not having been + // CI'd. + // + // @@ TMP Perhaps we should update the conclusion CR to failing + // with a message asking the user to sort the problem out + // manually and then re-request the checks in the UI if they + // want to re-CI the branch push or, if they want to CI one of + // the PRs, they can close and reopen it (action "reopened"). + // + if (sd.kind == service_data::remote) + { + l3 ([&]{trace << "remote pull request " << sd.event_node_id + << ": CI request already exists for " << sid;}); + } + } + } + else + { + error << "pull request " << sd.event_node_id + << ": unable to create unloaded CI request " + << "with tenant_service id " << sid; + + // Retry by bailing out before cancelling in order to get called + // again. + // + return nullptr; + } + } + + // Cancel this, the pre-check request. + // + if (!cancel (error, warn, verb_ ? &trace : nullptr, + *build_db_, ts.type, ts.id)) + { + // Should never happen (no such tenant). + // + error << "pull request " << sd.event_node_id + << ": failed to cancel pre-check request with tenant_service id " + << ts.id; + } + return nullptr; } -- cgit v1.1