From 84af9836831d9355f062223bb76d8005402bc996 Mon Sep 17 00:00:00 2001 From: Philip Chase Date: Wed, 7 Jun 2023 16:06:23 -0400 Subject: [PATCH 1/2] Update render_report.R to support quarto files Add quarto support. Use argparse in render_report.R to provide better error handling. Add argparse package to Dockerfile. Update docs to reflect the new feature. Update example files to reflect a syntax change. --- Dockerfile | 1 + report/render_report.R | 53 ++++++++++++++++----------- study_template/cron/sample_report | 2 +- study_template/report/render_report.R | 46 ++++++++++++++++------- vignettes/custom_rscript.Rmd | 2 +- 5 files changed, 67 insertions(+), 37 deletions(-) diff --git a/Dockerfile b/Dockerfile index 63595a0..c76af9c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,6 +11,7 @@ RUN R -e "install.packages(c( \ 'RCurl', \ 'REDCapR', \ 'RMariaDB', \ + 'argparse', \ 'checkmate', \ 'dbx', \ 'digest', \ diff --git a/report/render_report.R b/report/render_report.R index 2ae113c..643dae0 100644 --- a/report/render_report.R +++ b/report/render_report.R @@ -5,38 +5,49 @@ library(lubridate) library(rmarkdown) library(sendmailR) library(redcapcustodian) +library(argparse) init_etl("render_report") -if (!dir.exists("output")){ - dir.create("output") -} - +parser <- ArgumentParser() +parser$add_argument("script_name", nargs=1, help="Script to be run") if (!interactive()) { - args <- commandArgs(trailingOnly = T) - script_name <- word(args, 2, sep = "=") + args <- parser$parse_args() + script_name <- args$script_name + if(!fs::file_exists(script_name)) { + stop(sprintf("Specified file, %s, does not exist", script_name)) + } } else { - script_name <- "sample_report.Rmd" + script_name <- "dummy.qmd" + stop(sprintf("Specified file, %s, does not exist", script_name)) } report_name <- word(script_name, 1, sep = "\\.") +report_type <- word(script_name, 2, sep = "\\.") script_run_time <- set_script_run_time() +output_file <- + paste0(str_replace(report_name, ".*/", ""), + "_", + format(script_run_time, "%Y%m%d%H%M%S"), + if_else(report_type == "qmd", ".pdf", "") + ) + +if (report_type == "qmd") { + quarto::quarto_render( + script_name, + output_file = output_file, + output_format = "pdf" + ) +} else { + render( + script_name, + output_file = output_file + ) +} -output_file <- here::here( - "output", - paste0(report_name, - "_", - format(script_run_time, "%Y%m%d%H%M%S")) -) - -full_path_to_output_file <- render( - here::here("report", script_name), - output_file = output_file -) - -output_file_extension <- word(full_path_to_output_file, 2 , sep = "\\.") -attachment_object <- mime_part(full_path_to_output_file, basename(full_path_to_output_file)) +output_file_extension <- word(output_file, 2 , sep = "\\.") +attachment_object <- mime_part(output_file, output_file) email_subject <- paste(report_name, "|", script_run_time) body <- "Please see the attached report." diff --git a/study_template/cron/sample_report b/study_template/cron/sample_report index 2bbe5b0..0f40ad7 100644 --- a/study_template/cron/sample_report +++ b/study_template/cron/sample_report @@ -1,2 +1,2 @@ # Run the sample Rmd report -05 8-17 * * * root /usr/bin/docker run --rm --env-file /rcc/study_template/.env rcc.site Rscript report/render_report.R script_name=sample_report.Rmd +05 8-17 * * * root /usr/bin/docker run --rm --env-file /rcc/study_template/.env rcc.site Rscript report/render_report.R report/sample_report.Rmd diff --git a/study_template/report/render_report.R b/study_template/report/render_report.R index 7d0821d..643dae0 100644 --- a/study_template/report/render_report.R +++ b/study_template/report/render_report.R @@ -5,31 +5,49 @@ library(lubridate) library(rmarkdown) library(sendmailR) library(redcapcustodian) +library(argparse) init_etl("render_report") +parser <- ArgumentParser() +parser$add_argument("script_name", nargs=1, help="Script to be run") if (!interactive()) { - args <- commandArgs(trailingOnly = T) - script_name <- word(args, 2, sep = "=") + args <- parser$parse_args() + script_name <- args$script_name + if(!fs::file_exists(script_name)) { + stop(sprintf("Specified file, %s, does not exist", script_name)) + } } else { - script_name <- "sample_report.Rmd" + script_name <- "dummy.qmd" + stop(sprintf("Specified file, %s, does not exist", script_name)) } report_name <- word(script_name, 1, sep = "\\.") +report_type <- word(script_name, 2, sep = "\\.") script_run_time <- set_script_run_time() +output_file <- + paste0(str_replace(report_name, ".*/", ""), + "_", + format(script_run_time, "%Y%m%d%H%M%S"), + if_else(report_type == "qmd", ".pdf", "") + ) + +if (report_type == "qmd") { + quarto::quarto_render( + script_name, + output_file = output_file, + output_format = "pdf" + ) +} else { + render( + script_name, + output_file = output_file + ) +} -output_file = paste0(report_name, - "_", - format(script_run_time, "%Y%m%d%H%M%S")) - -full_path_to_output_file <- render( - paste0("report/", script_name), - output_file = output_file -) - -output_file_extension <- word(full_path_to_output_file, 2 , sep = "\\.") -attachment_object <- mime_part(full_path_to_output_file, paste0(output_file, ".", output_file_extension)) +output_file_extension <- word(output_file, 2 , sep = "\\.") +attachment_object <- mime_part(output_file, output_file) email_subject <- paste(report_name, "|", script_run_time) body <- "Please see the attached report." diff --git a/vignettes/custom_rscript.Rmd b/vignettes/custom_rscript.Rmd index 10e5fc0..6028a2b 100644 --- a/vignettes/custom_rscript.Rmd +++ b/vignettes/custom_rscript.Rmd @@ -194,7 +194,7 @@ Stop and think about architecture and study lifecycle. If you need something to run periodically, you need to make it easy to run with all of its dependencies packaged up and you need to schedule it. The modern way to package dependencies is to put them all into a container, add your application and run the container. REDCap Custodian supports containerization with Docker. The [`./study_template/Dockerfile`](https://github.com/ctsit/redcapcustodian/tree/master/study_template/Dockerfile) is template you can use to containerize your RScript and RMarkdown. Adapt it to your needs and build the container with [./build.sh](https://github.com/ctsit/redcapcustodian/tree/master/build.sh). If you have good container infrastructure, use it to build and deploy your containers. Running automated R Markdown reports from docker requires the use of an Rmd renderer. -[render_report.R](https://github.com/ctsit/redcapcustodian/tree/master/study_template/report/render_report.R) contains functionality to knit an Rmd, email it and then log the job run. The Rmd script name is passed as a command line argument to [render_report.R](https://github.com/ctsit/redcapcustodian/tree/master/study_template/report/render_report.R) via cron. Refer to [sample_report](https://github.com/ctsit/redcapcustodian/tree/master/study_template/cron/sample_report) for an example cron job. +[render_report.R](https://github.com/ctsit/redcapcustodian/tree/master/study_template/report/render_report.R) contains functionality to knit an Rmd or a Qmd, email it and then log the job run. The Rmd/Qmd script name is passed as a command line argument to [render_report.R](https://github.com/ctsit/redcapcustodian/tree/master/study_template/report/render_report.R) via cron. Refer to [sample_report](https://github.com/ctsit/redcapcustodian/tree/master/study_template/cron/sample_report) for an example cron job. ## Automation with Linux and cron From cec0ea3dac3cf9149e54b629da7e46b745cbef6b Mon Sep 17 00:00:00 2001 From: Philip Chase Date: Fri, 16 Jun 2023 09:55:21 -0400 Subject: [PATCH 2/2] Add quarto examples to study template --- study_template/cron/quarto_html_example | 2 ++ study_template/report/quarto_html_example.qmd | 27 +++++++++++++++++++ study_template/report/quarto_pdf_example.qmd | 26 ++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 study_template/cron/quarto_html_example create mode 100644 study_template/report/quarto_html_example.qmd create mode 100644 study_template/report/quarto_pdf_example.qmd diff --git a/study_template/cron/quarto_html_example b/study_template/cron/quarto_html_example new file mode 100644 index 0000000..17ceb05 --- /dev/null +++ b/study_template/cron/quarto_html_example @@ -0,0 +1,2 @@ +# Run the example Quarto report +17 8-17 * * * root /usr/bin/docker run --rm --env-file /rcc/study_template/.env rcc.site Rscript report/render_report.R report/quarto_html_example.qmd diff --git a/study_template/report/quarto_html_example.qmd b/study_template/report/quarto_html_example.qmd new file mode 100644 index 0000000..1a89e4b --- /dev/null +++ b/study_template/report/quarto_html_example.qmd @@ -0,0 +1,27 @@ +--- +title: "Quarto HTML example" +author: "John Doe" +format: html +editor: visual +--- + +## Quarto + +Quarto enables you to weave together content and executable code into a finished document. To learn more about Quarto see . + +## Running Code + +When you click the **Render** button a document will be generated that includes both content and the output of embedded code. You can embed code like this: + +```{r} +1 + 1 +``` + +You can add options to executable code like this + +```{r} +#| echo: false +2 * 2 +``` + +The `echo: false` option disables the printing of code (only output is displayed). diff --git a/study_template/report/quarto_pdf_example.qmd b/study_template/report/quarto_pdf_example.qmd new file mode 100644 index 0000000..cf09dd6 --- /dev/null +++ b/study_template/report/quarto_pdf_example.qmd @@ -0,0 +1,26 @@ +--- +title: "Quarto PDF example" +format: pdf +editor: visual +--- + +## Quarto + +Quarto enables you to weave together content and executable code into a finished document. To learn more about Quarto see . + +## Running Code + +When you click the **Render** button a document will be generated that includes both content and the output of embedded code. You can embed code like this: + +```{r} +1 + 1 +``` + +You can add options to executable code like this + +```{r} +#| echo: false +2 * 2 +``` + +The `echo: false` option disables the printing of code (only output is displayed).