Skip to content
Merged
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: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: reportifyr
Title: Reproducible Reporting Made Simple with R
Version: 0.3.2
Version: 0.3.3
Authors@R: c(
person("Jacob", "Dumbleton", , "jacob@a2-ai.com", role = c("aut", "cre")),
person("Matthew", "Smith", , "matthews@a2-ai.com", role = "aut"),
Expand Down Expand Up @@ -39,7 +39,7 @@ Imports:
processx,
purrr,
rlang,
rstudioapi,
this.path,
tictoc,
yaml
Suggests:
Expand Down
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# reportifyr 0.3.3
## Bug Fixes

* Fixed an issue where the source path of an object being written out with `write_object_metadata()` during a quarto render was being captured as the intermediate `.rmarkdown`.

# reportifyr 0.3.2
## Improvements

Expand Down
57 changes: 51 additions & 6 deletions R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ get_uv_path <- function(quiet = FALSE) {
# Use default expansion
home_dir <- path.expand("~")
}

if (.Platform$OS.type == "windows") {
# Windows paths
uv_paths <- c(
Expand Down Expand Up @@ -212,25 +212,70 @@ get_uv_version <- function(uv_path) {
#' @noRd
find_project_root <- function(start_path = getwd()) {
current_path <- normalizePath(start_path)

while (TRUE) {
# Look for any .*_init.json file (e.g., .report_init.json, .custom_init.json)
init_files <- list.files(current_path, pattern = "^\\.[^.]*_init\\.json$", full.names = TRUE, all.files = TRUE)
if (length(init_files) > 0) {
return(current_path)
}

# Move up one directory
parent_path <- dirname(current_path)

# If we've reached the root directory, stop
if (parent_path == current_path) {
break
}

current_path <- parent_path
}

# Return NULL if not found
return(NULL)
}

detect_quarto_render <- function() {
log4r::debug(.le$logger, "Starting detect_quarto_render()")

# --- Detect Quarto context ---
quarto_vars <- Sys.getenv(c("QUARTO_PROJECT_ROOT", "QUARTO_BIN_PATH", "QUARTO_RENDER_TOKEN"))
is_quarto <- any(quarto_vars != "")
log4r::debug(.le$logger, paste0("Quarto environment vars detected: ", is_quarto))

if (!is_quarto) {
log4r::debug(.le$logger, "Not running in a Quarto context, returning NULL")
return(NULL)
}

# --- Get current input ---
current <- tryCatch(knitr::current_input(), error = function(e) NULL)
log4r::debug(.le$logger, paste0("knitr::current_input() returned: ", ifelse(is.null(current), "NULL", current)))

# --- Validate current file pattern ---
if (is.null(current) || !grepl("\\.(Rmd|rmarkdown)$", current, ignore.case = TRUE)) {
log4r::debug(.le$logger, "Current input is NULL or not an .Rmd/.rmarkdown file, returning NULL")
return(NULL)
}

# --- Attempt to resolve .qmd equivalent ---
qmd_candidate <- sub("\\.(rmd|rmarkdown)$", ".qmd", basename(current))
project_root <- Sys.getenv("QUARTO_PROJECT_ROOT", unset = getwd())
qmd_path <- file.path(project_root, qmd_candidate)
log4r::debug(.le$logger, paste0("Candidate .qmd path: ", qmd_path))

if (file.exists(qmd_path)) {
log4r::info(.le$logger, paste0(
"Detected Quarto render: .Rmd intermediate '", current,
"' mapped to existing .qmd: ", qmd_path
))
return(normalizePath(qmd_path))
} else {
log4r::warn(.le$logger, paste0(
"Quarto environment detected, but .qmd not found at: ", qmd_path,
", returning NULL"
))
return(NULL)
}
}

62 changes: 28 additions & 34 deletions R/write_object_metadata.R
Original file line number Diff line number Diff line change
Expand Up @@ -49,50 +49,44 @@ write_object_metadata <- function(
hash <- digest::digest(file = object_file, algo = "blake3")
log4r::info(.le$logger, paste0("Generated file hash: ", hash))

source_path <- tryCatch(
{
# Check if the script is being sourced
src_path <- if (!is.null(sys.frame(1)$ofile)) {
normalizePath(sys.frame(1)$ofile) # Path of the currently sourced file
} else if (!is.null(knitr::current_input())) {
normalizePath(knitr::current_input())
} else if (
requireNamespace("rstudioapi", quietly = TRUE) &&
rstudioapi::isAvailable()
) {
context <- rstudioapi::getSourceEditorContext()
if (!is.null(context$path) && nzchar(context$path)) {
normalizePath(context$path)
} else {
normalizePath("Object created from console")
}
} else if (!is.null(rmarkdown::metadata$input_file)) {
normalizePath(rmarkdown::metadata$input_file)
} else if (!is.null(getOption("knitr.in.file"))) {
normalizePath(getOption("knitr.in.file"))
} else if (testthat::is_testing()) {
normalizePath(testthat::test_path())
source_path <- tryCatch({
qmd_path <- detect_quarto_render()
if (!is.null(qmd_path)) {
log4r::info(.le$logger,
paste0("Detected Quarto render; using .qmd file: ", qmd_path))
qmd_path
} else if (requireNamespace("this.path", quietly = TRUE)) {
sp <- this.path::this.path()
if (!is.null(sp) && nzchar(sp)) {
sp <- normalizePath(sp)
log4r::info(.le$logger,
paste0("Source path detected via this.path: ", sp))
sp
} else {
stop("Unable to detect input file")
log4r::warn(.le$logger,
"this.path did not return a valid script path; setting placeholder")
"SOURCE_PATH_NOT_DETECTED"
}
src_path
},
error = function(e) {
log4r::error(.le$logger, "Error detecting source file path")
stop(e)
} else {
log4r::warn(.le$logger,
"Unable to detect source path via Quarto or this.path(); setting placeholder")
"SOURCE_PATH_NOT_DETECTED"
}
)

log4r::info(.le$logger, paste0("Source file path detected: ", source_path))
},
error = function(e) {
log4r::warn(.le$logger,
paste0("Error detecting source path: ", e$message))
"SOURCE_PATH_NOT_DETECTED"
})

# Find project root directory (containing .*_init.json)
project_root <- find_project_root()

if (is.null(project_root)) {
log4r::error(.le$logger, "Could not find project root directory (no *_init.json file found)")
stop("Could not find project root directory. Make sure you're in a reportifyr project (run initialize_report_project() first)")
}

# Convert source path to relative path from project root
source_path_relative <- fs::path_rel(source_path, project_root)
log4r::info(.le$logger, paste0("Source file path (relative): ", source_path_relative))
Expand Down
2 changes: 2 additions & 0 deletions rproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ r_version = "4.4"
repositories = [
#{ alias = "PRISM", url = "https://prism.dev.a2-ai.cloud/rpkgs/stratus/2025-07-28/" },
{alias = "ppm", url = "https://packagemanager.posit.co/cran/latest"},
{alias = "CRAN", url = "https://cran.r-project.org"},
]

dependencies = [
"devtools",
{name = "reportifyr", path = ".", dependencies_only = true, install_suggestions = true },
{name = "gdtools", repository = "CRAN"},
]