diff --git a/.Rbuildignore b/.Rbuildignore index cfb54dff..16783eb9 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -1,16 +1,19 @@ ^_pkgdown.yml$ ^.*\.Rproj$ +^.*\.zenodo.json$ ^.dockerignore$ ^\.github$ ^\.httr-oauth$ ^\.Rproj\.user$ ^\.zenodo\.json$ ^checklist.yml$ +^CITATION\.cff$ ^codecov\.yml$ +^codemeta\.json$ ^data-raw$ +^docker-compose.test.yml$ ^docker$ ^Dockerfile$ -^docker-compose.test.yml$ ^docs$ ^LICENSE.md$ ^man-roxygen$ diff --git a/.github/workflows/check_on_branch.yml b/.github/workflows/check_on_branch.yml index 00ade4b3..07541d98 100644 --- a/.github/workflows/check_on_branch.yml +++ b/.github/workflows/check_on_branch.yml @@ -11,8 +11,9 @@ jobs: check-package: runs-on: ubuntu-latest name: "check package" + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + ORCID_TOKEN: ${{ secrets.ORCID_TOKEN }} + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - uses: inbo/actions/check_pkg@master - with: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - ORCID_TOKEN: ${{ secrets.ORCID_TOKEN }} diff --git a/.github/workflows/check_on_different_r_os.yml b/.github/workflows/check_on_different_r_os.yml index 996e060f..e43bc9cf 100644 --- a/.github/workflows/check_on_different_r_os.yml +++ b/.github/workflows/check_on_different_r_os.yml @@ -97,3 +97,4 @@ jobs: with: name: ${{ runner.os }}-r${{ matrix.config.r }}-results path: check + retention-days: 5 diff --git a/.github/workflows/check_on_main.yml b/.github/workflows/check_on_main.yml index f9b22e9a..91cb7c70 100644 --- a/.github/workflows/check_on_main.yml +++ b/.github/workflows/check_on_main.yml @@ -12,9 +12,9 @@ jobs: check-package: runs-on: ubuntu-latest name: "check package" + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + ORCID_TOKEN: ${{ secrets.ORCID_TOKEN }} + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - uses: inbo/actions/check_pkg@master - with: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - ORCID_TOKEN: ${{ secrets.ORCID_TOKEN }} - token: ${{ secrets.pat }} diff --git a/.github/workflows/remove_old_artifacts.yml b/.github/workflows/remove_old_artifacts.yml deleted file mode 100644 index 715b00d9..00000000 --- a/.github/workflows/remove_old_artifacts.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Remove old artifacts - -on: - schedule: - # Every day at 1am - - cron: '0 1 * * *' - -jobs: - remove-old-artifacts: - runs-on: ubuntu-latest - timeout-minutes: 10 - - steps: - - name: Remove old artifacts - uses: c-hive/gha-remove-artifacts@v1 - with: - age: '1 days' - skip-recent: 4 diff --git a/.zenodo.json b/.zenodo.json index 5e38c3ce..f97273c7 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -1,22 +1,23 @@ { - "title": "A Thorough and Strict Set of Checks for R Packages and Source Code", - "description": "An opinated set of rules for R packages and R source code projects an used at the Research Institute for Nature and Forest (INBO), Brussels, Belgium (www.inbo.be).", - "license": "GPL-3.0", - "upload_type": "other", - "access_right": "open", - "creators": [ - { - "name": "Onkelinx, Thierry", - "affiliation": "Research Institute for Nature and Forest", - "orcid": "0000-0001-8804-4216" - } - ], - "keywords": [ - "R", - "package", - "open science", - "continous integreation", - "unit test", - "code style" - ] + "title": ["checklist: A Thorough and Strict Set of Checks for R Packages and Source Code"], + "version": ["0.1.14"], + "description": ["An opinated set of rules for R packages and R source code projects."], + "creators": [ + { + "name": ["Onkelinx, Thierry"], + "orcid": ["https://orcid.org/0000-0001-8804-4216"] + } + ], + "contributors": [ + { + "name": ["Lommelen, Els"], + "orcid": ["https://orcid.org/0000-0002-3481-5684"] + } + ], + "upload_type": ["software"], + "access_rights": ["open"], + "license": ["GPL-3.0"], + "communities": { + "identifier": ["inbo"] + } } diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 00000000..c1e298d2 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,22 @@ +cff-version: 1.2.0 +message: If you use this software, please cite it as below. +authors: +- family-names: Onkelinx + given-names: Thierry + orcid: https://orcid.org/0000-0001-8804-4216 +contact: +- email: thierry.onkelinx@inbo.be + family-names: Onkelinx + given-names: Thierry +- email: info@inbo.be + name: Research Institute for Nature and Forest +title: 'checklist: A Thorough and Strict Set of Checks for R Packages and Source Code' +version: 0.1.14 +abstract: An opinated set of rules for R packages and R source code projects. +license: GPL-3.0 +type: software +doi: 10.5281/zenodo.4028303 +repository-code: https://github.com/inbo/checklist +identifiers: +- type: url + value: https://inbo.github.io/checklist/ diff --git a/DESCRIPTION b/DESCRIPTION index 7fa1db53..8b102ea6 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,21 +1,14 @@ Type: Package Package: checklist Title: A Thorough and Strict Set of Checks for R Packages and Source Code -Version: 0.1.13 -Authors@R: - c(person(given = "Thierry", - family = "Onkelinx", - role = c("aut", "cre"), - email = "thierry.onkelinx@inbo.be", - comment = c(ORCID = "0000-0001-8804-4216")), - person(given = "Els", - family = "Lommelen", - role = "ctb", - email = "els.lommelen@inbo.be", - comment = c(ORCID = "0000-0002-3481-5684")), - person(given = "Research Institute for Nature and Forest", - role = c("cph", "fnd"), - email = "info@inbo.be")) +Version: 0.1.14 +Authors@R: c( + person("Thierry", "Onkelinx", , "thierry.onkelinx@inbo.be", role = c("aut", "cre"), + comment = c(ORCID = "0000-0001-8804-4216")), + person("Els", "Lommelen", , "els.lommelen@inbo.be", role = "ctb", + comment = c(ORCID = "0000-0002-3481-5684")), + person("Research Institute for Nature and Forest", , , "info@inbo.be", role = c("cph", "fnd")) + ) Description: An opinated set of rules for R packages and R source code projects. License: GPL-3 @@ -30,6 +23,7 @@ Imports: devtools (> 2.4.0), git2r, httr, + jsonlite, lintr, pkgdown, rcmdcheck, @@ -53,4 +47,4 @@ Additional_repositories: https://ropensci.r-universe.dev Encoding: UTF-8 LazyData: true Roxygen: list(markdown = TRUE) -RoxygenNote: 7.1.1 +RoxygenNote: 7.1.2 diff --git a/NAMESPACE b/NAMESPACE index a8a6a06b..467f42d5 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -24,6 +24,8 @@ export(tidy_desc) export(update_citation) export(validate_email) export(write_checklist) +export(write_citation_cff) +export(write_zenodo_json) export(yesno) importFrom(R6,R6Class) importFrom(assertthat,"on_failure<-") @@ -75,6 +77,7 @@ importFrom(grDevices,svg) importFrom(graphics,plot.new) importFrom(graphics,text) importFrom(httr,HEAD) +importFrom(jsonlite,toJSON) importFrom(lintr,lint_dir) importFrom(lintr,lint_package) importFrom(pkgdown,build_site) diff --git a/NEWS.md b/NEWS.md index d9a18f62..c421511d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,17 @@ +# checklist 0.1.14 + +* Improve error message when changes in `CITATION` need to be commit. (#64) +* `create_package()` can use maintainer information stored in the options. + See `usethis::use_description()` on how to set the option. +* Add R universe badges to README. +* Add `write_zenodo_json()` and `write_citation_cff()`. +* Improve the checklist Github Actions. + +## Bugfix + +* `create_package()` replaces package name place holder with actual package name + in `_pkgdown.yml`. + # checklist 0.1.13 * A new function `update_citation()` creates or updates a default citation in diff --git a/R/check_description.R b/R/check_description.R index d83d7fe9..a956ac4b 100644 --- a/R/check_description.R +++ b/R/check_description.R @@ -174,7 +174,7 @@ tidy_desc <- function(x = ".") { unchanged_repo <- function(repo, old_status) { current_status <- status(repo) - identical( + ok <- identical( current_status$staged, old_status$staged ) && @@ -186,6 +186,15 @@ unchanged_repo <- function(repo, old_status) { current_status$untracked, old_status$untracked ) + new_files <- unlist(current_status) + old_files <- unlist(old_status) + changes <- c( + new_files[!new_files %in% old_files], old_files[!old_files %in% new_files] + ) + attr(ok, "files") <- sprintf( + "changed files:\n%s", paste(changes, collapse = "\n") + ) + return(ok) } #' Check the license of a package diff --git a/R/check_documentation.R b/R/check_documentation.R index f26faad0..5479853f 100644 --- a/R/check_documentation.R +++ b/R/check_documentation.R @@ -66,20 +66,24 @@ check_documentation <- function(x = ".") { repo <- repository(x$get_path) status_before <- status(repo) document(x$get_path) + detect_changes <- unchanged_repo(repo, status_before) + si <- session_info(pkgs = "roxygen2") doc_error <- c( doc_error, - "Missing documentation. Run `devtools::document()`"[ - !unchanged_repo(repo, status_before) - ] + sprintf( + "Running `devtools::document()` with roxygen2 %s %s", + si$packages$loadedversion[si$packages$package == "roxygen2"], + attr(detect_changes, "files") + )[!detect_changes] ) if (file_test("-f", file.path(x$get_path, "README.Rmd"))) { - status_before <- status(repo) build_readme(x$get_path, encoding = "UTF-8") + current <- unlist(status(repo, ignored = TRUE)) doc_error <- c( doc_error, "`README.Rmd` need to be rendered. Run `devtools::build_readme()`"[ - !unchanged_repo(repo, status_before) + "README.md" %in% current ] ) } diff --git a/R/check_filename.R b/R/check_filename.R index ca8b5580..7a5bb757 100644 --- a/R/check_filename.R +++ b/R/check_filename.R @@ -104,7 +104,7 @@ Failing folder: `%s`", paste( c( "\\.[a-zA-Z]+ignore", "\\.Rprofile", "\\.[a-zA-Z]+\\.(json|yml)", - "CITATION", "DESCRIPTION", "NAMESPACE", + "CITATION", "DESCRIPTION", "NAMESPACE", "CITATION.cff", "README\\.R?md", "NEWS\\.md", # nolint "CODE_OF_CONDUCT.md", "CONTRIBUTING.md", "LICENSE.md", "SUPPORT.md", "SECURITY.md", "FUNDING.yml", diff --git a/R/create_package.R b/R/create_package.R index fb16c0c3..76f90609 100644 --- a/R/create_package.R +++ b/R/create_package.R @@ -13,6 +13,8 @@ #' @param maintainer The output of [utils::person()] or [`orcid2person()`]. #' If you use [utils::person()], then you must provide `given`, `family`, #' `role`, `email` and `comment` with valid `ORCID`. +#' When missing, the functions looks for `usethis.description` in the options. +#' See [usethis::use_description()] for more information. #' @export #' @importFrom assertthat assert_that is.string #' @importFrom git2r add init @@ -48,6 +50,17 @@ create_package <- function( msg = "Please install the `roxygen2` package. `install.packages(\"roxygen2\")`" ) + if (missing(maintainer)) { + utd <- getOption("usethis.description") + assert_that( + has_name(utd, "Authors@R"), + msg = paste( + "maintainer not provided and no usethis::use_description defaults", + "available." + ) + ) + maintainer <- head(eval(parse(text = utd$"Authors@R")), 1) + } assert_that(inherits(maintainer, "person")) assert_that(dir.exists(path), msg = sprintf("`%s` is not a directory", path)) assert_that(is.string(package)) @@ -241,25 +254,15 @@ allowed: add( repo = repo, file.path(".github", "workflows", "release.yml"), force = TRUE ) - file.copy( - system.file( - file.path("package_template", "remove_old_artifacts.yml"), - package = "checklist" - ), - file.path(path, ".github", "workflows", "remove_old_artifacts.yml"), - overwrite = TRUE - ) - add( - repo = repo, file.path(".github", "workflows", "release.yml"), force = TRUE - ) # prepare pkgdown - file.copy( + pkgd <- readLines( system.file( file.path("package_template", "_pkgdown.yml"), package = "checklist" - ), - file.path(path, "_pkgdown.yml") + ) ) + pkgd <- gsub("\\{\\{\\{ Package \\}\\}\\}", package, pkgd) + writeLines(pkgd, file.path(path, "_pkgdown.yml")) add(repo = repo, "_pkgdown.yml") dir.create(file.path(path, "pkgdown"), showWarnings = FALSE) diff --git a/R/setup_package.R b/R/setup_package.R index 93761d59..40d03b71 100644 --- a/R/setup_package.R +++ b/R/setup_package.R @@ -194,25 +194,15 @@ allowed: add( repo = repo, file.path(".github", "workflows", "release.yml"), force = TRUE ) - file.copy( - system.file( - file.path("package_template", "remove_old_artifacts.yml"), - package = "checklist" - ), - file.path(path, ".github", "workflows", "remove_old_artifacts.yml"), - overwrite = TRUE - ) - add( - repo = repo, file.path(".github", "workflows", "release.yml"), force = TRUE - ) # Add pkgdown website - file.copy( + pkgd <- readLines( system.file( file.path("package_template", "_pkgdown.yml"), package = "checklist" - ), - file.path(path, "_pkgdown.yml") + ) ) + pkgd <- gsub("\\{\\{\\{ Package \\}\\}\\}", package, pkgd) + writeLines(pkgd, file.path(path, "_pkgdown.yml")) add(repo = repo, "_pkgdown.yml", force = TRUE) dir.create(file.path(path, "pkgdown"), showWarnings = FALSE) file.copy( diff --git a/R/update_citation.R b/R/update_citation.R index d2e412a9..74025d81 100644 --- a/R/update_citation.R +++ b/R/update_citation.R @@ -28,7 +28,7 @@ update_citation <- function(x = ".", roles) { } assert_that( x$package, - msg = "`check_description()` is only relevant for packages. + msg = "`update_citation()` is only relevant for packages. `checklist.yml` indicates this is not a package." ) @@ -101,19 +101,19 @@ update_citation <- function(x = ".", roles) { this_desc$get_field("Title"), this_desc$get_field("Version") ), author = sprintf("c(%s)", authors_bibtex), - year = gsub("-.*", "", Sys.Date()), + year = format(Sys.Date(), "%Y"), url = paste0("\"", gsub(",.*", "", this_desc$get_field("URL")), "\""), abstract = paste0("\"", this_desc$get_field("Description"), "\""), textVersion = sprintf( "\"%s (%s) %s: %s. Version %s. %s\"", - paste(authors_plain, collapse = "; "), gsub("-.*", "", Sys.Date()), + paste(authors_plain, collapse = "; "), format(Sys.Date(), "%Y"), this_desc$get_field("Package"), this_desc$get_field("Title"), this_desc$get_field("Version"), this_desc$get_field("URL") ) ) doi <- this_desc$get_field("URL") if (any(grepl("https:\\/\\/doi.org/", doi))) { - doi <- gsub(".*?https:\\/\\/doi.org/(.*)", "\\1", doi) + doi <- gsub(".*?https:\\/\\/doi.org/(.*)(, .*)?", "\\1", doi) package_citation <- c( package_citation, doi = paste0("\"", gsub("(.*),.*", "\\1", doi), "\"") ) @@ -131,10 +131,17 @@ update_citation <- function(x = ".", roles) { repo <- repository(x$get_path) current <- unlist(status(repo, ignored = TRUE)) x$add_error( - "CITATION file needs an update."[ - file.path("inst", "CITATION") %in% current - ], + paste( + "CITATION file needs an update.", + "Run `update_citation()` or `check_package()` locally.", + "Then commit\n`inst/CITATION`." + )[ + file.path("inst", "CITATION") %in% current + ], "CITATION" ) + + write_zenodo_json(x = x) + write_citation_cff(x = x, roles = roles) return(x) } diff --git a/R/write_citation_cff.R b/R/write_citation_cff.R new file mode 100644 index 00000000..058c9a1d --- /dev/null +++ b/R/write_citation_cff.R @@ -0,0 +1,133 @@ +#' Write a CITATION.cff file +#' +#' This file format contains the citation information. +#' It is supported by GitHub, Zenodo and Zotero. +#' @inheritParams read_checklist +#' @inheritParams update_citation +#' @export +#' @importFrom assertthat assert_that +#' @family package +write_citation_cff <- function(x = ".", roles) { + x <- read_checklist(x = x) + assert_that( + x$package, + msg = "`write_citation_cff()` currently only handles packages. + `checklist.yml` indicates this is not a package." + ) + if (!missing(roles)) { + x$set_roles(roles = roles) + } + + this_desc <- description$new( + file = file.path(x$get_path, "DESCRIPTION") + ) + + authors <- eval(parse(text = this_desc$get_field("Authors@R"))) + maintainer <- authors[vapply( + authors, FUN.VALUE = logical(1), FUN = function(z) { + any(z$role %in% "cre") + } + )] + contact <- list(list( + email = maintainer$email, `family-names` = maintainer$family, + `given-names` = maintainer$given + )) + copyright <- authors[vapply( + authors, FUN.VALUE = logical(1), FUN = function(z) { + any(z$role %in% "cph") + } + )] + if (length(copyright) == 1) { + if (is.null(copyright$family)) { + contact <- c(contact, + list(list(email = copyright$email, name = copyright$given)) + ) + } else { + contact <- c(contact, + list(list( + email = copyright$email, `family-names` = copyright$family, + `given-names` = copyright$given + )) + ) + } + } + relevant <- vapply( + authors, FUN.VALUE = logical(1), FUN = function(z) { + any(z$role %in% x$get_roles) + } + ) + authors <- authors[relevant] + authors <- vapply( + authors, FUN.VALUE = vector("list", 1), + FUN = function(i) { + z <- list(list(`family-names` = i$family, `given-names` = i$given)) + if (!is.null(i$comment["ORCID"])) { + z[[1]]$orcid <- sprintf( + "https://orcid.org/%s", unname(i$comment["ORCID"]) + ) + } + return(z) + } + ) + description <- gsub(" +", " ", gsub("\n", " ", this_desc$get("Description"))) + + license <- this_desc$get_field("License") + license <- ifelse(license == "GPL-3", "GPL-3.0", license) + citation <- list( + `cff-version` = "1.2.0", + message = "If you use this software, please cite it as below.", + authors = authors, contact = contact, + title = sprintf("%s: %s", this_desc$get("Package"), this_desc$get("Title")), + version = as.character(this_desc$get_version()), abstract = description, + license = license, type = "software" + ) + + url <- this_desc$get_field("URL") + url <- strsplit(url, ", ")[[1]] + if (any(grepl("https:\\/\\/doi.org/", url))) { + doi <- url[grepl("https:\\/\\/doi.org/", url)] + url <- url[!grepl("https:\\/\\/doi.org/", url)] + citation$doi <- gsub("https:\\/\\/doi.org/(.*)", "\\1", doi) + } + if (any(grepl("https:\\/\\/github.com/", url))) { + citation[["repository-code"]] <- url[grepl("https:\\/\\/github.com/", url)] + url <- url[!grepl("https:\\/\\/github.com/", url)] + } + citation$identifiers <- vapply( + url, FUN.VALUE = vector("list", 1), USE.NAMES = FALSE, FUN = function(i) { + list(list(type = "url", value = i)) + } + ) + + write_yaml(x = citation, file = "CITATION.cff", fileEncoding = "UTF-8") + + if (!file_test("-f", file.path(x$get_path, ".Rbuildignore"))) { + file.copy( + system.file( + file.path("package_template", "rbuildignore"), package = "checklist" + ), + file.path(x$get_path, ".Rbuildignore") + ) + } else { + current <- readLines(file.path(x$get_path, ".Rbuildignore")) + new <- "^CITATION\\.cff$" + writeLines( + sort(unique(c(new, current))), file.path(x$get_path, ".Rbuildignore") + ) + } + + repo <- repository(x$get_path) + current <- unlist(status(repo, ignored = TRUE)) + x$add_error( + paste( + "CITATION.cff file needs an update.", + "Run `update_citation()` or `check_package()` locally.", + "Then\ncommit `CITATION.cff`." + )[ + "CITATION.cff" %in% current + ], + "CITATION" + ) + + return(invisible(NULL)) +} diff --git a/R/write_zenodo_json.R b/R/write_zenodo_json.R new file mode 100644 index 00000000..40af603c --- /dev/null +++ b/R/write_zenodo_json.R @@ -0,0 +1,116 @@ +#' Write a .zenodo.json file +#' +#' Zenodo uses the .zenodo.json file to define the citation information. +#' See +#' https://developers.zenodo.org/#add-metadata-to-your-github-repository-release +#' for more information. +#' @inheritParams read_checklist +#' @export +#' @importFrom assertthat assert_that +#' @importFrom desc description +#' @importFrom jsonlite toJSON +#' @family package +write_zenodo_json <- function(x = ".") { + x <- read_checklist(x = x) + assert_that( + x$package, + msg = "`write_zenodo_json()` currently only handles packages. + `checklist.yml` indicates this is not a package." + ) + this_desc <- description$new( + file = file.path(x$get_path, "DESCRIPTION") + ) + + authors <- eval(parse(text = this_desc$get_field("Authors@R"))) + authors_plain <- format( + authors, include = c("family", "given"), + braces = list(family = c("", ",")) + ) + authors_orcid <- format( + authors, include = "comment", braces = list(comment = c("", "")) + ) + authors_orcid[!grepl("orcid.org", authors_orcid)] <- "" + authors_orcid <- gsub( + ".*orcid.org/(([0-9]{4}-){3}[0-9]{4}).*", "https://orcid.org/\\1", # nolint + authors_orcid + ) + + relevant <- vapply( + authors, FUN.VALUE = logical(1), + FUN = function(z) { + any(z$role %in% c("aut", "cre")) + } + ) + creators <- vapply( + which(relevant), FUN.VALUE = vector("list", 1), + FUN = function(i) { + if (authors_orcid[[i]] == "") { + list(list(name = authors_plain[[i]])) + } else { + list(list(name = authors_plain[[i]], orcid = authors_orcid[[i]])) + } + } + ) + relevant <- vapply( + authors, FUN.VALUE = logical(1), + FUN = function(z) { + any(z$role %in% "ctb") + } + ) + contributors <- vapply( + which(relevant), FUN.VALUE = vector("list", 1), + FUN = function(i) { + if (authors_orcid[[i]] == "") { + list(list(name = authors_plain[[i]])) + } else { + list(list(name = authors_plain[[i]], orcid = authors_orcid[[i]])) + } + } + ) + + description <- gsub(" +", " ", gsub("\n", " ", this_desc$get("Description"))) + license <- this_desc$get("License") + license <- ifelse(license == "GPL-3", "GPL-3.0", license) + zenodo <- list( + title = sprintf("%s: %s", this_desc$get("Package"), this_desc$get("Title")), + version = as.character(this_desc$get_version()), description = description, + creators = creators, contributors = contributors, upload_type = "software", + access_rights = "open", license = license, + communities = list(identifier = "inbo") + ) + if (!is.na(this_desc$get("Language"))) { + zenodo$language <- gsub("(-.*)", "", this_desc$get("Language")) + } + + if (!file_test("-f", file.path(x$get_path, ".Rbuildignore"))) { + file.copy( + system.file( + file.path("package_template", "rbuildignore"), package = "checklist" + ), + file.path(x$get_path, ".Rbuildignore") + ) + } else { + current <- readLines(file.path(x$get_path, ".Rbuildignore")) + new <- "^\\.zenodo\\.json$" + writeLines( + sort(unique(c(new, current))), file.path(x$get_path, ".Rbuildignore") + ) + } + + writeLines(toJSON(zenodo, pretty = TRUE, auto_unbox = FALSE), ".zenodo.json") + + repo <- repository(x$get_path) + current <- unlist(status(repo, ignored = TRUE)) + x$add_error( + paste( + ".zenodo.json file needs an update.", + "Run `update_citation()` or `check_package()` locally.", + "Then\ncommit `.zenodo.json`." + )[ + ".zenodo.json" %in% current + ], + "CITATION" + ) + + return(invisible(NULL)) +} diff --git a/README.Rmd b/README.Rmd index 4904c4c4..b41cd11d 100644 --- a/README.Rmd +++ b/README.Rmd @@ -5,12 +5,15 @@ output: github_document -[![Project Status: WIP – Initial development is in progress, but there has not yet been a stable, usable release suitable for the public.](https://www.repostatus.org/badges/latest/wip.svg)](https://www.repostatus.org/#wip) -[![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental-1) +[![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active) +[![Lifecycle:maturing](https://img.shields.io/badge/lifecycle-maturing-blue.svg)](https://lifecycle.r-lib.org/articles/stages.html#maturing-1) ![GitHub](https://img.shields.io/github/license/inbo/checklist) +[![License](https://img.shields.io/badge/license-GPL--3-blue.svg?style=flat)](https://www.gnu.org/licenses/gpl-3.0.html) +[![Release](https://img.shields.io/github/release/inbo/checklist.svg)](https://github.com/inbo/checklist/releases) [![R build status](https://github.com/inbo/checklist/workflows/check%20package%20on%20main/badge.svg)](https://github.com/inbo/checklist/actions) -![r-universe](https://inbo.r-universe.dev/badges/checklist) -[![Codecov test coverage](https://codecov.io/gh/inbo/checklist/branch/main/graph/badge.svg)](https://codecov.io/gh/inbo/checklist?branch=main) +![r-universe name](https://inbo.r-universe.dev/badges/:name?color=c04384) +![r-universe package](https://inbo.r-universe.dev/badges/checklist) +[![Codecov test coverage](https://codecov.io/gh/inbo/checklist/branch/main/graph/badge.svg)](https://app.codecov.io/gh/inbo/checklist?branch=main) ![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/inbo/checklist.svg) ![GitHub repo size](https://img.shields.io/github/repo-size/inbo/checklist.svg) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.4028303.svg)](https://doi.org/10.5281/zenodo.4028303) diff --git a/README.md b/README.md index 84b474a7..7d099441 100644 --- a/README.md +++ b/README.md @@ -2,17 +2,20 @@ -[![Project Status: WIP – Initial development is in progress, but there -has not yet been a stable, usable release suitable for the -public.](https://www.repostatus.org/badges/latest/wip.svg)](https://www.repostatus.org/#wip) -[![Lifecycle: -experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental-1) -![GitHub](https://img.shields.io/github/license/inbo/checklist) [![R -build +[![Project Status: Active – The project has reached a stable, usable +state and is being actively +developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active) +[![Lifecycle:maturing](https://img.shields.io/badge/lifecycle-maturing-blue.svg)](https://lifecycle.r-lib.org/articles/stages.html#maturing-1) +![GitHub](https://img.shields.io/github/license/inbo/checklist) +[![License](https://img.shields.io/badge/license-GPL--3-blue.svg?style=flat)](https://www.gnu.org/licenses/gpl-3.0.html) +[![Release](https://img.shields.io/github/release/inbo/checklist.svg)](https://github.com/inbo/checklist/releases) +[![R build status](https://github.com/inbo/checklist/workflows/check%20package%20on%20main/badge.svg)](https://github.com/inbo/checklist/actions) -![r-universe](https://inbo.r-universe.dev/badges/checklist) [![Codecov -test -coverage](https://codecov.io/gh/inbo/checklist/branch/main/graph/badge.svg)](https://codecov.io/gh/inbo/checklist?branch=main) +![r-universe +name](https://inbo.r-universe.dev/badges/:name?color=c04384) +![r-universe package](https://inbo.r-universe.dev/badges/checklist) +[![Codecov test +coverage](https://codecov.io/gh/inbo/checklist/branch/main/graph/badge.svg)](https://app.codecov.io/gh/inbo/checklist?branch=main) ![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/inbo/checklist.svg) ![GitHub repo diff --git a/codecov.yml b/codecov.yml index 1e726b69..6c208bba 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,12 +1,17 @@ comment: true coverage: - precision: 2 + precision: 1 round: down range: "70...100" status: + patch: + default: + target: auto + threshold: 10% + informational: true project: default: target: auto - threshold: 0% + threshold: 1% informational: false diff --git a/docker/entrypoint_package.sh b/docker/entrypoint_package.sh index 6cb066d6..9372df07 100755 --- a/docker/entrypoint_package.sh +++ b/docker/entrypoint_package.sh @@ -1,7 +1,10 @@ #!/bin/sh -l +export CI=TRUE + + echo '\nGetting the code...\n' -git clone https://$2@github.com/$1 check +git clone https://$GITHUB_PAT@github.com/$GITHUB_REPOSITORY check cd check git config user.name "Checklist bot" @@ -9,14 +12,11 @@ git config user.email "checklist@inbo.be" git config advice.detachedHead false git checkout $GITHUB_SHA -cd $3 -export CODECOV_TOKEN=$4 -export ORCID_TOKEN=$5 -export CI=TRUE +cd $INPUT_PATH -if [ ! -z "$6" ]; then +if [ ! -z "$INPUT_APTGET" ]; then apt-get update - apt-get install -y --no-install-recommends $6 + apt-get install -y --no-install-recommends $INPUT_APTGET fi echo '\nTrying to install the package...\n' diff --git a/docker/entrypoint_source.sh b/docker/entrypoint_source.sh index 6398becb..d631fb36 100755 --- a/docker/entrypoint_source.sh +++ b/docker/entrypoint_source.sh @@ -1,11 +1,11 @@ #!/bin/sh -l echo '\nGetting the code...\n' -git clone https://$2@github.com/$1 check +git clone https://$INPUT_TOKEN@github.com/$INPUT_REPOSITORY check cd check git config advice.detachedHead false git checkout $GITHUB_SHA -cd $3 +cd $INPUT_PATH Rscript --no-save --no-restore -e 'checklist::check_source()' if [ $? -ne 0 ]; then diff --git a/inst/CITATION b/inst/CITATION index bf8a1f25..ac090eb2 100644 --- a/inst/CITATION +++ b/inst/CITATION @@ -2,12 +2,12 @@ citHeader("To cite `checklist` in publications please use:") # begin checklist entry citEntry( entry = "Manual", - title = "checklist: A Thorough and Strict Set of Checks for R Packages and Source Code. Version 0.1.13", + title = "checklist: A Thorough and Strict Set of Checks for R Packages and Source Code. Version 0.1.14", author = c(person(given = "Thierry", family = "Onkelinx")), year = 2021, url = "https://inbo.github.io/checklist/", abstract = "An opinated set of rules for R packages and R source code projects.", - textVersion = "Onkelinx, Thierry (2021) checklist: A Thorough and Strict Set of Checks for R Packages and Source Code. Version 0.1.13. https://inbo.github.io/checklist/, https://github.com/inbo/checklist, https://doi.org/10.5281/zenodo.4028303", + textVersion = "Onkelinx, Thierry (2021) checklist: A Thorough and Strict Set of Checks for R Packages and Source Code. Version 0.1.14. https://inbo.github.io/checklist/, https://github.com/inbo/checklist, https://doi.org/10.5281/zenodo.4028303", doi = "10.5281/zenodo.4028303", ) # end checklist entry diff --git a/inst/package_template/README.Rmd b/inst/package_template/README.Rmd index 7278ffee..fd652b7a 100644 --- a/inst/package_template/README.Rmd +++ b/inst/package_template/README.Rmd @@ -18,9 +18,13 @@ knitr::opts_chunk$set( [![Project Status: Concept – Minimal or no implementation has been done yet, or the repository is only intended to be a limited example, demo, or proof-of-concept.](https://www.repostatus.org/badges/latest/concept.svg)](https://www.repostatus.org/#concept) [![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental) +[![License](https://img.shields.io/badge/license-GPL--3-blue.svg?style=flat)](https://www.gnu.org/licenses/gpl-3.0.html) +[![Release](https://img.shields.io/github/release/inbo/{{{ Package }}}.svg)](https://github.com/inbo/{{{ Package }}}/releases) ![GitHub](https://img.shields.io/github/license/inbo/{{{ Package }}}) [![R build status](https://github.com/inbo/{{{ Package }}}/workflows/check%20package%20on%20main/badge.svg)](https://github.com/inbo/{{{ Package }}}/actions) -[![Codecov test coverage](https://codecov.io/gh/inbo/{{{ Package }}}/branch/main/graph/badge.svg)](https://codecov.io/gh/inbo/{{{ Package }}}?branch=main) +![r-universe name](https://inbo.r-universe.dev/badges/:name?color=c04384) +![r-universe package](https://inbo.r-universe.dev/badges/{{{ Package }}}) +[![Codecov test coverage](https://codecov.io/gh/inbo/{{{ Package }}}/branch/main/graph/badge.svg)](https://app.codecov.io/gh/inbo/{{{ Package }}}?branch=main) ![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/inbo/{{{ Package }}}.svg) ![GitHub repo size](https://img.shields.io/github/repo-size/inbo/{{{ Package }}}.svg) diff --git a/inst/package_template/check_on_branch.yml b/inst/package_template/check_on_branch.yml index 7e61c527..fca01301 100644 --- a/inst/package_template/check_on_branch.yml +++ b/inst/package_template/check_on_branch.yml @@ -16,3 +16,4 @@ jobs: with: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} ORCID_TOKEN: ${{ secrets.ORCID_TOKEN }} + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/inst/package_template/check_on_different_r_os.yml b/inst/package_template/check_on_different_r_os.yml index b7bd6c24..c332df9c 100644 --- a/inst/package_template/check_on_different_r_os.yml +++ b/inst/package_template/check_on_different_r_os.yml @@ -95,3 +95,4 @@ jobs: with: name: ${{ runner.os }}-r${{ matrix.config.r }}-results path: check + retention-days: 5 diff --git a/inst/package_template/check_on_main.yml b/inst/package_template/check_on_main.yml index f9b22e9a..4372eb9f 100644 --- a/inst/package_template/check_on_main.yml +++ b/inst/package_template/check_on_main.yml @@ -17,4 +17,4 @@ jobs: with: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} ORCID_TOKEN: ${{ secrets.ORCID_TOKEN }} - token: ${{ secrets.pat }} + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/inst/package_template/codecov.yml b/inst/package_template/codecov.yml index 1e726b69..6c208bba 100644 --- a/inst/package_template/codecov.yml +++ b/inst/package_template/codecov.yml @@ -1,12 +1,17 @@ comment: true coverage: - precision: 2 + precision: 1 round: down range: "70...100" status: + patch: + default: + target: auto + threshold: 10% + informational: true project: default: target: auto - threshold: 0% + threshold: 1% informational: false diff --git a/inst/package_template/rbuildignore b/inst/package_template/rbuildignore index 14d18f38..121c6547 100644 --- a/inst/package_template/rbuildignore +++ b/inst/package_template/rbuildignore @@ -5,6 +5,7 @@ ^\.Rproj\.user$ ^\.zenodo\.json$ ^checklist.yml$ +^CITATION\.cff$ ^codecov\.yml$ ^data-raw$ ^docs$ diff --git a/inst/package_template/remove_old_artifacts.yml b/inst/package_template/remove_old_artifacts.yml deleted file mode 100644 index 715b00d9..00000000 --- a/inst/package_template/remove_old_artifacts.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Remove old artifacts - -on: - schedule: - # Every day at 1am - - cron: '0 1 * * *' - -jobs: - remove-old-artifacts: - runs-on: ubuntu-latest - timeout-minutes: 10 - - steps: - - name: Remove old artifacts - uses: c-hive/gha-remove-artifacts@v1 - with: - age: '1 days' - skip-recent: 4 diff --git a/inst/source_template/check_source.yml b/inst/source_template/check_source.yml index 9bba34dc..03f2c763 100644 --- a/inst/source_template/check_source.yml +++ b/inst/source_template/check_source.yml @@ -12,4 +12,4 @@ jobs: steps: - uses: inbo/actions/check_src@master with: - token: ${{ secrets.pat }} + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/man/check_codemeta.Rd b/man/check_codemeta.Rd index 5fb9e140..5087b68a 100644 --- a/man/check_codemeta.Rd +++ b/man/check_codemeta.Rd @@ -25,6 +25,8 @@ Other package: \code{\link{check_package}()}, \code{\link{set_tag}()}, \code{\link{tidy_desc}()}, -\code{\link{update_citation}()} +\code{\link{update_citation}()}, +\code{\link{write_citation_cff}()}, +\code{\link{write_zenodo_json}()} } \concept{package} diff --git a/man/check_cran.Rd b/man/check_cran.Rd index beaad5b7..92dd3a12 100644 --- a/man/check_cran.Rd +++ b/man/check_cran.Rd @@ -30,6 +30,8 @@ Other package: \code{\link{check_package}()}, \code{\link{set_tag}()}, \code{\link{tidy_desc}()}, -\code{\link{update_citation}()} +\code{\link{update_citation}()}, +\code{\link{write_citation_cff}()}, +\code{\link{write_zenodo_json}()} } \concept{package} diff --git a/man/check_description.Rd b/man/check_description.Rd index a5af33ce..29c8acf6 100644 --- a/man/check_description.Rd +++ b/man/check_description.Rd @@ -45,6 +45,8 @@ Other package: \code{\link{check_package}()}, \code{\link{set_tag}()}, \code{\link{tidy_desc}()}, -\code{\link{update_citation}()} +\code{\link{update_citation}()}, +\code{\link{write_citation_cff}()}, +\code{\link{write_zenodo_json}()} } \concept{package} diff --git a/man/check_documentation.Rd b/man/check_documentation.Rd index bbe7e172..5a900bd3 100644 --- a/man/check_documentation.Rd +++ b/man/check_documentation.Rd @@ -60,6 +60,8 @@ Other package: \code{\link{check_package}()}, \code{\link{set_tag}()}, \code{\link{tidy_desc}()}, -\code{\link{update_citation}()} +\code{\link{update_citation}()}, +\code{\link{write_citation_cff}()}, +\code{\link{write_zenodo_json}()} } \concept{package} diff --git a/man/check_license.Rd b/man/check_license.Rd index bfeea530..f7c43c76 100644 --- a/man/check_license.Rd +++ b/man/check_license.Rd @@ -39,6 +39,8 @@ Other package: \code{\link{check_package}()}, \code{\link{set_tag}()}, \code{\link{tidy_desc}()}, -\code{\link{update_citation}()} +\code{\link{update_citation}()}, +\code{\link{write_citation_cff}()}, +\code{\link{write_zenodo_json}()} } \concept{package} diff --git a/man/check_package.Rd b/man/check_package.Rd index e9bd0892..134166ed 100644 --- a/man/check_package.Rd +++ b/man/check_package.Rd @@ -54,6 +54,8 @@ Other package: \code{\link{check_license}()}, \code{\link{set_tag}()}, \code{\link{tidy_desc}()}, -\code{\link{update_citation}()} +\code{\link{update_citation}()}, +\code{\link{write_citation_cff}()}, +\code{\link{write_zenodo_json}()} } \concept{package} diff --git a/man/create_package.Rd b/man/create_package.Rd index 340f9de2..edf3c260 100644 --- a/man/create_package.Rd +++ b/man/create_package.Rd @@ -17,7 +17,9 @@ create_package(package, path = ".", title, description, maintainer) \item{maintainer}{The output of \code{\link[utils:person]{utils::person()}} or \code{\link[=orcid2person]{orcid2person()}}. If you use \code{\link[utils:person]{utils::person()}}, then you must provide \code{given}, \code{family}, -\code{role}, \code{email} and \code{comment} with valid \code{ORCID}.} +\code{role}, \code{email} and \code{comment} with valid \code{ORCID}. +When missing, the functions looks for \code{usethis.description} in the options. +See \code{\link[usethis:use_description]{usethis::use_description()}} for more information.} } \description{ Creates a package template in a new folder. diff --git a/man/set_tag.Rd b/man/set_tag.Rd index a7332feb..2c056eb7 100644 --- a/man/set_tag.Rd +++ b/man/set_tag.Rd @@ -28,6 +28,8 @@ Other package: \code{\link{check_license}()}, \code{\link{check_package}()}, \code{\link{tidy_desc}()}, -\code{\link{update_citation}()} +\code{\link{update_citation}()}, +\code{\link{write_citation_cff}()}, +\code{\link{write_zenodo_json}()} } \concept{package} diff --git a/man/tidy_desc.Rd b/man/tidy_desc.Rd index e3a25764..45fa1f82 100644 --- a/man/tidy_desc.Rd +++ b/man/tidy_desc.Rd @@ -24,6 +24,8 @@ Other package: \code{\link{check_license}()}, \code{\link{check_package}()}, \code{\link{set_tag}()}, -\code{\link{update_citation}()} +\code{\link{update_citation}()}, +\code{\link{write_citation_cff}()}, +\code{\link{write_zenodo_json}()} } \concept{package} diff --git a/man/update_citation.Rd b/man/update_citation.Rd index 22af2f55..078f3e88 100644 --- a/man/update_citation.Rd +++ b/man/update_citation.Rd @@ -36,6 +36,8 @@ Other package: \code{\link{check_license}()}, \code{\link{check_package}()}, \code{\link{set_tag}()}, -\code{\link{tidy_desc}()} +\code{\link{tidy_desc}()}, +\code{\link{write_citation_cff}()}, +\code{\link{write_zenodo_json}()} } \concept{package} diff --git a/man/write_citation_cff.Rd b/man/write_citation_cff.Rd new file mode 100644 index 00000000..68fc41e9 --- /dev/null +++ b/man/write_citation_cff.Rd @@ -0,0 +1,33 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/write_citation_cff.R +\name{write_citation_cff} +\alias{write_citation_cff} +\title{Write a CITATION.cff file} +\usage{ +write_citation_cff(x = ".", roles) +} +\arguments{ +\item{x}{Either a \code{Checklist} object or a path to the source code. +Defaults to \code{.}.} + +\item{roles}{Roles to select the persons for the \code{DESCRIPTION}. +Defaults to \code{c("aut", "cre")}.} +} +\description{ +This file format contains the citation information. +It is supported by GitHub, Zenodo and Zotero. +} +\seealso{ +Other package: +\code{\link{check_codemeta}()}, +\code{\link{check_cran}()}, +\code{\link{check_description}()}, +\code{\link{check_documentation}()}, +\code{\link{check_license}()}, +\code{\link{check_package}()}, +\code{\link{set_tag}()}, +\code{\link{tidy_desc}()}, +\code{\link{update_citation}()}, +\code{\link{write_zenodo_json}()} +} +\concept{package} diff --git a/man/write_zenodo_json.Rd b/man/write_zenodo_json.Rd new file mode 100644 index 00000000..968de462 --- /dev/null +++ b/man/write_zenodo_json.Rd @@ -0,0 +1,32 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/write_zenodo_json.R +\name{write_zenodo_json} +\alias{write_zenodo_json} +\title{Write a .zenodo.json file} +\usage{ +write_zenodo_json(x = ".") +} +\arguments{ +\item{x}{Either a \code{Checklist} object or a path to the source code. +Defaults to \code{.}.} +} +\description{ +Zenodo uses the .zenodo.json file to define the citation information. +See +https://developers.zenodo.org/#add-metadata-to-your-github-repository-release +for more information. +} +\seealso{ +Other package: +\code{\link{check_codemeta}()}, +\code{\link{check_cran}()}, +\code{\link{check_description}()}, +\code{\link{check_documentation}()}, +\code{\link{check_license}()}, +\code{\link{check_package}()}, +\code{\link{set_tag}()}, +\code{\link{tidy_desc}()}, +\code{\link{update_citation}()}, +\code{\link{write_citation_cff}()} +} +\concept{package} diff --git a/tests/testthat/test_c_create_package.R b/tests/testthat/test_c_create_package.R index 5f476e6c..e045d86d 100644 --- a/tests/testthat/test_c_create_package.R +++ b/tests/testthat/test_c_create_package.R @@ -32,7 +32,7 @@ test_that("create_package() works", { ".github", "workflows", c( "check_on_branch.yml", "check_on_different_r_os.yml", - "check_on_main.yml", "release.yml", "remove_old_artifacts.yml" + "check_on_main.yml", "release.yml" ) ), file.path("pkgdown", "extra.css"), diff --git a/tests/testthat/test_c_setup_source.R b/tests/testthat/test_c_setup_source.R index ed148a71..487636fc 100644 --- a/tests/testthat/test_c_setup_source.R +++ b/tests/testthat/test_c_setup_source.R @@ -31,4 +31,15 @@ test_that("setup_source() works", { }, "Checklist" ) + + writeLines("sessionInfo()", file.path(path, "junk.r")) + expect_error( + check_source(path, fail = TRUE), + "Checking the source code revealed some problems" + ) + expect_is({ + x <- check_source(path, fail = FALSE) + }, + "Checklist" + ) }) diff --git a/tests/testthat/test_d_setup_package.R b/tests/testthat/test_d_setup_package.R index 203ca8c5..6fb6f460 100644 --- a/tests/testthat/test_d_setup_package.R +++ b/tests/testthat/test_d_setup_package.R @@ -27,7 +27,7 @@ test_that("setup_package() works", { ".github", "workflows", c( "check_on_branch.yml", "check_on_different_r_os.yml", - "check_on_main.yml", "release.yml", "remove_old_artifacts.yml" + "check_on_main.yml", "release.yml" ) ), file.path("pkgdown", "extra.css"), diff --git a/tests/testthat/test_d_update_citation.R b/tests/testthat/test_d_update_citation.R new file mode 100644 index 00000000..052dd2a0 --- /dev/null +++ b/tests/testthat/test_d_update_citation.R @@ -0,0 +1,53 @@ +test_that("update_citation() works", { + maintainer <- person( + given = "Thierry", + family = "Onkelinx", + role = c("aut", "cre"), + email = "thierry.onkelinx@inbo.be", + comment = c(ORCID = "0000-0001-8804-4216") + ) + path <- tempfile("citation") + dir.create(path) + on.exit(unlink(path, recursive = TRUE), add = TRUE) + package <- "citation" + create_package( + path = path, + package = package, + title = "testing the ability of checklist to create a minimal package", + description = "A dummy package.", + maintainer = maintainer + ) + + expect_is({ + x <- update_citation(file.path(path, package)) + }, + "Checklist" + ) + expect_identical(x$get_roles, c("aut", "cre")) + + expect_is({ + x <- update_citation(file.path(path, package), roles = c("aut")) + }, + "Checklist" + ) + expect_identical(x$get_roles, c("aut")) + + old_citation <- readLines(file.path(path, package, "inst", "CITATION")) + writeLines( + old_citation[!grepl("^# .* checklist entry", old_citation)], + file.path(path, package, "inst", "CITATION") + ) + expect_is({ + x <- update_citation(file.path(path, package)) + }, + "Checklist" + ) + expect_identical( + x$.__enclos_env__$private$warnings, + c( + "No `# begin checklist entry` found in `inst/CITATION`", + "No `# end checklist entry` found in `inst/CITATION`" + ) + ) + writeLines(old_citation, file.path(path, package, "inst", "CITATION")) +})