diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index 73efb7360..5432c0315 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -127,3 +127,10 @@ language: script minimum_pre_commit_version: "2.13.0" files: '^man/|_pkgdown\.yml' +- id: renv-lockfile-validate + name: renv-lockfile-validate + description: Validate that your `renv.lock` file is valid json and fits the default or provided schema + entry: Rscript inst/hooks/exported/renv-lockfile-validate.R + language: r + minimum_pre_commit_version: "2.13.0" + files: '^renv\.lock$' diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4c1252d80..393b5825c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,7 @@ # General Before making a pull request, discuss your ideas in an issue. + # Adding new hooks To create a new hook, have a look at the [official diff --git a/DESCRIPTION b/DESCRIPTION index 7298fa5e1..62e5fa46a 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: precommit Title: Pre-Commit Hooks -Version: 0.4.3.9004 +Version: 0.4.3.9005 Author: Lorenz Walthert Maintainer: Lorenz Walthert Description: Useful git hooks for R building on top of the multi-language @@ -22,16 +22,18 @@ Imports: rprojroot, withr, yaml -Suggests: +Suggests: desc, docopt (>= 0.7.1), git2r, glue, + jsonvalidate, knitr, lintr, pkgload, pkgdown, reticulate (>= 1.16), + renv (>= 1.0.8), rmarkdown, roxygen2, rstudioapi, @@ -40,7 +42,7 @@ Suggests: testthat (>= 2.1.0), tibble, usethis (>= 2.0.0) -VignetteBuilder: +VignetteBuilder: knitr Encoding: UTF-8 Roxygen: list(markdown = TRUE, roclets = c( "rd", "namespace", "collate", diff --git a/inst/WORDLIST b/inst/WORDLIST index 783d98695..c8a3f959d 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -82,6 +82,7 @@ issuehunt isTRUE jpeg json +jsonvalidate KernSmooth knitr Ko @@ -97,6 +98,7 @@ Lifecycle LinkingTo lintr loadCache +lockfile lorenz lorenzwalthert lt diff --git a/inst/hooks/exported/renv-lockfile-validate.R b/inst/hooks/exported/renv-lockfile-validate.R new file mode 100755 index 000000000..491ee5dfd --- /dev/null +++ b/inst/hooks/exported/renv-lockfile-validate.R @@ -0,0 +1,38 @@ +#!/usr/bin/env Rscript + +"Validate renv lockfiles +See `?renv::lockfile_validate()`. +Usage: + lockfile_validate [--schema=] [--greedy --error --verbose --strict] ... +Options: + --schema Path. Path to a custom schema. + --greedy Continue after first error? + --error Throw an error on parse failure? + --verbose If `TRUE`, then an attribute `errors` will list validation failures as a `data.frame`. + --strict Set whether the schema should be parsed strictly or not. +" -> doc + +if (!require(renv, quietly = TRUE)) { + stop("{renv} could not be loaded, please install it.") +} +if (packageVersion("renv") < package_version("1.0.8")) { + rlang::abort("You need at least version 1.0.8 of {renv} to run this hook.") +} +if (!require(jsonvalidate, quietly = TRUE)) { + stop("{jsonvalidate} could not be loaded, please install it.") +} + +arguments <- precommit::precommit_docopt(doc) +arguments$files <- normalizePath(arguments$files) +if (!is.null(arguments$schema)) { + arguments$schema <- normalizePath(arguments$schema) +} + +renv::lockfile_validate( + lockfile = arguments$files, + schema = arguments$schema, + greedy = arguments$greedy, + error = arguments$error, + verbose = arguments$verbose, + strict = arguments$strict +) diff --git a/inst/pre-commit-hooks.yaml b/inst/pre-commit-hooks.yaml index 73efb7360..5432c0315 100644 --- a/inst/pre-commit-hooks.yaml +++ b/inst/pre-commit-hooks.yaml @@ -127,3 +127,10 @@ language: script minimum_pre_commit_version: "2.13.0" files: '^man/|_pkgdown\.yml' +- id: renv-lockfile-validate + name: renv-lockfile-validate + description: Validate that your `renv.lock` file is valid json and fits the default or provided schema + entry: Rscript inst/hooks/exported/renv-lockfile-validate.R + language: r + minimum_pre_commit_version: "2.13.0" + files: '^renv\.lock$' diff --git a/inst/update-dependency-graph-existing-packages.R b/inst/update-dependency-graph-existing-packages.R index 4a965fb92..d4d761c68 100644 --- a/inst/update-dependency-graph-existing-packages.R +++ b/inst/update-dependency-graph-existing-packages.R @@ -7,7 +7,7 @@ hook_deps <- function(root) { "pkgdown", "httr" ) - out <- c(out, "docopt", "roxygen2", "spelling", "styler", "pkgload", "lintr", "knitr", "desc") + out <- c(out, "docopt", "roxygen2", "spelling", "styler", "pkgload", "lintr", "knitr", "desc", "jsonvalidate") out <- setdiff(c(unique(c(out, deps[deps$type == "Imports", ]$package))), dont) out <- names(renv:::renv_package_dependencies(out)) return(sort(out)) diff --git a/renv.lock b/renv.lock index 142c01480..f2d7383ea 100644 --- a/renv.lock +++ b/renv.lock @@ -84,6 +84,19 @@ ], "Hash": "f27411eb6d9c3dada5edd444b8416675" }, + "V8": { + "Package": "V8", + "Version": "6.0.0", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "Rcpp", + "curl", + "jsonlite", + "utils" + ], + "Hash": "6603bfcbc7883a5fed41fb13042a3899" + }, "backports": { "Package": "backports", "Version": "1.5.0", @@ -164,6 +177,16 @@ ], "Hash": "859d96e65ef198fd43e82b9628d593ef" }, + "curl": { + "Package": "curl", + "Version": "5.2.3", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R" + ], + "Hash": "d91263322a58af798f6cf3b13fd56dde" + }, "cyclocomp": { "Package": "cyclocomp", "Version": "1.1.1", @@ -277,6 +300,26 @@ ], "Hash": "e58f80d4c5b4f0bab1456956d6ca6aad" }, + "jsonlite": { + "Package": "jsonlite", + "Version": "1.8.9", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "methods" + ], + "Hash": "4e993b65c2c3ffbffce7bb3e2c6f832b" + }, + "jsonvalidate": { + "Package": "jsonvalidate", + "Version": "1.3.2", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "V8" + ], + "Hash": "cdc2843ef7f44f157198bb99aea7552d" + }, "knitr": { "Package": "knitr", "Version": "1.48", diff --git a/tests/testthat/in/renv-fail.lock b/tests/testthat/in/renv-fail.lock new file mode 100644 index 000000000..a49738217 --- /dev/null +++ b/tests/testthat/in/renv-fail.lock @@ -0,0 +1,20 @@ +{ + "R": { + "Version": "4.2.3", + "Repositories": [ + { + "Name": "CRAN", + "URL": "https://cloud.r-project.org" + } + ] + }, + "Packages": { + "markdown": { + "Package": "markdown", + "Version": "1.0", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "2324" + } + } +} diff --git a/tests/testthat/in/renv-success.lock b/tests/testthat/in/renv-success.lock new file mode 100644 index 000000000..f357273dd --- /dev/null +++ b/tests/testthat/in/renv-success.lock @@ -0,0 +1,19 @@ +{ + "R": { + "Version": "4.2.3", + "Repositories": [ + { + "Name": "CRAN", + "URL": "https://cloud.r-project.org" + } + ] + }, + "Packages": { + "markdown": { + "Package": "markdown", + "Version": "1.0", + "Source": "Repository", + "Repository": "CRAN" + } + } +} diff --git a/tests/testthat/reference-objects/pre-commit-config.yaml b/tests/testthat/reference-objects/pre-commit-config.yaml index 2044196d1..dd7b3a43f 100644 --- a/tests/testthat/reference-objects/pre-commit-config.yaml +++ b/tests/testthat/reference-objects/pre-commit-config.yaml @@ -65,6 +65,8 @@ repos: - id: no-debug-statement - id: deps-in-desc - id: pkgdown + - id: renv-lockfile-validate + args: [--error] - repo: local hooks: - id: consistent-release-tag diff --git a/tests/testthat/test-hook-renv-lockfile-validate.R b/tests/testthat/test-hook-renv-lockfile-validate.R new file mode 100644 index 000000000..d33250131 --- /dev/null +++ b/tests/testthat/test-hook-renv-lockfile-validate.R @@ -0,0 +1,12 @@ +# success +run_test("renv-lockfile-validate", + file_name = "renv-success", + suffix = ".lock", cmd_args = c("--error"), + std_err = NULL +) +# fail +run_test("renv-lockfile-validate", + file_name = "renv-fail", + suffix = ".lock", cmd_args = c("--error"), + std_err = "error validating json" +) diff --git a/vignettes/available-hooks.Rmd b/vignettes/available-hooks.Rmd index b793fdac0..d5d02d11b 100644 --- a/vignettes/available-hooks.Rmd +++ b/vignettes/available-hooks.Rmd @@ -1,14 +1,14 @@ --- title: "Available Hooks" -description: > +description: > Check out all hooks this repo contains and how they can be customized output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{available-hooks} %\VignetteEncoding{UTF-8} %\VignetteEngine{knitr::rmarkdown} -editor_options: - markdown: +editor_options: + markdown: wrap: 72 --- @@ -164,7 +164,7 @@ to run the `roxygenize` hook for that. id: parsable-roxygen args: [--eval] - + This hook was added in version 0.4.3.9000. ## `no-browser-statement` @@ -274,7 +274,7 @@ roclets you specified in `DESCRIPTION`. id: roxygenize - args: [--root=] + args: [--root=] - Argument `root` specifies the directory in the git repo that contains the R package. Defaults to `.` since for most R package git @@ -295,8 +295,8 @@ your DESCRIPTION file. Note that `README.Rmd` is never checked. - id: deps-in-desc - args: [--allow_private_imports] + id: deps-in-desc + args: [--allow_private_imports] - Argument `root` specifies the directory in the git repo that contains the R package. Defaults to `.` since for most R package git @@ -305,8 +305,8 @@ your DESCRIPTION file. Note that `README.Rmd` is never checked. - id: deps-in-desc - args: [--root=] + id: deps-in-desc + args: [--root=] This hook does not modify the file `DESCRIPTION` because the user should decide for each package if it should go to `Imports:` or `Suggests:`, @@ -324,7 +324,7 @@ This hook does modify the file `DESCRIPTION`. id: use-tidy-description - args: [--root=] + args: [--root=] - Argument `root` specifies the directory in the git repo that contains the R package. Defaults to `.` since for most R package git @@ -364,7 +364,7 @@ This hook does not modify any file. id: codemeta-description-updated - args: [--root=] + args: [--root=] - Argument `root` specifies the directory in the git repo that contains the R package. Defaults to `.` since for most R package git @@ -374,15 +374,36 @@ This hook does not modify any file. ## `pkgdown` -Check if your {pkgdown} config file (e.g. `_pkgdown.yml` in your root) has the -correct entries for references and articles. +Check if your {pkgdown} config file (e.g. `_pkgdown.yml` in your root) has the +correct entries for references and articles. This hook skips the time-consuming parts of building the index and reference and -only performs the validation. Hence we don't rely on the extensive dependency -graph of {pkgdown} being installed, including packages with heavy build-time +only performs the validation. Hence we don't rely on the extensive dependency +graph of {pkgdown} being installed, including packages with heavy build-time dependencies and system libraries. -For this check, we rely on the the global R package library and require all -development dependencies of the package you want to run this hook for to be +For this check, we rely on the the global R package library and require all +development dependencies of the package you want to run this hook for to be installed, as well as {pkgdown} (without its dependencies). This hook does not modify files. Added in version 0.3.2.9003. + + +## `renv-lockfile-validate` + +Guarantees that you don't accidentally commit an invalid `renv.lock` file. +See [`renv::lockfile_validate()` documentation](https://rstudio.github.io/renv/reference/lockfile_validate.html) +for details. + +The below config that uses only `--error` should suffice for most users. + + id: renv-lockfile-validate + args: [--error] + +This hook does not modify files. Added in version 0.4.3.9005. + +**Arguments** + + + + id: renv-lockfile-validate + args: [--schema=] [--greedy --error --verbose --strict]