From 3453c19d3fe52997bfcf47198dc421dc0804d717 Mon Sep 17 00:00:00 2001 From: MichaelHatherly Date: Mon, 8 Sep 2025 10:04:29 +0100 Subject: [PATCH 1/6] fix: refresh QUARTO_PROJECT_ROOT env var when rendering multiple projects Previously, QUARTO_PROJECT_ROOT would persist from the first project rendered, causing issues when rendering multiple projects sequentially. Now the environment variable is properly updated on each refresh by extracting projectDir from the options JSON and adding it to quarto_env. --- CHANGELOG.md | 4 ++++ src/server.jl | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad358395..6122a230 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 [#XXX]. + ## [v0.17.3] - 2025-05-19 ### Fixed diff --git a/src/server.jl b/src/server.jl index d0084d4d..96921fee 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. From a928def2be51e800e014ac4c545db163d2d18650 Mon Sep 17 00:00:00 2001 From: Julius Krumbiegel Date: Mon, 8 Sep 2025 12:35:04 +0200 Subject: [PATCH 2/6] feed projectDir through to options --- src/server.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/server.jl b/src/server.jl index 96921fee..5ce32c79 100644 --- a/src/server.jl +++ b/src/server.jl @@ -459,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 @@ -480,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") @@ -493,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) @@ -522,6 +525,7 @@ function _extract_relevant_options(file_frontmatter::Dict, options::Dict) params = params_merged, cache, env, + project_dir, ) end end @@ -539,6 +543,7 @@ function _options_template(; params, cache, env, + project_dir, ) D = Dict{String,Any} return D( @@ -558,6 +563,7 @@ function _options_template(; ), "params" => D(params), "env" => env, + "projectDir" => project_dir, ) end From a705cb2d8236af0dc49f599f213498da2c9ce2a4 Mon Sep 17 00:00:00 2001 From: MichaelHatherly Date: Mon, 8 Sep 2025 11:39:26 +0100 Subject: [PATCH 3/6] docs: add PR number to changelog entry --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6122a230..f904335e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- Refresh `QUARTO_PROJECT_ROOT` environment variable when rendering multiple projects sequentially [#XXX]. +- Refresh `QUARTO_PROJECT_ROOT` environment variable when rendering multiple projects sequentially [#336]. ## [v0.17.3] - 2025-05-19 @@ -472,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 From d6fff91363186bb416c8a3c615cc861a52b11818 Mon Sep 17 00:00:00 2001 From: Julius Krumbiegel Date: Mon, 8 Sep 2025 13:37:30 +0200 Subject: [PATCH 4/6] add test --- .../quarto_integration/projectA/_quarto.yml | 0 .../quarto_integration/projectA/projectA.qmd | 7 ++++ .../quarto_integration/projectB/_quarto.yml | 0 .../quarto_integration/projectB/projectB.qmd | 7 ++++ .../testsets/quarto_integration/projectdir.jl | 36 +++++++++++++++++++ 5 files changed, 50 insertions(+) create mode 100644 test/examples/quarto_integration/projectA/_quarto.yml create mode 100644 test/examples/quarto_integration/projectA/projectA.qmd create mode 100644 test/examples/quarto_integration/projectB/_quarto.yml create mode 100644 test/examples/quarto_integration/projectB/projectB.qmd create mode 100644 test/testsets/quarto_integration/projectdir.jl 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..4965f1ae --- /dev/null +++ b/test/testsets/quarto_integration/projectdir.jl @@ -0,0 +1,36 @@ +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__, "..", "..", "..")), + ) + # check that the project is not the same for both even though + run(cmd(file_a)) + + 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 + + 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 From 7f4a8447fa8f76b28357a6b817357c26ae6052d8 Mon Sep 17 00:00:00 2001 From: Julius Krumbiegel Date: Mon, 8 Sep 2025 13:40:27 +0200 Subject: [PATCH 5/6] cleanup --- test/testsets/quarto_integration/projectdir.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/testsets/quarto_integration/projectdir.jl b/test/testsets/quarto_integration/projectdir.jl index 4965f1ae..47df8af8 100644 --- a/test/testsets/quarto_integration/projectdir.jl +++ b/test/testsets/quarto_integration/projectdir.jl @@ -9,8 +9,6 @@ include("../../utilities/prelude.jl") `quarto render $file --to md`, "QUARTO_JULIA_PROJECT" => normpath(joinpath(@__DIR__, "..", "..", "..")), ) - # check that the project is not the same for both even though - run(cmd(file_a)) function server_start_time_and_pid() status = readchomp(`quarto call engine julia status`) @@ -19,6 +17,7 @@ include("../../utilities/prelude.jl") 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() From 423ff1bc93ebe9bf0ea1be871e47bfbfd2d8cd92 Mon Sep 17 00:00:00 2001 From: Julius Krumbiegel Date: Mon, 8 Sep 2025 14:05:52 +0200 Subject: [PATCH 6/6] update quarto to one that includes quarto call engine commands --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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