From f6230a7170e6c93af0dda7ec7f2821aede838a76 Mon Sep 17 00:00:00 2001 From: dgkf <18220321+dgkf@users.noreply.github.com> Date: Sat, 25 Apr 2026 22:17:31 -0400 Subject: [PATCH 1/6] feat(quarto): update package_render to use quarto template --- .gitignore | 12 +- .gitmodules | 6 + R/reporter.R | 241 ++++++------- inst/assessments/dplyr.rds | Bin 72015 -> 0 bytes inst/report | 1 + inst/report/package/bottom_page.html | 4 - inst/report/package/custom.scss | 143 -------- inst/report/package/custom_light.scss | 62 ---- inst/report/package/foldable_code.lua | 15 - inst/report/package/pkg_template.qmd | 360 ------------------- inst/report/package/r_validation_logo.png | Bin 9242 -> 0 bytes inst/report/package/top_page.html | 7 - inst/report/package/transform_pre_class.html | 13 - inst/report/repo_template.qmd | 137 ------- man/package_report.Rd | 54 +-- tests/testthat/_snaps/render_table.md | 5 - val.report.Rproj | 23 -- 17 files changed, 120 insertions(+), 963 deletions(-) create mode 100644 .gitmodules delete mode 100644 inst/assessments/dplyr.rds create mode 160000 inst/report delete mode 100644 inst/report/package/bottom_page.html delete mode 100644 inst/report/package/custom.scss delete mode 100644 inst/report/package/custom_light.scss delete mode 100644 inst/report/package/foldable_code.lua delete mode 100644 inst/report/package/pkg_template.qmd delete mode 100644 inst/report/package/r_validation_logo.png delete mode 100644 inst/report/package/top_page.html delete mode 100644 inst/report/package/transform_pre_class.html delete mode 100644 inst/report/repo_template.qmd delete mode 100644 tests/testthat/_snaps/render_table.md delete mode 100644 val.report.Rproj diff --git a/.gitignore b/.gitignore index 552fad2..a997c2f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,6 @@ -.Rproj.user +*.Rproj +*.Rproj.user .Rhistory .RData .Ruserdata -val.report.Rproj -inst/doc -inst/assessments -inst/source/Outputs/ -inst/source/Library -inst/source/*Rcheck -inst/source/*tar.gz -inst/source/ -inst/checks/ docs diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e665f6c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +# to use ssh credentials, run: +# git config url."ssh://git@".insteadOf https:// + +[submodule "inst/report"] + path = inst/report + url = https://github.com/pharmaR/rvalhub-report-quarto.git diff --git a/R/reporter.R b/R/reporter.R index c3efc85..73e26ad 100644 --- a/R/reporter.R +++ b/R/reporter.R @@ -1,172 +1,131 @@ -#' Reports about a package -#' -#' @param package_name Package name. -#' @param package_version Package version number. -#' @param package Path where to find a package source to retrieve name and -#' version number. -#' @param template_path Path to a directory with one quarto template file (and -#' the files required for rendering it). -#' @param output_format Output format for the report. Default is "all". -#' @param params A list of execute parameters passed to the template -#' @param ... Additional arguments passed to `quarto::quarto_render()` -#' -#' @return A path to the reports generated, called by its side effects. -#' -#' @details Please include source as part of `params` content. Source is -#' returned after calling function `riskmetric::pkg_ref` before the risk -#' assessment is executed +#' Generates an R Validation Hub package report #' #' @examples -#' options("valreport_output_dir" = tempdir()) -#' pr <- package_report( -#' package_name = "dplyr", -#' package_version = "1.1.4", -#' params = list( -#' assessment_path = -#' system.file("assessments/dplyr.rds", package = "val.report"), -#' image = "rhub/ref-image"), -#' quiet = FALSE +#' options( +#' val.meter.logs = TRUE, +#' val.meter.policy = val.meter::policy(permissions = TRUE) #' ) -#' pr -#' file.remove(pr) +#' +#' package_report(package = "path/to/package") #' #' @export package_report <- function( - package_name, - package_version, package = NULL, - template_path = system.file("report/package", package = "val.report"), - output_format = "all", - params = list(), + session = NULL, + options = val_options(plus = c("width")), + template = system.file("report", "template.qmd", package = "val.report"), + output_dir = getwd(), + quiet = FALSE, ... ) { - empty_pkg_info <- is.empty(package_name) && is.empty(package_version) - if (empty_pkg_info && !is.empty(package)) { - package_name <- basename(package) - desc <- read.dcf(file.path(package, "DESCRIPTION")) - - stopifnot( - "Mismatch between path and DESCRIPTION name" = package_name == - desc[, "Package"] - ) - package_version <- desc[, "Version"] - params$package <- package - Sys.setenv("INPUT_REPORT_PKG_DIR" = package) - } else if (empty_pkg_info && is.empty(package)) { - stop("Package information missing for the report") + # temp dir for report output + quarto_out_dir <- tempfile("val_report_") + dir.create(quarto_out_dir) + + # temp dir for passing Rds content from subprocess to parent + quarto_artifacts_dir <- tempfile("val_artifacts_") + dir.create(quarto_artifacts_dir) + + # derive metrics for package, write out to Rds + if (is_rds_path(package) && !is_rds_path(session)) { + stop("package provided as Rds file path, but session was not.") + } else if (!is.null(session)) { + stop("session provided, but package yet to be computed.") } else { - params$package <- package_name - } - - full_name <- paste0(package_name, "_v", package_version) - output_file <- paste0("validation_report_", full_name, ".qmd") + callr_args <- list( + package = package, + options = options, + artifacts_dir = quarto_artifacts_dir, + quiet = quiet + ) - params$package_name <- package_name - params$package_version <- package_version - params$image <- get_image_name(params) + res <- callr::r( + callr_val_package, + args = callr_args, + show = TRUE, + stderr = "2>&1" + ) - if (is.null(template_path) || !nzchar(template_path)) { - template_path <- system.file("report/package", package = "val.report") - } else if (!dir.exists(template_path)) { - stop("Template directory is not available") + package <- res$package + session <- res$session + options <- res$options # reset input options, no longer with Rds input } - params$package <- normalizePath( - params$package, - mustWork = FALSE, - winslash = "/" + quarto::quarto_render( + input = template, + execute_dir = getwd(), + execute_params = list( + package = package, + session = session, + options = options + ), + quarto_args = c("--output-dir", quarto_out_dir), + quiet = quiet %||% FALSE, + ... ) - if (length(params$assessment_path) == 1L && !nzchar(params$assessment_path)) { - params$assessment_path <- normalizePath( - params$assessment_path, - mustWork = TRUE, - winslash = "/" - ) - } - # Bug on https://github.com/quarto-dev/quarto-cli/issues/5765 - v <- quarto::quarto_version() - if (v < package_version("1.7.13")) { - warning("Please install the latest (devel) version of Quarto") - } + obj <- readRDS(package) + report_stem <- paste0("val_", obj$name, "_", obj$version) + rename_quarto_outputs( + input_dir = quarto_out_dir, + output_dir = output_dir, + output_stem = report_stem + ) +} - if (is.null(params$source)) { - warning("Please provide the source of the package assessment") - } +rename_quarto_outputs <- function(input_dir, output_dir, output_stem) { + files <- list.files(input_dir, full.names = TRUE) - # https://github.com/quarto-dev/quarto-r/issues/81#issuecomment-1375691267 - # quarto rendering happens in the same place as the file/project - # To avoid issues copy to a different place and render there. - render_dir <- output_dir() - if (!dir.exists(render_dir)) { - render_dir <- paste0(render_dir, "/") - if (!dir.exists(render_dir)) { - stop( - "Render directory doesn't exists. Please check the 'getOptions(\"valreport_output_dir\")' and sys.getEnv(\"VALREPORT_OUTPUT_DIR\")" - ) - } - } - files_to_copy <- list.files(template_path, full.names = TRUE) - fc <- file.copy( - from = files_to_copy, - to = render_dir, - overwrite = TRUE, - copy.date = TRUE - ) + for (i in rev(seq_along(files))) { + old_path <- files[[i]] + new_path <- gsub("\\.", "-", output_stem) + new_path <- paste0(new_path, ".", tools::file_ext(old_path)) + new_path <- file.path(output_dir, new_path) - if (any(!fc)) { - stop("Copying to the rendering directory failed.") + files[[i]] <- new_path + file.copy(old_path, new_path, overwrite = TRUE) + file.remove(old_path) } - template_all_files <- list.files(render_dir, full.names = TRUE) - template <- template_all_files[endsWith(template_all_files, "qmd")] + files +} - if (length(template) > 1) { - stop( - "There are more than one template!\n", - "Please have only one quarto file on the directory." - ) +callr_val_package <- function(package, options, artifacts_dir, quiet) { + library(S7) + library(val.meter) + + # pass through configured options + options(options) + if (is.logical(quiet)) { + options(val.meter.quiet = quiet) } - file_template <- file.path( - render_dir, - paste0("validation_report_", full_name, ".qmd") - ) - file.rename(template, file_template) - - # replace the title of the place header by the package name and header - top_page_file <- readLines(file.path(render_dir, "top_page.html")) - title_line <- grep(" - as.character() - writeLines(top_page_file, file.path(render_dir, "top_page.html")) - - pre_rendering <- list.files(render_dir, full.names = TRUE) - - out <- quarto::quarto_render( - input = file_template, - output_format = output_format, - execute_params = params, - ... - ) + # derive package metrics + pkg <- S7::convert(package, val.meter::pkg) + val.meter::metrics(pkg) - post_rendering <- list.files(render_dir, full.names = TRUE) + # save out to Rds + pkg_file <- paste0("val_", pkg$name, "_", pkg$version, "_") + pkg_file <- gsub("\\.", "-", pkg_file) + pkg_file <- file.path(artifacts_dir, paste0(pkg_file, ".Rds")) + saveRDS(pkg, pkg_file) - files_to_remove <- intersect(pre_rendering, post_rendering) - fr <- file.remove(files_to_remove) - if (any(!fr)) { - warning("Failed to remove the quarto template used from the directory.") - } + # record session info to Rds + session_file <- file.path(artifacts_dir, "val_session.Rds") + saveRDS(val.report::session(), session_file) + + list(package = pkg_file, session = session_file, options = list()) +} + +val_options <- function(prefix = "val.", plus = character(0L)) { + opts <- options() + append(opts[startsWith(names(opts), prefix)], opts[plus]) +} - output_files <- setdiff(post_rendering, pre_rendering) - invisible(output_files) +is_rds_path <- function(x) { + is.character(x) && file.exists(x) && endsWith(x, ".Rds") } -is.empty <- function(x) { +is_empty <- function(x) { is.null(x) || is.na(x) || !nzchar(x) } diff --git a/inst/assessments/dplyr.rds b/inst/assessments/dplyr.rds deleted file mode 100644 index 275c8f31edeca3b8caad66b272f512975795a12b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 72015 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 diff --git a/inst/report b/inst/report new file mode 160000 index 0000000..fc77ac1 --- /dev/null +++ b/inst/report @@ -0,0 +1 @@ +Subproject commit fc77ac17d75af3be2097a6694452a4403f61d83a diff --git a/inst/report/package/bottom_page.html b/inst/report/package/bottom_page.html deleted file mode 100644 index 8b57a87..0000000 --- a/inst/report/package/bottom_page.html +++ /dev/null @@ -1,4 +0,0 @@ -
- R Validation hub Logo - Created with riskreports from R Validation Hub. -
diff --git a/inst/report/package/custom.scss b/inst/report/package/custom.scss deleted file mode 100644 index 9313a3c..0000000 --- a/inst/report/package/custom.scss +++ /dev/null @@ -1,143 +0,0 @@ -/*-- scss:defaults --*/ -$link-color: #4697d2 !default; -$card-color: #2a424e; -$card-header-color: #cdcdcd; -$foldable-color: #0f0f0f; - -$code-color: var(--bs-body-color) !default; -$code-bg: $card-color !default; -$btn-code-copy-color: $link-color !default; -$btn-code-copy-color-active: white !default; - -/*-- scss:rules --*/ - -#quarto-content { - padding-top: 2rem; -} - -.top-page { - display: flex; - padding: 15px 15px 15px 45px; - gap: 1rem; - box-shadow: 0px 5px 75px var(--bs-black); - align-items: center; - - .btn { - margin-top: 5px; - } - - p { - font-weight: bold; - font-size: larger; - margin-top: 1.2rem; - } -} - -.card { - background-color: $card-color; - border-radius: 15px; - padding-bottom: 10px; - margin-bottom: 0.5em; - - .card-header { - display: flex; - gap: 1em; - border-bottom: unset; - background-color: unset; - color: $card-header-color; - margin-left: 5px; - - i { - color: $link-color; - padding-top: 0.15em; - font-size: 27px; - } - } - - .card-title { - padding-left: 0.75em; - } - - .card-text { - color: $card-header-color; - padding-left: 1em; - } - - -} - -.top-card { - display: flex; - gap: 1em; - - .top-left-card { - .card-title { - margin-top: 0.5rem; - } - } - - .top-right-card { - display: flex; - flex: 1 2; - - .left-card { - border-radius: 15px 0px 0px 15px; - border-right: unset; - width: 100%; - } - - .right-card { - border-radius: 0% 15px 15px 0; - width: 100%; - border-left: unset; - } - } -} - -.bottom-card { - display: flex; - flex-direction: row; - - .card-title { - margin-top: 10px; - padding-top: 10px; - - } - - .card-header { - flex: 1; - margin-top: 10px - } -} - -.metrics-table { - color: $card-header-color; - border-color: $card-header-color; - background-color: var(--bs-body-bg) !important; - - .rt-expander::after { - border-top: 7px solid $card-header-color; - } -} - - -details > summary { - color: $card-header-color; - background-color: $foldable-color; - padding: 10px 1rem 10px 1rem; - border-bottom: 2px solid $link-color; - border-radius: 10px 10px 0px 0px; - font-weight: bold; - font-size: medium; -} - -pre.details { - color: $link-color; - background-color: $foldable-color; - border-radius: 0px; - padding: 10px 1rem 10px 1rem; - - code { - overflow:auto; - } -} diff --git a/inst/report/package/custom_light.scss b/inst/report/package/custom_light.scss deleted file mode 100644 index 5ff72a1..0000000 --- a/inst/report/package/custom_light.scss +++ /dev/null @@ -1,62 +0,0 @@ -/*-- scss:defaults --*/ -$body-bg: #e8f7f7 !default; -$link-color: #4697d2 !default; -$card-light-color: #fcfcf7 !default; -$card-header-light-color: #636363; -$card-header-color: $card-header-light-color !default; - -$code-bg: #d6e9f7 !default; -$btn-code-copy-color: black !default; -$btn-code-copy-color-active: $link-color !default; -/*-- scss:rules --*/ - -.card { - background-color: $card-light-color; - - .card-header { - color: $card-header-light-color; - } - - .card-text { - color: $card-header-light-color; - } -} - -.top-page { - box-shadow: 0px 5px 75px #f8fafa; - - .btn { - background-color: var(--bs-black); - color: var(--bs-white); - } -} - -.metrics-table { - color: $card-header-light-color; - border-bottom: 1px solid $card-header-light-color; - - .rt-th { - border-bottom: 1px solid $card-header-light-color; - } - - .rt-td { - border-top: 1px solid $card-header-light-color; - } - - .rt-expander::after { - border-top: 7px solid $card-header-light-color; - } -} - -details > summary { - background-color: $code-bg; - color: var(--bs-body-color); -} - -pre.details { - color: var(--bs-body-color); - background-color: $code-bg; -} - - - diff --git a/inst/report/package/foldable_code.lua b/inst/report/package/foldable_code.lua deleted file mode 100644 index 33be254..0000000 --- a/inst/report/package/foldable_code.lua +++ /dev/null @@ -1,15 +0,0 @@ -function CodeBlock(elem) - if elem.classes and elem.classes:find("details") then - local summary = "Code" - if elem.attributes.summary then - summary = elem.attributes.summary - end - return{ - pandoc.RawBlock( - "html", "
" .. summary .. "" - ), - elem, - pandoc.RawBlock("html", "
") - } - end -end \ No newline at end of file diff --git a/inst/report/package/pkg_template.qmd b/inst/report/package/pkg_template.qmd deleted file mode 100644 index f4ced33..0000000 --- a/inst/report/package/pkg_template.qmd +++ /dev/null @@ -1,360 +0,0 @@ ---- -title: "Validation Report" -date-format: "YYYY-MM-DD hh:mm:ss" -date: today -published-title: "" -params: - package_name: dplyr - package_version: 1.0.0 - package: NULL - image: "rhub/ref-image" - assessment_path: "assessments/dplyr.rds" - hide_reverse_deps: true - source: "pgk_install" -format: - html: - toc: true - embed-resources: true - include-in-header: "top_page.html" - include-after-body: "transform_pre_class.html" - theme: - dark: [darkly, custom.scss] - light: [default, custom.scss, custom_light.scss] - gfm: - html-math-method: webtex - pdf: - toc: true - number-depth: 3 - # FIXME: Typst didn't handle well the relative paths to images - # typst: - # toc: true - # section-numbering: 1.1.1 - # df-print: default - # margin: - # x: 2cm - # y: 2cm -filters: - - foldable_code.lua ---- - -```{r setup, include = FALSE} -options(width = 80L, covr.record_tests = TRUE) - -knitr::opts_chunk$set( - echo = FALSE, - eval = TRUE, - error = TRUE, - cache = FALSE -) -library("tools") -library("knitr") -library("val.report") - -header <- val.report::knitr_mutable_header() -log <- val.report::knitr_logger() -``` - -# Context - - -```{r loading} -pkg <- params$package -pkg_name <- params$package_name -pkg_version <- params$package_version - -log("Loaded package: ", pkg_name, " @ v", pkg_version, "\n") -header$title <- paste0(pkg_name, " (v", pkg_version, ")") - -risk_path <- params$assessment_path -image <- params$image -``` - -Documents the installation of this package on an open source R environment, focusing on: - -- Installation environment description -- Testing coverage - -It is limited to assess whether unit tests and documentation are present and can execute without error. -An assessment would be required that the tests and documentation are meaningful. - - -# Package `r basename(pkg)` - -## Metric based risk assessment - -The following metrics are derived from the `riskmetric` R package. - -```{r read-riskmetric, warning=FALSE} -d_riskmetric <- readRDS(risk_path) - -# Required fields -required_fields <- c("r_cmd_check", "license", "remote_checks", "covr_coverage") - -# Missing fields -missing_fields <- setdiff(required_fields, names(d_riskmetric)) - -# Assign default error structure for missing fields to avoid errors -for (field in missing_fields) { - d_riskmetric[[field]] <- structure(NA, class = "risk_metric_error") -} -``` - -```{r create_r_riskmetric, warning=FALSE} -# Assesment produces a data.frame with one row -r_riskmetric <- val.report::assessment(d_riskmetric) -is_na <- sapply(r_riskmetric, function(x) { - is.na(x) || (is.character(x) && startsWith(x, "no applicable")) -}) -r_riskmetric$origin <- val.report:::get_pkg_origin(params$source) -``` - - -::: {.content-visible when-format="html"} - -```{r info_cards} -val.report:::create_metrics_cards(r_riskmetric) -``` - -::: - -::: {.content-hidden when-format="html"} - -```{r simple_cards} -simple_cards <- data.frame( - "Downloads 1 year" = as.character(r_riskmetric$downloads_1yr), - "Reverse dependencies" = r_riskmetric$reverse_dependencies, - "License" = as.character(r_riskmetric$license), - "Origin" = r_riskmetric$origin -) -r_riskmetric$origin <- NULL -knitr::kable(simple_cards) -``` - -::: - -```{r prepare_tables_namespace} -namespace_table <- val.report:::prepare_namespace_table(d_riskmetric) -``` - - -```{r prepare_tables_dependencies} -deps <- d_riskmetric$dependencies -deps$package <- gsub("\\n", " ", deps$package) -row.names(deps) <- NULL -dependencies_table <- htmltools::div( - htmltools::span( - "Overall the package has these dependencies:" - ), - reactable::reactable( - deps, - class = "metrics-table" - ) -) -``` - -```{r prepare_tables_reverse_dependencies} -reverse_dependencies <- paste(d_riskmetric$reverse_dependencies, collapse = ", ") -``` - -```{r prepare_tables_examples} -examples_content <- paste0( - "There are ", - if (!is_na["has_examples"]) sum(d_riskmetric$has_examples), - " examples from ", - if (!is_na["has_examples"]) length(d_riskmetric$has_examples), - " help pages (", - if (!is_na["has_examples"]) { - sprintf("%.2f%%", sum(d_riskmetric$has_examples) / length(d_riskmetric$has_examples) * 100) - } else { - "?" - }, - ")." -) -``` - -```{r prepare_tables_news} -news_content <- paste0( - "The package has ", - if ("has_news" %in% names(d_riskmetric) && !is.null(d_riskmetric$has_news)) d_riskmetric$has_news, - " NEWS file and it is ", - if (is.null(d_riskmetric$news_current) && !d_riskmetric$news_current) "not", - "current." -) -``` - -```{r general-riskmetric, warning=FALSE} -#| tab.cap: "**Package general assessment:** Coverage, check results, size, -#| download the last year, reverse dependencies and number of dependencies." - -summary_data <- summary_table(r_riskmetric[, !is.na(as.vector(r_riskmetric))]) - -values_collapsed_rows <- c( - "Has news", - "Exported namespace", - "Dependencies", - "Reverse dependencies", - "Has examples" -) - -indexes_collapsed_rows <- which(summary_data$Section %in% values_collapsed_rows) - -is_html <- knitr::is_html_output(excludes = "markdown") - -# Certain rows of this table are collapsible, containing detailed information. -if (isTRUE(is_html)) { - reactable::reactable( - summary_data, - rownames = FALSE, - pagination = FALSE, - details = function(index) { - if(index %in% indexes_collapsed_rows) { - collapsed_content <- switch(summary_data$Section[index], - "Exported namespace" = namespace_table, - "Dependencies" = dependencies_table, - "Reverse dependencies" = reverse_dependencies, - "Has examples" = examples_content, - "Has news" = news_content - ) - htmltools::div( - style = "padding: 1rem;", - collapsed_content - ) - } - }, - columns = list( - Section = reactable::colDef( - name = "" - ), - Values = reactable::colDef( - name = "", - cell = function(value) { - if (value == "Yes") { - # Green 'Yes' - htmltools::span(value, style = "color:var(--bs-success); font-weight: bold;") - } else if (value == "No") { - # Red 'No' - htmltools::span(value, style = "color: var(--bs-danger); font-weight: bold;") - } else { - htmltools::span(value, style = "color: var(--bs-body-color); font-weight: bold;") - } - }, - align = "center" - ) - ), - class = "metrics-table" -) -} else { - knitr::kable(summary_data) -} -``` - -::: {.content-hidden unless-meta=`r !is_risk_error(d_riskmetric[["license"]])`} - -## License - -The package uses `r if ("license" %in% names(d_riskmetric) && !is.null(d_riskmetric$license)) cat(d_riskmetric$license)`. - -::: - -::: {.content-hidden unless-meta=`r !is_risk_error(d_riskmetric[["r_cmd_check"]]) || !is_risk_error(d_riskmetric[["remote_checks"]])`} - -## Code checks - - -```{r r_cmd_check, eval=!is_risk_error(d_riskmetric[["r_cmd_check"]])} -d_riskmetric[["r_cmd_check"]] -``` - - - -```{r remote_checks, eval=!is_risk_error(d_riskmetric[["remote_checks"]])} -d_riskmetric[["remote_checks"]] -``` - -::: - -::: {.content-hidden unless-meta=`r !is_risk_error(d_riskmetric[["covr_coverage"]])`} - -## Code coverage - -Code coverage for this package is: - -```{r covr_coverage} -d_riskmetric[["covr_coverage"]] -``` - -::: - -# Installation environment - - -## System Info - -```{r execution_info} -#| tab.cap: "**System information**. Table about the system used to check the package." -tt_sys_info_df <- data.frame( - Field = c("Image", "OS", "Platform", "System", "Execution Time"), - Value = c( - image, - sessionInfo()$running, - R.version$platform, - R.version$system, - format(Sys.time(), tz = "UTC", usetz = TRUE) - )) - -knitr::kable(tt_sys_info_df) -``` - - - -## R Session Info - -```{r session_info, attr.output='.details summary="Session info"'} -sessionInfo() -``` - -```{r Platform, attr.output='.details summary="Platform"'} -unlist(.Platform) -``` - -```{r capabilities, attr.output='.details summary="R\'s capabilities"'} -capabilities() -``` - -```{r external-software, attr.output='.details summary="External software"'} -extSoftVersion() -``` - -```{r graphic-software, attr.output='.details summary="Graphics external software"'} -grSoftVersion() -``` - -```{r machine, attr.output='.details summary="Numerical characteristics of the machine"'} -unlist(.Machine) -``` - -```{r RNGKind, attr.output='.details summary="Random number generation process"'} -RNGkind() -``` - -## Information about the environment -Environmental and options variables affect how package checks and software in it might behave. - -```{r computing, attr.output='.details summary="Environmental variables when running this report"'} -val.report::environ_report(exclude = c("APPDATA", "GITHUB", "GITHUB_PAT", "GITHUB_PAT_GITHUB_COM", - "GITLAB", "GITLAB_PAT", "ProgramFiles", "ProgramFiles(x86)", - "R_DptShare", "R_USER", "USERDNSDOMAIN", "USERDOMAIN", "USERDOMAIN_ROAMINGPROFILE", - "USERNAME", "USERPROFILE")) -``` - -```{r options, attr.output='.details summary="These are the options set to generate the report"'} -val.report::options_report(exclude = c("usethis.full_name", "usethis.description", "usethis.destdir")) -``` diff --git a/inst/report/package/r_validation_logo.png b/inst/report/package/r_validation_logo.png deleted file mode 100644 index 093cec7bdf5107b746926e0af7d8884a6e37018b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9242 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 diff --git a/inst/report/package/top_page.html b/inst/report/package/top_page.html deleted file mode 100644 index 5f66182..0000000 --- a/inst/report/package/top_page.html +++ /dev/null @@ -1,7 +0,0 @@ -
-R Validation hub Logo - - -

Validation Report dplyr

- -
diff --git a/inst/report/package/transform_pre_class.html b/inst/report/package/transform_pre_class.html deleted file mode 100644 index 8a5d0f4..0000000 --- a/inst/report/package/transform_pre_class.html +++ /dev/null @@ -1,13 +0,0 @@ - - \ No newline at end of file diff --git a/inst/report/repo_template.qmd b/inst/report/repo_template.qmd deleted file mode 100644 index a96db68..0000000 --- a/inst/report/repo_template.qmd +++ /dev/null @@ -1,137 +0,0 @@ ---- -title: "Validation Report - Repository `r param$repo`" -date: "`r Sys.time()`" -date-format: "ddd MMM DD hh:mm:ss A YYYY" -params: - repo: ../source - image: "rhub/ref-image" -format: - html: - toc: true - embed-resources: true - # typst: - # toc: true - # section-numbering: 1.1.1 - # df-print: default - # margin: - # x: 2cm - # y: 2cm ---- - -```{r setup, include = FALSE} -options(width = 80L, covr.record_tests = TRUE) -knitr::opts_chunk$set( - echo = FALSE, - eval = TRUE, - error = TRUE, - cache = FALSE -) -library("tools") -``` - -# Context - - -```{r image} -image <- Sys.getenv("DOCKER_IMAGE", unset = NA) -if (!is.na(image) && nzchar(params$image)) { - image <- params$image -} -``` - -This report is fully automated and builds on `r image` image. -Documents the installation of this package on an open source R environment, focusing on: - -- Installation environment description -- Testing coverage - -It is limited to assess whether unit tests and documentation are present and can execute without error. -An assessment would be required that the tests and documentation are meaningful. - -# Installation environment - -```{r loading} -library("riskmetric") -path <- params$repo -pkg <- params$package -risk_path <- params$assessment_path -``` - - -## System Info - -```{r execution_info} -tt_sys_info_df <- data.frame( - Field = c("OS", "Platform", "System", "Execution Time"), - Value = c( - sessionInfo()$running, - R.version$platform, - R.version$system, - format(Sys.time(), tz = "UTC", usetz = TRUE) - )) - -tt_sys_info_df -``` - -## R Session Info - -Information about the R environment and capabilities: - -```{r session_info} -sessionInfo() -unlist(.Platform) - -capabilities() -extSoftVersion() -grSoftVersion() -unlist(.Machine) -RNGkind() -``` - - -## Information about the environment - -Environmental and options variables affect how package checks and software in it might behave. -Here is the environ variables when running this report - -```{r computing} -val.report::environ_report(exclude = c("APPDATA", "GITHUB", "GITHUB_PAT", "GITHUB_PAT_GITHUB_COM", - "GITLAB", "GITLAB_PAT", "ProgramFiles", "ProgramFiles(x86)", - "R_DptShare", "R_USER", "USERDNSDOMAIN", "USERDOMAIN", "USERDOMAIN_ROAMINGPROFILE", - "USERNAME", "USERPROFILE")) -``` - -```{r options} -val.report::options_report(exclude = c("usethis.full_name", "usethis.description", "usethis.destdir")) -``` - - -## Repository status - -```{r repo-files} -# This repository is to fill the packages. It could be replaced with a common -# repository or expanded (new option?) to an internal repository. -options("repos" = c("https://cloud.r-project.org")) -lf <- list.files(path, full.names = TRUE) -pfiles <- lf[endsWith(lf, ".tar.gz")] -tar_file <- pfiles[startsWith(basename(pfiles), pkg)] -``` - - -```{r check-repo, cache=TRUE, cache.extra=file.mtime(tar_file)} -# Cache.extra is to avoid rechecking the file when it hasn't changed/updated -cpd <- tools::check_packages_in_dir(path, - pfiles = basename(tar_file), - check_args = c( - "--timings", # include execution times in output - "--no-build-vignettes", # run vignette code, but disable pdf rendering - "--no-manual", # disable pdf manual rendering - "--with-keep.source")) -``` - -The repository has these packages with problems: - -```{r repo-summary} -summary_pkgs <- check_packages_in_dir_details(path) -as.data.frame(summary_pkgs)[, 1:4] -``` diff --git a/man/package_report.Rd b/man/package_report.Rd index debaf52..64799eb 100644 --- a/man/package_report.Rd +++ b/man/package_report.Rd @@ -2,58 +2,26 @@ % Please edit documentation in R/reporter.R \name{package_report} \alias{package_report} -\title{Reports about a package} +\title{Generates an R Validation Hub package report} \usage{ package_report( - package_name, - package_version, package = NULL, - template_path = system.file("report/package", package = "val.report"), - output_format = "all", - params = list(), + session = NULL, + options = val_options(plus = c("width")), + template = system.file("report", "template.qmd", package = "val.report"), + output_dir = getwd(), ... ) } -\arguments{ -\item{package_name}{Package name.} - -\item{package_version}{Package version number.} - -\item{package}{Path where to find a package source to retrieve name and -version number.} - -\item{template_path}{Path to a directory with one quarto template file (and -the files required for rendering it).} - -\item{output_format}{Output format for the report. Default is "all".} - -\item{params}{A list of execute parameters passed to the template} - -\item{...}{Additional arguments passed to \code{quarto::quarto_render()}} -} -\value{ -A path to the reports generated, called by its side effects. -} \description{ -Reports about a package -} -\details{ -Please include source as part of \code{params} content. Source is -returned after calling function \code{riskmetric::pkg_ref} before the risk -assessment is executed +Generates an R Validation Hub package report } \examples{ -options("valreport_output_dir" = tempdir()) -pr <- package_report( - package_name = "dplyr", - package_version = "1.1.4", - params = list( - assessment_path = - system.file("assessments/dplyr.rds", package = "val.report"), - image = "rhub/ref-image"), - quiet = FALSE +options( + val.meter.logs = TRUE, + val.meter.policy = val.meter::policy(permissions = TRUE) ) -pr -file.remove(pr) + +package_report(package = "path/to/package") } diff --git a/tests/testthat/_snaps/render_table.md b/tests/testthat/_snaps/render_table.md deleted file mode 100644 index 5712ff7..0000000 --- a/tests/testthat/_snaps/render_table.md +++ /dev/null @@ -1,5 +0,0 @@ -# Namespace table is created / It is created by without error from existing example package assessment - - Code - prepare_namespace_table(example_assessment) - diff --git a/val.report.Rproj b/val.report.Rproj deleted file mode 100644 index 679f4cb..0000000 --- a/val.report.Rproj +++ /dev/null @@ -1,23 +0,0 @@ -Version: 1.0 -ProjectId: 88b36725-d552-4dae-b9ae-e1088cec756b - -RestoreWorkspace: Default -SaveWorkspace: Default -AlwaysSaveHistory: Default - -EnableCodeIndexing: Yes -UseSpacesForTab: Yes -NumSpacesForTab: 2 -Encoding: UTF-8 - -RnwWeave: Sweave -LaTeX: pdfLaTeX - -AutoAppendNewline: Yes -StripTrailingWhitespace: Yes - -BuildType: Package -PackageUseDevtools: Yes -PackageInstallArgs: --no-multiarch --with-keep.source -PackageCheckArgs: --as-cran -PackageRoxygenize: rd,collate,namespace From 76e9b9101c3a1e05d9afd4e3ef688e4f1ad2b7b6 Mon Sep 17 00:00:00 2001 From: dgkf <18220321+dgkf@users.noreply.github.com> Date: Sun, 26 Apr 2026 14:31:51 -0400 Subject: [PATCH 2/6] chore: package cleanup, rewrite tests --- .Rbuildignore | 19 +-- DESCRIPTION | 11 +- NAMESPACE | 15 +- R/check.R | 74 --------- R/render_table.R | 28 ---- R/render_utils.R | 90 ----------- R/reporter.R | 48 ++++-- R/riskmetric.R | 147 ------------------ R/{utils_knitr.R => utils-knitr.R} | 0 R/utils.R | 61 +------- ...reports-package.R => val-report-package.R} | 0 man/assessment.Rd | 17 -- man/check_reporter.Rd | 25 --- man/create_info_card.Rd | 25 --- man/environ_report.Rd | 22 --- man/extract_license.Rd | 22 --- man/get_image_name.Rd | 12 -- man/get_pkg_origin.Rd | 22 --- man/is_risk_error.Rd | 20 --- man/knit_print.knitr_log.Rd | 2 +- man/knitr_logger.Rd | 2 +- man/knitr_logger_styles.Rd | 2 +- man/knitr_mutable_header.Rd | 2 +- man/knitr_update_options.Rd | 2 +- man/options_report.Rd | 22 --- man/package_report.Rd | 35 +++++ man/prepare_namespace_table.Rd | 15 -- man/replace_zero_or_false_by_no.Rd | 12 -- man/summary_table.Rd | 17 -- man/val.report-package.Rd | 2 +- tests/testthat/_snaps/card.md | 30 ---- tests/testthat/fixtures/test.pkg/DESCRIPTION | 14 ++ tests/testthat/fixtures/test.pkg/NAMESPACE | 3 + tests/testthat/fixtures/test.pkg/R/hello.R | 9 ++ tests/testthat/fixtures/test.pkg/man/hello.Rd | 17 ++ .../fixtures/test.pkg/tests/testthat.R | 12 ++ .../test.pkg/tests/testthat/test-hello.R | 3 + tests/testthat/test-card.R | 20 --- tests/testthat/test-check.R | 5 - tests/testthat/test-render_table.R | 7 - tests/testthat/test-render_utils.R | 89 ----------- tests/testthat/test-report.R | 40 ++--- tests/testthat/test-utils-knitr.R | 2 +- tests/testthat/test-utils.R | 32 +--- 44 files changed, 185 insertions(+), 869 deletions(-) delete mode 100644 R/check.R delete mode 100644 R/render_table.R delete mode 100644 R/render_utils.R delete mode 100644 R/riskmetric.R rename R/{utils_knitr.R => utils-knitr.R} (100%) rename R/{riskreports-package.R => val-report-package.R} (100%) delete mode 100644 man/assessment.Rd delete mode 100644 man/check_reporter.Rd delete mode 100644 man/create_info_card.Rd delete mode 100644 man/environ_report.Rd delete mode 100644 man/extract_license.Rd delete mode 100644 man/get_image_name.Rd delete mode 100644 man/get_pkg_origin.Rd delete mode 100644 man/is_risk_error.Rd delete mode 100644 man/options_report.Rd delete mode 100644 man/prepare_namespace_table.Rd delete mode 100644 man/replace_zero_or_false_by_no.Rd delete mode 100644 man/summary_table.Rd delete mode 100644 tests/testthat/_snaps/card.md create mode 100644 tests/testthat/fixtures/test.pkg/DESCRIPTION create mode 100644 tests/testthat/fixtures/test.pkg/NAMESPACE create mode 100644 tests/testthat/fixtures/test.pkg/R/hello.R create mode 100644 tests/testthat/fixtures/test.pkg/man/hello.Rd create mode 100644 tests/testthat/fixtures/test.pkg/tests/testthat.R create mode 100644 tests/testthat/fixtures/test.pkg/tests/testthat/test-hello.R delete mode 100644 tests/testthat/test-card.R delete mode 100644 tests/testthat/test-check.R delete mode 100644 tests/testthat/test-render_table.R delete mode 100644 tests/testthat/test-render_utils.R diff --git a/.Rbuildignore b/.Rbuildignore index 727f1f6..831e3a7 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -4,16 +4,11 @@ ^README\.Rmd$ ^codecov\.yml$ ^val.report\.Rproj$ -inst/source/Outputs -inst/checks/* -inst/source/* -inst/source/Library -inst/source/*Rcheck -inst/source/*tar.gz -inst/*.rds -validation_report_* -_pkgdown.yaml -pkgdown -.github -docs +^inst/report/\.git +^inst/report/\.quarto +^_pkgdown.yml$ +^_pkgdown.yaml$ +^pkgdown +^.github ^\.github$ +^docs diff --git a/DESCRIPTION b/DESCRIPTION index cac5fbc..f644f33 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -14,18 +14,17 @@ BugReports: https://github.com/pharmaR/val.report/issues Depends: R (>= 4.3.0) Imports: - grDevices, + callr, + knitr, methods, - htmltools, quarto (>= 1.4.4), - reactable, + S7, + tools, utils, + val.meter, yaml Suggests: - knitr, - riskmetric (>= 0.2.4), rmarkdown, - S7, spelling, testthat (>= 3.0.0), withr (>= 3.0.2) diff --git a/NAMESPACE b/NAMESPACE index 4384d48..53633f9 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,25 +1,24 @@ # Generated by roxygen2: do not edit by hand -export(assessment) -export(check_reporter) -export(environ_report) -export(is_risk_error) export(knit_print.knitr_log) export(knitr_logger) export(knitr_mutable_header) export(knitr_update_options) -export(options_report) export(package_report) export(session) -export(summary_table) +importFrom(S7,convert) +importFrom(callr,r) importFrom(grDevices,grSoftVersion) -importFrom(htmltools,div) importFrom(methods,is) +importFrom(quarto,quarto_render) +importFrom(quarto,quarto_version) importFrom(tools,check_packages_in_dir_details) +importFrom(tools,file_ext) importFrom(utils,capture.output) -importFrom(utils,getFromNamespace) importFrom(utils,head) importFrom(utils,packageName) importFrom(utils,sessionInfo) importFrom(utils,tail) +importFrom(val.meter,metrics) +importFrom(val.meter,pkg) importFrom(yaml,yaml.load) diff --git a/R/check.R b/R/check.R deleted file mode 100644 index 599024a..0000000 --- a/R/check.R +++ /dev/null @@ -1,74 +0,0 @@ - - -#' Reports check results -#' -#' Experimental function to use the default log to create a report. -#' -#' @param path Path to check results folder (aka `pkgname.Rcheck`). -#' -#' @return A base report -#' @export -#' @seealso [tools::check_packages_in_dir()] -#' @examples -#' # Requires the package to be installed (or be in inst/ folder) -#' # check_reporter("checks/riskmetric.Rcheck") -#' -check_reporter <- function(path){ - log <- file.path(path, "00check.log") - lines <- readLines(log) -} - - -#' Export environmental variables -#' -#' @param show Character vector of environmental variables to show. -#' @param exclude Character vector of environmental variables to hide. -#' -#' @return A character vector with environmental variables. -#' @export -#' -#' @examples -#' environ_report() -environ_report <- function(show = NULL, exclude = NULL) { - environ <- Sys.getenv() - - keep_names <- include_exclude_from(names(environ), show, exclude) - - if (length(keep_names) == 0) { - return(NULL) - } - - environ[keep_names] -} - -#' Export options -#' -#' @param show Character vector of options to show. -#' @param exclude Character vector of options variables to hide. -#' -#' @return A list with the options -#' @export -#' -#' @examples -#' options_report() -options_report <- function(show = NULL, exclude = NULL) { - options <- options() - - keep_names <- include_exclude_from(names(options), show, exclude) - - if (length(keep_names) == 0) { - return(NULL) - } - fill_in(options, keep_names) -} - -check_summary <- function(path) { - out <- tools::check_packages_in_dir_details(path) - summary(out) -} - -check_packages <- function(path) { - - check_packages_in_dir_details(path) - -} diff --git a/R/render_table.R b/R/render_table.R deleted file mode 100644 index b682fd7..0000000 --- a/R/render_table.R +++ /dev/null @@ -1,28 +0,0 @@ -#' Prepare subtable for metric based risk assessment main table -#' -#' @param riskmetric_assessment object coming from rismetric::pkg_assess function -#' @keywords internal -prepare_namespace_table <- function(riskmetric_assessment) { - namespace_vector <- riskmetric_assessment$export_help[sort(riskmetric_assessment$exported_namespace)] - namespace_table <- data.frame(object = names(namespace_vector), value = namespace_vector) - rownames(namespace_table) <- NULL - namespace_table |> - reactable::reactable( - columns = list( - value = reactable::colDef( - cell = function(value) { - # Please to update icons search for unicodes here: https://icons.getbootstrap.com/ - if (isTRUE(value)) { - # Green checkmark - htmltools::tags$i(class = "bi bi-check-square", style = "background-color: var(--bs-success); font-weight: bold;") - } else { - # Red cross - htmltools::tags$i(class = "bi bi-x", style = "color: var(--bs-danger); font-weight: bold;") - } - }, - align = "center" - ) - ), - class = "metrics-table" - ) -} diff --git a/R/render_utils.R b/R/render_utils.R deleted file mode 100644 index 639927f..0000000 --- a/R/render_utils.R +++ /dev/null @@ -1,90 +0,0 @@ -#' analyze license output from risk assessment to display in cards -#' -#' @param assessment object returning from riskmetric assessment, it can also be data.frame from val.report::assessment -#' @return list with main card license string and footer if available -#' @details The function analyzes if the license is standard. If it is standard, then it will see if there is available -#' information for the footer. The footer information is only the multiple version number for the moment. -#' @keywords internal -#' @importFrom utils getFromNamespace -extract_license <- function(assessment) { - license_output <- list(main = as.character(assessment$license)) - # We use the internal version so that we can use old R versions analyze_license - if (getRversion() < "4.4.0") { - analyze_license <- utils::getFromNamespace("tools", "analyze_license") # nolint - } else { - analyze_license <- getExportedValue("tools", "analyze_license") - } - license_analysis <- analyze_license(license_output$main) - - if (isTRUE(license_analysis$is_standardizable)) { - license_output$main <- sub("\\(.+\\)", "", license_analysis$components[1]) - if (grepl("\\(.+\\)",license_analysis$components[1])) { - license_output$footer <- sub("^.+\\((.+)\\)", "\\1", license_analysis$components[1]) - } - - if (length(license_analysis$components) > 1) { - license_output$footer <- paste( - c(license_output$footer, - license_analysis$components[seq(2, length(license_analysis$components))]) - , collapse = "|") - } - } - license_output -} - -#' Create a info card for the report -#' -#' @importFrom htmltools div -#' @param title text to include in the card title -#' @param header text or html content to be included in the card header -#' @param text content to be included as class card text -#' @param extra_class whether to add additional class for the card div in order to modify style -#' @details check https://getbootstrap.com/docs/5.0/components/card/ for class names and card content -#' To style the card, assign a custom class and style the card within the quarto theme -#' @keywords internal -create_info_card <- function(title, header = NULL, text = NULL, extra_class = NULL) { - header_div <- if (!is.null(header)) div(header, class = "card-header") else header - text_div <- if (!is.null(text)) div(text, class = "card-text") else text - div( - class = paste("card", extra_class), - header_div, - htmltools::h3(title, class = "card-title"), - text_div - ) -} - -create_metrics_cards <- function(assessment_info) { - license_card_values <- extract_license(assessment_info) - div( - class = "info-card", - div( - class = "top-card", - create_info_card( - title = assessment_info$downloads_1yr, - # check for icon shapes here: https://icons.getbootstrap.com/ - header = htmltools::tagList(htmltools::tags$i(class = "bi bi-download"), htmltools::p("1 year")), - text = "Downloads", - extra_class = "top-left-card" - ), - div( - class = "top-right-card", - create_info_card(title = assessment_info$reverse_dependencies, header = "Reverse Dependencies", extra_class = "left-card"), - create_info_card(title = license_card_values$main, header = "License", text = license_card_values$footer, extra_class = "right-card") - ) - ), - create_info_card(title = assessment_info$origin, header = "Origin", extra_class = "bottom-card") - ) -} - -#' Return the Docker Image name to be printed on the report -#' -#' @keywords internal -get_image_name <- function(params) { - default_image <- "rhub/ref-image" - image <- Sys.getenv("DOCKER_IMAGE", unset = NA) - - if (is_empty(image) && !is_empty(params$image)) { - image <- params$image - } else if (is_empty(image)) image <- default_image - image -} diff --git a/R/reporter.R b/R/reporter.R index 73e26ad..32d6dfa 100644 --- a/R/reporter.R +++ b/R/reporter.R @@ -1,13 +1,42 @@ #' Generates an R Validation Hub package report #' +#' @details +#' This function uses a pre-built `quarto` extension which provides its own +#' template document. To replace the existing template with your own without +#' further changes, ensure that your template exposes the same parameters. +#' Custom templates likely want to begin as a copy of the original report. +#' +#' @param package A package name, source code file path, url or path to an +#' `Rds` file of a [val.meter::pkg] object . For details on accepted inputs, +#' see [val.meter::pkg]. +#' @param session A `list` of session information or a path to an `Rds` of a +#' [val.report::session] object. If `NULL`, the session informatino will be +#' derived when the package metrics are calculated. Will error if only one +#' of `package` or `session` is provided as a `Rds` file. +#' @param options Additional options to use when deriving package metrics. By +#' default, inherits any `val.*` options as well as a select few global +#' environment variables. +#' @param template A `quarto` template file to use. See details for more +#' information. +#' @param output_dir `character(1L)` directory path in which rendered files +#' should be generated. Defaults to the current working directory. +#' @param quiet `logical(1L)` flag indicating whether output should be emitted +#' to the console when rendering the report. +#' @param ... Additional arguments passed to [quarto::quarto_render()] +#' #' @examples +#' \dontrun{ #' options( +#' width = 80L, #' val.meter.logs = TRUE, #' val.meter.policy = val.meter::policy(permissions = TRUE) #' ) #' #' package_report(package = "path/to/package") +#' } #' +#' @importFrom quarto quarto_version quarto_render +#' @importFrom callr r #' @export package_report <- function( package = NULL, @@ -18,6 +47,9 @@ package_report <- function( quiet = FALSE, ... ) { + # used for side effect of emitting errors when quarto is not available + quarto::quarto_version() + # temp dir for report output quarto_out_dir <- tempfile("val_report_") dir.create(quarto_out_dir) @@ -73,6 +105,7 @@ package_report <- function( ) } +#' @importFrom tools file_ext rename_quarto_outputs <- function(input_dir, output_dir, output_stem) { files <- list.files(input_dir, full.names = TRUE) @@ -90,9 +123,12 @@ rename_quarto_outputs <- function(input_dir, output_dir, output_stem) { files } +#' @importFrom S7 convert +#' @importFrom val.meter pkg metrics callr_val_package <- function(package, options, artifacts_dir, quiet) { - library(S7) - library(val.meter) + requireNamespace("S7") + requireNamespace("val.meter") + requireNamespace("val.report") # pass through configured options options(options) @@ -121,11 +157,3 @@ val_options <- function(prefix = "val.", plus = character(0L)) { opts <- options() append(opts[startsWith(names(opts), prefix)], opts[plus]) } - -is_rds_path <- function(x) { - is.character(x) && file.exists(x) && endsWith(x, ".Rds") -} - -is_empty <- function(x) { - is.null(x) || is.na(x) || !nzchar(x) -} diff --git a/R/riskmetric.R b/R/riskmetric.R deleted file mode 100644 index 7a2f13f..0000000 --- a/R/riskmetric.R +++ /dev/null @@ -1,147 +0,0 @@ - - -#' Create a -#' -#' Vectorize assessment to be able to add it to a report for a package or the PACKAGES file. -#' -#' @param assessment An object created by `pkg_assess()` (`list_of_pkg_metric`) -#' @return A data.frame with simplified objects but no scoring of the assessment. -#' @export -#' -assessment <- function(assessment) { - stopifnot("Input is not from riskmetric::pkg_assess()"= is(assessment, "list_of_pkg_metric")) - - len <- lengths(assessment) - - out <- as.list(assessment) - - covr_coverage <- out[["covr_coverage"]] - if (length(covr_coverage) > 1) { - covr_coverage <- covr_coverage[["totalcoverage"]] - } - - out[["covr_coverage"]] <- covr_coverage - out[["exported_namespace"]] <- risk_error(out[["exported_namespace"]], length(assessment[["exported_namespace"]])) - out[["export_help"]] <- risk_error(out[["export_help"]], length(assessment[["export_help"]])) - out[["has_website"]] <- risk_error(out[["has_website"]], as.logical(length(assessment[["has_website"]]))) - out[["bugs_status"]] <- risk_error(out[["bugs_status"]], sum(assessment[["bugs_status"]])/length(assessment[["bugs_status"]])) - out[["reverse_dependencies"]] <- risk_error(out[["reverse_dependencies"]], length(assessment[["reverse_dependencies"]])) - out[["has_examples"]] <- risk_error(out[["has_examples"]], sum(assessment[["has_examples"]])/length(assessment[["has_examples"]])) - out[["dependencies"]] <- risk_error(out[["dependencies"]], nrow(assessment[["dependencies"]])) - l <- lengths(out) - - if (any(l) > 1) { - out[l > 1] <- lapply(l[l > 1], risk_error) - } - - if (any(lengths(out)>0)) { - big <- names(out)[lengths(out)>0] - warning(paste(big, collapse = ", "), ": cannot be summarized yet") - out <- out[lengths(out) == 1] - } - list2DF(out) -} - -#' Checks if it is a riskmetric error or not. -#' -#' Provide information whether the object metric is an error or not. -#' @param x An object -#' @returns A logical value: if it is not a riskmetric metric it returns `NA`, but normally `TRUE` or `FALSE`. -#' -#' @export -#' @examples -#' is_risk_error(1) -is_risk_error <- function(x) { - x <- tryCatch(x, error = identity) - if (is(x, "simpleError")) { - FALSE - } else if (inherits(x, "pkg_metric")) { - inherits(x, "pkg_metric_error") || inherits(x, "error") - } else { - NA - } -} - -risk_error <- function(output, y) { - if (is.null(output)) { - return(NULL) - } - if (is(output, "pkg_metric_error")) { - return(output$message) - } - y -} - -is_logical <- function(x) { - if (x == 1 || isTRUE(x)) { - "Yes" - } else { - x - } -} - -#' Replace 0 or FALSE by no in the summary table -#' @keywords internal -replace_zero_or_false_by_no <- function(value) { - if (value == 0 || isFALSE(value)) { - "No" - } else { - value - } -} - - -simple_cap <- function(x) { - s <- toupper(substr(x, 1, 1)) - paste0(s, substring(x, 2)) -} - -#' Summary table -#' -#' @param risk The output of `assessment()`. -#' -#' @returns A data.frame with the two columns one for the fields and one for the values. -#' @export -summary_table <- function(risk) { - # excluded columns do not need to be analyzed by `is_logical`` to display information on the summary table - # for example, has_examples could go to 1 and be transformed (wrongly) to "Yes" - excluded_columns <- c("has_examples", "bug_status") - for (column in setdiff(colnames(risk), excluded_columns)) { - risk[,column] <- is_logical(risk[, column]) - } - - columns_to_add_no <- c("has_news", "has_vignettes", "has_website", "has_bug_reports_url", "news_current") |> - intersect(colnames(risk)) - for (column in columns_to_add_no) risk[,column] <- replace_zero_or_false_by_no(risk[, column]) - - - if(is.numeric(risk$has_examples)) risk$has_examples <- sprintf("%.2f%%", risk$has_examples*100) - if(is.numeric(risk$bugs_status)) risk$bugs_status <- sprintf("%.2f%% closed", risk$bugs_status*100) - - # We change to numeric because it is a list with different elements we only use the numeric value - if(!is.null(risk$size_codebase)) risk$size_codebase <- as.numeric(risk$size_codebase) - if (risk$has_vignettes > 0) { - risk$has_vignettes <- "Yes" - } - transposed_risk <- t(risk) - - # Reorder by - fields <- rownames(transposed_risk) - important_fields <- c("has_news", "exported_namespace", "license", "has_vignettes", "export_help", - "has_website", "has_maintainer", "bugs_status", "size_codebase", - "has_bug_reports_url", "has_examples", "dependencies", "reverse_dependencies") - # fields in report cards are duplicated and should be removed - fields_in_cards <- c("downloads_1yr", "reverse_dependencies", "license") - - transposed_risk <- transposed_risk[c(intersect(important_fields, fields), - setdiff(fields, important_fields)) |> - setdiff(fields_in_cards), ,drop = FALSE] - - - transformed_risk <- simple_cap(gsub("_", " ", rownames(transposed_risk), fixed = TRUE)) - summary_data <- as.data.frame(transposed_risk) - summary_data <- cbind(Section = transformed_risk, Values = summary_data) - colnames(summary_data) <- c("Section", "Values") - rownames(summary_data) <- NULL - summary_data -} diff --git a/R/utils_knitr.R b/R/utils-knitr.R similarity index 100% rename from R/utils_knitr.R rename to R/utils-knitr.R diff --git a/R/utils.R b/R/utils.R index 445bb64..ca89232 100644 --- a/R/utils.R +++ b/R/utils.R @@ -1,62 +1,7 @@ -include_exclude_from <- function(from, include = NULL, exclude = NULL) { - if (!is.null(include) && !is.null(exclude)) { - names <- setdiff(include, exclude) - } else if (is.null(exclude) && !is.null(include)) { - names <- include - } else if (is.null(exclude) && is.null(include)) { - names <- from - } else if (is.null(include) && !is.null(exclude)) { - names <- setdiff(from, exclude) - } - names -} - - -fill_in <- function(list, names) { - missing_names <- setdiff(names(list), names) - list[missing_names] <- NA - list -} - -`%||%` <- function (x, y) { +`%||%` <- function(x, y) { if (is.null(x)) y else x } -output_dir <- function() { - getOption("valreport_output_dir", - default = Sys.getenv("VALREPORT_OUTPUT_DIR", - unset = getwd() - ) - ) -} - -rendering_dir <- function() { - opt <- getOption("valreport_rendering_dir", default = NULL) - env <- Sys.getenv("VALREPORT_RENDERING_DIR", unset = tempdir()) - - opt %||% env -} - -is_empty <- function(x) { - is.null(x) || is.na(x) || !nzchar(x) -} - - -is.empty <- function(x) { - is.null(x) || is.na(x) || !nzchar(x) -} - -#' Return string to display Origin depending on source of the assessment -#' -#' @param source return value of function `pkg_ref` -#' @returns depending on source transformed string for the origin -#' @keywords internal -#' @details Please check `riskmetric::pkg_ref_class_hierarchy` and `riskmetric::pkg_ref` code -#' to see the allowed values and structure -get_pkg_origin <- function(source) { - pkg_ref_classes <- getNamespace("riskmetric")[["pkg_ref_class_hierarchy"]] - source_values <- unlist(pkg_ref_classes) - report_source_values <- c("Missing Origin", "Source Package", "Internal Package", "CRAN", "Bioconductor", "Github") - names(report_source_values) <- source_values - report_source_values[source] +is_rds_path <- function(x) { + is.character(x) && file.exists(x) && endsWith(x, ".Rds") } diff --git a/R/riskreports-package.R b/R/val-report-package.R similarity index 100% rename from R/riskreports-package.R rename to R/val-report-package.R diff --git a/man/assessment.Rd b/man/assessment.Rd deleted file mode 100644 index a836843..0000000 --- a/man/assessment.Rd +++ /dev/null @@ -1,17 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/riskmetric.R -\name{assessment} -\alias{assessment} -\title{Create a} -\usage{ -assessment(assessment) -} -\arguments{ -\item{assessment}{An object created by \code{pkg_assess()} (\code{list_of_pkg_metric})} -} -\value{ -A data.frame with simplified objects but no scoring of the assessment. -} -\description{ -Vectorize assessment to be able to add it to a report for a package or the PACKAGES file. -} diff --git a/man/check_reporter.Rd b/man/check_reporter.Rd deleted file mode 100644 index 552d30c..0000000 --- a/man/check_reporter.Rd +++ /dev/null @@ -1,25 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/check.R -\name{check_reporter} -\alias{check_reporter} -\title{Reports check results} -\usage{ -check_reporter(path) -} -\arguments{ -\item{path}{Path to check results folder (aka \code{pkgname.Rcheck}).} -} -\value{ -A base report -} -\description{ -Experimental function to use the default log to create a report. -} -\examples{ -# Requires the package to be installed (or be in inst/ folder) -# check_reporter("checks/riskmetric.Rcheck") - -} -\seealso{ -\code{\link[tools:check_packages_in_dir]{tools::check_packages_in_dir()}} -} diff --git a/man/create_info_card.Rd b/man/create_info_card.Rd deleted file mode 100644 index fab75f2..0000000 --- a/man/create_info_card.Rd +++ /dev/null @@ -1,25 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/render_utils.R -\name{create_info_card} -\alias{create_info_card} -\title{Create a info card for the report} -\usage{ -create_info_card(title, header = NULL, text = NULL, extra_class = NULL) -} -\arguments{ -\item{title}{text to include in the card title} - -\item{header}{text or html content to be included in the card header} - -\item{text}{content to be included as class card text} - -\item{extra_class}{whether to add additional class for the card div in order to modify style} -} -\description{ -Create a info card for the report -} -\details{ -check https://getbootstrap.com/docs/5.0/components/card/ for class names and card content -To style the card, assign a custom class and style the card within the quarto theme -} -\keyword{internal} diff --git a/man/environ_report.Rd b/man/environ_report.Rd deleted file mode 100644 index 5a278b5..0000000 --- a/man/environ_report.Rd +++ /dev/null @@ -1,22 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/check.R -\name{environ_report} -\alias{environ_report} -\title{Export environmental variables} -\usage{ -environ_report(show = NULL, exclude = NULL) -} -\arguments{ -\item{show}{Character vector of environmental variables to show.} - -\item{exclude}{Character vector of environmental variables to hide.} -} -\value{ -A character vector with environmental variables. -} -\description{ -Export environmental variables -} -\examples{ -environ_report() -} diff --git a/man/extract_license.Rd b/man/extract_license.Rd deleted file mode 100644 index 90df4dc..0000000 --- a/man/extract_license.Rd +++ /dev/null @@ -1,22 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/render_utils.R -\name{extract_license} -\alias{extract_license} -\title{analyze license output from risk assessment to display in cards} -\usage{ -extract_license(assessment) -} -\arguments{ -\item{assessment}{object returning from riskmetric assessment, it can also be data.frame from val.report::assessment} -} -\value{ -list with main card license string and footer if available -} -\description{ -analyze license output from risk assessment to display in cards -} -\details{ -The function analyzes if the license is standard. If it is standard, then it will see if there is available -information for the footer. The footer information is only the multiple version number for the moment. -} -\keyword{internal} diff --git a/man/get_image_name.Rd b/man/get_image_name.Rd deleted file mode 100644 index 2bbd8f0..0000000 --- a/man/get_image_name.Rd +++ /dev/null @@ -1,12 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/render_utils.R -\name{get_image_name} -\alias{get_image_name} -\title{Return the Docker Image name to be printed on the report} -\usage{ -get_image_name(params) -} -\description{ -Return the Docker Image name to be printed on the report -} -\keyword{internal} diff --git a/man/get_pkg_origin.Rd b/man/get_pkg_origin.Rd deleted file mode 100644 index 7002bd8..0000000 --- a/man/get_pkg_origin.Rd +++ /dev/null @@ -1,22 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/utils.R -\name{get_pkg_origin} -\alias{get_pkg_origin} -\title{Return string to display Origin depending on source of the assessment} -\usage{ -get_pkg_origin(source) -} -\arguments{ -\item{source}{return value of function \code{pkg_ref}} -} -\value{ -depending on source transformed string for the origin -} -\description{ -Return string to display Origin depending on source of the assessment -} -\details{ -Please check \code{riskmetric::pkg_ref_class_hierarchy} and \code{riskmetric::pkg_ref} code -to see the allowed values and structure -} -\keyword{internal} diff --git a/man/is_risk_error.Rd b/man/is_risk_error.Rd deleted file mode 100644 index 9c1d765..0000000 --- a/man/is_risk_error.Rd +++ /dev/null @@ -1,20 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/riskmetric.R -\name{is_risk_error} -\alias{is_risk_error} -\title{Checks if it is a riskmetric error or not.} -\usage{ -is_risk_error(x) -} -\arguments{ -\item{x}{An object} -} -\value{ -A logical value: if it is not a riskmetric metric it returns \code{NA}, but normally \code{TRUE} or \code{FALSE}. -} -\description{ -Provide information whether the object metric is an error or not. -} -\examples{ -is_risk_error(1) -} diff --git a/man/knit_print.knitr_log.Rd b/man/knit_print.knitr_log.Rd index 56ba133..329369f 100644 --- a/man/knit_print.knitr_log.Rd +++ b/man/knit_print.knitr_log.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/utils_knitr.R +% Please edit documentation in R/utils-knitr.R \name{knit_print.knitr_log} \alias{knit_print.knitr_log} \title{Special handler for emitting knitr logs} diff --git a/man/knitr_logger.Rd b/man/knitr_logger.Rd index b66b463..d503cb2 100644 --- a/man/knitr_logger.Rd +++ b/man/knitr_logger.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/utils_knitr.R +% Please edit documentation in R/utils-knitr.R \name{knitr_logger} \alias{knitr_logger} \title{Create a knitr log function} diff --git a/man/knitr_logger_styles.Rd b/man/knitr_logger_styles.Rd index 9859a8d..04dbfad 100644 --- a/man/knitr_logger_styles.Rd +++ b/man/knitr_logger_styles.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/utils_knitr.R +% Please edit documentation in R/utils-knitr.R \docType{data} \name{knitr_logger_styles} \alias{knitr_logger_styles} diff --git a/man/knitr_mutable_header.Rd b/man/knitr_mutable_header.Rd index 6e0bda8..c0f565a 100644 --- a/man/knitr_mutable_header.Rd +++ b/man/knitr_mutable_header.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/utils_knitr.R +% Please edit documentation in R/utils-knitr.R \name{knitr_mutable_header} \alias{knitr_mutable_header} \title{Create mutable header object} diff --git a/man/knitr_update_options.Rd b/man/knitr_update_options.Rd index e0ca853..56b43e7 100644 --- a/man/knitr_update_options.Rd +++ b/man/knitr_update_options.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/utils_knitr.R +% Please edit documentation in R/utils-knitr.R \name{knitr_update_options} \alias{knitr_update_options} \title{Handler for complex option passing through from a quarto parameter} diff --git a/man/options_report.Rd b/man/options_report.Rd deleted file mode 100644 index 73dcf61..0000000 --- a/man/options_report.Rd +++ /dev/null @@ -1,22 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/check.R -\name{options_report} -\alias{options_report} -\title{Export options} -\usage{ -options_report(show = NULL, exclude = NULL) -} -\arguments{ -\item{show}{Character vector of options to show.} - -\item{exclude}{Character vector of options variables to hide.} -} -\value{ -A list with the options -} -\description{ -Export options -} -\examples{ -options_report() -} diff --git a/man/package_report.Rd b/man/package_report.Rd index 64799eb..6620bcc 100644 --- a/man/package_report.Rd +++ b/man/package_report.Rd @@ -10,18 +10,53 @@ package_report( options = val_options(plus = c("width")), template = system.file("report", "template.qmd", package = "val.report"), output_dir = getwd(), + quiet = FALSE, ... ) } +\arguments{ +\item{package}{A package name, source code file path, url or path to an +\code{Rds} file of a \link[val.meter:pkg]{val.meter::pkg} object . For details on accepted inputs, +see \link[val.meter:pkg]{val.meter::pkg}.} + +\item{session}{A \code{list} of session information or a path to an \code{Rds} of a +\link{session} object. If \code{NULL}, the session informatino will be +derived when the package metrics are calculated. Will error if only one +of \code{package} or \code{session} is provided as a \code{Rds} file.} + +\item{options}{Additional options to use when deriving package metrics. By +default, inherits any \verb{val.*} options as well as a select few global +environment variables.} + +\item{template}{A \code{quarto} template file to use. See details for more +information.} + +\item{output_dir}{\code{character(1L)} directory path in which rendered files +should be generated. Defaults to the current working directory.} + +\item{quiet}{\code{logical(1L)} flag indicating whether output should be emitted +to the console when rendering the report.} + +\item{...}{Additional arguments passed to \code{\link[quarto:quarto_render]{quarto::quarto_render()}}} +} \description{ Generates an R Validation Hub package report } +\details{ +This function uses a pre-built \code{quarto} extension which provides its own +template document. To replace the existing template with your own without +further changes, ensure that your template exposes the same parameters. +Custom templates likely want to begin as a copy of the original report. +} \examples{ +\dontrun{ options( + width = 80L, val.meter.logs = TRUE, val.meter.policy = val.meter::policy(permissions = TRUE) ) package_report(package = "path/to/package") +} } diff --git a/man/prepare_namespace_table.Rd b/man/prepare_namespace_table.Rd deleted file mode 100644 index 8a77031..0000000 --- a/man/prepare_namespace_table.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/render_table.R -\name{prepare_namespace_table} -\alias{prepare_namespace_table} -\title{Prepare subtable for metric based risk assessment main table} -\usage{ -prepare_namespace_table(riskmetric_assessment) -} -\arguments{ -\item{riskmetric_assessment}{object coming from rismetric::pkg_assess function} -} -\description{ -Prepare subtable for metric based risk assessment main table -} -\keyword{internal} diff --git a/man/replace_zero_or_false_by_no.Rd b/man/replace_zero_or_false_by_no.Rd deleted file mode 100644 index 3af22d9..0000000 --- a/man/replace_zero_or_false_by_no.Rd +++ /dev/null @@ -1,12 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/riskmetric.R -\name{replace_zero_or_false_by_no} -\alias{replace_zero_or_false_by_no} -\title{Replace 0 or FALSE by no in the summary table} -\usage{ -replace_zero_or_false_by_no(value) -} -\description{ -Replace 0 or FALSE by no in the summary table -} -\keyword{internal} diff --git a/man/summary_table.Rd b/man/summary_table.Rd deleted file mode 100644 index 08c4020..0000000 --- a/man/summary_table.Rd +++ /dev/null @@ -1,17 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/riskmetric.R -\name{summary_table} -\alias{summary_table} -\title{Summary table} -\usage{ -summary_table(risk) -} -\arguments{ -\item{risk}{The output of \code{assessment()}.} -} -\value{ -A data.frame with the two columns one for the fields and one for the values. -} -\description{ -Summary table -} diff --git a/man/val.report-package.Rd b/man/val.report-package.Rd index 56dea6d..c42622a 100644 --- a/man/val.report-package.Rd +++ b/man/val.report-package.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/riskreports-package.R +% Please edit documentation in R/val-report-package.R \docType{package} \name{val.report-package} \alias{val.report} diff --git a/tests/testthat/_snaps/card.md b/tests/testthat/_snaps/card.md deleted file mode 100644 index ab4e274..0000000 --- a/tests/testthat/_snaps/card.md +++ /dev/null @@ -1,30 +0,0 @@ -# Card is created with the expected components depending on arguments / only has title if no other argument is set - - Code - create_info_card("test title") - Output -
-

test title

-
- -# Card is created with the expected components depending on arguments / has title and header - - Code - create_info_card(title = "test title", header = "Information header") - Output -
-
Information header
-

test title

-
- -# Card is created with the expected components depending on arguments / has all arguments set - - Code - create_info_card(title = "test title", header = "Information header", text = "Extra test") - Output -
-
Information header
-

test title

-
Extra test
-
- diff --git a/tests/testthat/fixtures/test.pkg/DESCRIPTION b/tests/testthat/fixtures/test.pkg/DESCRIPTION new file mode 100644 index 0000000..95e7ea5 --- /dev/null +++ b/tests/testthat/fixtures/test.pkg/DESCRIPTION @@ -0,0 +1,14 @@ +Package: test.pkg +Title: What the Package Does (One Line, Title Case) +Version: 0.0.0.9000 +Authors@R: + person("First", "Last", , "first.last@example.com", role = c("aut", "cre")) +Description: What the package does (one paragraph). +License: `use_mit_license()`, `use_gpl3_license()` or friends to pick a + license +Encoding: UTF-8 +Roxygen: list(markdown = TRUE) +RoxygenNote: 7.3.3 +Suggests: + testthat (>= 3.0.0) +Config/testthat/edition: 3 diff --git a/tests/testthat/fixtures/test.pkg/NAMESPACE b/tests/testthat/fixtures/test.pkg/NAMESPACE new file mode 100644 index 0000000..01843dc --- /dev/null +++ b/tests/testthat/fixtures/test.pkg/NAMESPACE @@ -0,0 +1,3 @@ +# Generated by roxygen2: do not edit by hand + +export(hello) diff --git a/tests/testthat/fixtures/test.pkg/R/hello.R b/tests/testthat/fixtures/test.pkg/R/hello.R new file mode 100644 index 0000000..680bf6f --- /dev/null +++ b/tests/testthat/fixtures/test.pkg/R/hello.R @@ -0,0 +1,9 @@ +#' Hello +#' +#' @param who Who to say hello to +#' @returns A character value with a greeting +#' +#' @export +hello <- function(who = "world") { + paste0("Hello, ", who, "!") +} diff --git a/tests/testthat/fixtures/test.pkg/man/hello.Rd b/tests/testthat/fixtures/test.pkg/man/hello.Rd new file mode 100644 index 0000000..e2c11fe --- /dev/null +++ b/tests/testthat/fixtures/test.pkg/man/hello.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/hello.R +\name{hello} +\alias{hello} +\title{Hello} +\usage{ +hello(who = "world") +} +\arguments{ +\item{who}{Who to say hello to} +} +\value{ +A character value with a greeting +} +\description{ +Hello +} diff --git a/tests/testthat/fixtures/test.pkg/tests/testthat.R b/tests/testthat/fixtures/test.pkg/tests/testthat.R new file mode 100644 index 0000000..6c2586a --- /dev/null +++ b/tests/testthat/fixtures/test.pkg/tests/testthat.R @@ -0,0 +1,12 @@ +# This file is part of the standard setup for testthat. +# It is recommended that you do not modify it. +# +# Where should you do additional test configuration? +# Learn more about the roles of various files in: +# * https://r-pkgs.org/testing-design.html#sec-tests-files-overview +# * https://testthat.r-lib.org/articles/special-files.html + +library(testthat) +library(test.pkg) + +test_check("test.pkg") diff --git a/tests/testthat/fixtures/test.pkg/tests/testthat/test-hello.R b/tests/testthat/fixtures/test.pkg/tests/testthat/test-hello.R new file mode 100644 index 0000000..4d7d5c6 --- /dev/null +++ b/tests/testthat/fixtures/test.pkg/tests/testthat/test-hello.R @@ -0,0 +1,3 @@ +test_that("hello works", { + expect_equal(hello("friend"), "Hello, friend!") +}) diff --git a/tests/testthat/test-card.R b/tests/testthat/test-card.R deleted file mode 100644 index c741f5a..0000000 --- a/tests/testthat/test-card.R +++ /dev/null @@ -1,20 +0,0 @@ -describe("Card is created with the expected components depending on arguments", { - it("only has title if no other argument is set", { - expect_snapshot(create_info_card("test title")) - }) - - it("has title and header", { - expect_snapshot(create_info_card( - title = "test title", - header = "Information header" - )) - }) - - it("has all arguments set", { - expect_snapshot(create_info_card( - title = "test title", - header = "Information header", - text = "Extra test" - )) - }) -}) diff --git a/tests/testthat/test-check.R b/tests/testthat/test-check.R deleted file mode 100644 index 05bf004..0000000 --- a/tests/testthat/test-check.R +++ /dev/null @@ -1,5 +0,0 @@ -test_that("multiplication works", { - var <- "R_ARCH" - env <- environ_report(exclude = var) - expect_true(is.na(env[var])) -}) diff --git a/tests/testthat/test-render_table.R b/tests/testthat/test-render_table.R deleted file mode 100644 index 6a00795..0000000 --- a/tests/testthat/test-render_table.R +++ /dev/null @@ -1,7 +0,0 @@ -describe("Namespace table is created", { - example_assessment <- readRDS(system.file("assessments/dplyr.rds", package = "riskreports")) - it("It is created by without error from existing example package assessment", { - testthat::expect_no_error(prepare_namespace_table(example_assessment)) - testthat::expect_snapshot(prepare_namespace_table(example_assessment)) - }) -}) diff --git a/tests/testthat/test-render_utils.R b/tests/testthat/test-render_utils.R deleted file mode 100644 index f23986e..0000000 --- a/tests/testthat/test-render_utils.R +++ /dev/null @@ -1,89 +0,0 @@ -describe("get_image_name returns the expected name depending on the arguments", { - it("image is set on report params", { - # Given - simulated_image <- "r-minimal" - params <- list(image = simulated_image) - - # When - image_name <- get_image_name(params) - - # Then - expect_identical(simulated_image, image_name) - }) - - it ("DOCKER_IMAGE is set then should return the value", { - # Given - simulated_docker_image <- "r-minimal" - - - # When - withr::with_envvar( - new = c("DOCKER_IMAGE" = simulated_docker_image), - code = image_name <- get_image_name(list())) - - # Then - expect_identical(simulated_docker_image, image_name) - }) - - it ("No image is set then returns default value", { - # Given - params <- list() - - # When - image_name <- get_image_name(params) - - # Then - expect_false(is.na(image_name)) - }) -}) - -describe("the license information is correctly processed for the cards", { - it("returns license with empty footer if the license is non standarizable", { - # Given - assessment <- list(license = "random license") - - # When - license_for_card <- extract_license(assessment) - - # Then - expect_true(is.null(license_for_card$footer)) - expect_equal(license_for_card$main, assessment$license) - }) - - it("returns license with footer if the license is standarizable and with multiple version number", { - # Given - assessment <- list(license = "LGPL (>= 2.0, < 3) | Mozilla Public License") - - # When - license_for_card <- extract_license(assessment) - - # Then - expect_false(is.null(license_for_card$footer)) - expect_false(license_for_card$main == assessment$license) - }) - - it("returns license with no footer if provided standardizable license with single version number", { - # Given - assessment <- list(license = "GPL2") - - # When - license_for_card <- extract_license(assessment) - - # Then - expect_true(is.null(license_for_card$footer)) - expect_false(license_for_card$main == assessment$license) - }) - - it("returns license with footer if provided standardizable license with more components", { - # Given - assessment <- list(license = "GPL-2 | file LICENCE") - - # When - license_for_card <- extract_license(assessment) - - # Then - expect_false(is.null(license_for_card$footer)) - expect_false(license_for_card$main == assessment$license) - }) - -}) diff --git a/tests/testthat/test-report.R b/tests/testthat/test-report.R index 0b0121d..428b96a 100644 --- a/tests/testthat/test-report.R +++ b/tests/testthat/test-report.R @@ -1,25 +1,25 @@ describe("Run test for the report", { - tmp_folder <- withr::local_tempdir( - pattern = "report", - tmpdir = tempdir(), - fileext = "", - .local_envir = parent.frame(), - clean = TRUE - ) - withr::local_options("valreport_output_dir" = tmp_folder) - it("should be generated in all formats", { + skip_if(is.null(quarto::quarto_path())) + + output_dir <- tempfile() + dir.create(output_dir) + on.exit(unlink(output_dir, recursive = TRUE)) + + options( + val.meter.logs = TRUE, + val.meter.policy = val.meter::policy(permissions = TRUE) + ) + expect_no_error( - package_report( - package_name = "dplyr", - package_version = "1.1.4", - params = list( - assessment_path = system.file("assessments/dplyr.rds", package = "val.report"), - source = "pkg_install"), - quiet = TRUE, - output_format = "all" - ) - ) - }) + package_report( + package = testthat::test_path("fixtures", "test.pkg"), + quiet = TRUE, + output_dir = output_dir + ) + ) + expect_length(list.files(output_dir, pattern = "\\.html$"), 1L) + expect_length(list.files(output_dir, pattern = "\\.pdf$"), 1L) + }) }) diff --git a/tests/testthat/test-utils-knitr.R b/tests/testthat/test-utils-knitr.R index 2296120..97e6339 100644 --- a/tests/testthat/test-utils-knitr.R +++ b/tests/testthat/test-utils-knitr.R @@ -133,7 +133,7 @@ test_that("knitr_mutable_header can modify yaml frontmatter during runtime", { ) content <- readLines(example_md) - expect_match(paste(content, collapse = "\n"), "^Mutable Title\n===", ) + expect_match(paste(content, collapse = "\n"), "^Example\n===", ) }) test_that("knitr_logger writes to console output", { diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index 1120812..94067fc 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -1,28 +1,6 @@ -test_that("include_exclude_from works", { - from <- c("a", "b") - expect_equal(include_exclude_from(from = from), from) - expect_equal(include_exclude_from(from = from, exclude = "a"), "b") - expect_equal(include_exclude_from(from = from, include = "c"), "c") -}) - -test_that("All riskmetric:::pkg_ref_class_hierarchy have value to display in our report", { - allowed_names <- unlist(riskmetric:::pkg_ref_class_hierarchy) - - expect_true(all(!is.na(sapply(allowed_names, get_pkg_origin)))) -}) - -test_that("is_empty returns TRUE if the argument is withint the expected empty categories", { - expect_true(is_empty(NULL)) - expect_true(is_empty(NA)) - expect_true(is_empty("")) - expect_false(is_empty(letters[1])) -}) - -test_that("replace_zero_or_false_by_no returns 'No' if value is zero ir FALSE", { - value_1 <- FALSE - value_2 <- 0 - - expect_identical("No", replace_zero_or_false_by_no(value_1)) - expect_identical("No", replace_zero_or_false_by_no(value_2)) - expect_identical(TRUE, replace_zero_or_false_by_no(TRUE)) +test_that("is_rds_path checks for existing Rds file", { + f <- tempfile("test", fileext = ".Rds") + expect_false(is_rds_path(f)) + write("test", f) + expect_true(is_rds_path(f)) }) From e77218dce7d52027c06fd6b6305db97f0ecca848 Mon Sep 17 00:00:00 2001 From: dgkf <18220321+dgkf@users.noreply.github.com> Date: Sun, 26 Apr 2026 14:36:21 -0400 Subject: [PATCH 3/6] chore(deps): add remote for val.meter --- DESCRIPTION | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DESCRIPTION b/DESCRIPTION index f644f33..04cdb41 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -28,6 +28,8 @@ Suggests: spelling, testthat (>= 3.0.0), withr (>= 3.0.2) +Remotes: + val.meter=github::pharmaR/val.meter VignetteBuilder: knitr Config/testthat/edition: 3 From c51ce8aabba1fd6cd0adb1a3dfa963af9fd4adf7 Mon Sep 17 00:00:00 2001 From: dgkf <18220321+dgkf@users.noreply.github.com> Date: Sun, 31 May 2026 16:42:01 -0400 Subject: [PATCH 4/6] chore(docs): update with git install instructions --- DESCRIPTION | 1 + R/reporter.R | 31 +++++++++++++++++++---- R/session.R | 2 +- R/utils-knitr.R | 2 +- R/utils.R | 16 ++++++++++++ R/zzz.R | 3 +++ README.Rmd | 58 +++++++++++++++++++++++++----------------- README.md | 59 +++++++++++++++++++++++++------------------ man/knitr_logger.Rd | 2 +- man/package_report.Rd | 4 +-- man/session.Rd | 2 +- 11 files changed, 121 insertions(+), 59 deletions(-) create mode 100644 R/zzz.R diff --git a/DESCRIPTION b/DESCRIPTION index 04cdb41..2b08238 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -36,4 +36,5 @@ Config/testthat/edition: 3 Encoding: UTF-8 Language: en-US Roxygen: list(markdown = TRUE) +Config/roxygen2/version: 8.0.0 RoxygenNote: 7.3.3 diff --git a/R/reporter.R b/R/reporter.R index 32d6dfa..72acf8c 100644 --- a/R/reporter.R +++ b/R/reporter.R @@ -10,7 +10,7 @@ #' `Rds` file of a [val.meter::pkg] object . For details on accepted inputs, #' see [val.meter::pkg]. #' @param session A `list` of session information or a path to an `Rds` of a -#' [val.report::session] object. If `NULL`, the session informatino will be +#' [val.report::session] object. If `NULL`, the session information will be #' derived when the package metrics are calculated. Will error if only one #' of `package` or `session` is provided as a `Rds` file. #' @param options Additional options to use when deriving package metrics. By @@ -42,7 +42,7 @@ package_report <- function( package = NULL, session = NULL, options = val_options(plus = c("width")), - template = system.file("report", "template.qmd", package = "val.report"), + template = NULL, output_dir = getwd(), quiet = FALSE, ... @@ -52,12 +52,29 @@ package_report <- function( # temp dir for report output quarto_out_dir <- tempfile("val_report_") + on.exit(unlink(quarto_out_dir, recursive = TRUE), add = TRUE) dir.create(quarto_out_dir) # temp dir for passing Rds content from subprocess to parent quarto_artifacts_dir <- tempfile("val_artifacts_") + on.exit(unlink(quarto_artifacts_dir, recursive = TRUE), add = TRUE) dir.create(quarto_artifacts_dir) + # if not provided, copy bundled template into temporary directory + if (is.null(template)) { + file.copy( + system.file("report", package = "val.report"), + tempdir(), + recursive = TRUE + ) + + template_dir <- tempfile("val_report_template_") + file.rename(file.path(tempdir(), "report"), template_dir) + on.exit(unlink(template_dir, recursive = TRUE), add = TRUE) + + template <- file.path(template_dir, "template.qmd") + } + # derive metrics for package, write out to Rds if (is_rds_path(package) && !is_rds_path(session)) { stop("package provided as Rds file path, but session was not.") @@ -98,7 +115,7 @@ package_report <- function( obj <- readRDS(package) report_stem <- paste0("val_", obj$name, "_", obj$version) - rename_quarto_outputs( + copy_quarto_outputs( input_dir = quarto_out_dir, output_dir = output_dir, output_stem = report_stem @@ -106,18 +123,22 @@ package_report <- function( } #' @importFrom tools file_ext -rename_quarto_outputs <- function(input_dir, output_dir, output_stem) { +copy_quarto_outputs <- function(input_dir, output_dir, output_stem) { files <- list.files(input_dir, full.names = TRUE) for (i in rev(seq_along(files))) { old_path <- files[[i]] + if (dir.exists(old_path)) { + files[[i]] <- NULL + next + } + new_path <- gsub("\\.", "-", output_stem) new_path <- paste0(new_path, ".", tools::file_ext(old_path)) new_path <- file.path(output_dir, new_path) files[[i]] <- new_path file.copy(old_path, new_path, overwrite = TRUE) - file.remove(old_path) } files diff --git a/R/session.R b/R/session.R index 9894e76..901ccf1 100644 --- a/R/session.R +++ b/R/session.R @@ -1,6 +1,6 @@ #' Collect session information #' -#' Catalogues characteristics of the R session and execution environment. +#' Catalogs characteristics of the R session and execution environment. #' #' @importFrom grDevices grSoftVersion #' @importFrom utils sessionInfo diff --git a/R/utils-knitr.R b/R/utils-knitr.R index 106a67f..724dbb7 100644 --- a/R/utils-knitr.R +++ b/R/utils-knitr.R @@ -205,7 +205,7 @@ knit_print.knitr_log <- local({ #' #' @return A `function` accepting `...` arguments, which will be used for #' printing out to the console while rendering the knitr document. Character -#' values are logged directrly, while any other object is printed as though +#' values are logged directly, while any other object is printed as though #' being printed to the console. To render character values as they would #' be printed, mark them as "AsIs" using [I()]. #' diff --git a/R/utils.R b/R/utils.R index ca89232..052af3f 100644 --- a/R/utils.R +++ b/R/utils.R @@ -5,3 +5,19 @@ is_rds_path <- function(x) { is.character(x) && file.exists(x) && endsWith(x, ".Rds") } + +check_submodules_clone <- function() { + report_dir <- system.file("report", package = "val.report") + if (length(list.files(report_dir)) == 0L) { + stop(paste0( + packageName(), + " `inst/report` directory is empty. \n", + "It looks like you're using a development build that was installed ", + "without cloned git submodules. If you cloned this repository from git, ", + "make sure that you've cloned it using:\n\n", + " git clone --recurse-submodules ... \n\n", + "or update an existing clone using:\n\n", + " git submodule update --init --recursive\n\n" + )) + } +} diff --git a/R/zzz.R b/R/zzz.R new file mode 100644 index 0000000..db98da9 --- /dev/null +++ b/R/zzz.R @@ -0,0 +1,3 @@ +.onLoad <- function(lib, pkg) { + check_submodules_clone() +} diff --git a/README.Rmd b/README.Rmd index d336b96..3eb61b6 100644 --- a/README.Rmd +++ b/README.Rmd @@ -20,43 +20,55 @@ knitr::opts_chunk$set( [![R-CMD-check](https://github.com/pharmaR/val.report/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/pharmaR/val.report/actions/workflows/R-CMD-check.yaml) -The goal of val.report is to documents results of package checks for validation. +_documents package validation checks_ ## Installation -You can install the development version of val.report from [GitHub](https://github.com/) with: +You can install the development version of val.report from +[GitHub](https://github.com/pharmaR/val.report) with: ``` r # install.packages("pak") pak::pak("pharmaR/val.report") ``` -## Example +## Quick Start -This is a basic example which shows you how to solve a common problem: +Generate reports easily -```{r cleanup, echo=FALSE} -unlink("pkgdown/assets/*") -``` - -```{r example} +```{r example, eval=FALSE} library(val.report) -# Specify the folder where the files should go (here for easy access on the website) -options("valreport_output_dir" = "pkgdown/assets") -pr <- package_report( - package_name = "dplyr", - package_version = "1.1.4", - params = list( - assessment_path = system.file("assessments/dplyr.rds", package = "val.report")), - quiet = TRUE # To silence quarto output for readability + +options( + width = 80L, + val.meter.logs = TRUE, + val.meter.policy = val.meter::policy(permissions = TRUE) ) -pr + +package_report("praise") ``` -We first selected were reports should go. -Then we used [{riskmetric}](https://cran.r-project.org/package=riskmetric) data to generate the report for the package. +Because we've given `val.meter` permission to download packages from the +network, passing simply a package name will pull the latest version from +a package repository for evaluation. -Then we can access those files on the website: +If you'd like to be more prescriptive, you can also pass a local source code +directory or package archive (`.tar.gz` or `.zip`). `package_report` accepts +any input that can be converted into a `val.meter::pkg` object. - - [HTML](https://pharmar.github.io/val.report/validation_report_dplyr_v1.1.4.html) - - [markdown](https://pharmar.github.io/val.report/validation_report_dplyr_v1.1.4.md) +> [!NOTE] +> +> We are continuing to add more supported input types. Currently, locally source +> code directories have the best support to cover the most concrete use case. +> We plan to improve support for more user-friendly inputs such as packages by +> name and `.tar.gz` by url. + +## For Developers + +This repository vendors the R Validation Hub quarto template, which is +included as a `git` submodule. Submodules require slightly different syntax +in order to be included. When cloning, be sure to use: + +```sh +git clone --recurse-submodules ... +``` diff --git a/README.md b/README.md index 29ddf9b..502faf1 100644 --- a/README.md +++ b/README.md @@ -10,47 +10,56 @@ coverage](https://codecov.io/gh/pharmaR/val.report/graph/badge.svg)](https://app [![R-CMD-check](https://github.com/pharmaR/val.report/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/pharmaR/val.report/actions/workflows/R-CMD-check.yaml) -The goal of val.report is to documents results of package checks for -validation. +*documents package validation checks* ## Installation You can install the development version of val.report from -[GitHub](https://github.com/) with: +[GitHub](https://github.com/pharmaR/val.report) with: ``` r # install.packages("pak") pak::pak("pharmaR/val.report") ``` -## Example +## Quick Start -This is a basic example which shows you how to solve a common problem: +Generate reports easily ``` r library(val.report) -# Specify the folder where the files should go (here for easy access on the website) -options("valreport_output_dir" = "pkgdown/assets") -pr <- package_report( - package_name = "dplyr", - package_version = "1.1.4", - params = list( - assessment_path = system.file("assessments/dplyr.rds", package = "val.report")), - quiet = TRUE # To silence quarto output for readability + +options( + width = 80L, + val.meter.logs = TRUE, + val.meter.policy = val.meter::policy(permissions = TRUE) ) -#> Warning in package_report(package_name = "dplyr", package_version = "1.1.4", : -#> Please provide the source of the package assessment -pr -#> [1] "pkgdown/assets/validation_report_dplyr_v1.1.4.html" -#> [2] "pkgdown/assets/validation_report_dplyr_v1.1.4.md" -#> [3] "pkgdown/assets/validation_report_dplyr_v1.1.4.pdf" + +package_report("praise") ``` -We first selected were reports should go. Then we used -[{riskmetric}](https://cran.r-project.org/package=riskmetric) data to -generate the report for the package. +Because we’ve given `val.meter` permission to download packages from the +network, passing simply a package name will pull the latest version from +a package repository for evaluation. + +If you’d like to be more prescriptive, you can also pass a local source +code directory or package archive (`.tar.gz` or `.zip`). +`package_report` accepts any input that can be converted into a +`val.meter::pkg` object. -Then we can access those files on the website: +> \[!NOTE\] +> +> We are continuing to add more supported input types. Currently, +> locally source code directories have the best support to cover the +> most concrete use case. We plan to improve support for more +> user-friendly inputs such as packages by name and `.tar.gz` by url. -- [HTML](https://pharmar.github.io/val.report/validation_report_dplyr_v1.1.4.html) -- [markdown](https://pharmar.github.io/val.report/validation_report_dplyr_v1.1.4.md) +## For Developers + +This repository vendors the R Validation Hub quarto template, which is +included as a `git` submodule. Submodules require slightly different +syntax in order to be included. When cloning, be sure to use: + +``` sh +git clone --recurse-submodules ... +``` diff --git a/man/knitr_logger.Rd b/man/knitr_logger.Rd index d503cb2..f56f755 100644 --- a/man/knitr_logger.Rd +++ b/man/knitr_logger.Rd @@ -9,7 +9,7 @@ knitr_logger() \value{ A \code{function} accepting \code{...} arguments, which will be used for printing out to the console while rendering the knitr document. Character -values are logged directrly, while any other object is printed as though +values are logged directly, while any other object is printed as though being printed to the console. To render character values as they would be printed, mark them as "AsIs" using \code{\link[=I]{I()}}. } diff --git a/man/package_report.Rd b/man/package_report.Rd index 6620bcc..6452f9e 100644 --- a/man/package_report.Rd +++ b/man/package_report.Rd @@ -8,7 +8,7 @@ package_report( package = NULL, session = NULL, options = val_options(plus = c("width")), - template = system.file("report", "template.qmd", package = "val.report"), + template = NULL, output_dir = getwd(), quiet = FALSE, ... @@ -20,7 +20,7 @@ package_report( see \link[val.meter:pkg]{val.meter::pkg}.} \item{session}{A \code{list} of session information or a path to an \code{Rds} of a -\link{session} object. If \code{NULL}, the session informatino will be +\link{session} object. If \code{NULL}, the session information will be derived when the package metrics are calculated. Will error if only one of \code{package} or \code{session} is provided as a \code{Rds} file.} diff --git a/man/session.Rd b/man/session.Rd index f0c5b08..4087b94 100644 --- a/man/session.Rd +++ b/man/session.Rd @@ -7,5 +7,5 @@ session() } \description{ -Catalogues characteristics of the R session and execution environment. +Catalogs characteristics of the R session and execution environment. } From 9c1807cc3c4fc39a8552b0e21c06dfdb8bce3133 Mon Sep 17 00:00:00 2001 From: dgkf <18220321+dgkf@users.noreply.github.com> Date: Sun, 31 May 2026 17:52:30 -0400 Subject: [PATCH 5/6] chore(ci): enable submodules for checkout --- .github/workflows/R-CMD-check.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index d7401aa..d1e6f61 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -40,6 +40,8 @@ jobs: steps: - uses: actions/checkout@v4 + with: + submodules: 'true' - uses: r-lib/actions/setup-pandoc@v2 From bcf83953e911612fac2be06086626622d7e1ea45 Mon Sep 17 00:00:00 2001 From: dgkf <18220321+dgkf@users.noreply.github.com> Date: Sun, 31 May 2026 20:33:01 -0400 Subject: [PATCH 6/6] chore(ci): update pkgdown actions --- .github/workflows/pkgdown.yaml | 2 ++ pkgdown/favicon/apple-touch-icon.png | Bin 0 -> 4957 bytes pkgdown/favicon/favicon-96x96.png | Bin 0 -> 2615 bytes pkgdown/favicon/favicon.ico | Bin 0 -> 15086 bytes pkgdown/favicon/favicon.svg | 1 + pkgdown/favicon/site.webmanifest | 21 +++++++++++++++++++ pkgdown/favicon/web-app-manifest-192x192.png | Bin 0 -> 5343 bytes pkgdown/favicon/web-app-manifest-512x512.png | Bin 0 -> 15525 bytes 8 files changed, 24 insertions(+) create mode 100644 pkgdown/favicon/apple-touch-icon.png create mode 100644 pkgdown/favicon/favicon-96x96.png create mode 100644 pkgdown/favicon/favicon.ico create mode 100644 pkgdown/favicon/favicon.svg create mode 100644 pkgdown/favicon/site.webmanifest create mode 100644 pkgdown/favicon/web-app-manifest-192x192.png create mode 100644 pkgdown/favicon/web-app-manifest-512x512.png diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index bfc9f4d..c9a2d1e 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -24,6 +24,8 @@ jobs: contents: write steps: - uses: actions/checkout@v4 + with: + submodules: 'true' - uses: r-lib/actions/setup-pandoc@v2 diff --git a/pkgdown/favicon/apple-touch-icon.png b/pkgdown/favicon/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f17126fdb59d8ef3dddc7aa4c21f2ebea7583b2d GIT binary patch literal 4957 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 MtfN$;@FwDa0FS+*;{X5v literal 0 HcmV?d00001 diff --git a/pkgdown/favicon/favicon-96x96.png b/pkgdown/favicon/favicon-96x96.png new file mode 100644 index 0000000000000000000000000000000000000000..90bb6723495034327763653d702ecf08de47a50a GIT binary patch literal 2615 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 literal 0 HcmV?d00001 diff --git a/pkgdown/favicon/favicon.svg b/pkgdown/favicon/favicon.svg new file mode 100644 index 0000000..c5d0abf --- /dev/null +++ b/pkgdown/favicon/favicon.svg @@ -0,0 +1 @@ +RealFaviconGeneratorhttps://realfavicongenerator.net \ No newline at end of file diff --git a/pkgdown/favicon/site.webmanifest b/pkgdown/favicon/site.webmanifest new file mode 100644 index 0000000..4ebda26 --- /dev/null +++ b/pkgdown/favicon/site.webmanifest @@ -0,0 +1,21 @@ +{ + "name": "", + "short_name": "", + "icons": [ + { + "src": "/web-app-manifest-192x192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "/web-app-manifest-512x512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} \ No newline at end of file diff --git a/pkgdown/favicon/web-app-manifest-192x192.png b/pkgdown/favicon/web-app-manifest-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..deacd8f2b935a2a17fe2e0d665658d895f253656 GIT binary patch literal 5343 zcmc&&_cI(0(?1D`<12)akSNhxlxR^eqSwP|Q9^J|Z+D2^@+GJD=rwwcE?T1Ha9X0D z5-xf@^>BDR^UnJ>JUg?yKYVs}KeIctv$IGYZ50YK1~LEuK%u6psCVnX|5r)x-CDhQ zr~9|=HA2Z40dciOc)$060`#Eoos{2u*;~81s6bty9`6yZ9xU8;2!tD4N>I?_7Pb99 z6!!n9fD07Clb&w4e47jCrur5R0FcxCSBU@_Sx*3fM@njn^7sA#fkd_6A>mjHH%Jk2XOL;H z-)$n7QLe>ZdzO{?uMKRE^SLftBnwICLn;L(%;*hT5=%?CJ2BpgcTzJJ17A>{Y=-oruW@)JB^t^49+G+w&DpKgZfEGFRbh^Hx0niqeZ#pmPWzCqLBfY#O3 zY5KLXm=6TYK)%;CA0k@g3gpA>5k2#b)WP(uKYP=|+7eKH~D?|>6n0Z zEJv_U1obgvV`U`vsSq~P80p=6SNwNfj4&9-{%l3CW9IgHoC&2B;9{mFM19=QsvCa!yFzW!xCbQNha=@8YM$N!xT@(Jl2PHiS)K23b|@r{s2 z`*uVwJZyuLi?nMWzZ?_G9C#7^<3LQrT^2*rGssV$(GM38{dnWJ*4bCI{28OUV^BCE zSiGI_N2tW@D%IKybn$IFB4VC}LBmy>iU|>Ra8Yz6UF^9MIgF>{sB8vLOTOp_mD959 zr?iQj-stRGv^cCYgQq=zypI%llD&anuBjsiSzpq}Q2+LH#$Xeu`(utJfb2>x#fXu_ zR~XgGfMOSznddk2-JrzloRt^BJ?SEs%^mY6g_nsri zy3hlepOiuGAfay4^p4$+wO_LPRPW-LXDa>40*e1l@P+zlCUpHc?F|$ISVxJ6z2{lJvD1^>E2I>a79Yh&*vHnqkCoB>%`ENLmw7C#e_nPP^phaaxACIJ zL%v)+xj<@3>ynfmttanLG=V|wNVdYTB4w2sZ>s2M;%1qGf_cG595{(x&9ED8YG*{&DsE`o&;M(F{fG66pNv28S6gYWHt%XmE>u!~-WZ&2e03dD z2-UiztD+NR?Nc*IdSHCpQ~Q0jU^eP$${Pi8c*U~T;Qc3ouY;z9CF6p=3n@JqIPVDG zq{eLdCk*$RU}*GeS2zCPKJ5flpl&3yi;AcnFxa3>vqIy*IAPzhrk{s{CE#6TFdG@y zCqw!*G_ooH_ICmKdndxE_zc50800K+tynh|XVl6vORw@?P8C?%&p{>@QoPcL$a5x0~qjdjPV?3OC z81h->p~=clw<{n4?evv-4{qdoMSf*&vckSgwVw7WhHT0pT>L<7D^)$tCS|PHJXQgXLy_qQ84H9*rN+^rj);`oVw*z zhL|Kqg#}rmYkIN7z-sFU#w}ZWpvkk8wzX6A-!gIJ3(m#qK}ofA$2#HTIUcciR?ceX z1*oDIllN8aH2o)S_*88BEUrg8l5R8M4dW5pmL&OhL{1gD)T85$q6OobRdmd=8RQ)F zF`tIjdW*I@Q~nt5F4xlcL%dWG)pT>fQc+~pNNcn1gsOG{vPM>ho+QtWFU33w0)mn0 ztd!_+&+-~BE(zb4*`;OSi6DJ5uKpsPM)5`q`1M$Fo`sO%js|UvmZ5#jT&rK!+L-8o zDi&ydaU0f?4OzZ;+*Ez z(*dmPc(&!PUW^yHP+f6iDv^7IbsNf|YsBMT23*Oc)(%C@?qqqs=gA$TXR{oON|%ox z@B0sYfT$W@WHfv*JanTE(r7z#@++{JdY-NmSN3jjzoAuWtRul*al~P&UX>3Z>HYRp zLiVYoeTn|p0kteuq7~R}M~^*(>(C$H^lE0+bl&9YhbMk0+}yTV2o zy)byzC6 zgV=Tpu3Uy`U>|fMmf1zsr4l9RU_|swj3AD^`K%XQGr?rGdIx(%+2mK#YPBku@{5r@ zU;J$IQ;K+v6)e^Qs{J)ug(WbCC)rajI4hCori-=Jw(O9>gifyL`2G<`AUyTX49Bu@ zw9&Q{DQ9Qdza~?1P+9AK%GIdVW{C9Pvq%E#QKutKg2O|xR#o@GXUSxvAHe1S)Z5Yun_AA6n+eXdEYol{}m+NIZZ4=4HT$2SrIdf;& zzxhJ$8TkNZ?V+=deZ3a(POaY6V0l{{^z(`WM4_vjj>gjHuxEsqhYBaKz|G- zjN4Y+lo59DA#iOT*^>zQ$D?I{Dakskd{tj5P`L z^;RcJEY0KpFme8z^VG{nA!t(gY0K5PGzG*y{d(S(fN|ynV9&OeGhHkRXXjo4*Bn>U z+Q$A12gUwnFO&Bd{7-D=a$u|A^80NXlx=m#tesP`ygtouuC!*i;H96F)t@K%t~9Fy z4Yj`j^bbl#9Un|?^?@9CUw3jZI?sDE_jN!`)iak2_%5)R6V&_|P@5;X=#X0v7c=9R zl^#cvrr)ZOyV~vnE8ymE&*`KCz8GE_8?Ac#Y4RO?X9JRY`o4;dO|=$@B?0&no48GT z?k-N_T^3MaEkOHyN4D-!@Q!5NLXsA3Er$el5`CwznQ`*6Eo?j~8kH=O-ZbRPI*Bo@ zBzPZwb66DO2{jqiC4(7?Mrb}dv0{SQ>J{IK&#vLxOd8IS0~-n6sA^G#$Bu7*`PH>) zjfM9`s{96-8U*{xOtT7*jH=2^zA0{ZkP9;T&L6v_T?l+iGg}rLIXIipD zg@FKkRj|3xb7N<^;Ygkd6mgyGo){!pd5pp&r$y>g9>=_aMM(%hJCVx#%BcE!vNhnP z&qU*CQl7m^&PPtZd|C_&SL^5d>=dmJFlZB<;x4hwAe+E&ZI_e>zs@j0RLxJ9-}##i z{$&SbP*>zQ`xba5f=G`3C|FM+1}ZBVuNT`N>O5@1q9|2e>9A*wj(0X;i`?7QC37Z~ zD_&?(^X;Z~7WdFFp>${w-4}*T?tjz;m0>{WekyNB^;4qg2y@c%n?&yKmWUA>Obz@_ zxzSa)eN*Z3JE@dMWoki2Cl~G*-}3@xve)DuWv8GF=t~{_0ilo$BZP8h$7@r}aJhn= zJ+b9#yVP3A+x0KHGg-V0pW|V1#)tFK7By0_6~#lqseIQcT&CW%iA~1$Z-fqA`?g(V z_F$ztx{zLJilp!DpNJFkSjUTPt|rk#B6NP`6kFU9x>12=IW-wx!gUQ;#rR{hQmHRsK&y zIUqZnzL<-BvN>eQW@I#noP?!|*D;&h`62sta^x3iI_%;tYGcmnMey3a@j1mO_j}l1 z=Bej!83H(&wyjb?g`=AmR|nf4e_@+9kA8iUKhcmn6Ph&noZNb<0og#jG6I4Vw){{Q zU!QbMRjM24riW|Sj!4I2mHCX~%V^FBgbYQYlmVJiH%JoF?rMTHNRX!s(QUx4MrNR9 zHWf?bR8jYc0lBeW&Rq|B-X)R&693n7d@VpVM|W#PCrttIC&Nicu_1Y|V3EvpQGT$a~oMReDPUBMEnJ;o*YT zoSV`vBf9g>*wWY6u*D_xn1clxW;JF&HjFgQ(aSkWNl4u z9`?uj`I%n|zI9s~^#2|;sXyUpWXQL3Qd>&ZQYL)E+1hwQ_pQioUY}^yS&7kI-#tDv zTMz_bxhv!R{>gBHz>0~-yC89I#PbP7sv<>lftVz*`GM7^VF&N5L#m}4JjSwYVM5== zaD}cAAMt;!7g(%Bk<2wfG;iH2fluKSBCFDy&*Q^o42IysT2Jx|1nOdV46~th@hmWb zrHu%Q_&=}_{fa8DvxRQUDl|hdeVActVa_a7Ck6Y?-h@TqvZtiPFkyXeKcZj1*N`B+`CU882U~1_ zRO_&;KbpvV5nBjdTpvxj@>7vFMj;`i;vmDUsWxN z0H~>j$`769tRbK3K!aKSvNZ8MnT=#hY{wbO+EiD*UM8e#6t<&+3h`m%|1Mmkl&YCy z890Z|Y#X)iCWwu*b}&f(dLkJz>&WqH$Ng&Kr1)Uk0DD3S;^Of<=utQhds_e0gMxX? zmg2?VNz}gEm0QKK-~_Ed(O7c#YtORxTmCOQmT-lmoZYk^4`Fe(QE#XMXAV?OCFN%d zukP~>d{U?wkFER#1ek=f$_%jcY7#jm@;LT z`%a+u>bHqY^5?@U?@<((ma=Eo4QNxPlF8#^Tb&-K-Pc)&x%NcuI5{Jh6uVvkzAx7h z2ev#PY7agLW4m{e(7yM>O<1zMp8k~hfAc`Qt%?Y~xv$tW1uUtI4gD_(H6?Au>Nl35 F{{cWlGmQWM literal 0 HcmV?d00001 diff --git a/pkgdown/favicon/web-app-manifest-512x512.png b/pkgdown/favicon/web-app-manifest-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..1eff7ef72a0fa78d5612961dd5f120db5ef75d4a GIT binary patch literal 15525 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