diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index 4ec92b3..9988070 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -39,7 +39,7 @@ jobs: R_KEEP_PKG_SOURCE: yes steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: r-lib/actions/setup-pandoc@v2 diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index 087f0b0..c9f0165 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -11,6 +11,8 @@ on: name: pkgdown +permissions: read-all + jobs: pkgdown: runs-on: ubuntu-latest @@ -19,8 +21,10 @@ jobs: group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + permissions: + contents: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: r-lib/actions/setup-pandoc@v2 @@ -39,7 +43,7 @@ jobs: - name: Deploy to GitHub pages 🚀 if: github.event_name != 'pull_request' - uses: JamesIves/github-pages-deploy-action@v4.4.1 + uses: JamesIves/github-pages-deploy-action@v4.5.0 with: clean: false branch: gh-pages diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml index 82e9446..4625a6c 100644 --- a/.github/workflows/test-coverage.yaml +++ b/.github/workflows/test-coverage.yaml @@ -23,7 +23,7 @@ jobs: COMMENTED_COMMIT: '5666b975e168866ed77ae61d4cd5402a74f3d6c6' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: r-lib/actions/setup-r@v2 with: @@ -31,28 +31,38 @@ jobs: - uses: r-lib/actions/setup-r-dependencies@v2 with: - extra-packages: any::covr + extra-packages: any::covr, any::xml2 needs: coverage + - name: Test coverage run: | - covr::codecov( + cov <- covr::package_coverage( quiet = FALSE, clean = FALSE, - install_path = file.path(Sys.getenv("RUNNER_TEMP"), "package") + install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") ) + covr::to_cobertura(cov) shell: Rscript {0} + - uses: codecov/codecov-action@v4 + with: + fail_ci_if_error: ${{ github.event_name != 'pull_request' && true || false }} + file: ./cobertura.xml + plugin: noop + disable_search: true + token: ${{ secrets.CODECOV_TOKEN }} + - name: Show testthat output if: always() run: | ## -------------------------------------------------------------------- - find ${{ runner.temp }}/package -name 'testthat.Rout*' -exec cat '{}' \; || true + find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true shell: bash - name: Upload test results if: failure() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: coverage-test-failures path: ${{ runner.temp }}/package diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3932101..11fd60f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -86,6 +86,8 @@ devtools::test() ## run all tests testthat::test_file("tests/testthat/test_ci.R") ## run test on one file ``` +_Note that if the test suite fails, you may leave the repository in a state that is not cleaned._ +_Hence, you may have to manually clean the repository on GitLab before running the tests again._ ### How to check the package with GitHub Actions on your own fork @@ -116,6 +118,8 @@ I recommend to keep only one OS tested to avoid unit tests to be run in parallel To do so, you can comment all but one OS in ".github/workflows/R-CMD-check.yaml", and change the values of the variable according to your configuration. --> +_Note that if the test suite fails, you may leave the repository in a state that is not cleaned._ +_Hence, you may have to manually clean the repository on GitLab before running the tests again._ ### API version diff --git a/DESCRIPTION b/DESCRIPTION index 33f31db..8ec6285 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: gitlabr Title: Access to the 'Gitlab' API -Version: 2.0.1.9000 +Version: 2.0.1.9002 Authors@R: c( person("Jirka", "Lewandowski", , "jirka.lewandowski@wzb.eu", role = "aut"), person("Sébastien", "Rochette", , "sebastien@thinkr.fr", role = c("aut", "cre"), @@ -25,14 +25,15 @@ Imports: httr (>= 1.1.0), magrittr, purrr (>= 0.2.2), - shiny (>= 0.13.0), stringr, tibble (>= 1.1), tidyr, utils Suggests: + DT, knitr, rmarkdown, + shiny (>= 0.13.0), testthat (>= 3.0.0), yaml VignetteBuilder: @@ -42,4 +43,4 @@ Config/testthat/edition: 3 Encoding: UTF-8 LazyData: true Roxygen: list(markdown = TRUE) -RoxygenNote: 7.2.2 +RoxygenNote: 7.3.1 diff --git a/NAMESPACE b/NAMESPACE index cea9e00..f71900b 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,30 +1,8 @@ # Generated by roxygen2: do not edit by hand export("%>%") -export(archive) -export(assign_issue) -export(close_issue) -export(comment_commit) -export(comment_issue) -export(create_branch) -export(create_merge_request) -export(delete_branch) -export(edit_commit_comment) -export(edit_issue) -export(edit_issue_comment) -export(file_exists) -export(get_comments) -export(get_commit_comments) -export(get_commits) -export(get_diff) -export(get_file) export(get_gitlab_connection) -export(get_issue) -export(get_issue_comments) -export(get_issues) -export(get_project_id) export(gitlab) -export(gitlab_connection) export(gitlabr_options_set) export(glLoginInput) export(glReactiveLogin) @@ -41,10 +19,13 @@ export(gl_create_branch) export(gl_create_issue) export(gl_create_merge_request) export(gl_delete_branch) +export(gl_delete_file) +export(gl_delete_group) export(gl_delete_issue) export(gl_delete_merge_request) export(gl_delete_project) export(gl_edit_commit_comment) +export(gl_edit_group) export(gl_edit_issue) export(gl_edit_issue_comment) export(gl_edit_merge_request) @@ -56,22 +37,27 @@ export(gl_get_commit_comments) export(gl_get_commits) export(gl_get_diff) export(gl_get_file) +export(gl_get_group_id) export(gl_get_issue) export(gl_get_issue_comments) export(gl_get_project) export(gl_get_project_id) export(gl_get_projects) +export(gl_group_req) export(gl_jobs) export(gl_latest_build_artifact) export(gl_list_branches) export(gl_list_files) export(gl_list_group_members) export(gl_list_group_projects) +export(gl_list_groups) export(gl_list_issues) export(gl_list_merge_requests) export(gl_list_project_members) export(gl_list_projects) +export(gl_list_sub_groups) export(gl_list_user_projects) +export(gl_new_group) export(gl_new_issue) export(gl_new_project) export(gl_pipelines) @@ -82,19 +68,8 @@ export(gl_reopen_issue) export(gl_repository) export(gl_to_issue_id) export(gl_unassign_issue) -export(list_branches) -export(list_files) -export(list_projects) export(multilist_to_tibble) -export(new_issue) -export(proj_req) -export(project_connection) -export(push_file) -export(reopen_issue) -export(repository) export(set_gitlab_connection) -export(to_issue_id) -export(unassign_issue) export(unset_gitlab_connection) export(use_gitlab_ci) importFrom(arpr,iff) diff --git a/NEWS.md b/NEWS.md index 7e2424d..ecdffcb 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,28 +2,38 @@ ## Breaking changes +* Functions deprecated since version 0.7 are removed * Transfer ownership of the project to ThinkR-open +## New features + +* `gl_new_group()`, `gl_edit_group()`, `gl_delete_group()`, `gl_list_groups()`, `gl_list_sub_groups()` to deal with groups on a GitLab instance (@mpolano) +* `gl_delete_file()` to delete a file in a repository +* `gl_list_project_members()` and `gl_list_group_members` to retrieve members of a project or a group (#61, @datawookie) + ## Minor changes * `multilist_to_tibble()` transforms a deep structured nested list from an API into a tibble (#86, @statnmap, @ymansiaux) +## Bug fixes + +* `gl_file_exists()`, `gl_list_files()`, `gl_push_file()`, `gl_delete_file()` now work with files in subdirectories + # gitlabr 2.0.1 -New features +## New features * Connection now uses the token as "header" instead of being sent clearly in the URL (#66, @ei-ds) * `gl_list_group_projects()` lists projects of a group (@Yoshinobu-Ishizaki) -* `gl_list_project_members()` and `gl_list_group_members` to retrieve members of a project or a group (#61, @datawookie) -Minor changes +## Minor changes * doc HTML5 re-created with last version of roxygen2 # gitlabr 2.0.0 -Breaking changes +## Breaking changes * Default branch is named `main` whenever required. + This can be changed with `gitlabr_options_set("gitlabr.main", "master")` @@ -36,14 +46,14 @@ Breaking changes * Changed use of `api_version = "v4"` by `api_version = 4` * Changed use of `force_api_v3 = TRUE` by `api_version = 4` for deprecation by default -Major +## Major * New use of `use_gitlab_ci()` with pre-defined templates * Add new functions to manage projects: `gl_get_project()`, `gl_new_project()`, `gl_edit_project()`, `gl_delete_project()` * Update documentation: recommend using `gl_*` functions -Minor +## Minor * `gl_archive()` is used to archive a project (not to download an archive) * fix use of `max_page` with `gl_()` functions calling `gitlab()` diff --git a/R/ci.R b/R/ci.R index 842338d..9980693 100644 --- a/R/ci.R +++ b/R/ci.R @@ -1,49 +1,29 @@ -#' Define GitLab CI jobs content -#' -#' Exploration of job content is deprecated as of 'gitlabr' 1.1.7. -#' Content of .gitlab-ci.yml file is now created using templates with -#' use_gitlab_ci(type = "check-coverage-pkgdown"). See [use_gitlab_ci()]. -#' -#' @export -#' @rdname gitlabci -#' @seealso [use_gitlab_ci()] -#' @return Creates the content of a .gitlab-ci.yml file as character. -#' -#' @examples -#' \dontrun{ -#' # Deprecated -#' gl_ci_job() -#' } -gl_ci_job <- function() { - .Deprecated('use_gitlab_ci', package = 'gitlabr', old = 'gl_ci_job') -} - #' Add .gitlab-ci.yml file in your current project from template -#' +#' #' @param image Docker image to use in GitLab ci. If NULL, not specified! #' @param path destination path for writing GitLab CI yml file #' @param overwrite whether to overwrite existing GitLab CI yml file #' @param repo_name REPO_NAME environment variable for R CRAN mirror used #' @param type type of the CI template to use -#' @param add_to_Rbuildignore add CI yml file and cache path used inside the +#' @param add_to_Rbuildignore add CI yml file and cache path used inside the #' CI workflow to .Rbuildignore? #' -#' @details -#' Types available are: -#' -#' - "check-coverage-pkgdown": Check package along with Code coverage with {covr} -#' and {pkgdown} site on GitLab Pages -#' - "check-coverage-pkgdown-renv": Check package built in a fixed {renv} state -#' along with Code coverage with {covr} and {pkgdown} site on GitLab Pages. -#' - "bookdown": Build {bookdown} HTML and PDF site on GitLab Pages -#' - "bookdown-production": Build {bookdown} HTML and PDF site on GitLab Pages. -#' Where default page is for branch named 'production' and "dev/" sub-folder is for +#' @details +#' Types available are: +#' +#' - "check-coverage-pkgdown": Check package along with Code coverage with 'covr' +#' and 'pkgdown' site on GitLab Pages +#' - "check-coverage-pkgdown-renv": Check package built in a fixed 'renv' state +#' along with Code coverage with 'covr' and 'pkgdown' site on GitLab Pages. +#' - "bookdown": Build 'bookdown' HTML and PDF site on GitLab Pages +#' - "bookdown-production": Build 'bookdown' HTML and PDF site on GitLab Pages. +#' Where default page is for branch named 'production' and "dev/" sub-folder is for #' 'main' (or 'master') branch. #' #' @export -#' +#' #' @return Used for side effects. Creates a .gitlab-ci.yml file in your directory. -#' +#' #' @examples #' # Create in another directory #' use_gitlab_ci(image = "rocker/verse:latest", path = tempfile(fileext = ".yml")) @@ -51,14 +31,17 @@ gl_ci_job <- function() { #' # Create in your current project with template for packages checking #' use_gitlab_ci(image = "rocker/verse:latest", type = "check-coverage-pkgdown") #' } -use_gitlab_ci <- function(image = "rocker/verse:latest", - repo_name = "https://packagemanager.rstudio.com/all/__linux__/focal/latest", - path = ".gitlab-ci.yml", - overwrite = TRUE, - add_to_Rbuildignore = TRUE, - type = "check-coverage-pkgdown") { - - choices <- gsub(".yml", "", list.files(system.file("gitlab-ci", package = "gitlabr"))) +use_gitlab_ci <- function( + image = "rocker/verse:latest", + repo_name = "https://packagemanager.rstudio.com/all/__linux__/focal/latest", + path = ".gitlab-ci.yml", + overwrite = TRUE, + add_to_Rbuildignore = TRUE, + type = "check-coverage-pkgdown") { + choices <- gsub( + ".yml", "", + list.files(system.file("gitlab-ci", package = "gitlabr")) + ) type <- match.arg(type, choices = choices, several.ok = FALSE) file <- system.file("gitlab-ci", paste0(type, ".yml"), package = "gitlabr") @@ -69,14 +52,14 @@ use_gitlab_ci <- function(image = "rocker/verse:latest", lines <- gsub(pattern = "\\{image\\}", replacement = image, x = lines) # Changer {repo_name} lines <- gsub(pattern = "\\{repo_name\\}", replacement = repo_name, x = lines) - # Changer {url} - $CI_API_V4_URL - # lines <- gsub(pattern = "\\{url\\}", replacement = url, x = lines) - + writeLines(enc2utf8(lines), path) - + if (isTRUE(add_to_Rbuildignore)) { path_build_ignore <- file.path(dirname(path), ".Rbuildignore") - if (!file.exists(path_build_ignore)) {writeLines("", path_build_ignore)} + if (!file.exists(path_build_ignore)) { + writeLines("", path_build_ignore) + } r_build_ignore <- readLines(path_build_ignore) path_rbuild <- paste0("^", gsub("[.]", "\\\\.", basename(path)), "$") if (!path_rbuild %in% r_build_ignore) { @@ -86,32 +69,31 @@ use_gitlab_ci <- function(image = "rocker/verse:latest", if (!"^ci/lib$" %in% r_build_ignore) { writeLines(enc2utf8(c(r_build_ignore, "^ci/lib$")), path_build_ignore) } - if (grepl("renv", type) & !"^cache$" %in% r_build_ignore) { + if (grepl("renv", type) && !"^cache$" %in% r_build_ignore) { writeLines(enc2utf8(c(r_build_ignore, "^cache$")), path_build_ignore) } } - } #' Access the GitLab CI builds -#' +#' #' List the jobs with `gl_jobs`, the pipelines with `gl_pipelines` or #' download the most recent artifacts #' archive with `gl_latest_build_artifact`. For every branch and job combination #' only the most recent artifacts archive is available. -#' `gl_builds` is the equivalent for GitLab API v3. -#' +#' #' @param project project name or id, required #' @param ... passed on to [gitlab()] API call #' @export -#' @rdname gl_builds -#' +#' @rdname gl_pipelines +#' #' @examples \dontrun{ #' # connect as a fixed user to a GitLab instance #' set_gitlab_connection( #' gitlab_url = "https://gitlab.com", -#' private_token = Sys.getenv("GITLAB_COM_TOKEN")) -#' +#' private_token = Sys.getenv("GITLAB_COM_TOKEN") +#' ) +#' #' # Get pipelines and jobs information #' gl_pipelines(project = "<>") #' gl_jobs(project = "<>") @@ -122,42 +104,32 @@ gl_pipelines <- function(project, ...) { } #' @export -#' @rdname gl_builds +#' @rdname gl_pipelines gl_jobs <- function(project, ...) { gitlab(gl_proj_req(project = project, "pipelines", ...), ...) } -#' @export -#' @param api_version Since `gl_builds` is no longer working for GitLab API v4, -#' this must be set to "3" in order to avoid deprecation warning and HTTP error. It currently -#' default to "4" with deprecation message.´ -#' @rdname gl_builds -gl_builds <- function(project, api_version = 4, ...) { - if (api_version != 3) { - .Deprecated("gl_pipelines", package = "gitlabr", old = "gl_builds") - } - gitlab(gl_proj_req(project = project, "builds", ...), ...) -} - #' @export -#' @rdname gl_builds +#' @rdname gl_pipelines #' @param job Name of the job to get build artifacts from #' @param ref_name name of ref (i.e. branch, commit, tag) #' @param save_to_file either a path where to store .zip file or NULL if raw should be returned #' @return returns the file path if `save_to_file` is TRUE, or the archive as raw otherwise. gl_latest_build_artifact <- function(project, job, ref_name = get_main(), save_to_file = tempfile(fileext = ".zip"), ...) { - - raw_build_archive <- gitlab(gl_proj_req(project = project, - c("jobs", "artifacts", ref_name, "download"), - ...), - job = job, auto_format = FALSE, ...) - + raw_build_archive <- gitlab( + gl_proj_req( + project = project, + c("jobs", "artifacts", ref_name, "download"), + ... + ), + job = job, auto_format = FALSE, ... + ) + if (!is.null(save_to_file)) { writeBin(raw_build_archive, save_to_file) return(save_to_file) - } - else { + } else { return(raw_build_archive) } } diff --git a/R/connect.R b/R/connect.R index c298caf..b2559f5 100644 --- a/R/connect.R +++ b/R/connect.R @@ -1,9 +1,9 @@ #' Connect to a specific GitLab instance API -#' +#' #' Creates a function that can be used to issue requests to the specified #' GitLab API instance with the specified user private token and (for `gl_project_connection`) #' only to a specified project. -#' +#' #' @details #' The returned function should serve as the primary way to access the GitLab #' API in the following. It can take vector/character arguments in the same way @@ -11,10 +11,10 @@ #' provided by this package or written by the user. If it is passed such that #' function it calls it with the arguments provided in `...` and the GitLab #' URL, api location and private_token provided when creating it via `gl_connection`. -#' +#' #' Note: currently GitLab API v4 is supported. GitLab API v3 is no longer supported, but #' you can give it a try. -#' +#' #' @examples #' \dontrun{ #' # Set the connection for the session @@ -23,7 +23,7 @@ #' gl_list_projects(max_page = 1) #' # Unset the connection for the session #' unset_gitlab_connection() -#' +#' #' # Set connection for a specific project #' my_project <- gl_project_connection( #' gitlab_url = "https://gitlab.com", @@ -33,40 +33,50 @@ #' # List files of a project #' my_project_list_files <- my_project(gl_list_files, max_page = 1) #' } -#' -#' @param gitlab_url URL to the GitLab instance (e.g. `https://gitlab.myserver.com`) -#' @param private_token private_token with which to identify. You can generate one in the web interface under +#' +#' @param gitlab_url URL to the GitLab instance +#' (e.g. `https://gitlab.myserver.com`) +#' @param private_token private_token with which to identify. +#' You can generate one in the web interface under #' `GITLABINSTANCEURL/-/profile/personal_access_tokens.html` when logged on. -#' @param api_version Currently "4" for the latest GitLab API version. See Details section on API versions. -#' @param api_location location of the GitLab API under the `gitlab_url`, usually and by default "/api/${api_version}/" +#' @param api_version Currently "4" for the latest GitLab API version. +#' See Details section on API versions. +#' @param api_location location of the GitLab API under the `gitlab_url`, +#' usually and by default "/api/<>/" #' @param project id or name of project to issue requests to -#' -#' @return A function to access a specific GitLab API as a specific user, see details -#' +#' +#' @return A function to access a specific GitLab API +#' as a specific user, see details +#' #' @section API versions: -#' "v4" is the standard API since GitLab version 9.0 and only this version is officially supported by -#' {gitlabr} since version 1.1.6. "v3" as a parameter value is not removed, since for many instances, {gitlabr} +#' "v4" is the standard API since GitLab version 9.0 +#' and only this version is officially supported by +#' 'gitlabr' since version 1.1.6. "v3" as a parameter value +#' is not removed, since for many instances, 'gitlabr' #' code will still work if you try. -#' -#' +#' +#' #' @export gl_connection <- function(gitlab_url, private_token, api_version = 4, api_location = paste0("/api/v", api_version, "/")) { - gl_con_root <- httr::modify_url(gitlab_url, path = api_location) - + return(function(req, ...) { if (is.function(req)) { - req(api_root = gl_con_root, - private_token = private_token, - ...) + req( + api_root = gl_con_root, + private_token = private_token, + ... + ) } else { - gitlab(req = req, - api_root = gl_con_root, - private_token = private_token, - ...) + gitlab( + req = req, + api_root = gl_con_root, + private_token = private_token, + ... + ) } }) } @@ -78,27 +88,31 @@ gl_project_connection <- function(gitlab_url, private_token, api_version = 4, api_location = paste0("/api/v", api_version, "/")) { - gl_con_root <- httr::modify_url(gitlab_url, path = api_location) return(function(req, ...) { if (is.function(req)) { - req(api_root = gl_con_root, - private_token = private_token, - project = to_project_id(project, - api_root = gl_con_root, - private_token = private_token), - ...) + req( + api_root = gl_con_root, + private_token = private_token, + project = to_project_id(project, + api_root = gl_con_root, + private_token = private_token + ), + ... + ) } else { - gitlab(req = gl_proj_req(project, - req = req, - api_root = gl_con_root, - private_token = private_token, - ...), - api_root = gl_con_root, - private_token = private_token, - ...) + gitlab( + req = gl_proj_req(project, + req = req, + api_root = gl_con_root, + private_token = private_token, + ... + ), + api_root = gl_con_root, + private_token = private_token, + ... + ) } }) - } diff --git a/R/files.R b/R/files.R index e5d2580..d307582 100644 --- a/R/files.R +++ b/R/files.R @@ -18,47 +18,95 @@ #' gl_repository(project = <>) #' # _All contributors #' gl_repository(project = <>, "contributors") -#' # _List files -#' gl_list_files(project = <>) #' # _Get content of one file #' gl_get_file(project = <>, file_path = "README.md") #' # _Test if file exists -#' gl_file_exists(project = <>, file_path = "README.md", ref = "main") +#' gl_file_exists( +#' project = <>, +#' file_path = "README.md", +#' ref = "main") #' } gl_repository <- function(project, req = c("tree"), ref = get_main(), ...) { gitlab(gl_proj_req(project, c("repository", req), ...), ref = ref, ...) } -#' @rdname gl_repository + +#' List of files in a folder +#' +#' @param project name or id of project (not repository!) +#' @param path path of the folder +#' @param ref name of ref (commit branch or tag) +#' @param ... passed on to [gitlab()] API call #' @importFrom purrr partial #' @export -gl_list_files <- function(project, ref = get_main(), ...) { - gitlab(gl_proj_req(project, c("repository", "tree"), ...), ref = ref, ...) +#' @examples \dontrun{ +#' # Set GitLab connection for examples +#' set_gitlab_connection( +#' gitlab_url = "https://gitlab.com", +#' private_token = Sys.getenv("GITLAB_COM_TOKEN")) +#' +#' gl_list_files(project = <>, path = <>) +#' } +gl_list_files <- function(project, path = "", ref = get_main(), ...) { + gitlab(gl_proj_req(project, c("repository", "tree"), ...), + path = utils::URLencode(path, reserved = FALSE), ref = ref, ... + ) } -#' For `gl_file_exists` dots are passed on to [gl_list_files()] and GitLab API call +#' For `gl_file_exists` dots are passed on to [gl_list_files()] +#' and GitLab API call +#' #' @export #' @rdname gl_repository gl_file_exists <- function(project, file_path, ref, ...) { - project_missing <- missing(project) - - list(ref = ref, - ref_name = ref, ## This is legacy for API v3 use and will be ignored by API v4 - ...) %>% - iff(dirname(file_path) != ".", c, path = dirname(file_path)) %>% - iffn(project_missing, c, project = project) %>% - pipe_into("args", do.call, what = gl_list_files) %>% - dplyr::filter(name == basename(file_path)) %>% - { nrow(.) > 0 } + + # Split file_path into each directory + path_parts <- unlist(strsplit(utils::URLdecode(file_path), "/")) + path_accumulated <- Reduce( + function(acc, part) paste(acc, part, sep = "/"), + path_parts, + accumulate = TRUE + ) + + # And test if each directory exists + # As gl_list_files only works if dir exists + for (tested_path in path_accumulated) { + path_exists <- list( + ref = ref, + # This is legacy for API v3 use and will be ignored by API v4 + ref_name = ref, + ... + ) %>% + iff(dirname(tested_path) != ".", c, path = dirname(tested_path)) %>% + iffn(project_missing, c, project = project) %>% + pipe_into("args", do.call, what = gl_list_files) %>% + dplyr::filter({ + if (nrow(.) > 0) name else "" + } == basename(tested_path)) %>% + { + nrow(.) > 0 + } + + if ( + !path_exists && + tested_path != path_accumulated[length(path_accumulated)] + ) { + return(FALSE) + } + } + + return(path_exists) } #' Get a file from a GitLab repository #' #' @param file_path path to file #' @param ref name of ref (commit branch or tag) -#' @param to_char flag if output should be converted to char; otherwise it is of class raw -#' @param api_version a switch to force deprecated GitLab API v3 behavior. See details section "API version" of [gl_connection()] +#' @param to_char flag if output should be converted to char; +#' otherwise it is of class raw +#' @param api_version a switch to force deprecated GitLab API v3 behavior. +#' See details section "API version" of [gl_connection()] #' @export #' @importFrom base64enc base64decode #' @rdname gl_repository @@ -69,22 +117,28 @@ gl_get_file <- function(project, api_version = 4, ...) { (if (api_version == 3) { - gl_repository(project = project, - req = "files", - file_path = file_path, - ref = ref, - verb = httr::GET, - ...) + gl_repository( + project = project, + req = "files", + file_path = file_path, + ref = ref, + verb = httr::GET, + ... + ) } else { - gl_repository(project = project, - req = c("files", file_path), - ref = ref, - verb = httr::GET, - ...) - })$content %>% + gl_repository( + project = project, + req = c( + "files", + utils::URLencode(file_path, reserved = TRUE) + ), + ref = ref, + verb = httr::GET, + ... + ) + })$content %>% base64decode() %>% iff(to_char, rawToChar) - } #' Upload, delete a file to a GitLab repository @@ -95,10 +149,11 @@ gl_get_file <- function(project, #' nothing was changed, since overwrite is FALSE) #' #' @param project Project name or id -#' @param file_path path where to store file in gl_repository. +#' @param file_path path where to store file in gl_repository. #' If in subdirectory, the parent directory should exist. #' @param content Character of length 1. File content (text) -#' @param branch name of branch where to append newly generated commit with new/updated file +#' @param branch name of branch where to append newly generated +#' commit with new/updated file #' @param commit_message Message to use for commit with new/updated file #' @param overwrite whether to overwrite files that already exist #' @param ... passed on to [gitlab()] @@ -126,13 +181,26 @@ gl_push_file <- function(project, exists <- gl_file_exists(project = project, file_path, ref = branch, ...) if (!exists || overwrite) { - gitlab(req = gl_proj_req(project = project, c("repository", "files", file_path), ...), - branch_name = branch, ## This is legacy for API v3 use and will be ignored by API v4 - branch = branch, - content = content, - commit_message = commit_message, - verb = if (exists) { httr::PUT } else { httr::POST }, - ...) + gitlab( + req = gl_proj_req( + project = project, + c( + "repository", "files", + utils::URLencode(file_path, reserved = TRUE) + ), + ... + ), + branch_name = branch, ## This is legacy for API v3 use and will be ignored by API v4 + branch = branch, + content = content, + commit_message = commit_message, + verb = if (exists) { + httr::PUT + } else { + httr::POST + }, + ... + ) } else { tibble::tibble(file_path = character(0), branch = character(0)) @@ -140,23 +208,30 @@ gl_push_file <- function(project, } #' @rdname onefile +#' @export gl_delete_file <- function(project, - file_path, - commit_message, - branch = get_main(), - ...) { - + file_path, + commit_message, + branch = get_main(), + ...) { exists <- gl_file_exists(project = project, file_path, ref = branch, ...) if (exists) { - gitlab(req = gl_proj_req(project = project, c("repository", "files", file_path), ...), - branch_name = branch, ## This is legacy for API v3 use and will be ignored by API v4 - branch = branch, - commit_message = commit_message, - verb = httr::DELETE, - ...) + gitlab( + req = gl_proj_req(project = project, c( + "repository", "files", + utils::URLencode(file_path, reserved = TRUE) + ), ...), + branch_name = branch, ## This is legacy for API v3 use and will be ignored by API v4 + branch = branch, + commit_message = commit_message, + verb = httr::DELETE, + ... + ) } else { - tibble::tibble(file_path = character(0), - branch = character(0)) + tibble::tibble( + file_path = character(0), + branch = character(0) + ) } } diff --git a/R/gitlab_api.R b/R/gitlab_api.R index c57348a..f77d031 100644 --- a/R/gitlab_api.R +++ b/R/gitlab_api.R @@ -1,21 +1,21 @@ #' Request GitLab API -#' -#' This is {gitlabr}'s core function to talk to GitLab's server API via HTTP(S). Usually you will not -#' use this function directly too often, but either use {gitlabr}'s convenience wrappers or write your -#' own. See the {gitlabr} vignette for more information on this. -#' +#' +#' This is 'gitlabr' core function to talk to GitLab's server API via HTTP(S). Usually you will not +#' use this function directly too often, but either use 'gitlabr' convenience wrappers or write your +#' own. See the 'gitlabr' vignette for more information on this. +#' #' @param req vector of characters that represents the call (e.g. `c("projects", project_id, "events")`) #' @param api_root URL where the GitLab API to request resides (e.g. `https://gitlab.myserver.com/api/v3/`) #' @param verb http verb to use for request in form of one of the `httr` functions #' [httr::GET()], [httr::PUT()], [httr::POST()], [httr::DELETE()] #' @param auto_format whether to format the returned object automatically to a flat data.frame #' @param debug if TRUE API URL and query will be printed, defaults to FALSE -#' @param gitlab_con function to use for issuing API requests (e.g. as returned by -#' [gitlab_connection()] +#' @param gitlab_con function to use for issuing API requests (e.g. as returned by +#' [get_gitlab_connection()] #' @param page number of page of API response to get; if "all" (default), all pages #' (up to max_page parameter!) are queried successively and combined. #' @param max_page maximum number of pages to retrieve. Defaults to 10. This is an upper limit -#' to prevent {gitlabr} getting stuck in retrieving an unexpectedly high number of entries (e.g. of a +#' to prevent 'gitlabr' getting stuck in retrieving an unexpectedly high number of entries (e.g. of a #' project list). It can be set to NA/Inf to retrieve all available pages without limit, but this #' is recommended only under controlled circumstances. #' @param enforce_api_root if multiple pages are requested, the API root URL is ensured @@ -25,29 +25,29 @@ #' @param argname_verb name of the argument of the verb that fields and information are passed on to #' @param ... named parameters to pass on to GitLab API (technically: modifies query parameters of request URL), #' may include private_token and all other parameters as documented for the GitLab API -#' +#' #' @importFrom utils capture.output #' @importFrom tibble tibble as_tibble #' @importFrom magrittr %T>% #' @importFrom dplyr bind_rows #' @importFrom stringr str_replace_all str_replace #' @export -#' +#' #' @return the response from the GitLab API, usually as a `tibble` and including all pages -#' -#' @details +#' +#' @details #' `gitlab()` function allows to use any request of the GitLab API . #' -#' For instance, the API documentation shows how to create a new project in -#' : -#' +#' For instance, the API documentation shows how to create a new project in +#' : +#' #' - The verb is `POST` #' - The request is `projects` #' - Required attributes are `name` or `path` (if `name` not set) #' - `default_branch` is an attribute that can be set if wanted -#' -#' The corresponding use of `gitlab()` is: -#' +#' +#' The corresponding use of `gitlab()` is: +#' #' ``` #' gitlab( #' req = "projects", @@ -56,22 +56,24 @@ #' default_branch = "main" #' ) #' ``` -#' +#' #' Note: currently GitLab API v4 is supported. GitLab API v3 is no longer supported, but #' you can give it a try. -#' +#' #' @examples \dontrun{ #' # Connect as a fixed user to a GitLab instance #' set_gitlab_connection( -#' gitlab_url = "https://gitlab.com", +#' gitlab_url = "https://gitlab.com", #' private_token = Sys.getenv("GITLAB_COM_TOKEN") #' ) -#' +#' #' # Use a simple request #' gitlab(req = "projects") #' # Use a combined request with extra parameters -#' gitlab(req = c("projects", 1234, "issues"), -#' state = "closed") +#' gitlab( +#' req = c("projects", 1234, "issues"), +#' state = "closed" +#' ) #' } gitlab <- function(req, api_root, @@ -82,37 +84,49 @@ gitlab <- function(req, page = "all", max_page = 10, enforce_api_root = TRUE, - argname_verb = if (identical(verb, httr::GET) | - identical(verb, httr::DELETE)) { "query" } else { "body" }, + argname_verb = if (identical(verb, httr::GET) || + identical(verb, httr::DELETE)) { + "query" + } else { + "body" + }, ...) { - if (!is.function(gitlab_con) && - gitlab_con == "default" && - !is.null(get_gitlab_connection())) { + gitlab_con == "default" && + !is.null(get_gitlab_connection())) { gitlab_con <- get_gitlab_connection() } - + if (!is.function(gitlab_con)) { url <- req %>% paste(collapse = "/") %>% prefix(api_root, "/") %T>% - iff(debug, function(x) { print(paste(c("URL:", x, " " - , "query:", paste(utils::capture.output(print((list(...)))), collapse = " "), " ", collapse = " "))); x }) - + iff(debug, function(x) { + print(paste(c("URL:", x, " ", + "query:", paste(utils::capture.output(print((list(...)))), collapse = " "), " ", + collapse = " " + ))) + x + }) + # Extract private token to put it in header l <- list(...) private_token <- l$private_token l <- within(l, rm(private_token)) private_token_header <- httr::add_headers("PRIVATE-TOKEN" = private_token) - - (if (page == "all") {l} else { c(page = page, l)}) %>% + + (if (page == "all") { + l + } else { + c(page = page, l) + }) %>% pipe_into(argname_verb, verb, url = url, private_token_header) %>% - http_error_or_content() -> resp - + http_error_or_content() -> resp + resp$ct %>% iff(auto_format, json_to_flat_df) %>% ## better would be to check MIME type iff(debug, print) -> resp$ct - + if (page == "all") { # pages_retrieved <- 0L pages_retrieved <- 1L @@ -124,15 +138,13 @@ gitlab <- function(req, http_error_or_content() resp$nxt <- nxt_resp$nxt resp$ct <- bind_rows(resp$ct, nxt_resp$ct %>% - iff(auto_format, json_to_flat_df)) + iff(auto_format, json_to_flat_df)) pages_retrieved <- pages_retrieved + 1 } } - + return(resp$ct) - } else { - if (!missing(req)) { dot_args <- list(req = req) } else { @@ -164,7 +176,6 @@ gitlab <- function(req, http_error_or_content <- function(response, handle = httr::stop_for_status, ...) { - if (!identical(handle(response), FALSE)) { ct <- httr::content(response, ...) nxt <- get_next_link(httr::headers(response)$link) @@ -178,19 +189,21 @@ get_rel <- function(links) { links %>% stringr::str_split(",\\s+") %>% getElement(1) -> strs - tibble::tibble(link = strs %>% - lapply(stringr::str_replace_all, "\\<(.+)\\>.*", "\\1") %>% - unlist(), - rel = strs %>% - lapply(stringr::str_replace_all, ".+rel=.(\\w+).", "\\1") %>% - unlist(), - stringsAsFactors = FALSE) + tibble::tibble( + link = strs %>% + lapply(stringr::str_replace_all, "\\<(.+)\\>.*", "\\1") %>% + unlist(), + rel = strs %>% + lapply(stringr::str_replace_all, ".+rel=.(\\w+).", "\\1") %>% + unlist(), + stringsAsFactors = FALSE + ) } #' @importFrom dplyr filter #' @noRd get_next_link <- function(links) { - if(is.null(links)) { + if (is.null(links)) { return(NULL) } else { links %>% @@ -211,7 +224,6 @@ is_named <- function(v) { is_single_row <- function(l) { - if (length(l) == 1 || !any(lapply(l, is.list) %>% unlist())) { return(TRUE) } else { @@ -219,7 +231,7 @@ is_single_row <- function(l) { # not named, then probably multiple rows # at least one name is the same shows multiple lines all_names <- lapply(l, names) - if(any( + if (any( lapply(all_names, function(x) any(x %in% all_names[[1]])) %>% unlist() )) { return(FALSE) @@ -255,7 +267,6 @@ format_row <- function(row, ...) { #' @importFrom dplyr bind_rows #' @noRd json_to_flat_df <- function(l) { - l %>% iff(is_single_row, list) %>% lapply(unlist, recursive = TRUE) %>% diff --git a/R/globals.R b/R/globals.R index cdb7e4c..8390b6e 100644 --- a/R/globals.R +++ b/R/globals.R @@ -1,9 +1,17 @@ - ## A fix to let CRAN check NOTEs diasappear for non-standard-evaluation used ## cf. https://stackoverflow.com/questions/9439256/how-can-i-handle-r-cmd-check-no-visible-binding-for-global-variable-notes-when -globalVariables(c("name", "id", "iid", "rel", ".", ## general - "gitlabr_0_7_renaming", "old_name", "new_name", ## update_code - "matches_name", "matches_path", "matches_path_with_namespace", "path", "path_with_namespace", ## get_project_id - "StopReporter", ## for NSE in use_gitlab_ci - "content" # used in multilist_to_tibble -)) \ No newline at end of file +globalVariables(c( + ## general + "name", "id", "iid", "rel", ".", + ## update_code + "old_name", "new_name", + ## get_project_id + "matches_name", "matches_path", "matches_path_with_namespace", + "path", "path_with_namespace", + ## gl_get_group_id + "full_path", "matches_full_path", + ## for NSE in use_gitlab_ci + "StopReporter", + # used in multilist_to_tibble + "content" +)) diff --git a/R/groups.R b/R/groups.R new file mode 100644 index 0000000..917c2b0 --- /dev/null +++ b/R/groups.R @@ -0,0 +1,158 @@ +#' List groups information +#' +#' @param ... passed on to [gitlab()] +#' @export +#' @return tibble of each group with corresponding information +#' +#' @details +#' When using `gl_list_sub_groups()`, if you request this list as: +#' - An unauthenticated user, the response returns only public groups. +#' - An authenticated user, the response returns only the groups you’re a member of and does not include public groups. +#' +#' @examples \dontrun{ +#' set_gitlab_connection( +#' gitlab_url = "https://gitlab.com", +#' private_token = Sys.getenv("GITLAB_COM_TOKEN") +#' ) +#' # List all groups +#' gl_list_groups(max_page = 1) +#' # List sub-groups of a group +#' gl_list_sub_groups(group_id = "<>", max_page = 1) +#' } +gl_list_groups <- function(...) { + gitlabr::gitlab("groups", ...) +} + +#' @param group The ID or URL-encoded path of the group +#' @export +#' @rdname gl_list_groups +gl_list_sub_groups <- function(group, ...) { + gitlab(c("groups", to_group_id(group), "subgroups"), ...) +} + +#' Create a group specific request +#' +#' Prefixes the request location with "groups/:id/subgroups" and automatically +#' translates group names into ids +#' +#' @param group group name or id +#' @param ... passed on to [gl_get_group_id()] +#' @export +#' @return A vector of character to be used as request for functions involving groups +#' @examples +#' \dontrun{ +#' gl_group_req("test_group"<>) +#' } +gl_group_req <- function(group, ...) { + if (missing(group) || is.null(group)) { + return(c("groups")) + } else { + return(c("groups", to_group_id(group, ...))) + } +} + +#' Get a group id by name +#' +#' @param group_name group name +#' @param ... passed on to [gitlab()] +#' @importFrom dplyr mutate filter +#' +#' @details +#' Number of pages searched is limited to (per_page =) 20 * (max_page =) 10 by default. +#' If the `group_name` is an old group lost in a big repository (position > 200), +#' `gl_get_group_id()` may not find the group id. +#' +#' @export +#' @return Integer. ID of the group if found. +#' @examples +#' \dontrun{ +#' gl_get_group_id("<>") +#' } +gl_get_group_id <- function(group_name, ...) { + + matching <- gitlab(req = "groups", ...) %>% + mutate(matches_name = name == group_name, + matches_path = path == group_name, + matches_full_path = full_path == group_name) %>% + filter(matches_full_path | + (sum(matches_full_path) == 0L & + matches_path | matches_name)) + + if (nrow(matching) == 0) { + stop("There was no matching 'id' with your group name. ", + "Either it does not exist, or most probably, ", + "it is not available in the first groups available to you. ", + "The name-matching is limited to the first pages of groups accessible. ", + "Please use directly the 'id' of your group.") + } else if (nrow(matching) > 1) { + warning(paste(c("Multiple groups with given name or path found,", + "please use explicit name with namespace:", + matching$path_with_namespace, + paste("Picking", matching[1,"path_with_namespace"], "as default")), + collapse = "\n")) + } + + matching[1,"id"] %>% + as.integer() +} + +to_group_id <- function(x, ...) { + if (!is.na(suppressWarnings(as.numeric(x))) | is.numeric(x)) { + as.numeric(x) + } else { + gl_get_group_id(x, ...) + } +} + + +#' Manage groups +#' @param path to the new group +#' @param name of the new group +#' @param ... passed on to [gitlab()] API call for "Create group" +#' @export +#' @return A tibble with the group information. `gl_delete_group()` returns an empty tibble. +#' @details +#' You can use extra parameters as proposed in the GitLab API. +#' +#' @examples \dontrun{ +#' set_gitlab_connection( +#' gitlab_url = "https://gitlab.com", +#' private_token = Sys.getenv("GITLAB_COM_TOKEN") +#' ) +#' # Create new group +#' gl_new_group(name = "mygroup") +#' # Edit existing group +#' gl_edit_group(group = "<>", default_branch = "main") +#' # Delete group +#' gl_delete_group(group = "<>") +#' } +gl_new_group <- function(name, + path, + ...) { + gitlab(req = "groups", + path = path, + name = name, + verb = httr::POST, + ...) +} + +#' @param group The ID or URL-encoded path of the group. +#' @rdname gl_new_group +#' @export +gl_edit_group <- function(group, + ...) { + + gitlab(req = c("groups", to_group_id(group)), + verb = httr::PUT, + ...) + +} + +#' @rdname gl_new_group +#' @export +gl_delete_group <- function(group) { + + gitlab(req = c("groups", to_group_id(group)), + verb = httr::DELETE) +} + diff --git a/R/legacy_headers.R b/R/legacy_headers.R index c8f8b77..bcd4471 100644 --- a/R/legacy_headers.R +++ b/R/legacy_headers.R @@ -1,288 +1,35 @@ #' Deprecated functions #' -#' Many functions were renamed with version 0.7 to the `gl_` naming scheme. -#' Note that the old function names are deprecated and might be removed without -#' further notice. -#' +#' List of deprecated functions that will be removed in future versions. +#' #' @param ... Parameters to the new function #' @name gitlabr-deprecated -#' @return Warning for deprecated functions and output depending on the superseeding function. +#' @return Warning for deprecated functions and +#' output depending on the superseeding function. #' @section Details: #' \tabular{rl}{ -#' `archive` \tab is now called `gl_archive` \cr -#' `assign_issue` \tab is now called `gl_assign_issue` \cr -#' `close_issue` \tab is now called `gl_close_issue` \cr -#' `comment_commit` \tab is now called `gl_comment_commit` \cr -#' `comment_issue` \tab is now called `gl_comment_issue` \cr -#' `create_branch` \tab is now called `gl_create_branch` \cr -#' `create_merge_request` \tab is now called `gl_create_merge_request` \cr -#' `delete_branch` \tab is now called `gl_delete_branch` \cr -#' `edit_commit_comment` \tab is now called `gl_edit_commit_comment` \cr -#' `edit_issue` \tab is now called `gl_edit_issue` \cr -#' `edit_issue_comment` \tab is now called `gl_edit_issue_comment` \cr -#' `file_exists` \tab is now called `gl_file_exists` \cr -#' `get_comments` \tab is now called `gl_get_comments` \cr -#' `get_commit_comments` \tab is now called `gl_get_commit_comments` \cr -#' `get_commits` \tab is now called `gl_get_commits` \cr -#' `get_diff` \tab is now called `gl_get_diff` \cr -#' `get_file` \tab is now called `gl_get_file` \cr -#' `get_issue` \tab is now called `gl_get_issue` \cr -#' `get_issue_comments` \tab is now called `gl_get_issue_comments` \cr -#' `get_issues` \tab is now called `gl_list_issues` \cr -#' `get_project_id` \tab is now called `gl_get_project_id` \cr -#' `gitlab_connection` \tab is now called `gl_connection` \cr -#' `list_branches` \tab is now called `gl_list_branches` \cr -#' `list_files` \tab is now called `gl_list_files` \cr -#' `list_projects` \tab is now called `gl_list_projects` \cr -#' `new_issue` \tab is now called `gl_new_issue` \cr -#' `project_connection` \tab is now called `gl_project_connection` \cr -#' `proj_req` \tab is now called `gl_proj_req` \cr -#' `push_file` \tab is now called `gl_push_file` \cr -#' `reopen_issue` \tab is now called `gl_reopen_issue` \cr -#' `repository` \tab is now called `gl_repository` \cr -#' `to_issue_id` \tab is now called `gl_to_issue_id` \cr -#' `unassign_issue` \tab is now called `gl_unassign_issue` \cr +#' `gl_builds` \tab in favour of `gl_pipelines` \cr +#' `gl_ci_job` \tab in favour of `use_gitlab_ci` \cr #' } NULL -#' renaming from {gitlabr} version 0.6.4 to 0.7 -#' -#' List of of old and new function name. -#' -#' -#' @docType data -#' @name gitlabr_0_7_renaming -#' @format A data frame with 33 rows and 2 variables -NULL - -#' @export -#' @rdname gitlabr-deprecated -archive <- function(...) { - .Deprecated('gl_archive', package = 'gitlabr', old = 'archive') - gl_archive(...) -} - -#' @export -#' @rdname gitlabr-deprecated -assign_issue <- function(...) { - .Deprecated('gl_assign_issue', package = 'gitlabr', old = 'assign_issue') - gl_assign_issue(...) -} - -#' @export -#' @rdname gitlabr-deprecated -close_issue <- function(...) { - .Deprecated('gl_close_issue', package = 'gitlabr', old = 'close_issue') - gl_close_issue(...) -} - -#' @export -#' @rdname gitlabr-deprecated -comment_commit <- function(...) { - .Deprecated('gl_comment_commit', package = 'gitlabr', old = 'comment_commit') - gl_comment_commit(...) -} - -#' @export -#' @rdname gitlabr-deprecated -comment_issue <- function(...) { - .Deprecated('gl_comment_issue', package = 'gitlabr', old = 'comment_issue') - gl_comment_issue(...) -} - -#' @export -#' @rdname gitlabr-deprecated -create_branch <- function(...) { - .Deprecated('gl_create_branch', package = 'gitlabr', old = 'create_branch') - gl_create_branch(...) -} - -#' @export -#' @rdname gitlabr-deprecated -create_merge_request <- function(...) { - .Deprecated('gl_create_merge_request', package = 'gitlabr', old = 'create_merge_request') - gl_create_merge_request(...) -} - -#' @export -#' @rdname gitlabr-deprecated -delete_branch <- function(...) { - .Deprecated('gl_delete_branch', package = 'gitlabr', old = 'delete_branch') - gl_delete_branch(...) -} - -#' @export -#' @rdname gitlabr-deprecated -edit_commit_comment <- function(...) { - .Deprecated('gl_edit_commit_comment', package = 'gitlabr', old = 'edit_commit_comment') - gl_edit_commit_comment(...) -} - -#' @export -#' @rdname gitlabr-deprecated -edit_issue <- function(...) { - .Deprecated('gl_edit_issue', package = 'gitlabr', old = 'edit_issue') - gl_edit_issue(...) -} - -#' @export -#' @rdname gitlabr-deprecated -edit_issue_comment <- function(...) { - .Deprecated('gl_edit_issue_comment', package = 'gitlabr', old = 'edit_issue_comment') - gl_edit_issue_comment(...) -} - -#' @export -#' @rdname gitlabr-deprecated -file_exists <- function(...) { - .Deprecated('gl_file_exists', package = 'gitlabr', old = 'file_exists') - gl_file_exists(...) -} - -#' @export -#' @rdname gitlabr-deprecated -get_comments <- function(...) { - .Deprecated('gl_get_comments', package = 'gitlabr', old = 'get_comments') - gl_get_comments(...) -} - -#' @export -#' @rdname gitlabr-deprecated -get_commit_comments <- function(...) { - .Deprecated('gl_get_commit_comments', package = 'gitlabr', old = 'get_commit_comments') - gl_get_commit_comments(...) -} - -#' @export -#' @rdname gitlabr-deprecated -get_commits <- function(...) { - .Deprecated('gl_get_commits', package = 'gitlabr', old = 'get_commits') - gl_get_commits(...) -} - #' @export +#' @param project Project name or ID +#' @param api_version Since `gl_builds` is no longer working for GitLab API v4, +#' this must be set to "3" in order to avoid deprecation warning and HTTP error. It currently +#' default to "4" with deprecation message.´ #' @rdname gitlabr-deprecated -get_diff <- function(...) { - .Deprecated('gl_get_diff', package = 'gitlabr', old = 'get_diff') - gl_get_diff(...) +gl_builds <- function(project, api_version = 4, ...) { + if (api_version != 3) { + .Deprecated("gl_pipelines", package = "gitlabr", old = "gl_builds") + } + gitlab(gl_proj_req(project = project, "builds", ...), ...) } -#' @export -#' @rdname gitlabr-deprecated -get_file <- function(...) { - .Deprecated('gl_get_file', package = 'gitlabr', old = 'get_file') - gl_get_file(...) -} #' @export #' @rdname gitlabr-deprecated -get_issue <- function(...) { - .Deprecated('gl_get_issue', package = 'gitlabr', old = 'get_issue') - gl_get_issue(...) -} - -#' @export -#' @rdname gitlabr-deprecated -get_issue_comments <- function(...) { - .Deprecated('gl_get_issue_comments', package = 'gitlabr', old = 'get_issue_comments') - gl_get_issue_comments(...) -} - -#' @export -#' @rdname gitlabr-deprecated -get_issues <- function(...) { - .Deprecated('gl_list_issues', package = 'gitlabr', old = 'get_issues') - gl_list_issues(...) -} - -#' @export -#' @rdname gitlabr-deprecated -get_project_id <- function(...) { - .Deprecated('gl_get_project_id', package = 'gitlabr', old = 'get_project_id') - gl_get_project_id(...) -} - -#' @export -#' @rdname gitlabr-deprecated -gitlab_connection <- function(...) { - .Deprecated('gl_connection', package = 'gitlabr', old = 'gitlab_connection') - gl_connection(...) -} - -#' @export -#' @rdname gitlabr-deprecated -list_branches <- function(...) { - .Deprecated('gl_list_branches', package = 'gitlabr', old = 'list_branches') - gl_list_branches(...) -} - -#' @export -#' @rdname gitlabr-deprecated -list_files <- function(...) { - .Deprecated('gl_list_files', package = 'gitlabr', old = 'list_files') - gl_list_files(...) -} - -#' @export -#' @rdname gitlabr-deprecated -list_projects <- function(...) { - .Deprecated('gl_list_projects', package = 'gitlabr', old = 'list_projects') - gl_list_projects(...) -} - -#' @export -#' @rdname gitlabr-deprecated -new_issue <- function(...) { - .Deprecated('gl_new_issue', package = 'gitlabr', old = 'new_issue') - gl_new_issue(...) -} - -#' @export -#' @rdname gitlabr-deprecated -project_connection <- function(...) { - .Deprecated('gl_project_connection', package = 'gitlabr', old = 'project_connection') - gl_project_connection(...) -} - -#' @export -#' @rdname gitlabr-deprecated -proj_req <- function(...) { - .Deprecated('gl_proj_req', package = 'gitlabr', old = 'proj_req') - gl_proj_req(...) -} - -#' @export -#' @rdname gitlabr-deprecated -push_file <- function(...) { - .Deprecated('gl_push_file', package = 'gitlabr', old = 'push_file') - gl_push_file(...) -} - -#' @export -#' @rdname gitlabr-deprecated -reopen_issue <- function(...) { - .Deprecated('gl_reopen_issue', package = 'gitlabr', old = 'reopen_issue') - gl_reopen_issue(...) -} - -#' @export -#' @rdname gitlabr-deprecated -repository <- function(...) { - .Deprecated('gl_repository', package = 'gitlabr', old = 'repository') - gl_repository(...) -} - -#' @export -#' @rdname gitlabr-deprecated -to_issue_id <- function(...) { - .Deprecated('gl_to_issue_id', package = 'gitlabr', old = 'to_issue_id') - gl_to_issue_id(...) -} - -#' @export -#' @rdname gitlabr-deprecated -unassign_issue <- function(...) { - .Deprecated('gl_unassign_issue', package = 'gitlabr', old = 'unassign_issue') - gl_unassign_issue(...) +#' +gl_ci_job <- function() { + .Deprecated("use_gitlab_ci", package = "gitlabr", old = "gl_ci_job") } - diff --git a/R/magrittr_extensions.R b/R/magrittr_extensions.R index b589dc1..a69b908 100644 --- a/R/magrittr_extensions.R +++ b/R/magrittr_extensions.R @@ -1,7 +1,7 @@ #' Import magrittr extensions -#' -#' The magrittr extensions implemented in {gitlabr} are -#' now migrated to package {arpr}. +#' +#' The magrittr extensions implemented in 'gitlabr' are +#' now migrated to package 'arpr'. #' @name iff #' @importFrom arpr iff iffn prefix remove_names pipe_into #' @noRd diff --git a/R/projects_and_repos.R b/R/projects_and_repos.R index 254f8e6..66d8725 100644 --- a/R/projects_and_repos.R +++ b/R/projects_and_repos.R @@ -114,7 +114,10 @@ gl_get_project_id <- function(project_name, ...) { warning(paste(c("Multiple projects with given name or path found,", "please use explicit name with namespace:", matching$path_with_namespace, - paste("Picking", matching[1,"path_with_namespace"], "as default")), + paste("Picking", + matching[1,"path_with_namespace"], + "as default" + )), collapse = "\n")) } @@ -123,7 +126,7 @@ gl_get_project_id <- function(project_name, ...) { } to_project_id <- function(x, ...) { - if (!is.na(suppressWarnings(as.numeric(x))) | is.numeric(x)) { + if (!is.na(suppressWarnings(as.numeric(x))) || is.numeric(x)) { as.numeric(x) } else { gl_get_project_id(x, ...) diff --git a/R/shiny_module_login.R b/R/shiny_module_login.R index 31bb139..c4dc651 100644 --- a/R/shiny_module_login.R +++ b/R/shiny_module_login.R @@ -1,12 +1,12 @@ #' Shiny module to login to GitLab API -#' +#' #' The UI contains a login and a password field as well as an (optional) #' login button. The server side function returns a reactive GitLab connection, just as [gl_connection()] #' and [gl_project_connection()]. -#' +#' #' `glLoginInput` is supposed to be used inside a `shinyUI`, while #' `glReactiveLogin` is supposed to be passed on to [shiny::callModule()] -#' +#' #' @param id shiny namespace for the login module #' @param login_button whether to show a login button (TRUE) or be purely reactive (FALSE) #' @param input from shinyServer function, usually not user provided @@ -14,27 +14,30 @@ #' @param session from shinyServer function, usually not user provided #' @param gitlab_url root URL of GitLab instance to login to #' @param api_version A character with value either "3" or "4" to specify the API version that should be used -#' @param project if not NULL, a code{[gl_project_connection]} is created to this project -#' @param success_message message text to be displayed in the UI on successful login +#' @param project if not NULL, a \code{[gl_project_connection]} is created to this project +#' @param success_message message text to be displayed in the UI on successful login #' @param failure_message message text to be displayed in the UI on login failure in addition to HTTP status #' @param on_error function to be returned instead of GitLab connection in case of login failure -#' +#' #' @rdname gl_shiny_login -#' @export +#' @export #' @return An input or output element for use in shiny UI. glLoginInput <- function(id, login_button = TRUE) { - if (!requireNamespace("shiny", quietly = TRUE)) { stop("Package shiny needs to be installed to use gl login module!") } - + ns <- shiny::NS(id) - - shiny::tagList(shiny::passwordInput(ns("private_token"), "Private Access Token"), - shiny::textOutput(ns("login_status")), - shiny::p("How to get a private access token? You have to create one manually in your GitLab Web-Interface under Profile Settings - Access Tokens.")) %>% - iff(login_button, shiny::tagAppendChild, shiny::actionButton(ns("login_button"), label = "Login")) - + + shiny::tagList( + shiny::passwordInput(ns("private_token"), "Private Access Token"), + shiny::textOutput(ns("login_status")), + shiny::p("How to get a private access token? You have to create one manually in your GitLab Web-Interface under Profile Settings - Access Tokens.") + ) %>% + iff( + login_button, shiny::tagAppendChild, + shiny::actionButton(ns("login_button"), label = "Login") + ) } #' @rdname gl_shiny_login @@ -48,38 +51,44 @@ glReactiveLogin <- function(input, output, session, on_error = function(...) { stop(failure_message) }) { - input_changed <- shiny::reactive( - if(!is.null(input$login_button)) { + if (!is.null(input$login_button)) { input$login_button } else { c(input$login, input$private_token) } ) - + shiny::eventReactive(input_changed(), { - - arglist <- list(gitlab_url = gitlab_url, - private_token = input$private_token, - api_version = api_version) - - tryCatch({ - gl_con <- if(is.null(project)) { - do.call(gl_connection, arglist) - } else { - do.call(gl_project_connection, c(arglist, project = project)) + arglist <- list( + gitlab_url = gitlab_url, + private_token = input$private_token, + api_version = api_version + ) + + tryCatch( + { + gl_con <- if (is.null(project)) { + do.call(gl_connection, arglist) + } else { + do.call(gl_project_connection, c(arglist, project = project)) + } + output$login_status <- shiny::renderText(success_message) + gl_con + }, + error = function(e) { + output$login_status <- shiny::renderText(paste( + c( + failure_message, + conditionMessage(e), + if (grepl("Unauthorized.*401", conditionMessage(e))) { + "Probably the provided token is incorrect." + } + ), + collapse = " " + )) + on_error } - output$login_status <- shiny::renderText(success_message) - gl_con - }, - error = function(e) { - output$login_status <- shiny::renderText(paste(c(failure_message, - conditionMessage(e), - if(grepl("Unauthorized.*401", conditionMessage(e))) { - "Probably the provided token is incorrect."}), - collapse = " ")) - on_error - }) + ) }) - } diff --git a/README.Rmd b/README.Rmd index 41803e4..c008f76 100644 --- a/README.Rmd +++ b/README.Rmd @@ -24,9 +24,10 @@ knitr::opts_chunk$set( [![R-CMD-check](https://github.com/ThinkR-open/gitlabr/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/ThinkR-open/gitlabr/actions/workflows/R-CMD-check.yaml) -**There are multiple breaking changes in {gitlabr} v2, please refer to the corresponding vignette: https://thinkr-open.github.io/gitlabr/articles/z-gitlabr-v2.html** - -_Note that the {gitlabr} package was originally created by [Jirka Lewandowski](https://github.com/jirkalewandowski/gitlabr). The present repository is a fork to be able to continue development of this package._ +Never dreamt of creating and managing your GitLab projects from R? +{gitlabr} is here to help you with that! +With {gitlabr}, you can interact with GitLab's API to manage your projects, issues, merge requests, pipelines, wikis, and more. +Now, the automation of your regular tasks with GitLab is just a few lines of R code away. ## Installation @@ -38,7 +39,7 @@ install.packages("gitlabr") To install the development version using [devtools](https://cran.r-project.org/package=devtools), type: ```{r, eval=FALSE} -install.packages("gitlabr", repos = 'https://thinkr-open.r-universe.dev') +install.packages("gitlabr", repos = "https://thinkr-open.r-universe.dev") ``` See the [CONTRIBUTING.md](https://github.com/ThinkR-open/gitlabr/blob/main/CONTRIBUTING.md) for instructions on how to run tests locally and contributor information. @@ -64,7 +65,8 @@ library(gitlabr) # connect as a fixed user to a GitLab instance for the session set_gitlab_connection( gitlab_url = "https://gitlab.com", - private_token = Sys.getenv("GITLAB_COM_TOKEN")) + private_token = Sys.getenv("GITLAB_COM_TOKEN") +) ``` - Find the list of projects available to you @@ -73,7 +75,7 @@ set_gitlab_connection( + For instance, we can set `owned = FALSE` to retrieve all projects except ours. ```{r} # a tibble is returned, as is always by {gitlabr} functions -gl_list_projects(max_page = 2, owned = FALSE) +gl_list_projects(max_page = 2, owned = FALSE) ``` ### Work with a specific project @@ -82,7 +84,7 @@ gl_list_projects(max_page = 2, owned = FALSE) + Let's explore [project "repo.rtask"](https://gitlab.com/statnmap/repo.rtask), with `ID = 20384533` on GitLab.com ```{r} -my_project <- 20384533 #repo.rtask", +my_project <- 20384533 # repo.rtask", ``` - If the default branch is not named `main`, you need to specify it with `gitlabr_options_set()` @@ -109,13 +111,15 @@ gl_list_issues(project = my_project) # create a new issue new_feature_issue <- gl_create_issue(project = my_project, title = "Implement new feature") -# statnmap user ID -my_id <- 4809823 +# Your user ID +my_id <- 0000000 # assign issue to me -gl_assign_issue(project = my_project, - issue_id = new_feature_issue$iid, - assignee_id = my_id) +gl_assign_issue( + project = my_project, + issue_id = new_feature_issue$iid, + assignee_id = my_id +) # Verify new issue is here gl_list_issues(project = my_project, state = "opened") @@ -180,3 +184,6 @@ You're welcome to contribute to {gitlabr} by editing the source code, adding mor ## Code of Conduct Please note that the gitlabr project is released with a [Contributor Code of Conduct](https://thinkr-open.github.io/gitlabr/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. + + +_Note that the {gitlabr} package was originally created by [Jirka Lewandowski](https://github.com/jirkalewandowski/gitlabr). The present repository is a fork to be able to continue development of this package._ \ No newline at end of file diff --git a/README.md b/README.md index e8a1145..dcc84ff 100644 --- a/README.md +++ b/README.md @@ -5,20 +5,18 @@ -[![CRAN_Status_Badge](https://www.r-pkg.org/badges/version/gitlabr)](https://cran.r-project.org/package=gitlabr) +[![CRAN\_Status\_Badge](https://www.r-pkg.org/badges/version/gitlabr)](https://cran.r-project.org/package=gitlabr) ![CRAN Downloads Badge](https://cranlogs.r-pkg.org/badges/gitlabr) [![codecov](https://codecov.io/gh/ThinkR-open/gitlabr/branch/main/graph/badge.svg?token=EVRTX5LST9)](https://codecov.io/gh/ThinkR-open/gitlabr) [![R-CMD-check](https://github.com/ThinkR-open/gitlabr/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/ThinkR-open/gitlabr/actions/workflows/R-CMD-check.yaml) -**There are multiple breaking changes in {gitlabr} v2, please refer to -the corresponding vignette: -** - -*Note that the {gitlabr} package was originally created by [Jirka -Lewandowski](https://github.com/jirkalewandowski/gitlabr). The present -repository is a fork to be able to continue development of this -package.* +Never dreamt of creating and managing your GitLab projects from R? +{gitlabr} is here to help you with that\! +With {gitlabr}, you can interact with GitLab’s API to manage your +projects, issues, merge requests, pipelines, wikis, and more. +Now, the automation of your regular tasks with GitLab is just a few +lines of R code away. ## Installation @@ -32,7 +30,7 @@ To install the development version using [devtools](https://cran.r-project.org/package=devtools), type: ``` r -install.packages("gitlabr", repos = 'https://thinkr-open.r-universe.dev') +install.packages("gitlabr", repos = "https://thinkr-open.r-universe.dev") ``` See the @@ -50,12 +48,14 @@ version 2.0.0 or higher. This {gitlabr} version uses the GitLab API v4. R code using {gitlabr} to perform some common GitLab actions can look like this -- Create a TOKEN on your GitLab instance with scopes: `api` - - For instance on gitlab.com: - `https://gitlab.com/-/profile/personal_access_tokens` -- Store your token in .Renviron as `GITLAB_COM_TOKEN` with - `usethis::edit_r_environ()` and restart your session -- Set a connection to GitLab instance + - Create a TOKEN on your GitLab instance with scopes: `api` + - For instance on gitlab.com: + `https://gitlab.com/-/profile/personal_access_tokens` + - Store your token in .Renviron as `GITLAB_COM_TOKEN` with + `usethis::edit_r_environ()` and restart your session + - Set a connection to GitLab instance + + ``` r library(gitlabr) @@ -66,63 +66,73 @@ library(gitlabr) # connect as a fixed user to a GitLab instance for the session set_gitlab_connection( gitlab_url = "https://gitlab.com", - private_token = Sys.getenv("GITLAB_COM_TOKEN")) + private_token = Sys.getenv("GITLAB_COM_TOKEN") +) ``` -- Find the list of projects available to you - - Define a limit of pages of projects to search in with `max_page`, - otherwise the entire GitLab.com will be downloaded here… - - Find all parameters available in the API for projects on this page: - - - For instance, we can set `owned = FALSE` to retrieve all projects - except ours. + - Find the list of projects available to you + - Define a limit of pages of projects to search in with + `max_page`, otherwise the entire GitLab.com will be downloaded + here… + - Find all parameters available in the API for projects on this + page: + - For instance, we can set `owned = FALSE` to retrieve all + projects except ours. + + ``` r # a tibble is returned, as is always by {gitlabr} functions -gl_list_projects(max_page = 2, owned = FALSE) -#> # A tibble: 40 × 135 -#> id description name name_with_names… path path_with_names… created_at -#> -#> 1 30670263 "" Proj… Enzo Lop / Proj… proj… enzo.lop.pro/pr… 2021-10-2… -#> 2 30670257 "" test Seung-hyun Lee … test faintblue324/te… 2021-10-2… -#> 3 30670253 "" s54 Zuitt-projects … s54 zuitt-projects3… 2021-10-2… -#> 4 30670220 "" temp… taka / template temp… hnam/template 2021-10-2… -#> 5 30670189 "" Jeng… NATALIA GARCIA … jeng… 22113346/jenga-… 2021-10-2… -#> 6 30670181 "" RStu… yannyven / RStu… rstu… yannyven/rstudi… 2021-10-2… -#> 7 30670175 "NAO ENSTA… NAO-… Danut POP / NAO… NAO-… blueDonuts69/NA… 2021-10-2… -#> 8 30670166 "A complet… remo… Alexa Fevic / r… remo… alexafevic/remo… 2021-10-2… -#> 9 30670163 "" YAOD… flagarde / YAOD… YAOD… flagarde/YAODAQ 2021-10-2… -#> 10 30670162 "" eval… zenika-poei-ren… eval… zenika-poei-ren… 2021-10-2… -#> # … with 30 more rows, and 128 more variables: default_branch , -#> # ssh_url_to_repo , http_url_to_repo , web_url , -#> # readme_url , forks_count , star_count , -#> # last_activity_at , namespace.id , namespace.name , -#> # namespace.path , namespace.kind , namespace.full_path , -#> # namespace.avatar_url , namespace.web_url , -#> # container_registry_image_prefix , _links.self , … +gl_list_projects(max_page = 2, owned = FALSE) +#> # A tibble: 40 × 129 +#> id name name_with_namespace path path_with_namespace created_at +#> +#> 1 57865685 nodejsappl… Arsalan Ahmed Zia … node… arsalanahmedzia_th… 2024-05-1… +#> 2 57865684 Self-Hoste… Anand R / Self-Hos… self… anandr72/self-host… 2024-05-1… +#> 3 57865661 cuda handcat / cuda cuda handcat/cuda 2024-05-1… +#> 4 57865656 TicTacToe Debeleac Vincenzzi… tict… Andreidoo/tictactoe 2024-05-1… +#> 5 57865597 Sparks Git… Nicolas Tatard / S… spar… tatardnicolas47/sp… 2024-05-1… +#> 6 57865595 Sparks Git… Patrick Poncy / Sp… spar… PatSopra/sparks-gi… 2024-05-1… +#> 7 57865594 Sparks Git… Emie Bourdeau / Sp… spar… Emie_Bourdeau/spar… 2024-05-1… +#> 8 57865590 ComMan UI ossama hassari / C… comm… ossamahassari98/co… 2024-05-1… +#> 9 57865581 Sparks Git… Raphaël Mechali / … spar… RaphaelMechali/spa… 2024-05-1… +#> 10 57865574 copy local… mvaskuri / copy lo… copy… mvaskuri1/copy-loc… 2024-05-1… +#> # ℹ 30 more rows +#> # ℹ 123 more variables: default_branch , ssh_url_to_repo , +#> # http_url_to_repo , web_url , readme_url , forks_count , +#> # star_count , last_activity_at , namespace.id , +#> # namespace.name , namespace.path , namespace.kind , +#> # namespace.full_path , namespace.avatar_url , +#> # namespace.web_url , container_registry_image_prefix , … ``` ### Work with a specific project -- Explore one of your projects. You can set the name of the project or - its ID. The ID is highly recommended, in particular if your project - does not appear in the first pages of projects above. - - Let’s explore [project - “repo.rtask”](https://gitlab.com/statnmap/repo.rtask), with - `ID = 20384533` on GitLab.com + - Explore one of your projects. You can set the name of the project or + its ID. The ID is highly recommended, in particular if your project + does not appear in the first pages of projects above. + - Let’s explore [project + “repo.rtask”](https://gitlab.com/statnmap/repo.rtask), with + `ID = 20384533` on GitLab.com + + ``` r -my_project <- 20384533 #repo.rtask", +my_project <- 20384533 # repo.rtask", ``` -- If the default branch is not named `main`, you need to specify it with - `gitlabr_options_set()` + - If the default branch is not named `main`, you need to specify it + with `gitlabr_options_set()` + + ``` r gitlabr_options_set("gitlabr.main", "master") ``` -- List files of the project using `gl_list_files()` + - List files of the project using `gl_list_files()` + + ``` r gl_list_files(project = my_project) @@ -133,37 +143,43 @@ gl_list_files(project = my_project) #> 2 c36b681bb31b80cbd090f07c95f09788c88629a6 example.txt blob example.txt 100644 ``` -- List issues with `gl_list_issues()` + - List issues with `gl_list_issues()` + + ``` r gl_list_issues(project = my_project) -#> # A tibble: 2 × 35 -#> id iid project_id title description state created_at updated_at author.id -#> -#> 1 69525849 2 20384533 A se… The blog p… open… 2020-08-0… 2020-08-0… 4809823 -#> 2 69525845 1 20384533 An e… No desc in… open… 2020-08-0… 2020-08-0… 4809823 -#> # … with 26 more variables: author.name , author.username , -#> # author.state , author.avatar_url , author.web_url , -#> # type , user_notes_count , merge_requests_count , -#> # upvotes , downvotes , confidential , issue_type , -#> # web_url , time_stats.time_estimate , -#> # time_stats.total_time_spent , task_completion_status.count , -#> # task_completion_status.completed_count , … +#> # A tibble: 2 × 40 +#> id iid project_id title description state created_at updated_at author.id +#> +#> 1 6952… 2 20384533 A se… The blog p… open… 2020-08-0… 2020-08-0… 4809823 +#> 2 6952… 1 20384533 An e… No desc in… open… 2020-08-0… 2020-08-0… 4809823 +#> # ℹ 31 more variables: author.username , author.name , +#> # author.state , author.locked , author.avatar_url , +#> # author.web_url , type , user_notes_count , +#> # merge_requests_count , upvotes , downvotes , +#> # confidential , issue_type , web_url , +#> # time_stats.time_estimate , time_stats.total_time_spent , +#> # task_completion_status.count , … ``` -- Create an issue + - Create an issue + + ``` r # create a new issue new_feature_issue <- gl_create_issue(project = my_project, title = "Implement new feature") -# statnmap user ID -my_id <- 4809823 +# Your user ID +my_id <- 0000000 # assign issue to me -gl_assign_issue(project = my_project, - issue_id = new_feature_issue$iid, - assignee_id = my_id) +gl_assign_issue( + project = my_project, + issue_id = new_feature_issue$iid, + assignee_id = my_id +) # Verify new issue is here gl_list_issues(project = my_project, state = "opened") @@ -185,11 +201,11 @@ If an API request is not already available in {gitlabr}, function For instance, the API documentation shows how to create a new project in : -- The verb is `POST` -- The request is `projects` -- Required attributes are `name` or `path` (if `name` not set) -- `default_branch` is an attribute that can be set if wanted, but not - required + - The verb is `POST` + - The request is `projects` + - Required attributes are `name` or `path` (if `name` not set) + - `default_branch` is an attribute that can be set if wanted, but not + required The corresponding use of `gitlab()` is: @@ -202,7 +218,7 @@ gitlab( ) ``` -Implement whatever suits your needs ! +Implement whatever suits your needs \! ### Unset connection @@ -219,20 +235,22 @@ and your CI should be ready to start in the next commit. There are pre-defined templates: -- bookdown-production.yml + - bookdown-production.yml -- bookdown.yml + - bookdown.yml -- check-coverage-pkgdown-renv.yml + - check-coverage-pkgdown-renv.yml -- check-coverage-pkgdown.yml + - check-coverage-pkgdown.yml ## Further information -- For an introduction see the `vignette("quick-start-guide-to-gitlabr")` -- When writing custom extensions (“convenience functions”) for {gitlabr} - or when you experience any trouble, the very extensive [GitLab API - documentation](https://docs.gitlab.com/ce/api/) can be helpful. + - For an introduction see the + `vignette("quick-start-guide-to-gitlabr")` + - When writing custom extensions (“convenience functions”) for + {gitlabr} or when you experience any trouble, the very extensive + [GitLab API documentation](https://docs.gitlab.com/ce/api/) can be + helpful. # Contributing to {gitlabr} @@ -247,3 +265,8 @@ Please note that the gitlabr project is released with a [Contributor Code of Conduct](https://thinkr-open.github.io/gitlabr/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. + +*Note that the {gitlabr} package was originally created by [Jirka +Lewandowski](https://github.com/jirkalewandowski/gitlabr). The present +repository is a fork to be able to continue development of this +package.* diff --git a/_pkgdown.yml b/_pkgdown.yml index be0be36..f9b34ce 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -9,7 +9,6 @@ reference: contents: - gl_new_project - gl_assign_issue - - gl_builds - gl_close_issue - gl_create_branch - gl_create_merge_request @@ -26,6 +25,7 @@ reference: - gl_get_commits - gl_get_diff - gl_get_file + - gl_get_group_id - gl_get_issue - gl_get_issue_comments - gl_jobs @@ -33,15 +33,17 @@ reference: - gl_list_issues - gl_list_branches - gl_list_files + - gl_list_groups + - gl_list_group_members - gl_list_projects + - gl_list_project_members + - gl_new_group - gl_new_issue - gl_pipelines - gl_push_file - gl_reopen_issue - gl_repository - gl_unassign_issue - - gl_list_group_members - - gl_list_project_members - title: Set global options desc: > Define connection to an instance of GitLab @@ -56,22 +58,24 @@ reference: - use_gitlab_ci - title: Extra tools desc: > - Internal tools that could be useful for projects out of {gitlabr} + Internal tools that could be useful for projects out of 'gitlabr' contents: - multilist_to_tibble - title: Other functions desc: > Functions requiring cleaning or deprecation contents: - - gl_ci_job - gitlabr - - gitlabr_0_7_renaming - gl_archive - gl_connection - gl_get_project_id - gl_proj_req + - gl_group_req - glLoginInput + - glReactiveLogin - gl_to_issue_id - title: Deprecated functions contents: - gitlabr-deprecated + - gl_builds + - gl_ci_job diff --git a/data/gitlabr_0_7_renaming.rda b/data/gitlabr_0_7_renaming.rda deleted file mode 100644 index 0697295..0000000 Binary files a/data/gitlabr_0_7_renaming.rda and /dev/null differ diff --git a/dev/bulk_renaming.R b/dev/bulk_renaming.R deleted file mode 100644 index 863bf3f..0000000 --- a/dev/bulk_renaming.R +++ /dev/null @@ -1,46 +0,0 @@ -library(dplyr) -library(functional) -library(purrr) -library(gitlabr) -library(magrittr) - -## bulk renaming - -tibble(old_name = ls(envir = as.environment("package:gitlabr"))) %>% - mutate(new_name = case_when( - .$old_name == "gitlab" ~ "gitlab", - .$old_name == "gitlab_connection" ~ "gl_connection", - grepl("(gitlab_connection)|(pipe_into)", .$old_name) ~ .$old_name, - TRUE ~ paste0("gl_", .$old_name) - )) %>% - subset(old_name != new_name) %>% - mutate(complete = paste0("#' @export -#' @rdname gitlabr-deprecated -", old_name, " <- function(...) { - .Deprecated('", new_name, "', package = 'gitlabr', old = '", old_name, "') - ", new_name, "(...) -} -")) -> replacements - -replacements %>% - mutate(doc_entry = paste0("#' \\code{", old_name, "} \\tab is now called \\code{", new_name, "}")) %$% - { c("#' Deprecated functions", - "#'", - "#' Many functions were renamed with version 0.7 to the \\code{gl_} naming scheme.", - "#' ", - "#' @param ... Parameters to the new function", - "#' @name gitlabr-deprecated", - "#' @section Details:", - "#' \\tabular{rl}{", - doc_entry, - "#' }", - "NULL", - "") } -> documentation_header - -unlink("R/legacy_headers.R") -replacements %$% - paste(c(documentation_header, complete), collapse = "\n") %>% - writeLines("R/legacy_headers.R") - -replacements %>% select(old_name, new_name) -> gitlabr_0_7_renaming -devtools::use_data(gitlabr_0_7_renaming, overwrite = TRUE) diff --git a/dev/config_attachment.yaml b/dev/config_attachment.yaml index 46e24ec..571eb26 100644 --- a/dev/config_attachment.yaml +++ b/dev/config_attachment.yaml @@ -3,8 +3,12 @@ path.d: DESCRIPTION dir.r: R dir.v: vignettes dir.t: tests -extra.suggests: ~ -pkg_ignore: ~ +extra.suggests: + - shiny + - DT +pkg_ignore: + - shiny + - DT document: yes normalize: yes inside_rmd: no diff --git a/dev/create_testor_on_gitlab.R b/dev/create_testor_on_gitlab.R index f42997f..bef1f52 100644 --- a/dev/create_testor_on_gitlab.R +++ b/dev/create_testor_on_gitlab.R @@ -19,8 +19,10 @@ set_gitlab_connection( # Create all projects for CI or local # Projects with name containing "master" will have default branch named "master", "main" otherwise # CI only - to allow run in parallel -projects_names <- c("testor.macos", "testor.windows", "testor.release", - "testor.devel", "testor.release.master", "testor.coverage") +projects_names <- c( + "testor.macos", "testor.windows", "testor.release", + "testor.devel", "testor.release.master", "testor.coverage" +) # Local - Only the first one is mandatory projects_names <- "testor.main" @@ -37,25 +39,26 @@ for (test_project_name in projects_names) { main_branch <- get_main() # 5. Create a project called `testor`, owned by the user - project_info <- gl_new_project(name = test_project_name, - default_branch = main_branch, - initialize_with_readme = TRUE) - + project_info <- gl_new_project( + name = test_project_name, + default_branch = main_branch, + initialize_with_readme = TRUE + ) + # Verify branches (depending on GitLab, main branch may still be "master") all_branches <- gl_list_branches(project = project_info$id) - if (main_branch == "main" & all_branches$name == "master") { + if (main_branch == "main" && all_branches$name == "master") { message("Change from master to main for tests") - + gl_create_branch(project = project_info$id, branch = "main", ref = "master") gl_edit_project(project = project_info$id, default_branch = "main") # Change default_branch = "main" gl_delete_branch(project = project_info$id, branch = "master") # Verify project_info <- gl_get_project(test_project) testthat::expect_equal(project_info$default_branch, "main") - - } else if (main_branch == "master" & all_branches$name == "main") { + } else if (main_branch == "master" && all_branches$name == "main") { message("Change from main to master for tests") - + gl_create_branch(project = project_info$id, branch = "master", ref = "main") gl_edit_project(project = project_info$id, default_branch = "master") # Change default_branch = "main" gl_delete_branch(project = project_info$id, branch = "main") @@ -63,33 +66,34 @@ for (test_project_name in projects_names) { project_info <- gl_get_project(test_project) testthat::expect_equal(project_info$default_branch, "master") } - + # browseURL(project_info$web_url) - + # 6. Get the ID of the project # This will be presented at the end of this script # message("Add variable in your dev/environment.yml: GITLABR_TEST_PROJECT_NAME: ", project_info$name) # message("Add variable in your dev/environment.yml: GITLABR_TEST_PROJECT_ID: ", project_info$id) - + # 7. Add/modify and commit the `README.md`: content_md <- paste(" # testor -Repository to test R package [{gitlabr}](https://github.com/ThinkR-open/gitlabr) +Repository to test R package ['gitlabr'](https://github.com/ThinkR-open/gitlabr) ") - + gl_push_file( project = project_info$id, file_path = "README.md", content = content_md, commit_message = "Update README", branch = main_branch, - overwrite = TRUE) - + overwrite = TRUE + ) + # 8. Go to Repository > Branches and create a branch named "for-tests". gl_create_branch(project = project_info$id, branch = "for-tests", ref = main_branch) # gl_list_branches(project = project_info$id) - + # 9. Add and commit a CI file (`.gitlab-ci.yml`) content_ci <- paste(" testing: @@ -98,33 +102,36 @@ testing: paths: - test.txt ") - + gl_push_file( project = project_info$id, file_path = ".gitlab-ci.yml", content = content_ci, commit_message = "Add CI to the main branch", branch = main_branch, - overwrite = TRUE) - + overwrite = TRUE + ) + # 10. Create a commit (or use the commit just created), add a follow-up comment commits_in_main <- gl_get_commits(project = project_info$id, ref_name = main_branch) - gl_comment_commit(project = project_info$id, - id = commits_in_main$id[1], - text = "Write a comment") - + gl_comment_commit( + project = project_info$id, + id = commits_in_main$id[1], + text = "Write a comment" + ) + # This will be presented at the end of this script # message("Add variable in dev/environment.yml: COMMENTED_COMMIT: ", comment_infos = commits_in_main$id[1]) - + # 11. Create a first issue (#1) with a follow-up comment issue_info <- gl_create_issue(project = project_info$id, title = "Dont close issue 1", description = "An example issue to not close for tests") gl_comment_issue(project = project_info$id, id = issue_info$iid, text = "A comment on issue to not close") - + # Remind environment variables to add in "dev/environment.yml" message("Add variable in your dev/environment.yml: GITLABR_TEST_PROJECT_NAME: ", project_info$name) message("Add variable in your dev/environment.yml: GITLABR_TEST_PROJECT_ID: ", project_info$id) message("Add variable in your dev/environment.yml: COMMENTED_COMMIT: ", commits_in_main$id[1]) - + all_outputs[[test_project_name]] <- list( ci.matrix = glue::glue( @@ -149,48 +156,64 @@ print(purrr::transpose(all_outputs)) # Also, only content of sub-list "local.env" is required # Create extra projects just to be sure there is something to test ---- +# This is to get some R styled projects so that we can test GitLab CI + +# Set connection +set_gitlab_connection( + gitlab_url = "https://gitlab.com", + private_token = Sys.getenv("GITLABR_TEST_TOKEN") +) + source(here::here("dev/testor_tools.R")) gitlabr_options_set("gitlabr.main", "main") # _ R package project_name <- "demo.package" -project_info <- gl_new_project(name = project_name, - default_branch = "main", - initialize_with_readme = TRUE) +project_info <- gl_new_project( + name = project_name, + default_branch = "main", + initialize_with_readme = TRUE +) # Create tmp dir tmpdir <- tempfile(pattern = "pkg-") dir.create(tmpdir) project_path <- file.path(tmpdir, project_name) # Clone in tmp dir -clone_locally(project_name = project_info$path, - group_url = project_info$namespace.web_url, - project_path = project_path, - open = TRUE) +clone_locally( + project_name = project_info$path, + group_url = project_info$namespace.web_url, + project_path = project_path, + open = TRUE +) usethis::with_project(project_path, { - usethis::create_package(path = project_path, open = FALSE) - attachment::att_amend_desc() + usethis::create_package(path = project_path, open = FALSE) + attachment::att_amend_desc() }) -push_to_repo(project_path, message = 'Init repo') +push_to_repo(project_path, message = "Init repo") # _ bookdown project_name <- "demo.bookdown" -project_info <- gl_new_project(name = project_name, - default_branch = "main", - initialize_with_readme = TRUE) +project_info <- gl_new_project( + name = project_name, + default_branch = "main", + initialize_with_readme = TRUE +) # Create tmp dir tmpdir <- tempfile(pattern = "pkg-") dir.create(tmpdir) project_path <- file.path(tmpdir, project_name) # Clone in tmp dir -clone_locally(project_name = project_info$path, - group_url = project_info$namespace.web_url, - project_path = project_path, - open = TRUE) +clone_locally( + project_name = project_info$path, + group_url = project_info$namespace.web_url, + project_path = project_path, + open = TRUE +) file.copy( list.files( @@ -198,12 +221,15 @@ file.copy( all.files = TRUE, full.names = TRUE, recursive = TRUE ), to = project_path, - recursive = TRUE) + recursive = TRUE +) # Add CI -gitlabr::use_gitlab_ci(path = file.path(project_path, ".gitlab-ci.yml"), - type = "bookdown") +gitlabr::use_gitlab_ci( + path = file.path(project_path, ".gitlab-ci.yml"), + type = "bookdown" +) -push_to_repo(project_path, message = 'Init repo') +push_to_repo(project_path, message = "Init repo") # _ bookdown production -# _ R package with {renv} +# _ R package with 'renv' diff --git a/dev/dev_history.R b/dev/dev_history.R index acb08c0..2a29e5e 100644 --- a/dev/dev_history.R +++ b/dev/dev_history.R @@ -22,13 +22,14 @@ usethis::use_coverage() usethis::use_github_action(url = "https://github.com/DavisVaughan/extrachecks-html5/blob/main/R-CMD-check-HTML5.yaml") # Check pr ---- -# To download a PR locally so that you can experiment with it, run pr_fetch(). -# If you make changes, run pr_push() to push them back to GitHub. +# To download a PR locally so that you can experiment with it, run pr_fetch(). +# If you make changes, run pr_push() to push them back to GitHub. # After you have merged the PR, run pr_finish() to delete the local branch. usethis::pr_fetch(24) usethis::pr_push() # Test pkgdown +pkgdown::check_pkgdown() usethis::use_build_ignore("_pkgdown.yml") usethis::use_git_ignore("public") usethis::use_build_ignore("public/") @@ -36,12 +37,23 @@ options(rmarkdown.html_vignette.check_title = FALSE) pkgdown::build_site() # Development ---- -attachment::att_amend_desc() #extra.suggests = "glue") +attachment::att_amend_desc( + update.config = TRUE, + extra.suggests = c("shiny", "DT"), + pkg_ignore = c("shiny", "DT") +) devtools::load_all() devtools::test() -devtools::check() # /!\ Tests are currently skip if no token in "dev/environment.yml"/!\ +devtools::check() +devtools::check(args = c("--no-tests")) devtools::build_vignettes() +# Deal with tests ---- +devtools::load_all() +## load test environment variables +do.call(Sys.setenv, yaml::yaml.load_file("dev/environment.yml")) +devtools::test() ## run all tests +testthat::test_file("tests/testthat/test_files.R") ## run test on one file # Prepare for CRAN ---- usethis::use_release_issue() @@ -128,13 +140,12 @@ library(purrr) repos <- gh::gh("/repos/ThinkR-open/gitlabr/stats/contributors") map(repos, "author") %>% map("login") -map_chr(repos, ~paste0( +map_chr(repos, ~ paste0( # "[@", "[", pluck(.x, "author", "login"), "](", pluck(.x, "author", "html_url"), ")" - ) -) %>% +)) %>% glue::glue_collapse(sep = ", ", last = " and ") diff --git a/man/gitlab.Rd b/man/gitlab.Rd index b9f7aff..9445a05 100644 --- a/man/gitlab.Rd +++ b/man/gitlab.Rd @@ -14,7 +14,7 @@ gitlab( page = "all", max_page = 10, enforce_api_root = TRUE, - argname_verb = if (identical(verb, httr::GET) | identical(verb, httr::DELETE)) { + argname_verb = if (identical(verb, httr::GET) || identical(verb, httr::DELETE)) { "query" } else { @@ -36,13 +36,13 @@ gitlab( \item{debug}{if TRUE API URL and query will be printed, defaults to FALSE} \item{gitlab_con}{function to use for issuing API requests (e.g. as returned by -\code{\link[=gitlab_connection]{gitlab_connection()}}} +\code{\link[=get_gitlab_connection]{get_gitlab_connection()}}} \item{page}{number of page of API response to get; if "all" (default), all pages (up to max_page parameter!) are queried successively and combined.} \item{max_page}{maximum number of pages to retrieve. Defaults to 10. This is an upper limit -to prevent {gitlabr} getting stuck in retrieving an unexpectedly high number of entries (e.g. of a +to prevent 'gitlabr' getting stuck in retrieving an unexpectedly high number of entries (e.g. of a project list). It can be set to NA/Inf to retrieve all available pages without limit, but this is recommended only under controlled circumstances.} @@ -60,9 +60,9 @@ may include private_token and all other parameters as documented for the GitLab the response from the GitLab API, usually as a \code{tibble} and including all pages } \description{ -This is {gitlabr}'s core function to talk to GitLab's server API via HTTP(S). Usually you will not -use this function directly too often, but either use {gitlabr}'s convenience wrappers or write your -own. See the {gitlabr} vignette for more information on this. +This is 'gitlabr' core function to talk to GitLab's server API via HTTP(S). Usually you will not +use this function directly too often, but either use 'gitlabr' convenience wrappers or write your +own. See the 'gitlabr' vignette for more information on this. } \details{ \code{gitlab()} function allows to use any request of the GitLab API \url{https://docs.gitlab.com/ce/api/}. @@ -93,14 +93,16 @@ you can give it a try. \dontrun{ # Connect as a fixed user to a GitLab instance set_gitlab_connection( - gitlab_url = "https://gitlab.com", + gitlab_url = "https://gitlab.com", private_token = Sys.getenv("GITLAB_COM_TOKEN") ) # Use a simple request gitlab(req = "projects") # Use a combined request with extra parameters -gitlab(req = c("projects", 1234, "issues"), - state = "closed") +gitlab( + req = c("projects", 1234, "issues"), + state = "closed" +) } } diff --git a/man/gitlabci.Rd b/man/gitlabci.Rd deleted file mode 100644 index e4c6e25..0000000 --- a/man/gitlabci.Rd +++ /dev/null @@ -1,25 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ci.R -\name{gl_ci_job} -\alias{gl_ci_job} -\title{Define GitLab CI jobs content} -\usage{ -gl_ci_job() -} -\value{ -Creates the content of a .gitlab-ci.yml file as character. -} -\description{ -Exploration of job content is deprecated as of 'gitlabr' 1.1.7. -Content of .gitlab-ci.yml file is now created using templates with -use_gitlab_ci(type = "check-coverage-pkgdown"). See \code{\link[=use_gitlab_ci]{use_gitlab_ci()}}. -} -\examples{ -\dontrun{ -# Deprecated -gl_ci_job() -} -} -\seealso{ -\code{\link[=use_gitlab_ci]{use_gitlab_ci()}} -} diff --git a/man/gitlabr-deprecated.Rd b/man/gitlabr-deprecated.Rd index c3729d7..5609029 100644 --- a/man/gitlabr-deprecated.Rd +++ b/man/gitlabr-deprecated.Rd @@ -2,154 +2,35 @@ % Please edit documentation in R/legacy_headers.R \name{gitlabr-deprecated} \alias{gitlabr-deprecated} -\alias{archive} -\alias{assign_issue} -\alias{close_issue} -\alias{comment_commit} -\alias{comment_issue} -\alias{create_branch} -\alias{create_merge_request} -\alias{delete_branch} -\alias{edit_commit_comment} -\alias{edit_issue} -\alias{edit_issue_comment} -\alias{file_exists} -\alias{get_comments} -\alias{get_commit_comments} -\alias{get_commits} -\alias{get_diff} -\alias{get_file} -\alias{get_issue} -\alias{get_issue_comments} -\alias{get_issues} -\alias{get_project_id} -\alias{gitlab_connection} -\alias{list_branches} -\alias{list_files} -\alias{list_projects} -\alias{new_issue} -\alias{project_connection} -\alias{proj_req} -\alias{push_file} -\alias{reopen_issue} -\alias{repository} -\alias{to_issue_id} -\alias{unassign_issue} +\alias{gl_builds} +\alias{gl_ci_job} \title{Deprecated functions} \usage{ -archive(...) +gl_builds(project, api_version = 4, ...) -assign_issue(...) - -close_issue(...) - -comment_commit(...) - -comment_issue(...) - -create_branch(...) - -create_merge_request(...) - -delete_branch(...) - -edit_commit_comment(...) - -edit_issue(...) - -edit_issue_comment(...) - -file_exists(...) - -get_comments(...) - -get_commit_comments(...) - -get_commits(...) - -get_diff(...) - -get_file(...) - -get_issue(...) - -get_issue_comments(...) - -get_issues(...) - -get_project_id(...) - -gitlab_connection(...) - -list_branches(...) - -list_files(...) - -list_projects(...) - -new_issue(...) - -project_connection(...) - -proj_req(...) - -push_file(...) - -reopen_issue(...) - -repository(...) - -to_issue_id(...) - -unassign_issue(...) +gl_ci_job() } \arguments{ +\item{project}{Project name or ID} + +\item{api_version}{Since \code{gl_builds} is no longer working for GitLab API v4, +this must be set to "3" in order to avoid deprecation warning and HTTP error. It currently +default to "4" with deprecation message.´} + \item{...}{Parameters to the new function} } \value{ -Warning for deprecated functions and output depending on the superseeding function. +Warning for deprecated functions and +output depending on the superseeding function. } \description{ -Many functions were renamed with version 0.7 to the \code{gl_} naming scheme. -Note that the old function names are deprecated and might be removed without -further notice. +List of deprecated functions that will be removed in future versions. } \section{Details}{ \tabular{rl}{ -\code{archive} \tab is now called \code{gl_archive} \cr -\code{assign_issue} \tab is now called \code{gl_assign_issue} \cr -\code{close_issue} \tab is now called \code{gl_close_issue} \cr -\code{comment_commit} \tab is now called \code{gl_comment_commit} \cr -\code{comment_issue} \tab is now called \code{gl_comment_issue} \cr -\code{create_branch} \tab is now called \code{gl_create_branch} \cr -\code{create_merge_request} \tab is now called \code{gl_create_merge_request} \cr -\code{delete_branch} \tab is now called \code{gl_delete_branch} \cr -\code{edit_commit_comment} \tab is now called \code{gl_edit_commit_comment} \cr -\code{edit_issue} \tab is now called \code{gl_edit_issue} \cr -\code{edit_issue_comment} \tab is now called \code{gl_edit_issue_comment} \cr -\code{file_exists} \tab is now called \code{gl_file_exists} \cr -\code{get_comments} \tab is now called \code{gl_get_comments} \cr -\code{get_commit_comments} \tab is now called \code{gl_get_commit_comments} \cr -\code{get_commits} \tab is now called \code{gl_get_commits} \cr -\code{get_diff} \tab is now called \code{gl_get_diff} \cr -\code{get_file} \tab is now called \code{gl_get_file} \cr -\code{get_issue} \tab is now called \code{gl_get_issue} \cr -\code{get_issue_comments} \tab is now called \code{gl_get_issue_comments} \cr -\code{get_issues} \tab is now called \code{gl_list_issues} \cr -\code{get_project_id} \tab is now called \code{gl_get_project_id} \cr -\code{gitlab_connection} \tab is now called \code{gl_connection} \cr -\code{list_branches} \tab is now called \code{gl_list_branches} \cr -\code{list_files} \tab is now called \code{gl_list_files} \cr -\code{list_projects} \tab is now called \code{gl_list_projects} \cr -\code{new_issue} \tab is now called \code{gl_new_issue} \cr -\code{project_connection} \tab is now called \code{gl_project_connection} \cr -\code{proj_req} \tab is now called \code{gl_proj_req} \cr -\code{push_file} \tab is now called \code{gl_push_file} \cr -\code{reopen_issue} \tab is now called \code{gl_reopen_issue} \cr -\code{repository} \tab is now called \code{gl_repository} \cr -\code{to_issue_id} \tab is now called \code{gl_to_issue_id} \cr -\code{unassign_issue} \tab is now called \code{gl_unassign_issue} \cr +\code{gl_builds} \tab in favour of \code{gl_pipelines} \cr +\code{gl_ci_job} \tab in favour of \code{use_gitlab_ci} \cr } } diff --git a/man/gitlabr_0_7_renaming.Rd b/man/gitlabr_0_7_renaming.Rd deleted file mode 100644 index b850cb6..0000000 --- a/man/gitlabr_0_7_renaming.Rd +++ /dev/null @@ -1,12 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/legacy_headers.R -\docType{data} -\name{gitlabr_0_7_renaming} -\alias{gitlabr_0_7_renaming} -\title{renaming from {gitlabr} version 0.6.4 to 0.7} -\format{ -A data frame with 33 rows and 2 variables -} -\description{ -List of of old and new function name. -} diff --git a/man/gl_connection.Rd b/man/gl_connection.Rd index 1ad8536..738d280 100644 --- a/man/gl_connection.Rd +++ b/man/gl_connection.Rd @@ -21,19 +21,24 @@ gl_project_connection( ) } \arguments{ -\item{gitlab_url}{URL to the GitLab instance (e.g. \verb{https://gitlab.myserver.com})} +\item{gitlab_url}{URL to the GitLab instance +(e.g. \verb{https://gitlab.myserver.com})} -\item{private_token}{private_token with which to identify. You can generate one in the web interface under +\item{private_token}{private_token with which to identify. +You can generate one in the web interface under \verb{GITLABINSTANCEURL/-/profile/personal_access_tokens.html} when logged on.} -\item{api_version}{Currently "4" for the latest GitLab API version. See Details section on API versions.} +\item{api_version}{Currently "4" for the latest GitLab API version. +See Details section on API versions.} -\item{api_location}{location of the GitLab API under the \code{gitlab_url}, usually and by default "/api/${api_version}/"} +\item{api_location}{location of the GitLab API under the \code{gitlab_url}, +usually and by default "/api/<>/"} \item{project}{id or name of project to issue requests to} } \value{ -A function to access a specific GitLab API as a specific user, see details +A function to access a specific GitLab API +as a specific user, see details } \description{ Creates a function that can be used to issue requests to the specified @@ -53,8 +58,10 @@ you can give it a try. } \section{API versions}{ -"v4" is the standard API since GitLab version 9.0 and only this version is officially supported by -{gitlabr} since version 1.1.6. "v3" as a parameter value is not removed, since for many instances, {gitlabr} +"v4" is the standard API since GitLab version 9.0 +and only this version is officially supported by +'gitlabr' since version 1.1.6. "v3" as a parameter value +is not removed, since for many instances, 'gitlabr' code will still work if you try. } diff --git a/man/gl_get_group_id.Rd b/man/gl_get_group_id.Rd new file mode 100644 index 0000000..6efffbd --- /dev/null +++ b/man/gl_get_group_id.Rd @@ -0,0 +1,29 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/groups.R +\name{gl_get_group_id} +\alias{gl_get_group_id} +\title{Get a group id by name} +\usage{ +gl_get_group_id(group_name, ...) +} +\arguments{ +\item{group_name}{group name} + +\item{...}{passed on to \code{\link[=gitlab]{gitlab()}}} +} +\value{ +Integer. ID of the group if found. +} +\description{ +Get a group id by name +} +\details{ +Number of pages searched is limited to (per_page =) 20 * (max_page =) 10 by default. +If the \code{group_name} is an old group lost in a big repository (position > 200), +\code{gl_get_group_id()} may not find the group id. +} +\examples{ +\dontrun{ +gl_get_group_id("<>") +} +} diff --git a/man/gl_group_req.Rd b/man/gl_group_req.Rd new file mode 100644 index 0000000..27d2a31 --- /dev/null +++ b/man/gl_group_req.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/groups.R +\name{gl_group_req} +\alias{gl_group_req} +\title{Create a group specific request} +\usage{ +gl_group_req(group, ...) +} +\arguments{ +\item{group}{group name or id} + +\item{...}{passed on to \code{\link[=gl_get_group_id]{gl_get_group_id()}}} +} +\value{ +A vector of character to be used as request for functions involving groups +} +\description{ +Prefixes the request location with "groups/:id/subgroups" and automatically +translates group names into ids +} +\examples{ +\dontrun{ +gl_group_req("test_group"<>) +} +} diff --git a/man/gl_list_files.Rd b/man/gl_list_files.Rd new file mode 100644 index 0000000..2f7f957 --- /dev/null +++ b/man/gl_list_files.Rd @@ -0,0 +1,30 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/files.R +\name{gl_list_files} +\alias{gl_list_files} +\title{List of files in a folder} +\usage{ +gl_list_files(project, path = "", ref = get_main(), ...) +} +\arguments{ +\item{project}{name or id of project (not repository!)} + +\item{path}{path of the folder} + +\item{ref}{name of ref (commit branch or tag)} + +\item{...}{passed on to \code{\link[=gitlab]{gitlab()}} API call} +} +\description{ +List of files in a folder +} +\examples{ +\dontrun{ +# Set GitLab connection for examples +set_gitlab_connection( + gitlab_url = "https://gitlab.com", + private_token = Sys.getenv("GITLAB_COM_TOKEN")) + +gl_list_files(project = <>, path = <>) +} +} diff --git a/man/gl_list_groups.Rd b/man/gl_list_groups.Rd new file mode 100644 index 0000000..45306b4 --- /dev/null +++ b/man/gl_list_groups.Rd @@ -0,0 +1,41 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/groups.R +\name{gl_list_groups} +\alias{gl_list_groups} +\alias{gl_list_sub_groups} +\title{List groups information} +\usage{ +gl_list_groups(...) + +gl_list_sub_groups(group, ...) +} +\arguments{ +\item{...}{passed on to \code{\link[=gitlab]{gitlab()}}} + +\item{group}{The ID or URL-encoded path of the group} +} +\value{ +tibble of each group with corresponding information +} +\description{ +List groups information +} +\details{ +When using \code{gl_list_sub_groups()}, if you request this list as: +\itemize{ +\item An unauthenticated user, the response returns only public groups. +\item An authenticated user, the response returns only the groups you’re a member of and does not include public groups. +} +} +\examples{ +\dontrun{ +set_gitlab_connection( + gitlab_url = "https://gitlab.com", + private_token = Sys.getenv("GITLAB_COM_TOKEN") +) +# List all groups +gl_list_groups(max_page = 1) +# List sub-groups of a group +gl_list_sub_groups(group_id = "<>", max_page = 1) +} +} diff --git a/man/gl_new_group.Rd b/man/gl_new_group.Rd new file mode 100644 index 0000000..d6f0363 --- /dev/null +++ b/man/gl_new_group.Rd @@ -0,0 +1,46 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/groups.R +\name{gl_new_group} +\alias{gl_new_group} +\alias{gl_edit_group} +\alias{gl_delete_group} +\title{Manage groups} +\usage{ +gl_new_group(name, path, ...) + +gl_edit_group(group, ...) + +gl_delete_group(group) +} +\arguments{ +\item{name}{of the new group} + +\item{path}{to the new group} + +\item{...}{passed on to \code{\link[=gitlab]{gitlab()}} API call for "Create group"} + +\item{group}{The ID or URL-encoded path of the group.} +} +\value{ +A tibble with the group information. \code{gl_delete_group()} returns an empty tibble. +} +\description{ +Manage groups +} +\details{ +You can use extra parameters as proposed in the GitLab API. +} +\examples{ +\dontrun{ +set_gitlab_connection( + gitlab_url = "https://gitlab.com", + private_token = Sys.getenv("GITLAB_COM_TOKEN") +) +# Create new group +gl_new_group(name = "mygroup") +# Edit existing group +gl_edit_group(group = "<>", default_branch = "main") +# Delete group +gl_delete_group(group = "<>") +} +} diff --git a/man/gl_builds.Rd b/man/gl_pipelines.Rd similarity index 78% rename from man/gl_builds.Rd rename to man/gl_pipelines.Rd index 45de0ab..d4f362d 100644 --- a/man/gl_builds.Rd +++ b/man/gl_pipelines.Rd @@ -3,7 +3,6 @@ \name{gl_pipelines} \alias{gl_pipelines} \alias{gl_jobs} -\alias{gl_builds} \alias{gl_latest_build_artifact} \title{Access the GitLab CI builds} \usage{ @@ -11,8 +10,6 @@ gl_pipelines(project, ...) gl_jobs(project, ...) -gl_builds(project, api_version = 4, ...) - gl_latest_build_artifact( project, job, @@ -26,10 +23,6 @@ gl_latest_build_artifact( \item{...}{passed on to \code{\link[=gitlab]{gitlab()}} API call} -\item{api_version}{Since \code{gl_builds} is no longer working for GitLab API v4, -this must be set to "3" in order to avoid deprecation warning and HTTP error. It currently -default to "4" with deprecation message.´} - \item{job}{Name of the job to get build artifacts from} \item{ref_name}{name of ref (i.e. branch, commit, tag)} @@ -44,14 +37,14 @@ List the jobs with \code{gl_jobs}, the pipelines with \code{gl_pipelines} or download the most recent artifacts archive with \code{gl_latest_build_artifact}. For every branch and job combination only the most recent artifacts archive is available. -\code{gl_builds} is the equivalent for GitLab API v3. } \examples{ \dontrun{ # connect as a fixed user to a GitLab instance set_gitlab_connection( gitlab_url = "https://gitlab.com", - private_token = Sys.getenv("GITLAB_COM_TOKEN")) + private_token = Sys.getenv("GITLAB_COM_TOKEN") +) # Get pipelines and jobs information gl_pipelines(project = "<>") diff --git a/man/gl_repository.Rd b/man/gl_repository.Rd index 3cdf3fd..fddb344 100644 --- a/man/gl_repository.Rd +++ b/man/gl_repository.Rd @@ -2,15 +2,12 @@ % Please edit documentation in R/files.R \name{gl_repository} \alias{gl_repository} -\alias{gl_list_files} \alias{gl_file_exists} \alias{gl_get_file} \title{Access to repository files in GitLab} \usage{ gl_repository(project, req = c("tree"), ref = get_main(), ...) -gl_list_files(project, ref = get_main(), ...) - gl_file_exists(project, file_path, ref, ...) gl_get_file( @@ -34,9 +31,11 @@ in GitLab API, as vector or part of URL)} \item{file_path}{path to file} -\item{to_char}{flag if output should be converted to char; otherwise it is of class raw} +\item{to_char}{flag if output should be converted to char; +otherwise it is of class raw} -\item{api_version}{a switch to force deprecated GitLab API v3 behavior. See details section "API version" of \code{\link[=gl_connection]{gl_connection()}}} +\item{api_version}{a switch to force deprecated GitLab API v3 behavior. +See details section "API version" of \code{\link[=gl_connection]{gl_connection()}}} } \value{ Tibble of files available in the branch with descriptive variables. @@ -44,7 +43,8 @@ Tibble of files available in the branch with descriptive variables. \description{ Access to repository files in GitLab -For \code{gl_file_exists} dots are passed on to \code{\link[=gl_list_files]{gl_list_files()}} and GitLab API call +For \code{gl_file_exists} dots are passed on to \code{\link[=gl_list_files]{gl_list_files()}} +and GitLab API call Get a file from a GitLab repository } @@ -60,11 +60,12 @@ set_gitlab_connection( gl_repository(project = <>) # _All contributors gl_repository(project = <>, "contributors") -# _List files -gl_list_files(project = <>) # _Get content of one file gl_get_file(project = <>, file_path = "README.md") # _Test if file exists -gl_file_exists(project = <>, file_path = "README.md", ref = "main") +gl_file_exists( + project = <>, + file_path = "README.md", + ref = "main") } } diff --git a/man/gl_shiny_login.Rd b/man/gl_shiny_login.Rd index 5add752..c8d9ba3 100644 --- a/man/gl_shiny_login.Rd +++ b/man/gl_shiny_login.Rd @@ -34,7 +34,7 @@ glReactiveLogin( \item{gitlab_url}{root URL of GitLab instance to login to} -\item{project}{if not NULL, a code{\link{gl_project_connection}} is created to this project} +\item{project}{if not NULL, a \code{[gl_project_connection]} is created to this project} \item{api_version}{A character with value either "3" or "4" to specify the API version that should be used} diff --git a/man/onefile.Rd b/man/onefile.Rd index f41a015..aa66525 100644 --- a/man/onefile.Rd +++ b/man/onefile.Rd @@ -27,7 +27,8 @@ If in subdirectory, the parent directory should exist.} \item{commit_message}{Message to use for commit with new/updated file} -\item{branch}{name of branch where to append newly generated commit with new/updated file} +\item{branch}{name of branch where to append newly generated +commit with new/updated file} \item{overwrite}{whether to overwrite files that already exist} diff --git a/man/use_gitlab_ci.Rd b/man/use_gitlab_ci.Rd index dd5d78f..1d49b1f 100644 --- a/man/use_gitlab_ci.Rd +++ b/man/use_gitlab_ci.Rd @@ -36,12 +36,12 @@ Add .gitlab-ci.yml file in your current project from template \details{ Types available are: \itemize{ -\item "check-coverage-pkgdown": Check package along with Code coverage with {covr} -and {pkgdown} site on GitLab Pages -\item "check-coverage-pkgdown-renv": Check package built in a fixed {renv} state -along with Code coverage with {covr} and {pkgdown} site on GitLab Pages. -\item "bookdown": Build {bookdown} HTML and PDF site on GitLab Pages -\item "bookdown-production": Build {bookdown} HTML and PDF site on GitLab Pages. +\item "check-coverage-pkgdown": Check package along with Code coverage with 'covr' +and 'pkgdown' site on GitLab Pages +\item "check-coverage-pkgdown-renv": Check package built in a fixed 'renv' state +along with Code coverage with 'covr' and 'pkgdown' site on GitLab Pages. +\item "bookdown": Build 'bookdown' HTML and PDF site on GitLab Pages +\item "bookdown-production": Build 'bookdown' HTML and PDF site on GitLab Pages. Where default page is for branch named 'production' and "dev/" sub-folder is for 'main' (or 'master') branch. } diff --git a/tests/testthat.R b/tests/testthat.R index 19d4847..b0cb86e 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -11,23 +11,17 @@ if (file.exists("../dev/environment.yml")) { # There must be a token # Testers should own a project on gitlab.com named "testor" -# This part allows to test multiple versions of the API. Currently, only v4 is tested. +# This part allows to test multiple versions of the API. +# Currently, only v4 is tested. if (Sys.getenv("GITLABR_TEST_TOKEN") != "") { # Skip all tests if no token - + if (Sys.getenv("GITLABR_TEST_API_VERSION") == "") { - - # Sys.setenv(GITLABR_TEST_API_VERSION = 3) - # test_check("gitlabr") Sys.setenv(GITLABR_TEST_API_VERSION = 4) test_check("gitlabr") - # Sys.setenv(GITLABR_TEST_API_VERSION = "") - } else { - test_check("gitlabr") - } } else { # dont test on CRAN or without token available -} \ No newline at end of file +} diff --git a/tests/testthat/helper.R b/tests/testthat/helper.R index d211977..9af7556 100644 --- a/tests/testthat/helper.R +++ b/tests/testthat/helper.R @@ -17,7 +17,13 @@ test_password <- Sys.getenv("GITLABR_TEST_PASSWORD") test_commented_commit <- Sys.getenv("COMMENTED_COMMIT", unset = "12c5cd8b7e95d7b6cde856c305d32bb229fc6426") test_project_name <- Sys.getenv("GITLABR_TEST_PROJECT_NAME", unset = "testor.main") test_project_id <- Sys.getenv("GITLABR_TEST_PROJECT_ID", unset = "28485393") -test_group_id <- Sys.getenv("GITLABR_TEST_GROUP_ID", unset = "6567080") +test_group_name <- Sys.getenv("GITLABR_TEST_GROUP_NAME", unset = "thinkr-open") +test_group_id <- Sys.getenv("GITLABR_TEST_GROUP_ID", unset = "15567755") # thinkr-open +test_subgroup_name <- Sys.getenv("GITLABR_TEST_SUBGROUP_NAME", unset = "dontdelete.subgroup.for.gitlabr") +test_subgroup_id <- Sys.getenv("GITLABR_TEST_SUBGROUP_ID", unset = "68261328") +test_subgroup_project_name <- Sys.getenv("GITLABR_TEST_SUBGROUP_PROJECT_NAME", unset = "test.project.for.gitlab.in.group") +test_subgroup_project_id <- Sys.getenv("GITLABR_TEST_SUBGROUP_PROJECT_ID", unset = "46477404") + # Print to test what GitHub Actions see print(test_url) diff --git a/tests/testthat/test_branches.R b/tests/testthat/test_branches.R index e1c8d2d..f1fdc8f 100644 --- a/tests/testthat/test_branches.R +++ b/tests/testthat/test_branches.R @@ -1,17 +1,16 @@ - test_that("branch access works", { # Without project parameter named ## List branches list_branch <- gl_list_branches(test_project) expect_s3_class(list_branch, "data.frame") expect_true(all(list_branch[["name"]] %in% c(get_main(), "for-tests"))) # main and for-tests - + # With project parameter named ## List branches list_branch <- gl_list_branches(project = test_project) expect_s3_class(list_branch, "data.frame") expect_true(all(list_branch[["name"]] %in% c(get_main(), "for-tests"))) # main and for-tests - + ## creating branch new_branch <- gl_create_branch(project = test_project, branch = "testbranch", ref = "for-tests") expect_equal(nrow(new_branch), 1) @@ -21,7 +20,7 @@ test_that("branch access works", { # Sys.sleep(30) # Wait for branch to be really added 10 seconds is not long enough... # list_branch_new <- gl_list_branches(project = test_project) # expect_true("testbranch" %in% list_branch_new[["name"]]) - + ## delete branch deleted_branch <- gl_delete_branch(project = test_project, branch = "testbranch") expect_equal(nrow(deleted_branch), 0) @@ -29,11 +28,4 @@ test_that("branch access works", { # Sys.sleep(30) # Wait for branch to be really removed # list_branch_del <- gl_list_branches(project = test_project) # expect_false("testbranch" %in% list_branch_del[["name"]]) - - ## old API - expect_warning(list_branches(project = test_project), regexp = "deprecated") - }) - - - diff --git a/tests/testthat/test_ci.R b/tests/testthat/test_ci.R index 5eade3f..824e52e 100644 --- a/tests/testthat/test_ci.R +++ b/tests/testthat/test_ci.R @@ -1,50 +1,45 @@ ci_path <- tempfile(fileext = ".yml") test_that("CI yml generation works", { - # check-coverage use_gitlab_ci(path = ci_path, type = "check-coverage-pkgdown") - - # rstudioapi::navigateToFile(ci_path) - # file.copy(from = ci_path, to = "tests/testthat/gitlab-ci.yml", overwrite = TRUE) - expect_equal(yaml::yaml.load_file(ci_path), - yaml::yaml.load_file("gitlab-ci-check-coverage-pkgdown.yml")) + expect_equal( + yaml::yaml.load_file(ci_path), + yaml::yaml.load_file("gitlab-ci-check-coverage-pkgdown.yml") + ) expect_true(file.exists(file.path(dirname(ci_path), ".Rbuildignore"))) - + unlink(ci_path) - + # book -- use_gitlab_ci(path = ci_path, type = "bookdown-production") - # file.copy(from = ci_path, to = "tests/testthat/gitlab-ci-bookdown-production.yml", overwrite = TRUE) - - expect_equal(yaml::yaml.load_file(ci_path), - yaml::yaml.load_file("gitlab-ci-bookdown-production.yml")) - - + + expect_equal( + yaml::yaml.load_file(ci_path), + yaml::yaml.load_file("gitlab-ci-bookdown-production.yml") + ) + unlink(ci_path) - }) test_that("CI builds access works", { - # Without named project param all_jobs <- gl_jobs(test_project) expect_s3_class(all_jobs, "data.frame") - + # With named project param all_jobs <- gl_jobs(project = test_project) expect_s3_class(all_jobs, "data.frame") all_pipelines <- gl_pipelines(project = test_project) expect_s3_class(all_pipelines, "data.frame") - + # issue #13 # Create a job that will save an artifact - artifacts_zip <- gl_latest_build_artifact(project = test_project, job = "testing") + artifacts_zip <- gl_latest_build_artifact( + project = test_project, job = "testing" + ) expect_true(file.exists(artifacts_zip)) expect_true("test.txt" %in% unzip(artifacts_zip, list = TRUE)$Name) - }) - -# gl_ci_job("build", allowed_dependencies = "test") diff --git a/tests/testthat/test_comments.R b/tests/testthat/test_comments.R index 2aa9d91..c455352 100644 --- a/tests/testthat/test_comments.R +++ b/tests/testthat/test_comments.R @@ -1,51 +1,42 @@ - test_that("getting comments works", { # Dont name project parameter issue_1_comments <- gl_get_comments(test_project, object_type = "issue", id = 1, api_version = test_api_version) expect_s3_class(issue_1_comments, "data.frame") expect_gt(nrow(issue_1_comments), 0) - + issue_comments <- gl_get_issue_comments(test_project, id = 1, api_version = test_api_version) expect_s3_class(issue_comments, "data.frame") expect_gt(nrow(issue_comments), 0) - + commented_commit <- gl_get_commit_comments(test_project, id = test_commented_commit) expect_s3_class(commented_commit, "data.frame") - + # Name project parameter issue_1_comments <- gl_get_comments(project = test_project, object_type = "issue", id = 1, api_version = test_api_version) - + expect_s3_class(issue_1_comments, "data.frame") expect_gt(nrow(issue_1_comments), 0) - + commented_commit <- gl_get_comments(project = test_project, object_type = "commit", id = test_commented_commit) - + expect_s3_class(commented_commit, "data.frame") expect_gt(nrow(commented_commit), 0) expect_warning(gl_get_comments(project = test_project, object_type = "commit", id = test_commented_commit, note_id = 123)) - + issue_comments <- gl_get_issue_comments(project = test_project, id = 1, api_version = test_api_version) expect_s3_class(issue_comments, "data.frame") comment_id <- issue_comments$id[1] - + one_issue_comment <- gl_get_issue_comments(project = test_project, id = 1, comment_id = comment_id, api_version = test_api_version) expect_s3_class(one_issue_comment, "data.frame") expect_gt(nrow(one_issue_comment), 0) - + commented_commit <- gl_get_commit_comments(project = test_project, id = test_commented_commit) - + expect_s3_class(commented_commit, "data.frame") expect_warning(gl_get_commit_comments(project = test_project, id = test_commented_commit, note_id = 123)) - - if (test_api_version == 3) { - ## old API - expect_warning(get_comments(project = test_project, "issue", 1, api_version = test_api_version), regexp = "deprecated") - } - }) # test_that("Comment posting works", { # gl_comment_commit() # }) - - diff --git a/tests/testthat/test_files.R b/tests/testthat/test_files.R index 9411ea0..a723280 100644 --- a/tests/testthat/test_files.R +++ b/tests/testthat/test_files.R @@ -1,35 +1,36 @@ - - -test_that("Repo access works", { - # Dont not fail with character id +test_that("gl_repository Repo access works", { + # Dont not fail with character id expect_error(gl_repository("totostatnmap"), "no matching 'id'") out_with_chr <- gl_repository(as.character(test_project)) expect_s3_class(out_with_chr, "data.frame") - + # Without project named # list files repo_files <- gl_repository(test_project) expect_s3_class(repo_files, "data.frame") expect_true("README.md" %in% repo_files[["name"]]) - + # With project parameter named # list files repo_files <- gl_repository(project = test_project) expect_s3_class(repo_files, "data.frame") expect_true("README.md" %in% repo_files[["name"]]) - + # contributors contributors <- gl_repository(project = test_project, "contributors") expect_s3_class(contributors, "data.frame") expect_true(all(c("name", "email") %in% names(contributors))) expect_true(nrow(contributors) > 0) - +}) + +test_that("gl_list_files works", { + repo_files <- gl_repository(project = test_project) # List files list_files <- gl_list_files(project = test_project) expect_s3_class(list_files, "data.frame") # gl_list_files() is gl_repository() with req="tree" (default) expect_equal(repo_files, list_files) - + # Find file readme_content <- gl_get_file(project = test_project, file_path = "README.md") expect_type(readme_content, "character") @@ -37,46 +38,233 @@ test_that("Repo access works", { # File exists expect_true(gl_file_exists(project = test_project, file_path = "README.md", ref = get_main())) expect_false(gl_file_exists(project = test_project, file_path = "zzz", ref = get_main())) - +}) + +test_that("gl_push_file works for direct file", { # Push file list_files <- gl_list_files(project = test_project, ref = "for-tests") tmpfile <- tempfile(fileext = ".csv") write.csv(mtcars, file = tmpfile) out_push <- gl_push_file( - project = test_project, - file_path = "dataset.csv", + project = test_project, + file_path = "dataset.csv", content = paste(readLines(tmpfile), collapse = "\n"), commit_message = "Push file for test", branch = "for-tests", - overwrite = FALSE) - + overwrite = FALSE + ) + expect_s3_class(out_push, "data.frame") expect_equal(nrow(out_push), 1) expect_equal(out_push[["file_path"]], "dataset.csv") + # File exists + expect_true( + gl_file_exists( + project = test_project, file_path = "dataset.csv", + ref = "for-tests" + ) + ) + list_files <- gl_list_files(project = test_project, ref = "for-tests") expect_true("dataset.csv" %in% list_files[["name"]]) - + # _do not overwrite out_push <- gl_push_file( - project = test_project, - file_path = "dataset.csv", + project = test_project, + file_path = "dataset.csv", content = paste(readLines(tmpfile), collapse = "\n"), commit_message = "Push file for test", branch = "for-tests", - overwrite = FALSE) + overwrite = FALSE + ) expect_s3_class(out_push, "data.frame") expect_equal(nrow(out_push), 0) - + # Delete file out_del <- gl_delete_file( - project = test_project, - file_path = "dataset.csv", + project = test_project, + file_path = "dataset.csv", commit_message = "Delete file for test", branch = "for-tests" ) + + # File cleaned + expect_false( + gl_file_exists( + project = test_project, file_path = "dataset.csv", + ref = "for-tests" + ) + ) list_files <- gl_list_files(project = test_project, ref = "for-tests") expect_true(!"dataset.csv" %in% list_files[["name"]]) - - ## old API - expect_warning(repository(project = test_project), regexp = "deprecated") +}) + +test_that("gl_file_exists returns false for a file in a missing folder", { + expect_false( + gl_file_exists( + project = test_project, + file_path = "missing-folder/dataset.csv", + ref = get_main() + ) + ) + expect_false( + gl_file_exists( + project = test_project, + file_path = "missing-folder/subfolder/dataset.csv", + ref = get_main() + ) + ) +}) + +test_that("gl_push_file works for file in a folder", { + file_in_folder <- "test-folder/dataset.csv" + # Push file in a folder + list_files <- gl_list_files(project = test_project, ref = "for-tests") + tmpfile <- tempfile(fileext = ".csv") + write.csv(mtcars, file = tmpfile) + out_push <- gl_push_file( + project = test_project, + file_path = file_in_folder, + content = paste(readLines(tmpfile), collapse = "\n"), + commit_message = "Push file for test in a folder", + branch = "for-tests", + overwrite = FALSE + ) + + expect_s3_class(out_push, "data.frame") + expect_equal(nrow(out_push), 1) + expect_equal(out_push[["file_path"]], file_in_folder) + # File exists + expect_true( + gl_file_exists( + project = test_project, file_path = file_in_folder, + ref = "for-tests" + ) + ) + + list_files <- gl_list_files( + project = test_project, + path = dirname(file_in_folder), + ref = "for-tests" + ) + expect_true(file_in_folder %in% list_files[["path"]]) + + # Do not overwrite a file in a folder + out_push <- gl_push_file( + project = test_project, + file_path = file_in_folder, + content = paste(readLines(tmpfile), collapse = "\n"), + commit_message = "Push file for test in a folder", + branch = "for-tests", + overwrite = FALSE + ) + + expect_s3_class(out_push, "data.frame") + expect_equal(nrow(out_push), 0) + + # Get file in a folder + csv_content <- gl_get_file( + project = test_project, + file_path = file_in_folder, ref = "for-tests" + ) + expect_type(csv_content, "character") + + # Delete file in a folder + out_del <- gl_delete_file( + project = test_project, + file_path = file_in_folder, + commit_message = "Delete file in a folder for test", + branch = "for-tests" + ) + + # File cleaned + expect_false( + gl_file_exists( + project = test_project, file_path = file_in_folder, + ref = "for-tests" + ) + ) + list_files <- gl_list_files( + project = test_project, + path = ".", + ref = "for-tests" + ) + expect_false("test-folder" %in% list_files[["path"]]) + expect_false(file_in_folder %in% list_files[["path"]]) +}) + +test_that("gl_push_file works for file in a subfolder in a folder", { + file_in_subfolder <- "test-folder/test-subfolder/dataset.csv" + + # Push file in a subfolder + list_files <- gl_list_files(project = test_project, ref = "for-tests") + tmpfile <- tempfile(fileext = ".csv") + write.csv(mtcars, file = tmpfile) + out_push <- gl_push_file( + project = test_project, + file_path = file_in_subfolder, + content = paste(readLines(tmpfile), collapse = "\n"), + commit_message = "Push file for test in a subfolder", + branch = "for-tests", + overwrite = FALSE + ) + + expect_s3_class(out_push, "data.frame") + expect_equal(nrow(out_push), 1) + expect_equal(out_push[["file_path"]], file_in_subfolder) + # File exists + expect_true( + gl_file_exists( + project = test_project, file_path = file_in_subfolder, + ref = "for-tests" + ) + ) + + list_files <- gl_list_files( + project = test_project, + path = dirname(file_in_subfolder), ref = "for-tests" + ) + expect_true(file_in_subfolder %in% list_files[["path"]]) + + # Do not overwrite a file in a folder + out_push <- gl_push_file( + project = test_project, + file_path = file_in_subfolder, + content = paste(readLines(tmpfile), collapse = "\n"), + commit_message = "Push file for test in a subfolder", + branch = "for-tests", + overwrite = FALSE + ) + + expect_s3_class(out_push, "data.frame") + expect_equal(nrow(out_push), 0) + + # Get file in a folder + csv_content <- gl_get_file( + project = test_project, + file_path = file_in_subfolder, ref = "for-tests" + ) + expect_type(csv_content, "character") + + # Delete file in a folder + out_del <- gl_delete_file( + project = test_project, + file_path = file_in_subfolder, + commit_message = "Delete file in a subfolder for test", + branch = "for-tests" + ) + + # File cleaned + expect_false( + gl_file_exists( + project = test_project, file_path = file_in_subfolder, + ref = "for-tests" + ) + ) + list_files <- gl_list_files( + project = test_project, + path = ".", ref = "for-tests" + ) + expect_false("test-folder" %in% list_files[["path"]]) + expect_false(file_in_subfolder %in% list_files[["path"]]) }) diff --git a/tests/testthat/test_groups.R b/tests/testthat/test_groups.R new file mode 100644 index 0000000..d69f9a6 --- /dev/null +++ b/tests/testthat/test_groups.R @@ -0,0 +1,41 @@ + +test_that("gl_list_groups works", { + group_list <- gl_list_groups() + expect_gte(nrow(group_list), 0) + expect_true(all(c("id", "name", "path") %in% names(group_list))) + + if (test_group_name == "thinkr-open") { + expect_true("thinkr-open" %in% group_list[["name"]]) + } +}) + +test_that("gl_list_sub_groups works", { + subgroup_list <- gl_list_sub_groups(test_group_id) + + if (nrow(subgroup_list) >= 1) { + # Only work if user is member of the group with a subgroup + # expect_gte(nrow(subgroup_list), 1) + expect_true(all(c("id", "name", "path") %in% names(subgroup_list))) + + if (test_group_name == "thinkr-open") { + expect_true("dontdelete.subgroup.for.gitlabr" %in% subgroup_list[["name"]]) + } + } +}) + +# Dont test to avoid GitLab rejection. +# +# new_group <- gl_new_group(name = "gitlabr-temp-group", path = "gitlabr-temp-group") +# +# test_that("gl_new_group works", { +# expect_equal(nrow(new_group), 1) +# expect_true(all(c("id", "name", "path") %in% names(new_group))) +# }) +# +# test_that("gl_delete_group works", { +# res <- gl_delete_group(new_group$id) +# expect_equal(nrow(res), 1) +# expect_true( c("message") %in% names(res)) +# expect_equal(res$message, "202 Accepted") +# }) + \ No newline at end of file diff --git a/tests/testthat/test_issues.R b/tests/testthat/test_issues.R index 7ccfc3c..fe96169 100644 --- a/tests/testthat/test_issues.R +++ b/tests/testthat/test_issues.R @@ -11,22 +11,16 @@ if (test_api_version == 3) { new_issue_iid <- new_issue_infos$id[1] } test_that("getting issues works", { - expect_s3_class(new_issue_infos, "data.frame") expect_gt(nrow(new_issue_infos), 0L) - + expect_s3_class(all_issues, "data.frame") expect_gt(nrow(all_issues), 0L) # 20 lines max for max_page=1 expect_lte(nrow(all_issues), 20) - + expect_s3_class(opened_issues, "data.frame") expect_equal(nrow(opened_issues), 2) - - ## old API - if (test_api_version == 4) { - expect_warning(get_issues(test_project), regexp = "deprecated") - } }) # Edit issues ---- @@ -35,19 +29,19 @@ test_that("editing issues works", { ## close issue gl_close_issue(test_project, new_issue_iid, api_version = test_api_version) expect_true(gl_list_issues(test_project, new_issue_iid, api_version = test_api_version)$state == "closed") - + ## reopen issue gl_reopen_issue(test_project, new_issue_iid, api_version = test_api_version) expect_true(gl_list_issues(test_project, new_issue_iid, api_version = test_api_version)$state == "opened") - + ## edit its description gl_edit_issue(test_project, new_issue_iid, description = "This is a test", api_version = test_api_version) expect_true(gl_list_issues(test_project, new_issue_iid, api_version = test_api_version)$description == "This is a test") gl_edit_issue(test_project, new_issue_iid, description = "This is not a test", api_version = test_api_version) expect_false(gl_list_issues(test_project, new_issue_iid, api_version = test_api_version)$description == "This is a test") - + test_user <- new_issue_infos$author.name[1] - + ## assign it gl_assign_issue(test_project, new_issue_iid, assignee_id = test_user_id, api_version = test_api_version) expect_true(gl_list_issues(test_project, new_issue_iid, api_version = test_api_version)$assignee.id == test_user_id) diff --git a/tests/testthat/test_login_module.R b/tests/testthat/test_login_module.R index 8a9987d..27de3e6 100644 --- a/tests/testthat/test_login_module.R +++ b/tests/testthat/test_login_module.R @@ -6,14 +6,19 @@ test_login_module <- function(test_url = Sys.getenv("GITLABR_TEST_URL"), test_api_version = Sys.getenv("GITLABR_TEST_API_VERSION", unset = 4)) { require(shiny) - + require(DT) - shinyApp(ui = fluidPage(mainPanel(glLoginInput("login"), - dataTableOutput("project_list"))), - server = function(input, output, session) { - gl_con <- callModule(glReactiveLogin, "login", gitlab_url = test_url, api_version = test_api_version) - output$project_list <- renderDataTable(gl_list_projects(gitlab_con = gl_con())) - }) + + shinyApp( + ui = fluidPage(mainPanel( + glLoginInput("login"), + DT::DTOutput("project_list") + )), + server = function(input, output, session) { + gl_con <- callModule(glReactiveLogin, "login", gitlab_url = test_url, api_version = test_api_version) + output$project_list <- renderDataTable(gl_list_projects(gitlab_con = gl_con())) + } + ) } serv <- test_login_module() @@ -24,16 +29,18 @@ test_that("shinyApp is correct", { test_that("app server", { session <- as.environment(list( sendCustomMessage = function(type, message) { - session$lastCustomMessage = list(type = type, message = message) + session$lastCustomMessage <- list(type = type, message = message) }, sendInputMessage = function(inputId, message) { - session$lastInputMessage = list(id = inputId, message = message) + session$lastInputMessage <- list(id = inputId, message = message) } )) input <- as.environment(list()) output <- as.environment(list()) - - serv <- glReactiveLogin(input, output, session, gitlab_url = test_url, - api_version = test_api_version) + + serv <- glReactiveLogin(input, output, session, + gitlab_url = test_url, + api_version = test_api_version + ) expect_s3_class(serv, "reactive.event") }) diff --git a/tests/testthat/test_projects_repos.R b/tests/testthat/test_projects_repos.R index 59f0977..bd3910b 100644 --- a/tests/testthat/test_projects_repos.R +++ b/tests/testthat/test_projects_repos.R @@ -8,7 +8,7 @@ test_that("gl_list_projects work", { # gl_list_user_projects ---- # Chances are "testor" is one of the latest project with activity because of other unit tests -all_user_projects <- gl_list_user_projects(user_id = test_user_id, max_page = 1, order_by = "last_activity_at") +all_user_projects <- gl_list_user_projects(user_id = test_user_id, max_page = 2, order_by = "last_activity_at") test_that("gl_list_user_projects work", { expect_true(all(test_project_name %in% all_user_projects[["name"]])) @@ -16,12 +16,15 @@ test_that("gl_list_user_projects work", { }) # gl_list_group_projects ---- -all_group_projects <- gl_list_group_projects(group_id = test_group_id, max_page = 1) +all_group_projects <- gl_list_group_projects(group_id = test_subgroup_id, max_page = 1) test_that("gl_list_group_projects work", { - some_projects <- c("publication_guide") - expect_true(all(some_projects %in% all_group_projects[["name"]])) - expect_true(all(c("id", "name", "path") %in% names(all_group_projects))) + if (nrow(all_group_projects) >= 1) { + if (test_subgroup_name == "dontdelete.subgroup.for.gitlabr") { + expect_true(test_subgroup_project_name %in% all_group_projects[["name"]]) + } + expect_true(all(c("id", "name", "path") %in% names(all_group_projects))) + } }) # gl_get_project ---- @@ -44,8 +47,8 @@ test_that("gl_proj_req works", { # => Assume that the last modified is the current project # because of unit tests the_retrieved_id <- gl_get_project_id(test_project_name, - max_page = 3, owned = TRUE, - order_by = "last_activity_at") + max_page = 3, owned = TRUE, + order_by = "last_activity_at") # gitlab(req = "projects", # gitlab_url = file.path(test_url, all_user_projects$namespace.path[1]), # max_page = 1, owned = TRUE) @@ -81,7 +84,7 @@ test_that("Commits work", { expect_s3_class(my_commits, "data.frame") expect_s3_class(my_commit, "data.frame") expect_gt(length(intersect(names(my_commits), names(my_commit))), 0L) - + }) @@ -89,9 +92,9 @@ test_that("Commits work", { # gl_get_diff ---- # The commit with CI is the last one in main branch the_diff <- gl_get_diff(test_project, my_commits$short_id[1]) - -test_that("gl_get_diff work", { +test_that("gl_get_diff work", { + expect_s3_class(the_diff, "data.frame") expect_equal(nrow(the_diff), 1) expect_equal(the_diff$old_path, '.gitlab-ci.yml') diff --git a/vignettes/a-quick-start-guide-to-gitlabr.Rmd b/vignettes/a-quick-start-guide-to-gitlabr.Rmd index 79e3141..aa7e478 100644 --- a/vignettes/a-quick-start-guide-to-gitlabr.Rmd +++ b/vignettes/a-quick-start-guide-to-gitlabr.Rmd @@ -1,5 +1,5 @@ --- -title: "Quick Start Guide to {gitlabr}" +title: "Quick Start Guide to 'gitlabr'" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Quick-Start-Guide-to-gitlabr} @@ -24,7 +24,7 @@ To run the code in this vignette you'll need to have a GitLab account and you ne + Tick the fist checkboxes (the `api` scope) + Add the token in your ".Renviron" as `GITLAB_COM_TOKEN` -R code using {gitlabr} to perform some easy, common GitLab actions can look like this: +R code using 'gitlabr' to perform some easy, common GitLab actions can look like this: ```{r eval = FALSE} library(gitlabr) @@ -37,60 +37,69 @@ Sys.getenv("GITLAB_COM_TOKEN") # connect as a fixed user to a GitLab instance set_gitlab_connection( - gitlab_url = "https://about.gitlab.com/", + gitlab_url = "https://gitlab.com/", private_token = Sys.getenv("GITLAB_COM_TOKEN") ) -gl_list_projects(page = 1) # Returns all projects on GitLab, so we limit to just the first page of results. +gl_list_groups(page = 1) # Returns all groups you have access to +gl_list_projects(page = 1) # Returns all projects on GitLab, so we limit to just the first page of results. -# It's unlikely that you'll want to use {gitlabr} to interact with all the projects on GitLab, so a better approach is to define the project you want to work on. This is done by finding the the project ID on GitLab.com (it is listed right below the project name on the repo front page). +# It's unlikely that you'll want to use 'gitlabr' to interact with all the projects on GitLab, so a better approach is to define the project you want to work on. This is done by finding the the project ID on GitLab.com (it is listed right below the project name on the repo front page). # Here we use the [project "repo.rtask"](https://gitlab.com/statnmap/repo.rtask) my_project <- 20384533 gl_list_files(project = my_project) # create a new issue -new_feature_issue <- gl_create_issue(title = "Implement new feature", - project = my_project) +new_feature_issue <- gl_create_issue( + title = "Implement new feature", + project = my_project +) # statnmap user ID my_id <- 4809823 # assign issue to me -gl_assign_issue(assignee_id = example_user$id, - issue_id = new_feature_issue$iid, - project = my_project) +gl_assign_issue( + assignee_id = example_user$id, + issue_id = new_feature_issue$iid, + project = my_project +) # List opened issues -gl_list_issues(state = "opened", - project = my_project) +gl_list_issues( + state = "opened", + project = my_project +) # close the issue -gl_close_issue(issue_id = new_feature_issue$iid, - project = my_project)$state +gl_close_issue( + issue_id = new_feature_issue$iid, + project = my_project +)$state ``` -# Central features of {gitlabr} +# Central features of 'gitlabr' -- {gitlabr} provides a high and a low level interface to the GitLab API at the same time: - - Common queries are wrapped in special convenience functions that can be used without any knowledge of the GitLab API itself (convenience functions are listed in a dedicated section on {gitlabr}'s pkgdown [site](https://thinkr-open.github.io/gitlabr/reference/index.html)). +- 'gitlabr' provides a high and a low level interface to the GitLab API at the same time: + - Common queries are wrapped in special convenience functions that can be used without any knowledge of the GitLab API itself (convenience functions are listed in a dedicated section on 'gitlabr' pkgdown [site](https://thinkr-open.github.io/gitlabr/reference/index.html)). - Still, the package can be used to access the complete GitLab API -- learn how to use its full power in the section ["API calls"](#api-calls). -- The output of every call to a {gitlabr} function is a `tibble` to integrate seamless into dplyr's data manipulation mindset (often called the "tidyverse") +- The output of every call to a 'gitlabr' function is a `tibble` to integrate seamless into dplyr's data manipulation mindset (often called the "tidyverse") - Pagination is wrapped for the user, but can be controlled via parameters `page` and `per_page` if necessary. -- To allow programming in your favorite style, everything you can do with {gitlabr} you can do using any of a set of general idioms -- get to know them in the section ["Different ways to do it"](#different-ways-to-do-it). -- You can write your own convenience wrappers on top of the {gitlabr} logic following only one principle as described in the section ["Writing custom GitLab request functions"](#writing-custom-gitlab-request-functions). +- To allow programming in your favorite style, everything you can do with 'gitlabr' you can do using any of a set of general idioms -- get to know them in the section ["Different ways to do it"](#different-ways-to-do-it). +- You can write your own convenience wrappers on top of the 'gitlabr' logic following only one principle as described in the section ["Writing custom GitLab request functions"](#writing-custom-gitlab-request-functions). # Set connection and explore the GitLab instance -This is the recommended way of using {gitlabr}. -In order to avoid the repeated specification of `gitlab_con()` in the parameter style, you can also set a global variable managed by {gitlabr} to use a specific connection function for every call: +This is the recommended way of using 'gitlabr'. +In order to avoid the repeated specification of `gitlab_con()` in the parameter style, you can also set a global variable managed by 'gitlabr' to use a specific connection function for every call: ```{r eval = FALSE} set_gitlab_connection(my_gitlab) gl_create_issue(project = my_project, "Implement new feature") ``` -`gl_create_issue()` is an example function here, the principle works for all convenience functions of {gitlabr} starting with `gl_*()` +`gl_create_issue()` is an example function here, the principle works for all convenience functions of 'gitlabr' starting with `gl_*()` Note that the set style is not purely functional, since `set_gitlab_connection()` changes a saved global variable affecting the results of all future `gitlab()` calls. You can reset this variable to the default value using `unset_gitlab_connection()`. @@ -104,14 +113,15 @@ Hence, you can pass a GitLab connection (as returned by `gl_connection()`) with ```{r eval = FALSE} my_gitlab <- gl_connection( gitlab_url = "https://about.gitlab.com/", - private_token = Sys.getenv("GITLAB_COM_TOKEN")) + private_token = Sys.getenv("GITLAB_COM_TOKEN") +) gl_create_issue("Implement new feature", project = my_project, gitlab_con = my_gitlab) ``` -Again, `gl_create_issue()` is an example function here, the principle style works for all convenience functions of {gitlabr} listed in the ["Convenience function list"](#convenience-function-list) below or user-defined functions as described in the section ["Writing custom GitLab request functions"](#writing-custom-gitlab-request-functions). +Again, `gl_create_issue()` is an example function here, the principle style works for all convenience functions of 'gitlabr' listed in the ["Convenience function list"](#convenience-function-list) below or user-defined functions as described in the section ["Writing custom GitLab request functions"](#writing-custom-gitlab-request-functions). -# Using GitLab CI with {gitlabr} +# Using GitLab CI with 'gitlabr' -{gitlabr} can also be used to create a `.gitlab-ci.yml` file to test, build and check an R package using GitLab's CI software. See the `use_gitlab_ci()` and related functions for documentation. +'gitlabr' can also be used to create a `.gitlab-ci.yml` file to test, build and check an R package using GitLab's CI software. See the `use_gitlab_ci()` and related functions for documentation. diff --git a/vignettes/b-projects.Rmd b/vignettes/b-projects.Rmd index 45f4c5b..66dfd30 100644 --- a/vignettes/b-projects.Rmd +++ b/vignettes/b-projects.Rmd @@ -23,7 +23,7 @@ You can use this code to create all your new projects with a specific template. For instance, you can have a first issue to welcome all collaborators, explain them how your repository works and ask them to answer with a comment. This will make sure all collaborators know how to find issues and how to interact with you. -Given you have a [GitLab.com](https://about.gitlab.com/) account, this code can also be run to contribute to {gitlabr} and set a testing environment (See [CONTRIBUTING.md](https://github.com/ThinkR-open/gitlabr/blob/main/CONTRIBUTING.md)). +Given you have a [GitLab.com](https://about.gitlab.com/) account, this code can also be run to contribute to 'gitlabr' and set a testing environment (See [CONTRIBUTING.md](https://github.com/ThinkR-open/gitlabr/blob/main/CONTRIBUTING.md)). # Set up GitLab connection @@ -55,7 +55,7 @@ Project is initialized with a README file. ```{r} project_info <- gl_new_project( - name = test_project_name, + name = test_project_name, default_branch = main_branch, initialize_with_readme = TRUE ) @@ -78,7 +78,7 @@ browseURL(project_info$web_url) content_md <- paste(" # testor.main -Repository to test R package [{gitlabr}](https://github.com/statnmap/gitlabr) +Repository to test R package ['gitlabr'](https://github.com/statnmap/gitlabr) ") # Push file with a commit @@ -88,8 +88,8 @@ gl_push_file( content = content_md, commit_message = "Update README", branch = main_branch, - overwrite = TRUE) - + overwrite = TRUE +) ``` ## Create a new branch named "for-tests" @@ -124,8 +124,8 @@ gl_push_file( content = content_ci, commit_message = "Add CI to the main branch", branch = main_branch, - overwrite = TRUE) - + overwrite = TRUE +) ``` ## Use the commit created above and add a follow-up comment @@ -134,9 +134,10 @@ gl_push_file( commits_in_main <- gl_get_commits(project = project_info$id, ref_name = main_branch) # Add a comment to this commmit gl_comment_commit( - project = project_info$id, - id = commits_in_main$id[1], - text = "Write a comment") + project = project_info$id, + id = commits_in_main$id[1], + text = "Write a comment" +) ``` ## Create a first issue (#1) with a follow-up comment @@ -144,16 +145,17 @@ gl_comment_commit( ```{r} # Create an issue issue_info <- gl_create_issue( - project = project_info$id, - title = "Dont close issue 1", - description = "An example issue to not close for tests") + project = project_info$id, + title = "Dont close issue 1", + description = "An example issue to not close for tests" +) # Create a comment to the issue gl_comment_issue( - project = project_info$id, - id = issue_info$iid, - text = "A comment on issue to not close") - + project = project_info$id, + id = issue_info$iid, + text = "A comment on issue to not close" +) ``` ## Delete project diff --git a/vignettes/c-alternative-connection-to-projects.Rmd b/vignettes/c-alternative-connection-to-projects.Rmd index 1a2380c..a55661e 100644 --- a/vignettes/c-alternative-connection-to-projects.Rmd +++ b/vignettes/c-alternative-connection-to-projects.Rmd @@ -26,18 +26,20 @@ The recommended way to set a connection once and for all to a specific GitLab in ```{r} set_gitlab_connection( gitlab_url = "https://gitlab.com", - private_token = Sys.getenv("GITLAB_COM_TOKEN")) + private_token = Sys.getenv("GITLAB_COM_TOKEN") +) ``` However, if you are looking for connections to multiple GitLab instances in the same session or would like to set different accounts, you can define connections using `gl_connection()`. -The idea of connections in {gitlabr} is to generate functions with the same signature and capability as that of the central API call function `gitlab()`, but with certain parameters set to fixed values (["curried"](https://en.wikipedia.org/wiki/Currying)). +The idea of connections in 'gitlabr' is to generate functions with the same signature and capability as that of the central API call function `gitlab()`, but with certain parameters set to fixed values (["curried"](https://en.wikipedia.org/wiki/Currying)). This way these more specialized functions represent and provide the connection -- for example -- to a specific GitLab instance as a specific user. Such specialized functions can be created with the function `gl_connection()` and then used exactly as you would use `gitlab()`: ```{r eval = FALSE} my_gitlab <- gl_connection("https://gitlab.com", - private_token = Sys.getenv("GITLAB_COM_TOKEN")) + private_token = Sys.getenv("GITLAB_COM_TOKEN") +) my_gitlab("projects") ``` @@ -54,7 +56,7 @@ Similarly, `gl_project_connection()` can be used as a convenience wrapper to dir ## function-in-function style -The recommended way to use {gitlabr} functions is to directly use `gl_*()` function after setting the `set_gitlab_connection()`. +The recommended way to use 'gitlabr' functions is to directly use `gl_*()` function after setting the `set_gitlab_connection()`. For instance with `gl_create_issue()`. ```{r} @@ -74,21 +76,22 @@ Another option is to pass a *function* to the `req` argument that will then be c my_gitlab(gl_create_issue, title = "Implement new feature", project = "") ``` -`gl_create_issue()` is an example function here, the principle style works for all convenience functions of {gitlabr} starting with `gl_*()`. +`gl_create_issue()` is an example function here, the principle style works for all convenience functions of 'gitlabr' starting with `gl_*()`. Some of the convenience functions perform additional transformation or renaming of parameters. Hence, the parameters given to the exemplary `my_gitlab(...)` call after the function should be valid according to the specified function's documentation, and may differ from names used in the GitLab API itself, although this occurs only very rarely. ## Define a custom function with `gitlab()` and a temporary connection -All API possibilities are not available in {gitlabr}. You can look at vignette "Go further: understand and build your functions" if you want to build your own API function. +All API possibilities are not available in 'gitlabr'. You can look at vignette "Go further: understand and build your functions" if you want to build your own API function. Using a `gitlab()`, out of the recommended way for connection, requires using the `gitlab_con` parameter as follows. ```{r} gitlab( c("projects", "", "issues"), gitlab_con = gl_connection("https://gitlab.com", - private_token = Sys.getenv("GITLAB_COM_TOKEN")) + private_token = Sys.getenv("GITLAB_COM_TOKEN") + ) ) ``` diff --git a/vignettes/d-go-further-understand-and-build.Rmd b/vignettes/d-go-further-understand-and-build.Rmd index ec3e8dd..cc0aff3 100644 --- a/vignettes/d-go-further-understand-and-build.Rmd +++ b/vignettes/d-go-further-understand-and-build.Rmd @@ -24,18 +24,19 @@ See the [documentation of the GitLab API](https://docs.gitlab.com/ce/api/) for t # API calls -This section describes how R function calls are translated into HTTP requests to the GitLab API ({gitlabr}'s "low level interface"). For a documentation using {gitlabr} without knowledge of the GitLab API ({gitlabr}'s "high level interface"), see the ["Quick Start Example"](#quick-start-example) above or refer to the individual function documentation in the Reference section of {gitlabr}'s pkgdown [site](https://thinkr-open.github.io/gitlabr/reference/index.html). +This section describes how R function calls are translated into HTTP requests to the GitLab API ('gitlabr' "low level interface"). For a documentation using 'gitlabr' without knowledge of the GitLab API ('gitlabr' "high level interface"), see the ["Quick Start Example"](#quick-start-example) above or refer to the individual function documentation in the Reference section of 'gitlabr' pkgdown [site](https://thinkr-open.github.io/gitlabr/reference/index.html). -Currently ({gitlabr} >= 1.1.6) GitLab API v4 is supported. Support for GitLab API v3 (for GitLab version < 9.0) is still included via flag parameters, but is no longer maintained. For details see the section "API version" of the documentation of `gl_connection()`. +Currently ('gitlabr' >= 1.1.6) GitLab API v4 is supported. Support for GitLab API v3 (for GitLab version < 9.0) is still included via flag parameters, but is no longer maintained. For details see the section "API version" of the documentation of `gl_connection()`. The core function of the low level interface is `gitlab()`, with the help of which arbitrary calls to the GitLab API can be formulated. It takes as required arguments the request location as a character vector, API endpoint URL and HTTP verb and passes additional arguments as query parameters (keeping their names) on to the API request. ```{r eval = FALSE} -gitlab(c("projects", 12, "issues"), - api_root = "https://gitlab.com/api/v4", - private_token = "XXX", # authentication for API - verb = httr::GET, # defaults to GET, but POST, PUT, DELETE can be used likewise - state = "active") # additional parameters (...) for the query +gitlab(c("projects", 12, "issues"), + api_root = "https://gitlab.com/api/v4", + private_token = "XXX", # authentication for API + verb = httr::GET, # defaults to GET, but POST, PUT, DELETE can be used likewise + state = "active" +) # additional parameters (...) for the query ``` translates to @@ -44,26 +45,32 @@ translates to GET https://gitlab.com/api/v4/projects/12/issues?state=active&private_token=XXX ``` -This way, any request documented in the [GitLab API documentation](https://docs.gitlab.com/ce/api) can be issued from {gitlabr}. +This way, any request documented in the [GitLab API documentation](https://docs.gitlab.com/ce/api) can be issued from 'gitlabr'. The high level interface consists of a number of functions that each have additional arguments from which the request location is constructed, while all other arguments are simply passed on to `gitlab()`. For example: ```{r eval = FALSE} -gl_edit_issue(project = "test-project", 12, description = "Really cool new feature", - api_root = "...", private_token = "XXX") +gl_edit_issue( + project = "test-project", 12, description = "Really cool new feature", + api_root = "...", private_token = "XXX" +) ``` does nothing but ```{r eval = FALSE} -gitlab(c("projects", - 4, # numeric id of test-project is found by search - "issues", - 12), - description = "Really cool new feature", - api_root = "...", - private_token = "XXX", - verb = httr::PUT) +gitlab( + c( + "projects", + 4, # numeric id of test-project is found by search + "issues", + 12 + ), + description = "Really cool new feature", + api_root = "...", + private_token = "XXX", + verb = httr::PUT +) ``` and hence translates to @@ -72,32 +79,28 @@ and hence translates to PUT .../projects/4/issues/12?private_token=XXX?description=Really%20cool%20new%20feature ``` -To spare you the repetitive task of specifying the API root and key in every call, you can use `gitlab_connection()` as described below. - -{gitlabr} is implemented following the functional programming paradigm. -Several of its functions return or accept functions as arguments. -This results in huge flexibility in how API requests using {gitlabr} can be formulated in your R code. -Three major styles are described below, after introducing the central mechanism of creating more specific API connection functions. +To spare you the repetitive task of specifying the API root and key in every call, you can use `set_gitlab_connection()` as described in the "quick start guide" vignette. # Writing custom gitlab request functions -It is very easy to write your own convenience wrappers for accessing API endpoints you wish and make sure they fully integrate into {gitlabr} and work conveniently with all connection and call idioms described in this vignette. +It is very easy to write your own convenience wrappers for accessing API endpoints you wish and make sure they fully integrate into 'gitlabr' and work conveniently with all connection and call idioms described in this vignette. The only requirement to your function is that it executes an R function call to `gitlab()` (or another convenience function) to which the `...` argument is passed on. That is, a simple function to block users directly from R is as simple as: ```{r} gl_block_user <- function(uid, ...) { - gitlab(c("users", uid, "block"), ## for API side documentation see: - verb = httr::PUT, ## https://docs.gitlab.com/ce/api/users.html#block-user - ...) ## don't forget the dots to make {gitlabr} features fully available + gitlab(c("users", uid, "block"), ## for API side documentation see: + verb = httr::PUT, ## https://docs.gitlab.com/ce/api/users.html#block-user + ... + ) ## don't forget the dots to make 'gitlabr' features fully available } ``` More hints for more convenience: -- To be consistent with another important {gitlabr} principle, make sure your function returns a `tibble` (which it does if you simply pass up the return value of `gitlab()` or one of the package's own convenience functions). +- To be consistent with another important 'gitlabr' principle, make sure your function returns a `tibble` (which it does if you simply pass up the return value of `gitlab()` or one of the package's own convenience functions). `gitlab()` has some heuristics to format the API response to a `tibble`, if these fail for your specific request, you can pass `auto_format = FALSE` and format the response manually. -- To translate project names to numeric ids automatically, you can use {gitlabr}'s internal functions `proj_req()` translating the request location. -- To translate user-visible project-wide issue ids to global ids used by the GitLab API, you can use {gitlabr}'s internal function `to_issue_id()` when constructing the request. +- To translate project names to numeric ids automatically, you can use 'gitlabr's internal functions `proj_req()` translating the request location. +- To translate user-visible project-wide issue ids to global ids used by the GitLab API, you can use 'gitlabr' internal function `to_issue_id()` when constructing the request. -And last but not least, if you've written a convenience wrapper for yourself, keep in mind that it might be of help to many others and you can contribute it to {gitlabr} on [https://github.com/ThinkR-open/gitlabr](https://github.com/ThinkR-open/gitlabr). +And last but not least, if you've written a convenience wrapper for yourself, keep in mind that it might be of help to many others and you can contribute it to 'gitlabr' on [https://github.com/ThinkR-open/gitlabr](https://github.com/ThinkR-open/gitlabr). diff --git a/vignettes/z-gitlabr-v2.Rmd b/vignettes/z-gitlabr-v2.Rmd index 5252204..8968081 100644 --- a/vignettes/z-gitlabr-v2.Rmd +++ b/vignettes/z-gitlabr-v2.Rmd @@ -1,5 +1,5 @@ --- -title: "Breaking changes in {gitlabr} V2" +title: "Breaking changes in 'gitlabr' V2" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{gitlabr-v2}