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..140dd81b4 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -27,11 +27,13 @@ Suggests: docopt (>= 0.7.1), git2r, glue, + jsonvalidate, knitr, lintr, pkgload, pkgdown, reticulate (>= 1.16), + renv (>= 1.0.8), rmarkdown, roxygen2, rstudioapi, 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..1cdc8492e 100644 --- a/vignettes/available-hooks.Rmd +++ b/vignettes/available-hooks.Rmd @@ -386,3 +386,21 @@ 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 you that you don't accidentally commit an invalid renv.lock file. +The below config that uses only `--error` should suffice for most users. + + id: renv-lockfile-validate + args: [--error] + +This hook does not modify files. + +**Arguments** + + + + id: renv-lockfile-validate + args: [--schema=] [--greedy --error --verbose --strict]