diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index c76bf09f..16cae3ba 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -97,7 +97,7 @@ jobs: # TODO: use quarto_jll for integration tests once modern enough versions are available - uses: quarto-dev/quarto-actions/setup@9e48da27e184aa238fcb49f5db75469626d43adb # v2.1.9 with: - version: 1.7.17 + version: 1.7.34 - uses: julia-actions/julia-buildpkg@e3eb439fad4f9aba7da2667e7510e4a46ebc46e1 # v1.7.0 - uses: julia-actions/julia-runtest@678da69444cd5f13d7e674a90cb4f534639a14f9 # v1.11.2 diff --git a/CHANGELOG.md b/CHANGELOG.md index ad358395..f904335e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 explicitly in the notebook process [#306]. - Contributing guidelines with AI assistance policy and AGENTS.md for AI coding assistants [#335]. +### Fixed + +- Refresh `QUARTO_PROJECT_ROOT` environment variable when rendering multiple projects sequentially [#336]. + ## [v0.17.3] - 2025-05-19 ### Fixed @@ -468,3 +472,4 @@ caching is enabled. Delete this folder to clear the cache. [#259] [#305]: https://github.com/PumasAI/QuartoNotebookRunner.jl/issues/305 [#306]: https://github.com/PumasAI/QuartoNotebookRunner.jl/issues/306 [#335]: https://github.com/PumasAI/QuartoNotebookRunner.jl/issues/335 +[#336]: https://github.com/PumasAI/QuartoNotebookRunner.jl/issues/336 diff --git a/src/server.jl b/src/server.jl index d0084d4d..5ce32c79 100644 --- a/src/server.jl +++ b/src/server.jl @@ -161,6 +161,14 @@ function _exeflags_and_env(options) # that the user has not set themselves to show up there. quarto_env = Base.byteenv(options["env"]) + # Add QUARTO_PROJECT_ROOT if projectDir is provided in options. + # This ensures the environment variable is refreshed when rendering + # multiple projects sequentially. + project_dir = get(options, "projectDir", nothing) + if !isnothing(project_dir) + push!(quarto_env, "QUARTO_PROJECT_ROOT=$project_dir") + end + # Ensure that coverage settings are passed to the worker so that worker # code is tracked correctly during tests. # Based on https://github.com/JuliaLang/julia/blob/eed18bdf706b7aab15b12f3ba0588e8fafcd4930/base/util.jl#L216-L229. @@ -451,6 +459,7 @@ function _extract_relevant_options(file_frontmatter::Dict, options::Dict) eval_default = get(get(D, file_frontmatter, "execute"), "eval", true) daemon_default = get(get(D, file_frontmatter, "execute"), "daemon", true) cache_default = get(get(D, file_frontmatter, "execute"), "cache", false) + project_dir_default = get(file_frontmatter, "projectDir", nothing) pandoc_to_default = nothing @@ -472,6 +481,7 @@ function _extract_relevant_options(file_frontmatter::Dict, options::Dict) params = params_default, cache = cache_default, env = Dict{String,Any}(), + project_dir = project_dir_default, ) else format = get(D, options, "format") @@ -485,6 +495,7 @@ function _extract_relevant_options(file_frontmatter::Dict, options::Dict) eval = get(execute, "eval", eval_default) daemon = get(execute, "daemon", daemon_default) cache = get(execute, "cache", cache_default) + project_dir = get(options, "projectDir", nothing) pandoc = get(D, format, "pandoc") pandoc_to = get(pandoc, "to", pandoc_to_default) @@ -514,6 +525,7 @@ function _extract_relevant_options(file_frontmatter::Dict, options::Dict) params = params_merged, cache, env, + project_dir, ) end end @@ -531,6 +543,7 @@ function _options_template(; params, cache, env, + project_dir, ) D = Dict{String,Any} return D( @@ -550,6 +563,7 @@ function _options_template(; ), "params" => D(params), "env" => env, + "projectDir" => project_dir, ) end diff --git a/test/examples/quarto_integration/projectA/_quarto.yml b/test/examples/quarto_integration/projectA/_quarto.yml new file mode 100644 index 00000000..e69de29b diff --git a/test/examples/quarto_integration/projectA/projectA.qmd b/test/examples/quarto_integration/projectA/projectA.qmd new file mode 100644 index 00000000..aab42874 --- /dev/null +++ b/test/examples/quarto_integration/projectA/projectA.qmd @@ -0,0 +1,7 @@ +--- +engine: julia +--- + +```{julia} +@show ENV["QUARTO_PROJECT_ROOT"] +``` diff --git a/test/examples/quarto_integration/projectB/_quarto.yml b/test/examples/quarto_integration/projectB/_quarto.yml new file mode 100644 index 00000000..e69de29b diff --git a/test/examples/quarto_integration/projectB/projectB.qmd b/test/examples/quarto_integration/projectB/projectB.qmd new file mode 100644 index 00000000..aab42874 --- /dev/null +++ b/test/examples/quarto_integration/projectB/projectB.qmd @@ -0,0 +1,7 @@ +--- +engine: julia +--- + +```{julia} +@show ENV["QUARTO_PROJECT_ROOT"] +``` diff --git a/test/testsets/quarto_integration/projectdir.jl b/test/testsets/quarto_integration/projectdir.jl new file mode 100644 index 00000000..47df8af8 --- /dev/null +++ b/test/testsets/quarto_integration/projectdir.jl @@ -0,0 +1,35 @@ +include("../../utilities/prelude.jl") + +@testset "quarto project root env variable" begin + dir = joinpath(@__DIR__, "..", "..", "examples", "quarto_integration") + file_a = joinpath(dir, "projectA", "projectA.qmd") + file_b = joinpath(dir, "projectB", "projectB.qmd") + # TODO: use quarto_jll for integration tests once modern enough versions are available + cmd(file) = addenv( + `quarto render $file --to md`, + "QUARTO_JULIA_PROJECT" => normpath(joinpath(@__DIR__, "..", "..", "..")), + ) + + function server_start_time_and_pid() + status = readchomp(`quarto call engine julia status`) + started_at = something(match(r"started at: ([\d\:]+)", status))[1] + pid = something(match(r"pid: (\d+)", status))[1] + return started_at, pid + end + + run(cmd(file_a)) + time_pid_a = server_start_time_and_pid() + run(cmd(file_b)) + time_pid_b = server_start_time_and_pid() + + # make sure server process hasn't changed so the env variable + # can't have been updated this way + @test time_pid_a == time_pid_b + + outputfile_a = joinpath(dir, "projectA", "projectA.md") + outputfile_b = joinpath(dir, "projectB", "projectB.md") + @test occursin(r"QUARTO_PROJECT_ROOT.*?projectA", read(outputfile_a, String)) + @test occursin(r"QUARTO_PROJECT_ROOT.*?projectB", read(outputfile_b, String)) + rm(outputfile_a) + rm(outputfile_b) +end