Skip to content

Commit

Permalink
Merge pull request #499 from r-world-devs/492-fix-get_repos
Browse files Browse the repository at this point in the history
492 get_repos() for users
  • Loading branch information
maciekbanas authored Oct 11, 2024
2 parents 8b751aa + 3f6e9ef commit 18a2574
Show file tree
Hide file tree
Showing 24 changed files with 978 additions and 197 deletions.
5 changes: 2 additions & 3 deletions .github/workflows/test-coverage.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
on:
push:
branches: [master]
Expand All @@ -14,6 +12,7 @@ jobs:
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
GITLAB_PAT_PUBLIC: ${{ secrets.GITLAB_PAT}}
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
USE_RENV: "FALSE"

steps:
Expand All @@ -28,7 +27,7 @@ jobs:
extra-packages: any::covr
needs: coverage

- name: Test coverage
- name: Code coverage
run: |
covr::codecov(
quiet = FALSE,
Expand Down
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: GitStats
Title: Get Statistics from GitHub and GitLab
Version: 2.1.0.9000
Version: 2.1.0.9001
Authors@R: c(
person(given = "Maciej", family = "Banas", email = "[email protected]", role = c("aut", "cre")),
person(given = "Kamil", family = "Koziej", email = "[email protected]", role = "aut"),
Expand Down
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# GitStats (development version)

- Added possibility to get repositories for individual users with `get_repos()` ([#492](https://github.com/r-world-devs/GitStats/issues/492)). Earlier this was only possible for GitHub organizations and GitLab groups.
- Fixed getting large search responses for GitHub ([#491](https://github.com/r-world-devs/GitStats/issues/491)).

# GitStats 2.1.0
Expand Down
37 changes: 27 additions & 10 deletions R/EngineGraphQLGitHub.R
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,22 @@ EngineGraphQLGitHub <- R6::R6Class(
},

# Pull all repositories from organization
get_repos_from_org = function(org = NULL) {
get_repos_from_org = function(org = NULL,
type = c("organization", "user")) {
full_repos_list <- list()
next_page <- TRUE
repo_cursor <- ""
while (next_page) {
repos_response <- private$get_repos_page(
org = org,
login = org,
type = type,
repo_cursor = repo_cursor
)
repositories <- repos_response$data$repositoryOwner$repositories
repositories <- if (type == "organization") {
repos_response$data$repositoryOwner$repositories
} else {
repos_response$data$user$repositories
}
repos_list <- repositories$nodes
next_page <- repositories$pageInfo$hasNextPage
if (is.null(next_page)) next_page <- FALSE
Expand Down Expand Up @@ -87,6 +93,7 @@ EngineGraphQLGitHub <- R6::R6Class(

# Pull all given files from all repositories of an organization.
get_files_from_org = function(org,
type,
repos,
file_paths,
host_files_structure,
Expand All @@ -95,6 +102,7 @@ EngineGraphQLGitHub <- R6::R6Class(
progress = TRUE) {
repo_data <- private$get_repos_data(
org = org,
type = type,
repos = repos
)
repositories <- repo_data[["repositories"]]
Expand All @@ -117,13 +125,15 @@ EngineGraphQLGitHub <- R6::R6Class(

# Pull all files from all repositories of an organization.
get_files_structure_from_org = function(org,
type,
repos,
pattern = NULL,
depth = Inf,
verbose = FALSE,
progress = TRUE) {
repo_data <- private$get_repos_data(
org = org,
type = type,
repos = repos
)
repositories <- repo_data[["repositories"]]
Expand Down Expand Up @@ -162,14 +172,20 @@ EngineGraphQLGitHub <- R6::R6Class(
private = list(

# Wrapper over building GraphQL query and response.
get_repos_page = function(org = NULL,
get_repos_page = function(login = NULL,
type = c("organization", "user"),
repo_cursor = "") {
repos_query <- self$gql_query$repos_by_org(
repo_cursor = repo_cursor
)
repos_query <- if (type == "organization") {
self$gql_query$repos_by_org()
} else {
self$gql_query$repos_by_user()
}
response <- self$gql_response(
gql_query = repos_query,
vars = list("org" = org)
vars = list(
"login" = login,
"repoCursor" = repo_cursor
)
)
return(response)
},
Expand Down Expand Up @@ -225,9 +241,10 @@ EngineGraphQLGitHub <- R6::R6Class(
return(response)
},

get_repos_data = function(org, repos = NULL) {
get_repos_data = function(org, type, repos = NULL) {
repos_list <- self$get_repos_from_org(
org = org
org = org,
type = type
)
if (!is.null(repos)) {
repos_list <- purrr::keep(repos_list, ~ .$repo_name %in% repos)
Expand Down
180 changes: 107 additions & 73 deletions R/EngineGraphQLGitLab.R
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,22 @@ EngineGraphQLGitLab <- R6::R6Class(
},

# Iterator over pulling pages of repositories.
get_repos_from_org = function(org = NULL) {
get_repos_from_org = function(org = NULL,
type = c("organization", "user")) {
full_repos_list <- list()
next_page <- TRUE
repo_cursor <- ""
while (next_page) {
repos_response <- private$get_repos_page(
org = org,
type = type,
repo_cursor = repo_cursor
)
if (length(repos_response$data$group) == 0) {
cli::cli_abort("Empty")
core_response <- if (type == "organization") {
repos_response$data$group$projects
} else {
repos_response$data$projects
}
core_response <- repos_response$data$group$projects
repos_list <- core_response$edges
next_page <- core_response$pageInfo$hasNextPage
if (is.null(next_page)) next_page <- FALSE
Expand All @@ -81,6 +84,7 @@ EngineGraphQLGitLab <- R6::R6Class(
# pulled files_structure. In such a case GitStats will switch from this function
# to iterator over repositories (multiple queries), as it is done for GitHub.
get_files_from_org = function(org,
type,
repos,
file_paths,
host_files_structure,
Expand All @@ -100,73 +104,87 @@ EngineGraphQLGitLab <- R6::R6Class(
} else if (is.null(host_files_structure) && only_text_files) {
file_paths <- file_paths[!grepl(non_text_files_pattern, file_paths)]
}
while (next_page) {
files_query <- self$gql_query$files_by_org(
end_cursor = end_cursor
)
files_response <- tryCatch(
{
self$gql_response(
gql_query = files_query,
vars = list(
"org" = org,
"file_paths" = file_paths
if (type == "organization") {
while (next_page) {
files_query <- self$gql_query$files_by_org(
end_cursor = end_cursor
)
files_response <- tryCatch(
{
self$gql_response(
gql_query = files_query,
vars = list(
"org" = org,
"file_paths" = file_paths
)
)
)
},
error = function(e) {
list()
}
)
if (private$is_query_error(files_response)) {
if (verbose) {
purrr::walk(files_response$errors, ~ cli::cli_alert_warning(.))
}
if (private$is_complexity_error(files_response)) {
},
error = function(e) {
list()
}
)
if (private$is_query_error(files_response)) {
if (verbose) {
cli::cli_alert_info(
cli::col_br_cyan("I will switch to pulling files per repository.")
purrr::walk(files_response$errors, ~ cli::cli_alert_warning(.))
}
if (private$is_complexity_error(files_response)) {
if (verbose) {
cli::cli_alert_info(
cli::col_br_cyan("I will switch to pulling files per repository.")
)
}
full_files_list <- self$get_files_from_org_per_repo(
org = org,
type = type,
repos = repos,
file_paths = file_paths,
host_files_structure = host_files_structure,
only_text_files = only_text_files,
verbose = verbose,
progress = progress
)
return(full_files_list)
}
full_files_list <- self$get_files_from_org_per_repo(
org = org,
repos = repos,
file_paths = file_paths,
host_files_structure = host_files_structure,
only_text_files = only_text_files,
verbose = verbose,
progress = progress
)
return(full_files_list)
}
if (length(files_response$data$group) == 0 && verbose) {
cli::cli_alert_danger("Empty response.")
}
projects <- files_response$data$group$projects
files_list <- purrr::map(projects$edges, function(edge) {
edge$node
}) %>%
purrr::discard(~ length(.$repository$blobs$nodes) == 0)
if (is.null(files_list)) files_list <- list()
if (length(files_list) > 0) {
next_page <- files_response$pageInfo$hasNextPage
} else {
next_page <- FALSE
}
if (is.null(next_page)) next_page <- FALSE
if (next_page) {
end_cursor <- files_response$pageInfo$endCursor
} else {
end_cursor <- ""
}
full_files_list <- append(full_files_list, files_list)
}
if (length(files_response$data$group) == 0 && verbose) {
cli::cli_alert_danger("Empty response.")
}
projects <- files_response$data$group$projects
files_list <- purrr::map(projects$edges, function(edge) {
edge$node
}) %>%
purrr::discard(~ length(.$repository$blobs$nodes) == 0)
if (is.null(files_list)) files_list <- list()
if (length(files_list) > 0) {
next_page <- files_response$pageInfo$hasNextPage
} else {
next_page <- FALSE
}
if (is.null(next_page)) next_page <- FALSE
if (next_page) {
end_cursor <- files_response$pageInfo$endCursor
} else {
end_cursor <- ""
if (!is.null(repos)) {
full_files_list <- purrr::keep(full_files_list, function(project) {
repo_name <- private$get_repo_name_from_url(project$webUrl)
repo_name %in% repos
})
}
full_files_list <- append(full_files_list, files_list)
}
if (!is.null(repos)) {
full_files_list <- purrr::keep(full_files_list, function(project) {
repo_name <- private$get_repo_name_from_url(project$webUrl)
repo_name %in% repos
})
} else {
full_files_list <- self$get_files_from_org_per_repo(
org = org,
type = type,
repos = repos,
file_paths = file_paths,
host_files_structure = host_files_structure,
only_text_files = only_text_files,
verbose = verbose,
progress = progress
)
}
return(full_files_list)
},
Expand All @@ -175,6 +193,7 @@ EngineGraphQLGitLab <- R6::R6Class(
# one query way applied with get_files_from_org() fails due to its complexity.
# For more info see docs above.
get_files_from_org_per_repo = function(org,
type,
repos,
file_paths = NULL,
host_files_structure = NULL,
Expand All @@ -184,6 +203,7 @@ EngineGraphQLGitLab <- R6::R6Class(
if (is.null(repos)) {
repo_data <- private$get_repos_data(
org = org,
type = type,
repos = repos
)
repos <- repo_data[["repositories"]]
Expand Down Expand Up @@ -213,13 +233,15 @@ EngineGraphQLGitLab <- R6::R6Class(
return(org_files_list)
},
get_files_structure_from_org = function(org,
type,
repos,
pattern = NULL,
depth = Inf,
verbose = TRUE,
progress = TRUE) {
repo_data <- private$get_repos_data(
org = org,
type = type,
repos = repos
)
repositories <- repo_data[["repositories"]]
Expand Down Expand Up @@ -259,14 +281,25 @@ EngineGraphQLGitLab <- R6::R6Class(

# Wrapper over building GraphQL query and response.
get_repos_page = function(org = NULL,
type = "organization",
repo_cursor = "") {
repos_query <- self$gql_query$repos_by_org(
repo_cursor = repo_cursor
)
response <- self$gql_response(
gql_query = repos_query,
vars = list("org" = org)
)
if (type == "organization") {
response <- self$gql_response(
gql_query = self$gql_query$repos_by_org(),
vars = list(
"org" = org,
"repo_cursor" = repo_cursor
)
)
} else {
response <- self$gql_response(
gql_query = self$gql_query$repos_by_user(),
vars = list(
"username" = org,
"repo_cursor" = repo_cursor
)
)
}
return(response)
},

Expand All @@ -277,9 +310,10 @@ EngineGraphQLGitLab <- R6::R6Class(
return(repo_name)
},

get_repos_data = function(org, repos = NULL) {
get_repos_data = function(org, type, repos = NULL) {
repos_list <- self$get_repos_from_org(
org = org
org = org,
type = type
)
if (!is.null(repos)) {
repos_list <- purrr::keep(repos_list, ~ .$node$repo_path %in% repos)
Expand Down
Loading

0 comments on commit 18a2574

Please sign in to comment.