Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ Imports:
methods,
htmltools,
quarto (>= 1.4.4),
reactable
reactable,
yaml
Suggests:
knitr,
riskmetric (>= 0.2.4),
rmarkdown,
S7,
spelling,
testthat (>= 3.0.0),
withr (>= 3.0.2)
Expand Down
9 changes: 9 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,19 @@ 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(summary_table)
importFrom(htmltools,div)
importFrom(methods,is)
importFrom(tools,check_packages_in_dir_details)
importFrom(utils,capture.output)
importFrom(utils,getFromNamespace)
importFrom(utils,head)
importFrom(utils,packageName)
importFrom(utils,tail)
importFrom(yaml,yaml.load)
250 changes: 140 additions & 110 deletions R/reporter.R
Original file line number Diff line number Diff line change
Expand Up @@ -2,139 +2,169 @@
#'
#' @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 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
#' @export
#'
#' @details Please include source as part of `params` content. Source is
#' returned after calling function `riskmetric::pkg_ref` before the risk
#' assessment is executed
#'
#' @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"),
#' assessment_path =
#' system.file("assessments/dplyr.rds", package = "val.report"),
#' image = "rhub/ref-image"),
#' quiet = FALSE
#' )
#' pr
#' file.remove(pr)
#'
#' @export
package_report <- function(
package_name,
package_version,
package = NULL,
template_path = system.file("report/package", package = "val.report"),
output_format = "all",
params = list(),
...
package_name,
package_version,
package = NULL,
template_path = system.file("report/package", package = "val.report"),
output_format = "all",
params = list(),
...
) {
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")
} else {
params$package <- package_name
}

full_name <- paste0(package_name, "_v", package_version)
output_file <- paste0("validation_report_", full_name, ".qmd")

params$package_name <- package_name
params$package_version <- package_version
params$image <- get_image_name(params)

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")
}

params$package <- normalizePath(params$package, mustWork = FALSE, winslash = "/")
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")
}

if (is.null(params$source)) warning("Please provide the source of the package assessment")

# 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()
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")
} else {
params$package <- package_name
}

full_name <- paste0(package_name, "_v", package_version)
output_file <- paste0("validation_report_", full_name, ".qmd")

params$package_name <- package_name
params$package_version <- package_version
params$image <- get_image_name(params)

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")
}

params$package <- normalizePath(
params$package,
mustWork = FALSE,
winslash = "/"
)
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")
}

if (is.null(params$source)) {
warning("Please provide the source of the package assessment")
}

# 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)) {
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)

if (any(!fc)) {
stop("Copying to the rendering directory failed.")
}

template_all_files <- list.files(render_dir, full.names = TRUE)
template <- template_all_files[endsWith(template_all_files, "qmd")]

if (length(template) > 1) {
stop("There are more than one template!\n",
"Please have only one quarto file on the directory.")
}

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("<p", top_page_file)
top_page_file[title_line] <- htmltools::p(paste0("Validation Report - ", package_name, "@", package_version)) |>
as.character()
writeLines(top_page_file, file.path(render_dir, "top_page.html"))

pre_rendering <- list.files(render_dir, full.names = TRUE)

suppressMessages({suppressWarnings({
out <- quarto::quarto_render(
input = file_template,
output_format = output_format,
execute_params = params,
...
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
)

if (any(!fc)) {
stop("Copying to the rendering directory failed.")
}

template_all_files <- list.files(render_dir, full.names = TRUE)
template <- template_all_files[endsWith(template_all_files, "qmd")]

if (length(template) > 1) {
stop(
"There are more than one template!\n",
"Please have only one quarto file on the directory."
)
}

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("<p", top_page_file)
top_page_file[title_line] <- htmltools::p(paste0(
"Validation Report - ",
package_name,
"@",
package_version
)) |>
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,
...
)

post_rendering <- list.files(render_dir, full.names = TRUE)
post_rendering <- list.files(render_dir, full.names = TRUE)

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.")
}
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.")
}

output_files <- setdiff(post_rendering, pre_rendering)
invisible(output_files)
output_files <- setdiff(post_rendering, pre_rendering)
invisible(output_files)
}

is.empty <- function(x) {
Expand Down
Loading