check_n_covr(): check plus coverage in a single test pass
- New
check_n_covr(pkg)runsR 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 listlist(check, coverage).
Closes #67. covris now in Imports.
audit_downloads(): surface network / download calls in package code
- New
audit_downloads(pkg)walksR/,tests/,vignettes/and
inst/, parses every.R/.Rmd/.qmd/.Rnwfile, 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 theRCurl::getURL/getURI/getBinaryURLlegacy set.
Each hit is paired with asuggestionto 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 withfile,line,
functionandsuggestion. Closes #27.
audit_description(): catch unquoted package names in DESCRIPTION
- New
audit_description(pkg)reads theDescriptionfield 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 fieldwhen
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 withword,
positionandsuggestion. Closes #52.
audit_dontrun(): surface every \dontrun{} block in man/*.Rd
- New
audit_dontrun(pkg)walksman/*.Rdline 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@importFromline, not aglobalVariables()entry.audit_globals()/.get_no_visible()now return a third tibble
operatorsnext toglobalVariablesandfunctions. 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@importFromlines into NAMESPACE manually.- The internal regex that extracts the function name from a check
note (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.R
- Previously,
fix_globals(write = TRUE)overwroteR/globals.R
with a freshutils::globalVariables(unique(c(...)))block. That
was unsafe:R CMD checkalready filters out names covered by an
existingglobalVariables()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). - The function now parses the existing
R/globals.R, extracts the
names from anyglobalVariables()/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 sameunique(c(...))payload.
audit_userspace() / check_clean_userspace() robustness
- The
Run examplesstep is now wrapped in atryCatch(). When
devtools::run_examples()fails deep insidepkgload(e.g. the
srcrefs[[1L]]: subscript out of boundscrash 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). - On a partial run, the snapshot diff is still computed (rows tagged
source = "Run examples (partial)") so files created before the
crash do not slip into the next baseline and disappear from the
report. - The follow-up warning that surfaces files added during examples
now lists the files instead of telling the user to "not bother
about it" - a real leak written from inside an example would
previously have been silently dismissed. tests/testthat/test-check_clean_userspace.Rno longer hardcodes a
nrow == 5/6/11cascade. 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 calls
- New
audit_citation(pkg)parsesinst/CITATIONstatically (no
eval()) and surfaces every call topersonList(),
as.personList()orcitEntry()that CRAN rejects on submission
(Package CITATION file contains call(s) to old-style ...).
Returns a tibble withcall,lineand a one-linesuggestion
for the modern equivalent (c()onperson()objects;
bibentry()instead ofcitEntry()). Closes #62.
audit_globals() / fix_globals() skip vignettes / tests / examples
- The internal
R CMD checktriggered byaudit_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 problemsstep
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 asbuild_args/argsarguments to.get_notes()
so a caller can still opt back in if needed.
audit_tags() / find_missing_tags() now detect S3 cases
audit_tags()andfind_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 strictclass(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\valueon
generics' Rd files (e.g.strand_chr.Rd,
dim.gggenomes_layout.Rd).- Bare-
@exportblocks (no title, no@rdname/@describeIn/
@name) are intentionally not flagged: they produce no Rd file and
CRAN does not ask for\valueon them.
create_example_pkg() covers every audit
create_example_pkg()gains two opt-in flags so the same one-line
fixture can demonstrate every audit:with_nonascii = TRUEcopies a French-flavouredR/nonascii.R
(accents in comments + string literals + amessage()body) so
audit_ascii()andfix_ascii()have something to surface.with_undocumented_data = TRUEwrites a tiny
data/demo_dataset.rdawithout a roxygen block so
audit_dataset_doc()flags it as undocumented.
- Both default to
FALSEto keep the historic behaviour for tests.
TheREADMEQuick start and the "Auditing an R package" vignette
now activate them so a copy-paste demo trips every audit.
Share one R CMD check across audits
audit_globals()andfix_globals()gain achecks =argument
that accepts a pre-computedrcmdcheck::rcmdcheck()result. When
supplied, they skip runningR CMD checkand 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".
Documentation
- Vignettes consolidated to two: "Auditing an R package you have just
received" (canonical dev-time workflow with the sharedchk
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. READMEQuick start now uses the shared-chkworkflow as the
default example.
API refresh - audit_* / fix_* façades
The 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() |
Other changes
- The
%>%re-export frommagrittris 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. UsesuppressMessages()to silence.asciify_pkg()andasciify_file()gain ann_charscolumn /
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-aware
asciify_pkg(),asciify_file(),asciify_r_source(),
find_nonascii_tokens()andfind_nonascii_files()rewrite
non-ASCII characters in an R package the way CRAN expects:\uXXXX
escapes in string literals,Latin-ASCIItransliteration in
comments and roxygen blocks, refusal to auto-rename non-ASCII
identifiers. AST-based viagetParseData(). Defaults to a dry run
for whole-package rewrites.