Skip to content

Commit 5860706

Browse files
authored
Merge pull request #27 from ropensci-review-tools/issues
gh issue data for #23
2 parents 0e08fea + 546b6da commit 5860706

11 files changed

+433
-127
lines changed

DESCRIPTION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: repometrics
22
Title: Metrics for Your Code Repository
3-
Version: 0.1.1.043
3+
Version: 0.1.1.050
44
Authors@R:
55
person("Mark", "Padgham", , "mark.padgham@email.com", role = c("aut", "cre"),
66
comment = c(ORCID = "0000-0003-2172-5265"))

R/cm-data-gh-contribs.R

+3-6
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,7 @@ contribs_from_gh_api <- function (path, n_per_page = 100) {
3131

3232
is_test_env <- Sys.getenv ("REPOMETRICS_TESTS") == "true"
3333

34-
or <- org_repo_from_path (path)
35-
u_base <- "https://api.github.com/repos/"
36-
u_org_repo <- paste0 (u_base, or [1], "/", or [2], "/")
37-
u_endpoint <- paste0 (u_org_repo, "contributors")
34+
u_endpoint <- gh_rest_api_endpoint (path = path, endpoint = "contributors")
3835

3936
req <- httr2::request (u_endpoint) |>
4037
httr2::req_url_query (per_page = n_per_page)
@@ -50,13 +47,13 @@ contribs_from_gh_api <- function (path, n_per_page = 100) {
5047

5148
body <- c (body, httr2::resp_body_json (resp))
5249

53-
next_page <- get_next_page (resp)
50+
next_page <- gh_next_page (resp)
5451
if (is_test_env) {
5552
next_page <- NULL
5653
}
5754

5855
req <- httr2::request (u_endpoint) |>
59-
httr2::req_url_query (per_page = 10) |>
56+
httr2::req_url_query (per_page = n_per_page) |>
6057
httr2::req_url_query (page = next_page)
6158
}
6259

R/cm-data-gh-issues.R

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
issues_from_gh_api <- function (path, n_per_page = 100) {
2+
3+
is_test_env <- Sys.getenv ("REPOMETRICS_TESTS") == "true"
4+
5+
u_endpoint <- gh_rest_api_endpoint (path = path, endpoint = "issues")
6+
7+
req0 <- req <- httr2::request (u_endpoint) |>
8+
httr2::req_url_query (state = "all") |>
9+
httr2::req_url_query (per_page = n_per_page) |>
10+
add_gh_token_to_req ()
11+
12+
body <- NULL
13+
next_page <- 1
14+
15+
while (!is.null (next_page)) {
16+
17+
resp <- httr2::req_perform (req)
18+
httr2::resp_check_status (resp)
19+
20+
body <- c (body, httr2::resp_body_json (resp))
21+
22+
next_page <- gh_next_page (resp)
23+
if (is_test_env) {
24+
next_page <- NULL
25+
}
26+
27+
req <- httr2::req_url_query (req0, page = next_page)
28+
}
29+
30+
issues <- data.frame (
31+
number = vapply (body, function (i) i$number, integer (1L)),
32+
title = vapply (body, function (i) i$title, character (1L)),
33+
id = vapply (body, function (i) i$id, double (1L)),
34+
url = vapply (body, function (i) i$html_url, character (1L)),
35+
user_login = vapply (body, function (i) i$user$login, character (1L)),
36+
user_id = vapply (body, function (i) i$user$id, integer (1L)),
37+
labels = vapply (body, function (i) {
38+
these_labels <- vapply (i$labels, function (j) j$name, character (1L))
39+
paste0 (these_labels, collapse = ", ")
40+
}, character (1L)),
41+
state = vapply (body, function (i) i$state, character (1L)),
42+
assignee = vapply (
43+
body,
44+
function (i) null2na_char (i$assignee$login),
45+
character (1L)
46+
),
47+
comments = vapply (body, function (i) i$comments, integer (1L)),
48+
created_at = vapply (body, function (i) i$created_at, character (1L)),
49+
updated_at = vapply (body, function (i) i$updated_at, character (1L)),
50+
closed_at = vapply (
51+
body,
52+
function (i) null2na_char (i$closed_at),
53+
character (1L)
54+
),
55+
issue_body = vapply (body, function (i) null2na_char (i$body), character (1L)),
56+
closed_by = vapply (
57+
body,
58+
function (i) null2na_char (i$closed_by$login),
59+
character (1L)
60+
),
61+
state_reason = vapply (
62+
body,
63+
function (i) null2na_char (i$state_reason),
64+
character (1L)
65+
)
66+
)
67+
68+
issues <- cbind (issues, get_issue_reactions (body))
69+
70+
return (issues)
71+
}
72+
73+
get_issue_reactions <- function (body) {
74+
75+
reactions <- c (
76+
"+1", "-1", "laugh", "hooray", "confused", "heart", "rocket", "eyes"
77+
)
78+
79+
reaction_counts <- lapply (reactions, function (i) {
80+
vapply (body, function (j) j$reaction [[i]], integer (1L))
81+
})
82+
83+
reaction_counts <- do.call (cbind, reaction_counts)
84+
reactions [1:2] <- c ("plus1", "minus1")
85+
colnames (reaction_counts) <- paste0 ("reaction_", reactions)
86+
87+
return (reaction_counts)
88+
}

R/gh-queries.R

+11-49
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@
55
github_repo_workflow_query <- function (org = NULL, repo = NULL, n = 30L) {
66

77
checkmate::assert_integer (n, lower = 1L)
8-
u_base <- "https://api.github.com/repos/"
9-
u_repo <- paste0 (u_base, org, "/", repo, "/")
10-
u_wf <- paste0 (u_repo, "actions/runs?per_page=", n)
8+
u_wf <- gh_rest_api_endpoint (orgrepo = c (org, repo), endpoint = "actions/runs")
119

1210
req <- httr2::request (u_wf) |>
13-
add_gh_token_to_req ()
11+
add_gh_token_to_req () |>
12+
httr2::req_url_query (per_page = n)
1413

1514
resp <- httr2::req_perform (req)
1615
httr2::resp_check_status (resp)
@@ -54,31 +53,29 @@ github_repo_workflow_query <- function (org = NULL, repo = NULL, n = 30L) {
5453
#' @noRd
5554
github_issues_prs_query <- function (org = NULL, repo = NULL) {
5655

57-
u_base <- "https://api.github.com/repos/"
58-
u_repo <- paste0 (u_base, org, "/", repo, "/")
59-
6056
is_test_env <- Sys.getenv ("REPOMETRICS_TESTS") == "true"
61-
url0 <- paste0 (u_repo, "events?per_page=", ifelse (is_test_env, 2, 100))
57+
58+
u_events <- gh_rest_api_endpoint (orgrepo = c (org, repo), endpoint = "events")
59+
60+
req <- req0 <- httr2::request (u_events) |>
61+
add_token_to_req () |>
62+
httr2::req_url_query (per_page = ifelse (is_test_env, 2, 100))
6263

6364
body <- NULL
6465
next_page <- 1
65-
this_url <- url0
6666
while (!is.null (next_page)) {
6767

68-
req <- httr2::request (this_url) |>
69-
add_token_to_req ()
70-
7168
resp <- httr2::req_perform (req)
7269
httr2::resp_check_status (resp)
7370

7471
this_body <- httr2::resp_body_json (resp)
7572
body <- c (body, this_body)
7673

77-
next_page <- get_next_page (resp)
74+
next_page <- gh_next_page (resp)
7875
if (is_test_env) {
7976
next_page <- NULL
8077
}
81-
this_url <- paste0 (url0, "&page=", next_page)
78+
req <- httr2::req_url_query (req0, page = next_page)
8279
}
8380

8481
# Extraction function for single fields which may not be present
@@ -148,38 +145,3 @@ github_issues_prs_query <- function (org = NULL, repo = NULL) {
148145
merged_at = merged_at
149146
)
150147
}
151-
152-
add_token_to_req <- function (req) {
153-
154-
if (!nzchar (Sys.getenv ("GITHUB_WORKFLOW"))) {
155-
tok <- get_gh_token ()
156-
headers <- list (Authorization = paste0 ("Bearer ", tok))
157-
req <- httr2::req_headers (req, "Authorization" = headers)
158-
}
159-
160-
return (req)
161-
}
162-
163-
#' Pagination for Rest API. see
164-
#' https://docs.github.com/en/rest/using-the-rest-api/using-pagination-in-the-rest-api
165-
#' @noRd
166-
get_next_page <- function (resp) {
167-
168-
link <- httr2::resp_headers (resp)$link
169-
170-
next_page <- NULL
171-
172-
if (!is.null (link)) {
173-
next_ptn <- "rel\\=\\\"next"
174-
if (grepl (next_ptn, link)) {
175-
links <- strsplit (link, ",\\s+") [[1]]
176-
link <- grep (next_ptn, links, value = TRUE)
177-
178-
ptn <- "<([^>]+)>"
179-
next_page <- regmatches (link, regexpr (ptn, link))
180-
next_page <- gsub ("^.*&page\\=|>", "", next_page)
181-
}
182-
}
183-
184-
return (next_page)
185-
}

R/utils-github.R

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# nocov start
2+
get_gh_token <- function () {
3+
e <- Sys.getenv ()
4+
nms <- names (e)
5+
tok <- unique (e [grep ("GITHUB", nms)])
6+
if (length (tok) != 1L) {
7+
tok <- unique (e [grep ("GITHUB\\_(PAT|TOK)", nms)])
8+
}
9+
if (length (tok) != 1L) {
10+
cli::cli_abort (
11+
"Unable to determine unique GitHub token from environment variables"
12+
)
13+
}
14+
return (tok)
15+
}
16+
# nocov end
17+
18+
add_gh_token_to_req <- function (req) {
19+
if (!nzchar (Sys.getenv ("GITHUB_WORKFLOW"))) {
20+
tok <- get_gh_token ()
21+
headers <- list (Authorization = paste0 ("Bearer ", tok))
22+
req <- httr2::req_headers (req, "Authorization" = headers)
23+
}
24+
25+
return (req)
26+
}
27+
28+
gh_rest_api_endpoint <- function (path = NULL, orgrepo = NULL, endpoint = NULL) {
29+
30+
checkmate::assert_character (endpoint, len = 1L)
31+
32+
if (!is.null (path)) {
33+
checkmate::assert_directory (path)
34+
orgrepo <- org_repo_from_path (path)
35+
} else {
36+
checkmate::assert_character (orgrepo, len = 2L)
37+
}
38+
39+
u_base <- "https://api.github.com/repos/"
40+
u_org_repo <- paste0 (u_base, orgrepo [1], "/", orgrepo [2], "/")
41+
paste0 (u_org_repo, endpoint)
42+
}
43+
44+
add_token_to_req <- function (req) {
45+
46+
if (!nzchar (Sys.getenv ("GITHUB_WORKFLOW"))) {
47+
tok <- get_gh_token ()
48+
headers <- list (Authorization = paste0 ("Bearer ", tok))
49+
req <- httr2::req_headers (req, "Authorization" = headers)
50+
}
51+
52+
return (req)
53+
}
54+
55+
#' Pagination for Rest API. see
56+
#' https://docs.github.com/en/rest/using-the-rest-api/using-pagination-in-the-rest-api
57+
#' @noRd
58+
gh_next_page <- function (resp) {
59+
60+
link <- httr2::resp_headers (resp)$link
61+
62+
next_page <- NULL
63+
64+
if (!is.null (link)) {
65+
next_ptn <- "rel\\=\\\"next"
66+
if (grepl (next_ptn, link)) {
67+
links <- strsplit (link, ",\\s+") [[1]]
68+
link <- grep (next_ptn, links, value = TRUE)
69+
70+
ptn <- "<([^>]+)>"
71+
next_page <- regmatches (link, regexpr (ptn, link))
72+
next_page <- gsub ("^.*&page\\=|>", "", next_page)
73+
}
74+
}
75+
76+
return (next_page)
77+
}

R/utils-path-pkg-manipulation.R

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
pkg_name_from_path <- function (path) {
2+
desc <- fs::dir_ls (path, type = "file", regexp = "DESCRIPTION$")
3+
checkmate::assert_file_exists (desc)
4+
5+
unname (read.dcf (desc) [, "Package"])
6+
}
7+
8+
pkg_gh_url_from_path <- function (path) {
9+
10+
desc <- fs::dir_ls (path, type = "file", regexp = "DESCRIPTION$")
11+
checkmate::assert_file_exists (desc)
12+
13+
desc <- read.dcf (desc)
14+
ret <- NULL
15+
if ("URL" %in% colnames (desc)) {
16+
url <- strsplit (unname (desc [, "URL"]), "\\n|,") [[1]]
17+
url <- gsub ("^[[:space:]]*", "", url)
18+
url <- gsub ("[[:space:]].*$", "", url)
19+
ret <- grep ("github\\.com", url, value = TRUE)
20+
}
21+
return (ret)
22+
}
23+
24+
org_repo_from_path <- function (path) {
25+
26+
url <- pkg_gh_url_from_path (path)
27+
if (length (url) == 0L) {
28+
return (FALSE)
29+
}
30+
31+
url_parts <- strsplit (url, "\\/") [[1]]
32+
i <- which (url_parts == "github.com")
33+
if (length (i) == 0L || i > (length (url_parts) + 2L)) {
34+
return (FALSE)
35+
}
36+
org <- url_parts [i + 1L]
37+
repo <- url_parts [i + 2L]
38+
39+
c (org, repo)
40+
}

0 commit comments

Comments
 (0)