check_n_covr():
check plus coverage in a single test passcheck_n_covr(pkg) runs R CMD check
(via devtools::check(args = "--no-tests")) and code
coverage (via covr::package_coverage(type = "tests"))
without running the unit test suite twice. Returns a named list
list(check, coverage). Closes #67.covr is now in Imports.audit_downloads():
surface network / download calls in package codeaudit_downloads(pkg) walks R/,
tests/, vignettes/ and inst/,
parses every .R / .Rmd / .qmd /
.Rnw file, and surfaces every call to a known download or
HTTP function: download.file() /
download.packages() (base / utils),
httr::GET() / POST / PUT /
PATCH / DELETE / HEAD,
httr2::req_perform() / req_perform_parallel /
req_perform_iterative, curl::curl_download() /
curl_fetch_memory / curl_fetch_disk /
curl_fetch_stream, and the RCurl::getURL /
getURI / getBinaryURL legacy set. Each hit is
paired with a suggestion to wrap the call in
tryCatch() / skip_if_offline() (tests) or move
it to \dontrun{} (examples) so the package degrades
gracefully on offline build farms. Detection is purely static (AST walk
via getParseData()), so user-defined functions that shadow
a known downloader
(download.file <- function(...) { ... }) do not trigger
a false positive on the definition site - only call sites are flagged.
Returns a tibble with file, line,
function and suggestion. Closes #27.audit_description():
catch unquoted package names in DESCRIPTIONaudit_description(pkg) reads the
Description field of DESCRIPTION, tokenises
it, and surfaces every word that matches an installed package name yet
is not wrapped in single quotes. CRAN incoming pretest emits
Package names should be quoted in the Description field
when this rule is violated. Detection is purely static: no package is
loaded, no namespace is touched. The package’s own name and compound
forms (dplyr-style, httr2-based, …) are
intentionally not flagged. Returns a tibble with word,
position and suggestion. Closes #52.audit_dontrun():
surface every \dontrun{} block in
man/*.Rdaudit_dontrun(pkg) walks man/*.Rd line
by line and surfaces every \dontrun{} block, with the
source Rd file, the documented topic, the line number and a one-line
suggestion to switch to \donttest{} unless the example
genuinely cannot be executed (missing API key, missing system
dependency, side effect on the user’s filespace). Detection is purely
static: each Rd file is read line-by-line and never sourced. Closes
#72.fix_globals()
separates operators / pronouns from real globals:=, .SD, .N, .I,
.GRP, .BY, .EACHI (data.table),
.data, .env, !!, !!!
(rlang) are no longer routed into the
utils::globalVariables(c(...)) block. They are exports from
another package - not undeclared variables - and the right fix is an
@importFrom line, not a globalVariables()
entry.audit_globals() / .get_no_visible() now
return a third tibble operators next to
globalVariables and functions. The token is
paired with its candidate source package(s).fix_globals() prints a third section “Operators /
pronouns to import via NAMESPACE” with ready-to-paste
#' @importFrom <pkg> <token> lines. When the
source is ambiguous (:= is exported by both data.table and
rlang) every candidate is listed and the user picks one consciously - no
silent guessing.fix_globals(write = TRUE) only writes real globals to
R/globals.R. The operators section is printed on stdout so
the user wires the @importFrom lines into NAMESPACE
manually.fun = str_extract(fun, ".+(?=:)")) was greedy and ate the
whole prose of := notes. Anchored to the first
: so it now reports the actual caller.fix_globals(write = TRUE)
now merges with the existing R/globals.Rfix_globals(write = TRUE) overwrote
R/globals.R with a fresh
utils::globalVariables(unique(c(...))) block. That was
unsafe: R CMD check already filters out names covered by an
existing globalVariables() call, so the second time
fix_globals() ran on a curated package, only the
uncovered names showed up in the notes - overwriting then
erased every previously-declared name and re-flagged it on the next
check (circular game).R/globals.R,
extracts the names from any globalVariables() /
utils::globalVariables() calls it finds, and rewrites the
file as the deduplicated union of the freshly detected names and the
already-declared ones. The preserved block is appended under a
# previously declared: banner inside the same
unique(c(...)) payload.audit_userspace()
/ check_clean_userspace() robustnessRun examples step is now wrapped in a
tryCatch(). When devtools::run_examples()
fails deep inside pkgload (e.g. the
srcrefs[[1L]]: subscript out of bounds crash on
@examplesIf examples whose body is fully under
\donttest{}, on older R + pkgload combos), the audit no
longer aborts: it warns, skips the examples slice, and still runs the
unit tests / full check / vignettes steps (#93).source = "Run examples (partial)") so files created before
the crash do not slip into the next baseline and disappear from the
report.tests/testthat/test-check_clean_userspace.R no longer
hardcodes a nrow == 5/6/11 cascade. It asserts the
invariants the function promises (the seeded leaks are caught, every row
has the right shape) instead of an exact OS-dependent row count, so the
test now runs on every OS (#54).audit_citation():
catch CRAN-rejected old-style CITATION callsaudit_citation(pkg) parses
inst/CITATION statically (no eval()) and
surfaces every call to personList(),
as.personList() or citEntry() that CRAN
rejects on submission
(Package CITATION file contains call(s) to old-style ...).
Returns a tibble with call, line and a
one-line suggestion for the modern equivalent
(c() on person() objects;
bibentry() instead of citEntry()). Closes
#62.audit_globals()
/ fix_globals() skip vignettes / tests / examplesR CMD check triggered by
audit_globals() and fix_globals() now passes
build_args = "--no-build-vignettes" and
args = c("--no-manual", "--no-tests", "--no-examples", "--no-vignettes").
The “no visible binding for global variable” / “no visible global
function definition” notes come from R CMD check’s static
* checking R code for possible problems step and never
depended on those phases. On a vignette-heavy package this turns a
multi-minute wait into a few seconds. The defaults are exposed as
build_args / args arguments to
.get_notes() so a caller can still opt back in if
needed.audit_tags()
/ find_missing_tags() now detect S3 casesaudit_tags() and find_missing_tags() now
flag missing @return on S3 generics and on S3 methods that
have their own Rd file (block carrying a title or @rdname /
@describeIn / @name). Previously a strict
class(object)[1] == "function" filter dropped these blocks
silently, so packages like the one reported in #92 were told “Good!”
while CRAN was still asking for \value on generics’ Rd
files (e.g. strand_chr.Rd,
dim.gggenomes_layout.Rd).@export blocks (no title, no @rdname
/ @describeIn / @name) are intentionally not
flagged: they produce no Rd file and CRAN does not ask for
\value on them.create_example_pkg()
covers every auditcreate_example_pkg() gains two opt-in flags so the same
one-line fixture can demonstrate every audit:
with_nonascii = TRUE copies a French-flavoured
R/nonascii.R (accents in comments + string literals + a
message() body) so audit_ascii() and
fix_ascii() have something to surface.with_undocumented_data = TRUE writes a tiny
data/demo_dataset.rda without a roxygen block so
audit_dataset_doc() flags it as undocumented.FALSE to keep the historic behaviour
for tests. The README Quick start and the “Auditing an
R package” vignette now activate them so a copy-paste demo trips
every audit.audit_globals() and fix_globals() gain a
checks = argument that accepts a pre-computed
rcmdcheck::rcmdcheck() result. When supplied, they skip
running R CMD check and reuse the existing output. Lets you
run the check once and feed both functions during a
full package audit. See the new vignette “Auditing an R package you
have just received”.chk pattern, plus a per-issue cheatsheet) and
“Pre-submission gates” (heavier audits run before release:
audit_check() and audit_userspace()). The
historic per-issue vignettes (deal-with-check-outputs,
check-with-real-cran-settings,
no-files-left-after-check) have been removed; their content
lives in those two and in the function reference.README Quick start now uses the shared-chk
workflow as the default example.audit_* / fix_* façadesThe package now exposes a uniform CRAN-oriented API: each category of
R CMD check issue gets one audit_* (read-only)
function and, when an automated fix is safe, one fix_*
(action) function. Type audit_<TAB> or
fix_<TAB> in RStudio to discover the surface.
| CRAN issue | Audit | Fix |
|---|---|---|
Globals to declare (no visible binding) |
audit_globals() |
fix_globals() |
| Missing roxygen tags | audit_tags() |
- |
| Non-ASCII characters | audit_ascii() |
fix_ascii() |
| Files left in user space | audit_userspace() |
- |
R CMD check with CRAN settings |
audit_check() |
- |
| Undocumented datasets | audit_dataset_doc() |
fix_dataset_doc() |
The 10 historic functions remain callable but emit
lifecycle::deprecate_warn() and delegate to the new
façades:
| Old | → New |
|---|---|
find_nonascii_files() |
audit_ascii() |
asciify_pkg() |
fix_ascii() |
get_no_visible() |
audit_globals() |
print_globals() |
fix_globals() |
find_missing_tags() |
audit_tags() |
check_as_cran() |
audit_check() |
check_clean_userspace() |
audit_userspace() |
use_data_doc() |
fix_dataset_doc() |
get_notes() |
(internal) audit_globals() |
get_data_info() |
(internal) fix_dataset_doc() |
%>% re-export from magrittr is
dropped. The pipe is no longer in the package’s exported surface; the
native pipe |> is available since R 4.1.asciify_pkg() now prints a one-line summary of how many
files were scanned, changed, and how many non-ASCII characters were
found. In dry-run mode it also prints how to apply the rewrite and how
to inspect the per-file detail. Use suppressMessages() to
silence.asciify_pkg() and asciify_file() gain an
n_chars column / list element: the count of non-ASCII
characters in the original file. n_tokens (number of source
locations to rewrite) is kept.asciify_*()
family: rewrite non-ASCII characters AST-awareasciify_pkg(), asciify_file(),
asciify_r_source(), find_nonascii_tokens() and
find_nonascii_files() rewrite non-ASCII characters in an R
package the way CRAN expects: \uXXXX escapes in string
literals, Latin-ASCII transliteration in comments and
roxygen blocks, refusal to auto-rename non-ASCII identifiers. AST-based
via getParseData(). Defaults to a dry run for whole-package
rewrites.find_missing_values only return messages instead of
warnings. (@MurielleDelmotte)check_clean_userspace() (#13)create_example_pkg() to get examples in
functions documentationcheck_as_cran() (#21)find_missing_tags()print_globals()rcmdcheck()NEWS.md file to track changes to the
package.