R Package Initialization Script

Overview

Sources:

This script provides a comprehensive template for initializing a production-grade R package with all standard configurations, testing infrastructure, linting, documentation, and GitHub integration.

Code

 
#  ------------------------------------------------------------------------
#
# Title : Package Initialization Script
#    By : Jimmy Briggs
#  Date : YYYY-MM-DD
#
#  ------------------------------------------------------------------------
 
# libraries ---------------------------------------------------------------
 
require(devtools)
require(usethis)
require(roxygen2)
require(testthat)
require(rmarkdown)
require(knitr)
require(attachment)
require(pak)
require(purrr)
require(lifecycle)
require(rlang)
require(cli)
require(pkgload)
require(pkgbuild)
require(rcmdcheck)
require(fs)
 
# parameters --------------------------------------------------------------
pkg_name <- "mypackage"
pkg_title <- "My Awesome Package"
pkg_desc <- "Does cool stuff."
pkg_repo_spec <- paste0("noclocks/", pkg_name)
 
# initialize --------------------------------------------------------------
if (FALSE) {
  usethis::create_package(pkg_name)
  usethis::use_namespace()
  usethis::use_roxygen_md()
  usethis::use_package_doc(open = FALSE)
  usethis::use_import_from("rlang", ".data")
  usethis::use_import_from("rlang", ".env")
  usethis::use_import_from("rlang", "%||%")
}
 
# setup dev directory -----------------------------------------------------
if (FALSE) {
  usethis::use_directory("dev", ignore = TRUE)
  fs::dir_create("dev/R")
  fs::dir_create("dev/scripts")
  fs::dir_create("dev/check")
  usethis::use_git_ignore(ignores = c("*", "!.gitignore"), directory = "dev/check")
  fs::file_create("dev/scripts/README.md")
  # package check script
  fs::file_create("dev/scripts/pkg_check.R")  
  cat(
    "# Package Check Script",
    "",
    "pkg_path <- here::here()",
    "pkg_check_path <- file.path(pkg_path, 'dev', 'check')",
    "if (dir.exists(pkg_check_path)) fs::dir_delete(pkg_check_path)",
    "dir.create(pkg_check_path, recursive = TRUE, showWarnings = FALSE)",
    "attachment::att_amend_desc()",
    "check <- rcmdcheck::rcmdcheck(path = pkg_path, check_dir = check_path, error_on = 'never', args = c('--no-examples', '--no-tests'))",
    "details <- rcmdcheck_results <- rcmdcheck::check_details(check)",
    "saveRDS(check, file = file.path(check_path, 'rcmdcheck.rds'))",
    "saveRDS(details, file = file.path(check_path, 'check_details.rds'))",
    "check",
    "",
    file = "dev/scripts/pkg_check.R",
    sep = "\n",
    append = FALSE
  )
}
 
# initialize NAMESPACE and man/ folder
attachment::att_amend_desc()
devtools::document()
 
# initial check
source("dev/scripts/pkg_check.R")
 
# description -------------------------------------------------------------
if (FALSE) {
  usethis::use_description(
    fields = list(
      Title = pkg_title,
      Description = pkg_desc,
      Language =  "en-US"
    )
  )
 
  # authors
  usethis::use_author(
    "Jimmy",
    "Briggs",
    email = "jimmy.briggs@noclocks.dev",
    role = c("aut", "cre"),
    comment = c(ORCID = "0000-0002-7489-8787")
  )
}
 
# initial docs ------------------------------------------------------------
if (FALSE) {
  usethis::use_readme_md(open = FALSE)
  usethis::use_proprietary_license("No Clocks, LLC")
  usethis::use_vignette("noclocksai")
}
 
# logo --------------------------------------------------------------------
if (FALSE) {
  logo_url <- "https://raw.githubusercontent.com/jimbrig/noclocksr/refs/heads/main/man/figures/noclocks-logo.png"
  fs::dir_create("man/figures")
  download.file(logo_url, destfile = "man/figures/logo.png", mode = "wb")
  usethis::use_logo("man/figures/logo.png")
}
 
# git & github ------------------------------------------------------------
if (FALSE) {
  usethis::use_git()
  usethis::use_github(organisation = "noclocks", private = FALSE, visibility = "public")
  usethis::use_github_links(overwrite = TRUE)
  
  # github labels
  gh_labels <- tibble::tribble(
    ~name,      ~description,                                              ~color,
    "feature",  "New feature or request",                                  "0e8a16",
    "release",  "Release related tasks",                                   "fbca04",
    "refactor", "Code change that neither fixes a bug nor adds a feature", "1d76db",
    "tests",    "Adding or updating tests",                                "bfe5bf",
    "data",     "Data related tasks",                                      "5319e7",
    "infra",    "Infrastructure related tasks",                            "f9d0c4",
    "database", "Database Schemas and DDL",                                "c2e0c6",
  )
 
  usethis::use_github_labels(labels = gh_labels$name, colours = gh_labels$color, descriptions = gh_labels$description, delete_default = FALSE)
}
 
# testing ----------------------------------------------------------------
if (FALSE) {
  usethis::use_testthat(edition = 3)
  
  # initialize a test file
  usethis::use_test(pkg_name, open = FALSE)
 
  # initial helper and setup
  file.create("tests/testthat/helpers.R")
  file.create("tests/testthat/setup.R")
 
  # httptest2
  httptest2::use_httptest2()
 
  # shinytest2
  shinytest2::use_shinytest2()
 
  # playwright
  pw::pw_init(getwd())
 
  # dittodb
  dittodb::use_dittodb()
 
  # spellcheck
  usethis::use_spell_check()
  cat(
    "if (requireNamespace(\"spelling\", quietly = TRUE)) {",
    "  spelling::spell_check_test(",
    "    vignettes = TRUE,",
    "    error = FALSE,",
    "    skip_on_cran = TRUE",
    "  )",
    "}",
    "",
    file = "tests/spelling.R",
    sep = "\n",
    append = FALSE
  )
  spelling::update_wordlist()
 
    # code coverage
  usethis::use_coverage(type = "codecov", repo_spec = pkg_repo_spec)
  usethis::use_covr_ignore("dev/")
  usethis::use_covr_ignore("inst/")
  usethis::use_covr_ignore("data-raw/")
  usethis::use_build_ignore("codecov.yml")
  usethis::use_build_ignore(".covrignore")
  usethis::use_build_ignore("~\\$.*", escape = FALSE)
}
 
# run tests
devtools::test()
 
# linting -----------------------------------------------------------------
if (FALSE) {
  # air
  usethis::use_air()
  cat(
    "[format]",
    "line-width = 120",
    "indent-width = 2",
    "indent-style = 'space'",
    "line-ending = 'auto'",
    "persistent-line-breaks = true",
    "skip = ['tryCatch', 'tribble', 'if']",
    "",
    file = "air.toml",
    sep = "\n",
    append = FALSE
  )
  
  # lintr
  lintr::use_lintr()
  cat(
    "linters: linters_with_defaults(",
    "    line_length_linter(120),",
    "    commented_code_linter = NULL,",
    "    trailing_blank_lines_linter = NULL",
    "  )",
    "exclusions: list()",
    "encoding: \"UTF-8\"",
    "",
    file = ".lintr",
    sep = "\n",
    append = FALSE
  )
  usethis::use_build_ignore(".lintr")
  lintr::lint_package()
}
 
# gitignore, gitattributes, editorconfig ----------------------------------
if (FALSE) {
  gitattributes <- c(
    "# Global",
    "# -------------",
    "* text=auto",
    "tests/fixtures/**/* -diff", # Ignore diff for fixtures
    "",
    "# R Files",
    "# -------------",
    "*.{R,Rmd,Rd,Rproj,[Rr]environ,[Rr]profile,[Rr]history} text",
    "",
    "# Binary Files",
    "# -------------",
    "*.{R[Dd]ata,R[Dd][Ss],rda,rdb,rds,Rdx} binary", # R data files
    "*.zip binary", # Zip files
    "*.{pdf,png,jpg,jpeg,gif} binary", # Image files
    "",
    "# Linguist",
    "# -------------",
    ".[Rr]md linguist-detectable",
    "*.{md,markdown,txt} linguist-documentation",
    "docs/** linguist-documentation",
    "vignettes/** linguist-documentation",
    "*.{js,css,scss,less} linguist-vendored",
    "*.{min.js,min.css} linguist-generated",
    ""
  )
 
  writeLines(gitattributes, ".gitattributes")
 
  editorconfig <- c(
    "[*]",
    "indent_style = space",
    "indent_size = 2",
    "end_of_line = lf",
    "charset = utf-8",
    "trim_trailing_whitespace = true",
    "insert_final_newline = true",
    "",
    "[*.R]",
    "indent_size = 2",
    "max_line_length = 120",
    "",
    "[*.md]",
    "trim_trailing_whitespace = false",
    "",
    "[*.json]",
    "insert_final_newline = ignore",
    "",
    "[Makefile]",
    "indent_style = tab",
    "",
    "[*.bat]",
    "indent_style = tab"
  )
 
  writeLines(editorconfig, ".editorconfig")
 
  gitignore <- c(
    ".Rproj.user"
    ".Rhistory",
    ".Rdata",
    ".DS_Store",
    ".quarto/",
    "*.code-workspace",
    ".Renviron",
    ".Rprofile",
    ".env",
    "config.yml",
    "*temp/",
    "*repomix*",
    ".cursor/"
  )
 
  writeLines(gitignore, ".gitignore")
 
  usethis::use_build_ignore(".gitattributes")
  usethis::use_build_ignore(".editorconfig")
  usethis::use_build_ignore(".gitignore")
}
 
# codemeta ----------------------------------------------------------------
if (FALSE) {
  # codemetar::write_codemeta()
  codemeta::write_codemeta()
  usethis::use_build_ignore("codemeta.json")
}
 
# news --------------------------------------------------------------------
if (FALSE) {
  usethis::use_news_md()
}
 
# inst --------------------------------------------------------------------
if (FALSE) {
  c(
    "inst",
    "inst/config",
    "inst/extdata",
    "inst/templates",
    "inst/www",
    "inst/www/images",
    "inst/www/scripts",
    "inst/www/styles"
  ) |>
    purrr::walk(fs::dir_create)
}
 
# config ------------------------------------------------------------------
if (FALSE) {
  require(noclocksr)
  cfg <- list(
    default = list(
      # define various configurations relevant to package, i.e. database connection
      db = list(
        dbname = "postgres",
        host = "localhost",
        port = 5432,
        user = "postgres",
        password = "postgres",
        uri = "postgresql://postgres:postgres@localhost:5432/postgres"
      )
    )
  )
  noclocksr::cfg_init(cfg = cfg)
  noclocksr::cfg_hooks_init()
  usethis::use_build_ignore("config.yml")
}
 
# data --------------------------------------------------------------------
if (FALSE) {
  usethis::use_data_raw("internal")
  usethis::use_data_raw("exported")
  fs::dir_create("data-raw/cache")
  fs::dir_create("data-raw/raw")
  fs::dir_create("data-raw/processed")
  fs::dir_create("data-raw/scripts")
  fs::file_create("data-raw/README.md")
}
 
# vignettes ----------------------------------------------------------------
if (FALSE) {
  usethis::use_vignette(name = "introduction", title = "Introduction")
  fs::file_create("vignettes/compile.R")
  usethis::use_git_ignore(ignores = c("*.html", "*.R"), directory = "vignettes")
}
 
# github actions -----------------------------------------------------------
if (FALSE) {
  usethis::use_build_ignore(".github/")
  usethis::use_github_action(name = "document", save_as = "roxygen.yml", badge = TRUE)
  usethis::use_github_action(name = "lint", save_as = "lint.yml", badge = TRUE)
  usethis::use_github_action(name = "pr-commands", save_as = "pull-requests.yml", badge = TRUE)
  usethis::use_github_action(name = "style", save_as = "style.yml", badge = TRUE)
  usethis::use_github_action(name = "test-coverage", save_as = "coverage.yml", badge = TRUE)
  usethis::use_github_action(name = "check-standard", save_as = "check.yml", badge = TRUE)
  # changelog
  fs::file_create(".github/workflows/changelog.yml")
  fs::file_create("CHANGELOG.md")
  usethis::use_build_ignore("CHANGELOG.md")
  # pkgdown
  usethis::use_pkgdown_github_pages()
}
 
# docker ------------------------------------------------------------------
if (FALSE) {
  usethis::use_build_ignore(".dockerignore")
  usethis::use_build_ignore("Dockerfile")
}
 
# R/ ----------------------------------------------------------------------
if (FALSE) {
  c("aaa", "zzz") |> purrr::walk(usethis::use_r, open = FALSE)
}
 
# man/fragments -----------------------------------------------------------
if (FALSE) {
  fs::dir_create("man/fragments")
  fs::file_create("man/fragments/README.md")
  fs::file_create("man/fragments/header.Rmd")
  fs::file_create("man/fragments/footer.Rmd")
  fs::file_create("man/fragments/badges.Rmd")
  fs::file_create("man/fragments/installation.Rmd")
}
 
# refresh -----------------------------------------------------------------
attachment::att_amend_desc()
devtools::document()
devtools::load_all()
devtools::check()
devtools::test()
devtools::install()
devtools::build()

Details

The script is a comprehensive example showcasing all of the various components needing initialization and setup when developing a new, robust, production-grade R package.


Appendix

Note created on 2025-12-24 and last modified on 2025-12-24.

See Also


(c) No Clocks, LLC | 2025