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/.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 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/.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/DESCRIPTION b/DESCRIPTION index cac5fbc..2b08238 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -14,25 +14,27 @@ 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) +Remotes: + val.meter=github::pharmaR/val.meter VignetteBuilder: knitr 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/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 c3efc85..72acf8c 100644 --- a/R/reporter.R +++ b/R/reporter.R @@ -1,172 +1,180 @@ -#' Reports about a package +#' Generates an R Validation Hub package report #' -#' @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()` +#' @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. #' -#' @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 +#' @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 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 +#' 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 -#' 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 +#' \dontrun{ +#' options( +#' width = 80L, +#' val.meter.logs = TRUE, +#' val.meter.policy = val.meter::policy(permissions = TRUE) #' ) -#' pr -#' file.remove(pr) #' +#' package_report(package = "path/to/package") +#' } +#' +#' @importFrom quarto quarto_version quarto_render +#' @importFrom callr r #' @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 = NULL, + 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"] + # 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_") + 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 ) - 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") - } else { - params$package <- package_name + + 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") } - full_name <- paste0(package_name, "_v", package_version) - output_file <- paste0("validation_report_", full_name, ".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.") + } else if (!is.null(session)) { + stop("session provided, but package yet to be computed.") + } else { + 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) + copy_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") - } +#' @importFrom tools file_ext +copy_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\")" - ) + for (i in rev(seq_along(files))) { + old_path <- files[[i]] + if (dir.exists(old_path)) { + files[[i]] <- NULL + next } - } - 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 - ) - if (any(!fc)) { - stop("Copying to the rendering directory failed.") + 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) } - 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." - ) +#' @importFrom S7 convert +#' @importFrom val.meter pkg metrics +callr_val_package <- function(package, options, artifacts_dir, quiet) { + requireNamespace("S7") + requireNamespace("val.meter") + requireNamespace("val.report") + + # 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) - output_files <- setdiff(post_rendering, pre_rendering) - invisible(output_files) + list(package = pkg_file, session = session_file, options = list()) } -is.empty <- function(x) { - is.null(x) || is.na(x) || !nzchar(x) +val_options <- function(prefix = "val.", plus = character(0L)) { + opts <- options() + append(opts[startsWith(names(opts), prefix)], opts[plus]) } 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/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 similarity index 99% rename from R/utils_knitr.R rename to 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 445bb64..052af3f 100644 --- a/R/utils.R +++ b/R/utils.R @@ -1,62 +1,23 @@ -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() - ) - ) +is_rds_path <- function(x) { + is.character(x) && file.exists(x) && endsWith(x, ".Rds") } -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] +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/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/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/inst/assessments/dplyr.rds b/inst/assessments/dplyr.rds deleted file mode 100644 index 275c8f3..0000000 Binary files a/inst/assessments/dplyr.rds and /dev/null differ 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 093cec7..0000000 Binary files a/inst/report/package/r_validation_logo.png and /dev/null differ 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/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..f56f755 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} @@ -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/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 debaf52..6452f9e 100644 --- a/man/package_report.Rd +++ b/man/package_report.Rd @@ -2,58 +2,61 @@ % 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 = NULL, + output_dir = getwd(), + quiet = FALSE, ... ) } \arguments{ -\item{package_name}{Package name.} +\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{package_version}{Package version number.} +\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 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.} -\item{package}{Path where to find a package source to retrieve name and -version number.} +\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_path}{Path to a directory with one quarto template file (and -the files required for rendering it).} +\item{template}{A \code{quarto} template file to use. See details for more +information.} -\item{output_format}{Output format for the report. Default is "all".} +\item{output_dir}{\code{character(1L)} directory path in which rendered files +should be generated. Defaults to the current working directory.} -\item{params}{A list of execute parameters passed to the template} +\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{quarto::quarto_render()}} -} -\value{ -A path to the reports generated, called by its side effects. +\item{...}{Additional arguments passed to \code{\link[quarto:quarto_render]{quarto::quarto_render()}}} } \description{ -Reports about a package +Generates an R Validation Hub package report } \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 +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{ -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 +\dontrun{ +options( + width = 80L, + 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/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/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. } 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/pkgdown/favicon/apple-touch-icon.png b/pkgdown/favicon/apple-touch-icon.png new file mode 100644 index 0000000..f17126f Binary files /dev/null and b/pkgdown/favicon/apple-touch-icon.png differ diff --git a/pkgdown/favicon/favicon-96x96.png b/pkgdown/favicon/favicon-96x96.png new file mode 100644 index 0000000..90bb672 Binary files /dev/null and b/pkgdown/favicon/favicon-96x96.png differ diff --git a/pkgdown/favicon/favicon.ico b/pkgdown/favicon/favicon.ico new file mode 100644 index 0000000..6a77450 Binary files /dev/null and b/pkgdown/favicon/favicon.ico differ 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 0000000..deacd8f Binary files /dev/null and b/pkgdown/favicon/web-app-manifest-192x192.png differ diff --git a/pkgdown/favicon/web-app-manifest-512x512.png b/pkgdown/favicon/web-app-manifest-512x512.png new file mode 100644 index 0000000..1eff7ef Binary files /dev/null and b/pkgdown/favicon/web-app-manifest-512x512.png differ 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/_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/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)) }) 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