From ee8370a3139deae4a23307333a23100818ce4682 Mon Sep 17 00:00:00 2001 From: Francois Kritzinger Date: Mon, 29 Apr 2024 10:51:12 +0200 Subject: Handle warning_success webhook query parameter --- mod/mod-ci-github-gq.cxx | 52 +++++++++++++++++++++++--------------- mod/mod-ci-github-gq.hxx | 14 +++++++--- mod/mod-ci-github-service-data.cxx | 10 ++++++-- mod/mod-ci-github-service-data.hxx | 3 ++- mod/mod-ci-github.cxx | 42 +++++++++++++++++++++++++----- mod/mod-ci-github.hxx | 5 +++- 6 files changed, 92 insertions(+), 34 deletions(-) diff --git a/mod/mod-ci-github-gq.cxx b/mod/mod-ci-github-gq.cxx index b9e5908..c37c889 100644 --- a/mod/mod-ci-github-gq.cxx +++ b/mod/mod-ci-github-gq.cxx @@ -317,15 +317,16 @@ namespace brep // Serialize `createCheckRun` mutations for one or more builds to GraphQL. // - // The result_status is required if the build_state is built because GitHub - // does not allow a check run status of completed without a conclusion. + // The `co` (conclusion) argument is required if the build_state is built + // because GitHub does not allow a check run status of completed without a + // conclusion. // static string gq_mutation_create_check_runs (const string& ri, // Repository ID const string& hs, // Head SHA const vector& crs, - build_state st, - optional rs = nullopt) + const string& st, // Check run status. + const optional& co = nullopt) { ostringstream os; @@ -341,12 +342,11 @@ namespace brep << " name: " << gq_str (crs[i].name) << ',' << '\n' << " repositoryId: " << gq_str (ri) << ',' << '\n' << " headSha: " << gq_str (hs) << ',' << '\n' - << " status: " << gq_enum (gh_to_status (st)); - if (rs) + << " status: " << gq_enum (st); + if (co) { - // @@ TODO Pass valid boolean os << ',' << '\n' - << " conclusion: " << gq_enum (gh_to_conclusion (*rs, false)); + << " conclusion: " << gq_enum (*co); } os << "})" << '\n' // Specify the selection set (fields to be returned). @@ -367,14 +367,15 @@ namespace brep // Serialize an `updateCheckRun` mutation for one build to GraphQL. // - // The result_status is required if the build_state is built because GitHub - // does not allow updating a check run to completed without a conclusion. + // The `co` (conclusion) argument is required if the build_state is built + // because GitHub does not allow updating a check run to completed without a + // conclusion. // static string gq_mutation_update_check_run (const string& ri, // Repository ID. const string& ni, // Node ID. - build_state st, - optional rs) + const string& st, // Check run status. + const optional& co) { ostringstream os; @@ -382,12 +383,11 @@ namespace brep << "cr0:updateCheckRun(input: {" << '\n' << " checkRunId: " << gq_str (ni) << ',' << '\n' << " repositoryId: " << gq_str (ri) << ',' << '\n' - << " status: " << gq_enum (gh_to_status (st)); - if (rs) + << " status: " << gq_enum (st); + if (co) { - // @@ TODO Pass valid boolean os << ',' << '\n' - << " conclusion: " << gq_enum (gh_to_conclusion (*rs, false)); + << " conclusion: " << gq_enum (*co); } os << "})" << '\n' // Specify the selection set (fields to be returned). @@ -417,7 +417,7 @@ namespace brep assert (st != build_state::built); string rq (gq_serialize_request ( - gq_mutation_create_check_runs (rid, hs, crs, st))); + gq_mutation_create_check_runs (rid, hs, crs, gh_to_status (st)))); return gq_mutate_check_runs (error, crs, iat, move (rq), st); } @@ -429,7 +429,8 @@ namespace brep const string& rid, const string& hs, build_state st, - optional rs) + optional rs, + bool ws) { // Must have a result if state is built. // @@ -437,8 +438,12 @@ namespace brep vector crs {move (cr)}; + optional co; // Conclusion. + if (rs) + co = gh_to_conclusion (*rs, ws); + string rq (gq_serialize_request ( - gq_mutation_create_check_runs (rid, hs, crs, st, rs))); + gq_mutation_create_check_runs (rid, hs, crs, gh_to_status (st), co))); bool r (gq_mutate_check_runs (error, crs, iat, move (rq), st)); @@ -454,14 +459,19 @@ namespace brep const string& rid, const string& nid, build_state st, - optional rs) + optional rs, + bool ws) { // Must have a result if state is built. // assert (st != build_state::built || rs); + optional co; // Conclusion. + if (rs) + co = gh_to_conclusion (*rs, ws); + string rq (gq_serialize_request ( - gq_mutation_update_check_run (rid, nid, st, rs))); + gq_mutation_update_check_run (rid, nid, gh_to_status (st), co))); vector crs {move (cr)}; diff --git a/mod/mod-ci-github-gq.hxx b/mod/mod-ci-github-gq.hxx index 33aeec4..a8e5e02 100644 --- a/mod/mod-ci-github-gq.hxx +++ b/mod/mod-ci-github-gq.hxx @@ -38,6 +38,9 @@ namespace brep // The result_status is required if the build_state is built because GitHub // does not allow a check run status of `completed` without a conclusion. // + // If warning_success is true, then map result_status::warning to SUCCESS + // and to FAILURE otherwise. + // // @@ TODO Support output (title, summary, text). // bool @@ -47,7 +50,8 @@ namespace brep const string& repository_id, const string& head_sha, build_state, - optional = nullopt); + optional = nullopt, + bool warning_success = true); // Update a check run on GitHub. // @@ -56,7 +60,10 @@ namespace brep // failed. // // The result_status is required if the build_state is built because GitHub - // does not allow updating a check run to `completed` without a conclusion. + // does not allow a check run status of `completed` without a conclusion. + // + // If warning_success is true, then map result_status::warning to SUCCESS + // and to FAILURE otherwise. // // @@ TODO Support output (title, summary, text). // @@ -67,7 +74,8 @@ namespace brep const string& repository_id, const string& node_id, build_state, - optional = nullopt); + optional = nullopt, + bool warning_success = true); } #endif // MOD_MOD_CI_GITHUB_GQ_HXX diff --git a/mod/mod-ci-github-service-data.cxx b/mod/mod-ci-github-service-data.cxx index a53f445..83e952b 100644 --- a/mod/mod-ci-github-service-data.cxx +++ b/mod/mod-ci-github-service-data.cxx @@ -26,6 +26,8 @@ namespace brep to_string (version)); } + warning_success = p.next_expect_member_boolean ("warning_success"); + // Installation access token. // p.next_expect_member_object ("installation_access"); @@ -64,12 +66,14 @@ namespace brep } service_data:: - service_data (string iat_tok, + service_data (bool ws, + string iat_tok, timestamp iat_ea, uint64_t iid, string rid, string hs) - : installation_access (move (iat_tok), iat_ea), + : warning_success (ws), + installation_access (move (iat_tok), iat_ea), installation_id (iid), repository_id (move (rid)), head_sha (move (hs)) @@ -86,6 +90,8 @@ namespace brep s.member ("version", 1); + s.member ("warning_success", warning_success); + // Installation access token. // s.member_begin_object ("installation_access"); diff --git a/mod/mod-ci-github-service-data.hxx b/mod/mod-ci-github-service-data.hxx index 99c50ae..8d0b634 100644 --- a/mod/mod-ci-github-service-data.hxx +++ b/mod/mod-ci-github-service-data.hxx @@ -77,7 +77,8 @@ namespace brep explicit service_data (const string& json); - service_data (string iat_token, + service_data (bool warning_success, + string iat_token, timestamp iat_expires_at, uint64_t installation_id, string repository_id, diff --git a/mod/mod-ci-github.cxx b/mod/mod-ci-github.cxx index 644993b..4ee3cc0 100644 --- a/mod/mod-ci-github.cxx +++ b/mod/mod-ci-github.cxx @@ -226,6 +226,35 @@ namespace brep fail << "unable to compute request HMAC: " << e; } + // Process the `warning` webhook request query parameter. + // + bool warning_success; + { + const name_values& rps (rq.parameters (1024, true /* url_only */)); + + auto i (find_if (rps.begin (), rps.end (), + [] (auto&& rp) {return rp.name == "warning";})); + + if (i == rps.end ()) + throw invalid_request (400, + "missing 'warning' webhook query parameter"); + + if (!i->value) + throw invalid_request ( + 400, "missing 'warning' webhook query parameter value"); + + const string& v (*i->value); + + if (v == "success") warning_success = true; + else if (v == "failure") warning_success = false; + else + { + throw invalid_request ( + 400, + "invalid 'warning' webhook query parameter value: '" + v + '\''); + } + } + // There is a webhook event (specified in the x-github-event header) and // each event contains a bunch of actions (specified in the JSON request // body). @@ -257,14 +286,14 @@ namespace brep if (cs.action == "requested") { - return handle_check_suite_request (move (cs)); + return handle_check_suite_request (move (cs), warning_success); } else if (cs.action == "rerequested") { // Someone manually requested to re-run the check runs in this check // suite. Treat as a new request. // - return handle_check_suite_request (move (cs)); + return handle_check_suite_request (move (cs), warning_success); } else if (cs.action == "completed") { @@ -305,7 +334,7 @@ namespace brep } bool ci_github:: - handle_check_suite_request (gh_check_suite_event cs) + handle_check_suite_request (gh_check_suite_event cs, bool warning_success) { HANDLER_DIAG; @@ -331,7 +360,8 @@ namespace brep cs.check_suite.head_branch, repository_type::git); - string sd (service_data (move (iat->token), + string sd (service_data (warning_success, + move (iat->token), iat->expires_at, cs.installation.id, move (cs.repository.node_id), @@ -825,7 +855,7 @@ namespace brep sd.repository_id, *cr.node_id, build_state::built, - b.status)) + *b.status, sd.warning_success)) { assert (cr.state == build_state::built); @@ -848,7 +878,7 @@ namespace brep sd.repository_id, sd.head_sha, build_state::built, - b.status)) + *b.status, sd.warning_success)) { assert (cr.state == build_state::built); diff --git a/mod/mod-ci-github.hxx b/mod/mod-ci-github.hxx index 07feca8..b16085e 100644 --- a/mod/mod-ci-github.hxx +++ b/mod/mod-ci-github.hxx @@ -60,8 +60,11 @@ namespace brep // Handle the check_suite event `requested` and `rerequested` actions. // + // If warning_success is true, then map result_status::warning to SUCCESS + // and to FAILURE otherwise. + // bool - handle_check_suite_request (gh_check_suite_event); + handle_check_suite_request (gh_check_suite_event, bool warning_success); optional generate_jwt (const basic_mark& trace, const basic_mark& error) const; -- cgit v1.1