|
| 1 | +#' The GitHub GraphQL query to extract information from all pull requests. |
| 2 | +#' |
| 3 | +#' The Rest API pull request just dumps meta-information about each PR. Getting |
| 4 | +#' details on individual PRs then requires looping over each PR number and |
| 5 | +#' making a separate call. This GraphQL query does everything in a single call. |
| 6 | +#' |
| 7 | +#' @param org The GitHub organization. |
| 8 | +#' @param repo The GitHub repository. |
| 9 | +#' @param end_cursor The end cursor from the previous query. |
| 10 | +#' |
| 11 | +#' @return The GraphQL query to pass to a `gh::gh_gql()` call. |
| 12 | +#' @noRd |
| 13 | +gh_prs_qry <- function (org = "ropensci-review-tools", |
| 14 | + repo = "repometrics", |
| 15 | + n_per_page = 100L, |
| 16 | + end_cursor = NULL) { |
| 17 | + |
| 18 | + checkmate::assert_integerish (n_per_page) |
| 19 | + |
| 20 | + after_txt <- "" |
| 21 | + if (!is.null (end_cursor)) { |
| 22 | + after_txt <- paste0 (", after:\"", end_cursor, "\"") |
| 23 | + } |
| 24 | + |
| 25 | + q <- paste0 ("{ |
| 26 | + repository(owner:\"", org, "\", name:\"", repo, "\") { |
| 27 | + pullRequests (first: ", n_per_page, after_txt, ") { |
| 28 | + pageInfo { |
| 29 | + hasNextPage |
| 30 | + endCursor |
| 31 | + } |
| 32 | + nodes { |
| 33 | + number |
| 34 | + author { |
| 35 | + login |
| 36 | + } |
| 37 | + state |
| 38 | + closed |
| 39 | + title |
| 40 | + reviewDecision |
| 41 | + reviews (first: 100) { |
| 42 | + nodes { |
| 43 | + author { |
| 44 | + login |
| 45 | + } |
| 46 | + submittedAt |
| 47 | + state |
| 48 | + body |
| 49 | + } |
| 50 | + } |
| 51 | + merged |
| 52 | + mergedBy { |
| 53 | + login |
| 54 | + } |
| 55 | + mergeCommit { |
| 56 | + oid |
| 57 | + } |
| 58 | + assignees (first: 100) { |
| 59 | + nodes { |
| 60 | + name |
| 61 | + } |
| 62 | + } |
| 63 | + createdAt |
| 64 | + closedAt |
| 65 | + updatedAt |
| 66 | + closingIssuesReferences (first: 100) { |
| 67 | + nodes { |
| 68 | + number |
| 69 | + } |
| 70 | + } |
| 71 | + commits (first: 100) { |
| 72 | + nodes { |
| 73 | + commit { |
| 74 | + oid |
| 75 | + } |
| 76 | + } |
| 77 | + } |
| 78 | + additions |
| 79 | + changedFiles |
| 80 | + deletions |
| 81 | + participants (first: 100) { |
| 82 | + nodes { |
| 83 | + login |
| 84 | + } |
| 85 | + } |
| 86 | + labels (first: 100) { |
| 87 | + nodes { |
| 88 | + name, |
| 89 | + } |
| 90 | + } |
| 91 | + body |
| 92 | + totalCommentsCount |
| 93 | + comments (last: 100) { |
| 94 | + nodes { |
| 95 | + createdAt, |
| 96 | + author { |
| 97 | + login |
| 98 | + }, |
| 99 | + body |
| 100 | + } |
| 101 | + } |
| 102 | + } |
| 103 | + } |
| 104 | + } |
| 105 | + }") |
| 106 | + |
| 107 | + return (q) |
| 108 | +} |
| 109 | + |
| 110 | +prs_from_gh_api <- function (path, n_per_page = 30L) { |
| 111 | + |
| 112 | + is_test_env <- Sys.getenv ("REPOMETRICS_TESTS") == "true" |
| 113 | + if (is_test_env) { |
| 114 | + n_per_page <- 2L |
| 115 | + } |
| 116 | + |
| 117 | + or <- org_repo_from_path (path) |
| 118 | + end_cursor <- pr_data <- NULL |
| 119 | + has_next_page <- TRUE |
| 120 | + |
| 121 | + while (has_next_page) { |
| 122 | + |
| 123 | + q <- gh_prs_qry (org = or [1], repo = or [2], end_cursor = end_cursor, n_per_page = n_per_page) |
| 124 | + dat <- gh::gh_gql (query = q) |
| 125 | + |
| 126 | + pr_data <- c (pr_data, dat$data$repository$pullRequests$nodes) |
| 127 | + |
| 128 | + has_next_page <- dat$data$repository$pullRequests$pageInfo$hasNextPage |
| 129 | + end_cursor <- dat$data$repository$pullRequests$pageInfo$endCursor |
| 130 | + if (is_test_env) { |
| 131 | + has_next_page <- FALSE |
| 132 | + } |
| 133 | + } |
| 134 | + |
| 135 | + commit_oids <- vapply (pr_data, function (i) { |
| 136 | + oids <- vapply (i$commits$nodes, function (j) { |
| 137 | + j$commit$oid |
| 138 | + }, character (1L)) |
| 139 | + paste0 (oids, collapse = ",") |
| 140 | + }, character (1L)) |
| 141 | + participants <- vapply (pr_data, function (i) { |
| 142 | + p <- vapply (i$participants$nodes, function (j) j$login, character (1L)) |
| 143 | + paste0 (p, collapse = ",") |
| 144 | + }, character (1L)) |
| 145 | + comments <- lapply (pr_data, function (i) { |
| 146 | + created_at <- vapply (i$comments$nodes, function (j) j$createdAt, character (1L)) |
| 147 | + author <- vapply (i$comments$nodes, function (j) j$author$login, character (1L)) |
| 148 | + body <- vapply (i$comments$nodes, function (j) j$body, character (1L)) |
| 149 | + data.frame ( |
| 150 | + author = author, |
| 151 | + created_at = created_at, |
| 152 | + body = body |
| 153 | + ) |
| 154 | + }) |
| 155 | + closing_issue_refs <- lapply (pr_data, function (i) { |
| 156 | + vapply (i$closingIssuesReferences$nodes, function (j) j$number, integer (1L)) |
| 157 | + }) |
| 158 | + reviews <- lapply (pr_data, function (i) { |
| 159 | + login <- vapply (i$reviews$nodes, function (j) j$author$login, character (1L)) |
| 160 | + state <- vapply (i$reviews$nodes, function (j) j$state, character (1L)) |
| 161 | + submitted_at <- vapply (i$reviews$nodes, function (j) j$submittedAt, character (1L)) |
| 162 | + body <- vapply (i$reviews$nodes, function (j) j$body, character (1L)) |
| 163 | + data.frame ( |
| 164 | + login = login, |
| 165 | + state = state, |
| 166 | + submitted_at = submitted_at, |
| 167 | + body = body |
| 168 | + ) |
| 169 | + }) |
| 170 | + |
| 171 | + data.frame ( |
| 172 | + number = vapply (pr_data, function (i) i$number, integer (1L)), |
| 173 | + user_login = vapply (pr_data, function (i) i$author$login, character (1L)), |
| 174 | + state = vapply (pr_data, function (i) i$state, character (1L)), |
| 175 | + merged = vapply (pr_data, function (i) i$merged, logical (1L)), |
| 176 | + merged_by = vapply (pr_data, function (i) null2na_char (i$mergedBy$login), character (1L)), |
| 177 | + merge_commit = vapply (pr_data, function (i) null2na_char (i$mergeCommit$oid), character (1L)), |
| 178 | + closed = vapply (pr_data, function (i) i$closed, logical (1L)), |
| 179 | + title = vapply (pr_data, function (i) i$title, character (1L)), |
| 180 | + review_decision = vapply (pr_data, function (i) null2na_char (i$reviewDecision), character (1L)), |
| 181 | + created_at = vapply (pr_data, function (i) i$createdAt, character (1L)), |
| 182 | + closed_at = vapply (pr_data, function (i) null2na_char (i$closedAt), character (1L)), |
| 183 | + updated_at = vapply (pr_data, function (i) i$updatedAt, character (1L)), |
| 184 | + additions = vapply (pr_data, function (i) i$additions, integer (1L)), |
| 185 | + deletions = vapply (pr_data, function (i) i$deletions, integer (1L)), |
| 186 | + changed_files = vapply (pr_data, function (i) i$changedFiles, integer (1L)), |
| 187 | + commit_oids = commit_oids, |
| 188 | + closing_issue_refs = I (closing_issue_refs), |
| 189 | + total_comments = vapply (pr_data, function (i) i$totalCommentsCount, integer (1L)), |
| 190 | + participants = participants, |
| 191 | + body = vapply (pr_data, function (i) i$body, character (1L)), |
| 192 | + comments = I (comments), |
| 193 | + reviews = I (reviews) |
| 194 | + ) |
| 195 | +} |
0 commit comments