diff options
Diffstat (limited to 'mod/mod-ci-github-gq.hxx')
-rw-r--r-- | mod/mod-ci-github-gq.hxx | 233 |
1 files changed, 51 insertions, 182 deletions
diff --git a/mod/mod-ci-github-gq.hxx b/mod/mod-ci-github-gq.hxx index de7021a..994f8d1 100644 --- a/mod/mod-ci-github-gq.hxx +++ b/mod/mod-ci-github-gq.hxx @@ -7,21 +7,60 @@ #include <libbrep/types.hxx> #include <libbrep/utility.hxx> +#include <libbrep/build.hxx> + +#include <mod/tenant-service.hxx> // build_hints + #include <mod/mod-ci-github-gh.hxx> #include <mod/mod-ci-github-service-data.hxx> - namespace brep { // GraphQL functions (all start with gq_). // - // @@ TODO: - - gq_create_check_run (); - gq_update_check_run (); - - // @@ TODO Pass error, trace in same order everywhere. + // Create a new check run on GitHub for each build. Update `check_runs` with + // the new states and node IDs. Return false and issue diagnostics if the + // request failed. + // + bool + gq_create_check_runs (vector<check_run>& check_runs, + const string& installation_access_token, + const string& repository_id, + const string& head_sha, + const vector<reference_wrapper<const build>>&, + build_state, + const tenant_service_base::build_hints&, + const basic_mark& error); + + // Create a new check run on GitHub for a build. Update `cr` with the new + // state and the node ID. Return false and issue diagnostics if the request + // failed. + // + bool + gq_create_check_run (check_run& cr, + const string& installation_access_token, + const string& repository_id, + const string& head_sha, + const build&, + build_state, + const tenant_service_base::build_hints&, + const basic_mark& error); + + // Update a check run on GitHub. + // + // Send a GraphQL request that updates an existing check run. Update `cr` + // with the new state. Return false and issue diagnostics if the request + // failed. + // + bool + gq_update_check_run (check_run& cr, + const string& installation_access_token, + const string& repository_id, + const string& node_id, + const build&, + build_state, + const basic_mark& error); // Fetch from GitHub the check run with the specified name (hints-shortened // build ID). @@ -33,184 +72,14 @@ namespace brep // Note that the existence of more than one check run with the same name is // considered an error and reported as such. The API docs imply that there // can be more than one check run with the same name in a check suite, but - // the observed behavior is that creating a check run destroys the extant - // one, leaving only the new one with different node ID. + // the observed behavior is that creating a check run destroys the existent + // one, leaving only the new one with a different node ID. // - pair<optional<gh::check_run>, bool> - gq_fetch_check_run (const string& iat, + pair<optional<gh_check_run>, bool> + gq_fetch_check_run (const string& installation_access_token, const string& check_suite_id, const string& cr_name, - const basic_mark& error) noexcept - { - try - { - // Example request: - // - // query { - // node(id: "CS_kwDOLc8CoM8AAAAFQPQYEw") { - // ... on CheckSuite { - // checkRuns(last: 100, filterBy: {checkName: "linux_debian_..."}) { - // totalCount, - // edges { - // node { - // id, name, status - // } - // } - // } - // } - // } - // } - // - // This request does the following: - // - // - Look up the check suite by node ID ("direct node lookup"). This - // returns a Node (GraphQL interface). - // - // - Get to the concrete CheckSuite type by using a GraphQL "inline - // fragment" (`... on CheckSuite`). - // - // - Get the check suite's check runs - // - Filter by the sought name - // - Return only two check runs, just enough to be able to tell - // whether there are more than one check runs with this name (which - // is an error). - // - // - Return the id, name, and status fields from the matching check run - // objects. - // - string rq; - { - ostringstream os; - - os << "query {" << '\n'; - - os << "node(id: " << gq_str (check_suite_id) << ") {" << '\n' - << " ... on CheckSuite {" << '\n' - << " checkRuns(last: 2," << '\n' - << " filterBy: {" << '\n' - << "checkName: " << gq_str (cr_name) << '\n' - << " })" << '\n' - // Specify the selection set (fields to be returned). Note that - // edges and node are mandatory. - // - << " {" << '\n' - << " totalCount," << '\n' - << " edges {" << '\n' - << " node {" << '\n' - << " id, name, status" << '\n' - << " }" << '\n' - << " }" << '\n' - << " }" << '\n' - << " }" << '\n' - << "}" << '\n'; - - os << "}" << '\n'; - - rq = os.str (); - } - - // Example response (the part we need to parse here, at least): - // - // { - // "node": { - // "checkRuns": { - // "totalCount": 1, - // "edges": [ - // { - // "node": { - // "id": "CR_kwDOLc8CoM8AAAAFgeoweg", - // "name": "linux_debian_...", - // "status": "IN_PROGRESS" - // } - // } - // ] - // } - // } - // } - // - struct resp - { - optional<check_run> cr; - size_t cr_count = 0; - - resp (json::parser& p) - { - using event = json::event; - - parse_graphql_response (p, [this] (json::parser& p) - { - p.next_expect (event::begin_object); - p.next_expect_member_object ("node"); - p.next_expect_member_object ("checkRuns"); - - cr_count = p.next_expect_member_number<size_t> ("totalCount"); - - p.next_expect_member_array ("edges"); - - for (size_t i (0); i != cr_count; ++i) - { - p.next_expect (event::begin_object); - p.next_expect_name ("node"); - check_run cr (p); - p.next_expect (event::end_object); - - if (i == 0) - this->cr = move (cr); - } - - p.next_expect (event::end_array); // edges - p.next_expect (event::end_object); // checkRuns - p.next_expect (event::end_object); // node - p.next_expect (event::end_object); - }); - } - - resp () = default; - } rs; - - uint16_t sc (github_post (rs, - "graphql", - strings {"Authorization: Bearer " + iat}, - graphql_request (rq))); - - if (sc == 200) - { - if (rs.cr_count <= 1) - return {rs.cr, true}; - else - { - error << "unexpected number of check runs (" << rs.cr_count - << ") in response"; - } - } - else - error << "failed to get check run by name: error HTTP " - << "response status " << sc; - } - catch (const json::invalid_json_input& e) - { - // 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) - { - error << "malformed header(s) in response: " << e; - } - catch (const system_error& e) - { - error << "unable to get check run by name (errno=" << e.code () - << "): " << e.what (); - } - catch (const std::exception& e) - { - error << "unable to get check run by name: " << e.what (); - } - - return {nullopt, false}; - } + const basic_mark& error) noexcept; } #endif // MOD_MOD_CI_GITHUB_GQ_HXX |