Skip to content

Commit

Permalink
Merge pull request #22 from ropensci-review-tools/issues
Browse files Browse the repository at this point in the history
issues linked to change request metric for  #11
  • Loading branch information
mpadge authored Nov 14, 2024
2 parents 062c43e + 0bd82b2 commit 7b44c2b
Show file tree
Hide file tree
Showing 11 changed files with 498 additions and 4 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: repometrics
Title: Metrics for Your Code Repository
Version: 0.1.1.009
Version: 0.1.1.016
Authors@R:
person("Mark", "Padgham", , "[email protected]", role = c("aut", "cre"),
comment = c(ORCID = "0000-0003-2172-5265"))
Expand Down
25 changes: 25 additions & 0 deletions R/chaoss-external.R
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,28 @@ has_gh_ci_tests <- function (path) {
h <- gert::git_log (repo = path, max = 1e6)
any (ci_data$sha %in% h$commit)
}

#' The "Ratio of Code Commits linked with Change Requests" CHAOSS metric. This
#' is defined as, "Percentage of new code commits linked with change requests
#' in the last 90 days."
#' \url{https://chaoss.community/kb/metrics-model-collaboration-development-index/}.
prop_commits_in_change_req <- function (path, end_date = Sys.Date ()) {

or <- org_repo_from_path (path)

gh_dat <- github_issues_prs_query (org = or [1], repo = or [2])

# Reduce to PR open-close events:
gh_prs <- dplyr::filter (gh_dat, !is.na (number)) |>
dplyr::group_by (number) |>
dplyr::filter (action == "closed")

start_date <- as.Date (end_date - get_repometrics_period ())
index <- which (as.Date (gh_prs$merged_at) >= start_date)

num_commits_from_prs <- sum (gh_prs$commits [index])

log <- git_log_in_period (path, end_date, get_repometrics_period ())

ifelse (nrow (log) == 0, 0, num_commits_from_prs / nrow (log))
}
5 changes: 4 additions & 1 deletion R/chaoss-hybrid.R
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# Hybird metrics from both internal structure and external data

chaoss_metric_has_ci <- function (path) {
has_ci <- has_gh_ci_tests (path)

is_test_env <- Sys.getenv ("REPOMETRICS_TESTS") == "true"
has_ci <- ifelse (is_test_env, FALSE, has_gh_ci_tests (path))

if (!has_ci) {
ci_files <- repo_has_ci_files (path)
has_ci <- length (ci_files) > 0L
Expand Down
139 changes: 138 additions & 1 deletion R/gh-queries.R
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ github_repo_workflow_query <- function (org = NULL, repo = NULL, n = 30L) {
status <- vapply (workflows, function (i) i$status, character (1L))
conclusion <- vapply (workflows, function (i) i$conclusion, character (1L))
created <- vapply (workflows, function (i) i$created_at, character (1L))
created <- as.POSIXct (created, format = "%Y-%m-%dT%H:%M:%S", tz = "UTC")
created <- to_posix (created)

data.frame (
name = names,
Expand All @@ -42,3 +42,140 @@ github_repo_workflow_query <- function (org = NULL, repo = NULL, n = 30L) {
created = created
)
}

#' Use the GitHub Rest API activity list to extract event types.
#' Activity requests are described at
#' \url{https://docs.github.com/en/rest/repos/repos?apiVersion=2022-11-28#list-repository-activities}
#' and the list of all event types is at
#' \url{https://docs.github.com/en/rest/using-the-rest-api/github-event-types?apiVersion=2022-11-28}.
#' @noRd
github_issues_prs_query <- function (org = NULL, repo = NULL) {

u_base <- "https://api.github.com/repos/"
u_repo <- paste0 (u_base, org, "/", repo, "/")

is_test_env <- Sys.getenv ("REPOMETRICS_TESTS") == "true"
url0 <- paste0 (u_repo, "events?per_page=", ifelse (is_test_env, 2, 100))

body <- NULL
next_page <- 1
this_url <- url0
while (!is.null (next_page)) {

req <- httr2::request (this_url) |>
add_token_to_req ()

resp <- httr2::req_perform (req)
httr2::resp_check_status (resp)

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

next_page <- get_next_page (resp)
if (is_test_env) {
next_page <- NULL
}
this_url <- paste0 (url0, "&page=", next_page)
}

# Extraction function for single fields which may not be present
extract_one <- function (body, field = "action", naval = NA_character_) {
ret_type <- do.call (typeof (naval), list (1L))
vapply (body, function (i) {
ifelse (field %in% names (i$payload), i$payload [[field]], naval)
}, ret_type)
}

# Extraction function for doubly-nexted fields which may not be present
extract_two <- function (body,
field1 = "pull_request",
field2 = "comments",
naval = NA_character_) {

ret_type <- do.call (typeof (naval), list (1L))
vapply (body, function (i) {
ret <- naval
if (field1 %in% names (i$payload)) {
if (field2 %in% names (i$payload [[field1]])) {
ret <- i$payload [[field1]] [[field2]]
}
}
ifelse (is.null (ret), naval, ret)
}, ret_type)
}

# Items which are always present:
ids <- vapply (body, function (i) i$id, character (1L))
type <- vapply (body, function (i) i$type, character (1L))
login <- vapply (body, function (i) i$actor$login, character (1L))

# Single-nested items:
action <- extract_one (body, "action", NA_character_)
number <- extract_one (body, "number", NA_integer_)

# Doubly-nested items:
num_comments <- extract_two (body, "pull_request", "comments", NA_integer_)
num_review_comments <-
extract_two (body, "pull_request", "review_comments", NA_integer_)
commits <- extract_two (body, "pull_request", "commits", NA_integer_)
additions <- extract_two (body, "pull_request", "additions", NA_integer_)
deletions <- extract_two (body, "pull_request", "deletions", NA_integer_)
changed_files <-
extract_two (body, "pull_request", "changed_files", NA_integer_)
created_at <-
extract_two (body, "pull_request", "created_at", NA_character_)
created_at <- to_posix (created_at)
merged_at <-
extract_two (body, "pull_request", "created_at", NA_character_)
merged_at <- to_posix (merged_at)

data.frame (
id = ids,
type = type,
login = login,
action = action,
number = number,
commits = commits,
num_comments = num_comments,
num_review_comments = num_review_comments,
additions = additions,
deletions = deletions,
changed_files = changed_files,
created_at = created_at,
merged_at = merged_at
)
}

add_token_to_req <- function (req) {

if (!nzchar (Sys.getenv ("GITHUB_WORKFLOW"))) {
tok <- get_gh_token ()
headers <- list (Authorization = paste0 ("Bearer ", tok))
req <- httr2::req_headers (req, "Authorization" = headers)
}

return (req)
}

#' Pagination for Rest API. see
#' https://docs.github.com/en/rest/using-the-rest-api/using-pagination-in-the-rest-api
#' @noRd
get_next_page <- function (resp) {

link <- httr2::resp_headers (resp)$link

next_page <- NULL

if (!is.null (link)) {
next_ptn <- "rel\\=\\\"next"
if (grepl (next_ptn, link)) {
# "next" is always first; where there are multiples, "prev" comes
# after "next"
ptn <- "<([^>]+)>"
next_page <- regmatches (link, regexpr (ptn, link))
next_page <- gsub ("^.*&page\\=|>", "", next_page)
}
}

return (next_page)
}
4 changes: 4 additions & 0 deletions R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ set_num_cores <- function (num_cores) {
return (num_cores)
}

to_posix <- function (x) {
as.POSIXct (x, format = "%Y-%m-%dT%H:%M:%S", tz = "UTC")
}

# nocov start
get_gh_token <- function () {
e <- Sys.getenv ()
Expand Down
2 changes: 1 addition & 1 deletion codemeta.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"codeRepository": "https://github.com/ropensci-review-tools/repometrics",
"issueTracker": "https://github.com/ropensci-review-tools/repometrics/issues",
"license": "https://spdx.org/licenses/GPL-3.0",
"version": "0.1.1.009",
"version": "0.1.1.016",
"programmingLanguage": {
"@type": "ComputerLanguage",
"name": "R",
Expand Down
7 changes: 7 additions & 0 deletions inst/httptest2/redact.R
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ function (resp) {
fixed = TRUE
)

resp <- httptest2::gsub_response (
resp,
"ropensci-review-tools/goodpractice",
"repo/",
fixed = TRUE
)

test_repo <- "ropensci-review-tools/repometrics"
resp <- httptest2::gsub_response (
resp,
Expand Down
7 changes: 7 additions & 0 deletions tests/testthat/_snaps/chaoss-metrics-hybrid.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# chaoss metric has_ci

Code
chk <- chaoss_metric_has_ci(path)
Message
i Unable to determine whether runs are recent for CI service [github].

Loading

0 comments on commit 7b44c2b

Please sign in to comment.