aboutsummaryrefslogtreecommitdiff
path: root/mod/mod-ci-github-gq.cxx
diff options
context:
space:
mode:
authorFrancois Kritzinger <francois@codesynthesis.com>2025-02-20 10:50:16 +0200
committerFrancois Kritzinger <francois@codesynthesis.com>2025-02-20 15:56:51 +0200
commit8921de8fa65a2144e2eacf89b3009922ed849973 (patch)
treec775c6aba367c7195c9b7fa5013e4177ce27c137 /mod/mod-ci-github-gq.cxx
parent2abb3ab35426189a9c478564a6426680c7cd3af0 (diff)
ci-github: Re-request check suite on internal CI cancellation
Diffstat (limited to 'mod/mod-ci-github-gq.cxx')
-rw-r--r--mod/mod-ci-github-gq.cxx125
1 files changed, 125 insertions, 0 deletions
diff --git a/mod/mod-ci-github-gq.cxx b/mod/mod-ci-github-gq.cxx
index 24f8b47..9d20c9e 100644
--- a/mod/mod-ci-github-gq.cxx
+++ b/mod/mod-ci-github-gq.cxx
@@ -1038,6 +1038,131 @@ namespace brep
return r;
}
+
+ // Serialize a GraphQL query that rerequests a check suite.
+ //
+ // Throw invalid_argument if any of the node ids are not a valid GraphQL
+ // string.
+ //
+ static string
+ gq_mutation_rerequest_check_suite (const string& rid, const string& nid)
+ {
+ ostringstream os;
+
+ os << "mutation {" << '\n'
+ << " rerequestCheckSuite(input: {repositoryId: " << gq_str (rid) << '\n'
+ << " checkSuiteId: " << gq_str (nid) << '\n'
+ << " }) {" << '\n'
+ << " checkSuite { id }" << '\n'
+ << " }" << '\n'
+ << "}";
+
+ return os.str ();
+ }
+
+ bool
+ gq_rerequest_check_suite (const basic_mark& error,
+ const string& iat,
+ const string& rid,
+ const string& nid)
+ {
+ // Let invalid_argument from gq_mutation_rerequest_check_suite()
+ // propagate.
+ //
+ string rq (
+ gq_serialize_request (gq_mutation_rerequest_check_suite (rid, nid)));
+
+ try
+ {
+ // Response parser.
+ //
+ struct resp
+ {
+ // True if the check suite was found (i.e., the node id was valid).
+ //
+ bool found = false;
+
+ // Example response (note: outer `data` object already stripped at
+ // this point):
+ //
+ // {"rerequestCheckSuite":{"checkSuite":{"id":"CS_kwDOLc8CoM8AAAAIDgO-Qw"}}}
+ //
+ resp (json::parser& p)
+ {
+ using event = json::event;
+
+ gq_parse_response (p, [this] (json::parser& p)
+ {
+ p.next_expect (event::begin_object); // Outer {
+
+ // This object will be null if the repository or check suite node
+ // ids were invalid.
+ //
+ if (p.next_expect_member_object_null ("rerequestCheckSuite"))
+ {
+ found = true;
+
+ p.next_expect_member_object ("checkSuite");
+ p.next_expect_member_string ("id");
+ p.next_expect (event::end_object); // checkSuite
+ p.next_expect (event::end_object); // rerequestCheckSuite
+ }
+
+ p.next_expect (event::end_object); // Outer }
+ });
+ }
+
+ resp () = default;
+ } rs;
+
+ uint16_t sc (github_post (rs,
+ "graphql", // API Endpoint.
+ strings {"Authorization: Bearer " + iat},
+ move (rq)));
+
+ if (sc == 200)
+ {
+ if (!rs.found)
+ {
+ error << "check suite '" << nid
+ << "' not found in repository '" << rid << '\'';
+ return false;
+ }
+
+ return true;
+ }
+ else
+ error << "failed to re-request check suite: error HTTP response status "
+ << sc;
+ }
+ catch (const json::invalid_json_input& e) // struct resp (via github_post())
+ {
+ // Note: e.name is the GitHub API endpoint.
+ //
+ error << "malformed JSON in response from " << e.name << ", line: "
+ << e.line << ", column: " << e.column << ", byte offset: "
+ << e.position << ", error: " << e;
+ }
+ catch (const invalid_argument& e) // github_post()
+ {
+ error << "malformed header(s) in response: " << e;
+ }
+ catch (const system_error& e) // github_post()
+ {
+ error << "unable to re-request check suite (errno=" << e.code () << "): "
+ << e.what ();
+ }
+ catch (const runtime_error& e) // struct resp
+ {
+ // GitHub response contained error(s) (could be ours or theirs at this
+ // point).
+ //
+ error << "unable to re-request check suite: " << e;
+ }
+
+ return false;
+ }
+
// Serialize a GraphQL query that fetches a pull request from GitHub.
//
// Throw invalid_argument if the node id is not a valid GraphQL string.