Skip to content

Make roxygen hook work with language: r #247

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 36 commits into from
May 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
0b47183
make hooks repo a variable
lorenzwalthert May 5, 2021
9114150
assert dependencies
lorenzwalthert May 6, 2021
8a81aa6
must have pkgload in roxygen hook, fix checks. allow pre-commit confi…
lorenzwalthert May 6, 2021
cdffc48
add version requirement
lorenzwalthert May 6, 2021
a7c808f
explicitly rely on DESCRIPTION
lorenzwalthert May 6, 2021
6de8fff
better explanation
lorenzwalthert May 6, 2021
de7c228
move roxygenize_with_cache to pkg source. Check if pkapi and other no…
lorenzwalthert May 6, 2021
70cdf91
bump version
lorenzwalthert May 6, 2021
0742972
needs R.cache
lorenzwalthert May 7, 2021
f55a3ff
add test setup
lorenzwalthert May 7, 2021
fe016f8
trigger roxygenize
lorenzwalthert May 7, 2021
e92ef59
make sure you also show other errors and warnings
lorenzwalthert May 7, 2021
4ebb74d
fix tests
lorenzwalthert May 7, 2021
a1c98d1
fix test
lorenzwalthert May 7, 2021
4c1d65b
try to fix tests
lorenzwalthert May 7, 2021
afcdf60
remove quiet
lorenzwalthert May 7, 2021
5a4b83e
add quiet
lorenzwalthert May 7, 2021
4a5bd43
dependencies should be sorted
lorenzwalthert May 7, 2021
487daf4
order should be fix
lorenzwalthert May 7, 2021
0be73c5
dont need styler dev anymore
lorenzwalthert May 7, 2021
f090512
trigger roxygen
lorenzwalthert May 7, 2021
8486aa0
inherit params
lorenzwalthert May 7, 2021
b50171f
load R.cache to avoid random error
lorenzwalthert May 7, 2021
f28482e
more conda quiet errors
lorenzwalthert May 7, 2021
0c78d4c
styler is suggested, not imported
lorenzwalthert May 7, 2021
9a34763
also update R.cache for hooks test
lorenzwalthert May 7, 2021
c4986fe
import may help
lorenzwalthert May 7, 2021
f8e003f
fix function name
lorenzwalthert May 7, 2021
fd4132e
move library call up
lorenzwalthert May 7, 2021
1519f20
switch back to not loading the package
lorenzwalthert May 7, 2021
d7d26a0
add note
lorenzwalthert May 7, 2021
35bda57
indent consistently
lorenzwalthert May 7, 2021
66758fd
drop random file
lorenzwalthert May 7, 2021
8da1156
yaml formatting
lorenzwalthert May 7, 2021
1435aba
remove todo
lorenzwalthert May 7, 2021
71cc571
add newly exported functions to pkgdown
lorenzwalthert May 9, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
default_stages: ["commit"]
repos:
- repo: https://github.com/lorenzwalthert/precommit
rev: acc8657498d5bfb9e9891098ba00b36e82c7ebd6
rev: 1435aba4f2c91753517512d90fe9b4995db59874
hooks:
- id: style-files
args: [--style_pkg=styler, --style_fun=tidyverse_style]
Expand All @@ -13,7 +13,34 @@ repos:
renv/.*
)$
- id: roxygenize
# codemeta must be above use-tidy-description when both are used
additional_dependencies:
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- r-lib/pkgapi@35226e9
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected] # codemeta must be above use-tidy-description when both are used
# - id: codemeta-description-updated
- id: use-tidy-description
- id: spell-check
Expand Down
4 changes: 4 additions & 0 deletions API
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@

autoupdate(root = here::here())
diff_requires_run_roxygenize(root = here::here())
dirs_R.cache(hook_id)
install_precommit(force = FALSE)
may_require_permanent_cache(temp_cache_is_enough = FALSE)
open_config(root = here::here())
open_wordlist(root = here::here())
path_pre_commit_exec(check_if_exists = TRUE)
path_precommit_exec(check_if_exists = TRUE)
roxygen_assert_additional_dependencies()
roxygenize_with_cache(key, dirs)
snippet_generate(snippet, root = here::here())
uninstall_precommit(scope = "repo", ask = "user", root = here::here())
update_precommit()
use_precommit(config_source = getOption("precommit.config_source"), force = FALSE, legacy_hooks = "forbid", open = rstudioapi::isAvailable(), install_hooks = TRUE, root = here::here())
Expand Down
9 changes: 5 additions & 4 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: precommit
Title: Pre-Commit Hooks
Version: 0.1.3.9000
Version: 0.1.3.9002
Author: Lorenz Walthert
Maintainer: Lorenz Walthert <[email protected]>
Description: Useful git hooks for R building on top of the multi-language
Expand All @@ -26,20 +26,21 @@ Imports:
yaml
Suggests:
desc,
digest,
git2r,
glue,
knitr,
lintr,
mockery,
pkgload,
reticulate (>= 1.16),
rmarkdown,
roxygen2,
spelling,
styler (>= 1.3.2.9000),
styler,
testthat (>= 2.1.0)
VignetteBuilder:
knitr
Remotes:
r-lib/styler
Encoding: UTF-8
Roxygen: list(markdown = TRUE, roclets = c( "rd", "namespace", "collate",
if (rlang::is_installed("pkgapi")) "pkgapi::api_roclet" else {
Expand Down
5 changes: 5 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,20 @@

export(autoupdate)
export(diff_requires_run_roxygenize)
export(dirs_R.cache)
export(install_precommit)
export(may_require_permanent_cache)
export(open_config)
export(open_wordlist)
export(path_pre_commit_exec)
export(path_precommit_exec)
export(roxygen_assert_additional_dependencies)
export(roxygenize_with_cache)
export(snippet_generate)
export(uninstall_precommit)
export(update_precommit)
export(use_precommit)
export(use_precommit_config)
export(version_precommit)
importFrom(R.cache,saveCache)
importFrom(magrittr,"%>%")
16 changes: 15 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,21 @@
`language: script` from the [pre-commit framework](https://pre-commit.com).
This requires `pre-commit >= 2.11.1`. All hooks and dependencies are now
contained in a virtual environment with [`{renv}`](https://rstudio.github.io/renv/)
(#233).
(#233). Thanks to {renv}'s excellent
[caching](https://rstudio.github.io/renv/articles/renv.html#cache-1), this
does not consume much space and is fast. This makes output
of hooks more consistent across different local setups, make manual dependency
management redundant and will facilitate running R hooks as part of CI/CD,
e.g. https://pre-commit.ci or [GitHub Actions](https://github.com/pre-commit/action)
along with arbitrary other hooks.

- Because hooks run in a virtual environment and the `roxygenize` hook runs
`pkgload::load_all()`, you need to list all dependencies of your package in
`additional_dependencies` field in `.pre-commit-config.yaml`. You will be
prompted to add them if they are missing,
`precommit::snippet_generate("additional-deps-roxygenize")` generates
the code you can copy/paste ().


**Minor changes**

Expand Down
1 change: 1 addition & 0 deletions R/aaa.R
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hooks_repo <- "https://github.com/lorenzwalthert/precommit"
2 changes: 1 addition & 1 deletion R/assert.R
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ assert_correct_upstream_repo_url <- function() {
if (upstream_repo_url_is_outdated()) {
usethis::ui_info(c(
"The repo https://github.com/lorenzwalthert/pre-commit-hooks ",
"has moved to https://github.com/lorenzwalthert/precommit. ",
"has moved to ", hooks_repo, ". ",
"Please fix the URL in .pre-commit-config.yaml, ",
"most confortably with `precommit::open_config()`."
))
Expand Down
6 changes: 3 additions & 3 deletions R/config.R
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
#' pre-commit with [use_precommit()] using the argument `config_source` to
#' copy an existing config file into your repo. This argument defaults to the R
#' option `precommit.config_source`, so you may want to set this option in
#' your `.Rprofile` for convenience. Note that this is **not** equivalent
#' to the `--config` option in the CLI command `pre-commit install` and similar,
#' your `.Rprofile` for convenience. Note that this is **not** equivalent to the
#' `--config` option in the CLI command `pre-commit install` and similar,
#' which do *not* copy a config file into a project root (and allow to put it
#' under version control), but rather link it in some more or less transparent
#' way.
Expand Down Expand Up @@ -63,7 +63,7 @@ use_precommit_config <- function(config_source = getOption("precommit.config_sou
"All available hooks: ",
"https://pre-commit.com/hooks.html",
"R specific hooks:",
"https://github.com/lorenzwalthert/precommit."
hooks_repo, "."
))
config_source
}
Expand Down
6 changes: 3 additions & 3 deletions R/release.R
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
#' - update default config in inst/
#' - commit
#' - git tag
#' - run `inst/consistent-release-tag` hook with --release-mode (passing args to hooks
#' not possible interactively, hence we run in advance).
#' - run `inst/consistent-release-tag` hook with --release-mode (passing args to
#' hooks not possible interactively, hence we run in advance).
#' - commit and push with skipping `inst/consistent-release-tag`.
#' - autoupdate own config file
#' - bump description with dev
Expand Down Expand Up @@ -135,7 +135,7 @@ release_prechecks <- function(bump, is_cran) {
update_rev_in_config <- function(new_version,
path = "inst/pre-commit-config.yaml") {
config <- readLines(path)
ours <- grep("- repo: https://github.com/lorenzwalthert/precommit", config, fixed = TRUE)
ours <- grep(paste0("- repo: ", hooks_repo), config, fixed = TRUE)
others <- setdiff(grep("- repo:", config, fixed = TRUE), ours)
next_after_ours <- others[others > ours][1]
rev <- grep("rev:", config)
Expand Down
81 changes: 79 additions & 2 deletions R/roxygen2.R
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ extract_diff_files <- function(files) {

#' Extract old and new lines from `git diff --cached`
#'
#' This is useful to detect within a hook script if the core function
#' from a hook such as [roxygen2::roxygenize()] must run at all or not.
#' This is useful to detect within a hook script if the core function from a
#' hook such as [roxygen2::roxygenize()] must run at all or not.
#' @param root The root of project.
#' @keywords internal
extract_diff_root <- function(root = here::here()) {
Expand Down Expand Up @@ -73,3 +73,80 @@ diff_requires_run_roxygenize <- function(root = here::here()) {
any(grep("function(", without_comments, fixed = TRUE))
}
}

#' Assert if all dependencies are installed
#'
#' This function is only exported for use in hook scripts, but it's not intended
#' to be called by the end-user directly.
#' @family hook script helpers
#' @export
roxygen_assert_additional_dependencies <- function() {
out <- rlang::with_handlers(
# roxygen2 will load: https://github.com/r-lib/roxygen2/issues/771
pkgload::load_all(quiet = TRUE),
error = function(e) {
e
}
)
if (inherits(out, "packageNotFoundError")) {
# case used in package but not installed
rlang::abort(paste0(
"The roxygenize hook requires all* dependencies of your package to be listed in ",
"the file `.pre-commit-config.yaml` under `id: roxygenize` -> ",
"`additional_dependencies:`, like this:\n\n",
" - id: roxygenize",
"
additional_dependencies:
- tidyr
- dplyr\n\n",
"Call ",
"`precommit::snippet_generate('additional-deps-roxygenize')`",
"and paste the ",
"output into the file `.pre-commit-config.yaml`. This requires precommit",
" > 0.1.3 and assumes you declared all dependencies in `DESCRIPTION`.",
"\n\nContext: https://github.com/lorenzwalthert/precommit/issues/243",
"\n\nThe initial error (from `pkgload::load_all()`) was: ",
conditionMessage(out), ".\n\n===================================\n",
"*Some packages are already installed in the renv to run the hook, so ",
"these technically don't have to be listed as additional dependencies, ",
"but we recommend listing all for simplicity and consistency."
))
}
}

#' Roxygen depending on cache state
#'
#' This function is only exported for use in hook scripts, but it's not intended
#' to be called by the end-user directly.
#' @inheritParams R.cache::saveCache
#' @family hook script helpers
#' @export
#' @importFrom R.cache saveCache
# fails if accessed with R.cache::saveCache()!
roxygenize_with_cache <- function(key, dirs) {
if (diff_requires_run_roxygenize()) {
out <- rlang::with_handlers(
roxygen2::roxygenise(),
error = function(e) e
)
if (inherits(out, "packageNotFoundError")) {
rlang::abort(paste0(
conditionMessage(out),
". Please add the package as a dependency to ",
"`.pre-commit-config.yaml` -> `id: roxygenize` -> ",
"`additional_dependencies` and try again. The package must be ",
"specified so `renv::install()` understands it, e.g. like this:\n\n",
" - id: roxygenize",
"
additional_dependencies:
- r-lib/pkgapi
- [email protected]\n\n"
))
} else if (inherits(out, "error")) {
rlang::abort(conditionMessage(out))
} else if (inherits(out, "warning")) {
rlang::warn(conditionMessage(out))
}
saveCache(object = Sys.time(), key = key, dirs = dirs)
}
}
53 changes: 53 additions & 0 deletions R/setup.R
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,56 @@ upstream_repo_url_is_outdated <- function() {
grepl("https://github.com/lorenzwalthert/pre-commit-hooks", ., fixed = TRUE) %>%
any()
}

#' Generate code snippets
#'
#' Utility function to generate code snippets:
#'
#' @details
#' Currently supported:
#'
#' * additional-deps-roxygenize: Code to paste into
#' `.pre-commit-config.yaml` for the additional dependencies required by
#' roxygen2.
#' @param snippet Name of the snippet.
#' @inheritParams fallback_doc
#' @export
snippet_generate <- function(snippet = "", root = here::here()) {
rlang::arg_match(snippet, c("additional-deps-roxygenize"))
if (snippet == "additional-deps-roxygenize") {
rlang::inform(
"Generating snippet using installed versions of all dependencies.\n"
)
deps <- desc::desc_get_deps()
deps <- deps[order(deps$package), ]
paste0(
" - ", deps$package, "@",
purrr::map_chr(deps$package, ~ as.character(packageVersion(.x))), "\n",
collapse = ""
) %>%
sort() %>%
cat(sep = "")
remote_deps <- rlang::with_handlers(
desc::desc_get_field("Remotes"),
error = function(e) character()
)
if (length(remote_deps) > 0) {
rlang::warn(paste0(
"It seems you have remote dependencies in your `DESCRIPTION`. You ",
"need to edit the above list manually to match the syntax `renv::install()` ",
"understands, i.e. if you have in your `DESCRIPTION`", "

Imports:
tidyr
Remotes:
tidyverse/tidyr@2fd80d5

You need in your `.pre-commit-config.yaml`

additional_dependencies:
- tidyverse/tidyr@2fd80d5
"
))
}
}
}
43 changes: 38 additions & 5 deletions R/testing.R
Original file line number Diff line number Diff line change
Expand Up @@ -179,17 +179,50 @@ not_conda <- function() {
#' @param git Whether or not to init git in the local directory.
#' @param use_precommmit Whether or not to [use_precommit()].
#' @keywords internal
local_test_setup <- function(.local_envir = parent.frame(),
git = TRUE,
local_test_setup <- function(git = TRUE,
use_precommit = FALSE,
...) {
package = FALSE,
quiet = TRUE,
...,
.local_envir = parent.frame()) {
dir <- withr::local_tempdir(.local_envir = .local_envir)
withr::local_dir(dir, .local_envir = .local_envir)
if (quiet) {
withr::local_options("usethis.quiet" = TRUE, .local_envir = .local_envir)
}
if (git) {
git2r::init(path = dir)
git2r::init()
withr::defer(fs::dir_delete(fs::path(dir, ".git")), envir = .local_envir)
}
if (use_precommit) {
suppressMessages(use_precommit(...))
suppressMessages(use_precommit(..., root = dir))
}
if (package) {
usethis::create_package(dir)
withr::local_dir(dir)
usethis::proj_set(dir)
usethis::use_testthat()
}

dir
}

#' Generate a random package name that is not installed
#' @param n The number of times we should try
#' @keywords internal
generate_uninstalled_pkg_name <- function(n = 10) {
additional_pkg <- paste0("package", digest::digest(Sys.time()))
if (rlang::is_installed(additional_pkg)) {
if (n > 0) {
generate_uninstalled_pkg_name(n - 1)
} else {
rlang::abort("could not find a package name that was not yet installed")
}
} else {
additional_pkg
}
}

generate_uninstalled_pkg_call <- function(n = 10) {
paste0(generate_uninstalled_pkg_name(n), "::x")
}
Loading