#' Create an R package according to INBO requirements
#'
#' Creates a package template in a new folder.
#' Use this function when you want to start a new package.
#' Please DO READ `vignette("getting_started")` before running this function.
#'
#' @template checklist_structure
#'
#' @param package Name of the new package.
#' @param path Where to create the package directory.
#' @param title A single sentence with the title of the package.
#' @param description A single paragraph describing the package.
#' @param maintainer When missing, the function interactively lets you add the
#' maintainer and other authors.
#' Otherwise it must be the output of [utils::person()].
#' @param language Language of the project in `xx-YY` format.
#' `xx` is the two letter code for the language.
#' `YY` is the two letter code for the language variant.
#' E.g. `en-GB` for British English, `en-US` for American English, `nl-BE` for
#' Belgian Dutch.
#' @param license What type of license should be used?
#' Choice between GPL-3 and MIT.
#' Default GPL-3.
#' @param keywords A vector of keywords.
#' @param communities An optional vector of Zenodo community id's.
#' @export
#' @importFrom assertthat assert_that is.string
#' @importFrom desc description
#' @importFrom fs dir_create dir_ls file_copy is_dir path
#' @importFrom gert git_add git_init
#' @importFrom tools toTitleCase
#' @importFrom utils installed.packages
#' @family setup
#' @examples
#' # maintainer in `utils::person()` format
#' maintainer <- person(
#' given = "Thierry",
#' family = "Onkelinx",
#' role = c("aut", "cre"),
#' email = "thierry.onkelinx@inbo.be",
#' comment = c(ORCID = "0000-0001-8804-4216")
#' )
#'
#' # creating the package
#' path <- tempfile()
#' dir.create(path)
#' create_package(
#' path = path, package = "packagename", title = "package title",
#' description = "A short description.", maintainer = maintainer,
#' language = "en-GB", license = "GPL-3", keywords = "keyword"
#' )
create_package <- function(
package, path = ".", title, description, keywords, language = "en-GB",
license = c("GPL-3", "MIT"), communities = character(0), maintainer
) {
assert_that(
length(find.package("roxygen2", quiet = TRUE)) > 0,
msg =
"Please install the `roxygen2` package. `install.packages(\"roxygen2\")`"
)
if (missing(maintainer)) {
cat("Please select the maintainer")
maintainer <- author2person(role = c("aut", "cre"))
while (isTRUE(ask_yes_no("Add another author?", default = FALSE))) {
maintainer <- c(maintainer, author2person())
}
}
assert_that(inherits(maintainer, "person"))
assert_that(is_dir(path), msg = sprintf("`%s` is not a directory", path))
assert_that(is.string(package))
assert_that(valid_package_name(package))
assert_that(is.character(keywords), length(keywords) > 0)
assert_that(is.character(communities))
org <- read_organisation(path)
maintainer <- c(maintainer, org$as_person)
path <- path(path, package)
assert_that(
!is_dir(path) || length(dir_ls(path, recurse = TRUE)) == 0,
msg = sprintf("`%s` is not an empty directory", path)
)
assert_that(is.string(title))
validate_language(language)
license <- match.arg(license)
dir_create(path)
repo <- git_init(path = path)
dir_create(path(path, "R"))
# add checklist.yml
x <- checklist$new(x = path, package = TRUE, language = language)
x$set_ignore(c(".github", "LICENSE.md"))
write_checklist(x)
git_add("checklist.yml", repo = repo)
# create DESCRIPTION
desc <- desc::description$new("!new")
desc$set("Package", package)
desc$set("Title", toTitleCase(title))
desc$set_version("0.0.0")
desc$set_authors(maintainer)
desc$set("Description", description)
desc$set("License", ifelse(license == "MIT", "MIT + file LICENSE", license))
desc$set_urls(sprintf("https://github.com/%s/%s", org$get_github, package))
desc$set(
"BugReports",
sprintf("https://github.com/%s/%s/issues", org$get_github, package)
)
if (length(communities)) {
desc$set(
"Config/checklist/communities", paste(communities, collapse = "; ")
)
}
desc$set("Config/checklist/keywords", paste(keywords, collapse = "; "))
desc$set("Encoding", "UTF-8")
desc$set("Language", language)
desc$set("Roxygen", "list(markdown = TRUE)")
desc$set("RoxygenNote", installed.packages()["roxygen2", "Version"])
desc$del("Maintainer")
desc$write(path(path, "DESCRIPTION"))
git_add("DESCRIPTION", repo = repo)
# create NAMESPACE
c("# Generated by roxygen2: do not edit by hand", "") |>
writeLines(path(path, "NAMESPACE"))
git_add("NAMESPACE", repo = repo)
# create RStudio project
insert_file(
repo = repo, filename = "rproj.template", template = "package_template",
target = path, new_name = paste0(package, ".Rproj")
)
# add .gitignore
insert_file(
repo = repo, filename = "gitignore", template = "generic_template",
target = path, new_name = ".gitignore"
)
# add .Rbuildignore
insert_file(
repo = repo, filename = "rbuildignore", template = "package_template",
target = path, new_name = ".Rbuildignore"
)
# add codecov.yml
insert_file(
repo = repo, filename = "codecov.yml", template = "package_template",
target = path
)
# add NEWS.md
paste(
"# %s 0.0.0", "",
"* Added a `NEWS.md` file to track changes to the package.",
"* Add [`checklist`](https://inbo.github.io/checklist/) infrastructure.",
sep = "\n"
) |>
sprintf(package) |>
writeLines(path(path, "NEWS.md"))
git_add("NEWS.md", repo = repo)
# add README.Rmd
license_batch <- switch(
license,
"GPL-3" = "https://img.shields.io/badge/license-GPL--3-blue.svg?style=flat",
"MIT" = "https://img.shields.io/badge/license-MIT-blue.svg?style=flat"
)
license_site <- switch(
license,
"GPL-3" = "https://www.gnu.org/licenses/gpl-3.0.html",
"MIT" = "https://opensource.org/licenses/MIT"
)
path("package_template", "README.Rmd") |>
system.file(package = "checklist") |>
readLines() |>
gsub(pattern = "\\{\\{\\{ Package \\}\\}\\}", replacement = package) |>
gsub(
pattern = "\\{\\{\\{ license batch \\}\\}\\}", replacement = license_batch
) |>
gsub(
pattern = "\\{\\{\\{ license site \\}\\}\\}", replacement = license_site
) |>
writeLines(path(path, "README.Rmd"))
git_add("README.Rmd", repo = repo)
# add LICENSE.md
set_license(x)
git_add("LICENSE.md", repo = repo)
# Add code of conduct
target <- path(path, ".github")
dir_create(target)
insert_file(
repo = repo, filename = "CODE_OF_CONDUCT.md",
template = "generic_template", target = target
)
# Add contributing guidelines
insert_file(
repo = repo, filename = "CONTRIBUTING.md",
template = "package_template", target = target
)
# Add GitHub actions
target <- path(path, ".github", "workflows")
dir_create(target)
insert_file(
repo = repo, filename = "check_on_branch.yml",
template = "package_template", target = target
)
insert_file(
repo = repo, filename = "check_on_main.yml",
template = "package_template", target = target
)
insert_file(
repo = repo, filename = "check_on_different_r_os.yml",
template = "package_template", target = target
)
insert_file(
repo = repo, filename = "release.yml",
template = "package_template", target = target
)
# prepare pkgdown
path("package_template", "_pkgdown.yml") |>
system.file(package = "checklist") |>
readLines() |>
gsub(pattern = "\\{\\{\\{ Package \\}\\}\\}", replacement = package) |>
writeLines(path(path, "_pkgdown.yml"))
git_add("_pkgdown.yml", repo = repo)
target <- path(path, "pkgdown")
dir_create(target)
insert_file(
repo = repo, filename = "pkgdown.css", template = "package_template",
target = target, new_name = "extra.css"
)
target <- path(path, "man", "figures")
dir_create(target)
insert_file(
repo = repo, filename = "logo-en.png", template = "package_template",
target = target
)
insert_file(
repo = repo, filename = "background-pattern.png",
template = "package_template", target = target
)
insert_file(
repo = repo, filename = "flanders.woff2", template = "package_template",
target = target
)
insert_file(
repo = repo, filename = "flanders.woff", template = "package_template",
target = target
)
message("package created at `", path, "`")
if (
!interactive() || !requireNamespace("rstudioapi", quietly = TRUE) ||
!rstudioapi::isAvailable()
) {
return(invisible(NULL))
}
rstudioapi::openProject(path, newSession = TRUE)
}
valid_package_name <- function(x) {
grepl("^[a-zA-Z][a-zA-Z0-9.]+$", x) && !grepl("\\.$", x)
}
#' @importFrom assertthat on_failure<-
on_failure(valid_package_name) <- function(call, env) {
paste(deparse(call$x), "is not a valid package name.")
}
#' @importFrom fs file_copy path
#' @importFrom gert git_add
insert_file <- function(repo, filename, template, target, new_name) {
if (missing(new_name)) {
new_name <- path(target, filename)
} else {
new_name <- path(target, new_name)
}
path(template, filename) |>
system.file(package = "checklist") |>
file_copy(new_name, overwrite = TRUE)
if (is.null(repo)) {
return(invisible(NULL))
}
git_add(new_name, force = TRUE, repo = repo)
return(invisible(NULL))
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.