From d1b9f39372968c629a2f45e5ed90f9f914da14f0 Mon Sep 17 00:00:00 2001 From: prql-bot <107324867+prql-bot@users.noreply.github.com> Date: Mon, 14 Sep 2026 07:13:39 +0000 Subject: [PATCH 1/4] fix: keep watching when a file in the tree fails to compile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The initial pass in `find_and_compile` propagated a compile error, so `prqlc watch` exited before reaching the watch loop whenever any .prql file in the tree was broken — the state watch mode exists to iterate out of. Report and continue instead, matching what the watch loop already does for errors that appear after startup. --- CHANGELOG.md | 6 ++++++ prqlc/prqlc/src/cli/watch.rs | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 142c76b7fcaf..c39058562128 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -119,6 +119,12 @@ what it holds rather than panicking or silently dropping the default. (@prql-bot, #6311) +- `prqlc watch` no longer exits when a `.prql` file in the watched tree fails to + compile. The initial pass aborted on the first error, so the command never + reached the watch loop — precisely the state watch mode exists to iterate out + of. It now reports the error and keeps watching, as it already did for errors + that appear after it starts. (@prql-bot, #PRNUM) + **Documentation**: - The `prql-java` README now documents the actual API. It advertised a diff --git a/prqlc/prqlc/src/cli/watch.rs b/prqlc/prqlc/src/cli/watch.rs index 773428b19ab2..4430a166da9b 100644 --- a/prqlc/prqlc/src/cli/watch.rs +++ b/prqlc/prqlc/src/cli/watch.rs @@ -41,7 +41,11 @@ pub fn run(command: &mut WatchArgs) -> Result<()> { fn find_and_compile(path: &Path, opt: &prqlc::Options) -> Result<()> { for entry in WalkDir::new(path) { - compile_path(entry?.path(), opt)?; + // A file that doesn't compile is the ordinary starting state for + // `watch` — aborting here would leave the errors unwatched, so we + // report and carry on, as the watch loop below does. `compile_path` + // has already printed the compiler's diagnostics. + let _ignore = compile_path(entry?.path(), opt); } Ok(()) @@ -134,3 +138,31 @@ fn compile_path(path: &Path, opt: &prqlc::Options) -> Result<()> { Ok(()) } + +#[cfg(test)] +mod tests { + use std::fs; + + use tempfile::TempDir; + + use super::*; + + /// A file that fails to compile used to abort the initial pass, so + /// `prqlc watch` exited before printing "Watching path" — the one state + /// watch mode exists to iterate out of. The other files must still compile, + /// and the walk must reach the end. + #[test] + fn initial_compile_continues_past_a_failing_file() { + let dir = TempDir::new().unwrap(); + // Named so that the failing file is walked before the second good one. + fs::write(dir.path().join("a_good.prql"), "from tracks\n").unwrap(); + fs::write(dir.path().join("b_bad.prql"), "from tracks | filter\n").unwrap(); + fs::write(dir.path().join("c_good.prql"), "from albums\n").unwrap(); + + find_and_compile(dir.path(), &prqlc::Options::default()).unwrap(); + + assert!(dir.path().join("a_good.sql").is_file()); + assert!(dir.path().join("c_good.sql").is_file()); + assert!(!dir.path().join("b_bad.sql").exists()); + } +} From 8a1b3333a9f8dcb6a55b6044574ad1c528f3b7ab Mon Sep 17 00:00:00 2001 From: prql-bot <107324867+prql-bot@users.noreply.github.com> Date: Mon, 14 Sep 2026 07:14:07 +0000 Subject: [PATCH 2/4] docs: reference the PR number in the changelog entry --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c39058562128..6ac7c9a88d36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -123,7 +123,7 @@ compile. The initial pass aborted on the first error, so the command never reached the watch loop — precisely the state watch mode exists to iterate out of. It now reports the error and keeps watching, as it already did for errors - that appear after it starts. (@prql-bot, #PRNUM) + that appear after it starts. (@prql-bot, #6313) **Documentation**: From 77887744a56a209b20273df0effae59782af6931 Mon Sep 17 00:00:00 2001 From: prql-bot Date: Mon, 14 Sep 2026 07:29:15 +0000 Subject: [PATCH 3/4] fix: report the errors the initial watch pass discards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `let _ignore = compile_path(...)` dropped every error, but only the compile-error branch prints anything of its own — a failed `.sql` write or a Jinja pre-process error went entirely silent, so a read-only output directory left the watcher running and producing nothing. Both call sites now go through one helper that prints the error instead of discarding it, keeping the walk going past every failure without losing the failures themselves. --- prqlc/prqlc/src/cli/watch.rs | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/prqlc/prqlc/src/cli/watch.rs b/prqlc/prqlc/src/cli/watch.rs index 4430a166da9b..a829750d36a7 100644 --- a/prqlc/prqlc/src/cli/watch.rs +++ b/prqlc/prqlc/src/cli/watch.rs @@ -41,16 +41,26 @@ pub fn run(command: &mut WatchArgs) -> Result<()> { fn find_and_compile(path: &Path, opt: &prqlc::Options) -> Result<()> { for entry in WalkDir::new(path) { - // A file that doesn't compile is the ordinary starting state for - // `watch` — aborting here would leave the errors unwatched, so we - // report and carry on, as the watch loop below does. `compile_path` - // has already printed the compiler's diagnostics. - let _ignore = compile_path(entry?.path(), opt); + compile_path_reporting_errors(entry?.path(), opt); } Ok(()) } +/// Compile `path`, printing any error rather than propagating it. +/// +/// A file that doesn't compile is the ordinary starting state for `watch`, and +/// the one it exists to iterate out of, so neither the initial pass nor the +/// watch loop stops for one. `compile_path` prints the compiler's own +/// diagnostics, but it also returns errors it hasn't printed — an unwritable +/// `.sql` path, say — which would otherwise leave the watcher silently +/// producing nothing. +fn compile_path_reporting_errors(path: &Path, opt: &prqlc::Options) { + if let Err(error) = compile_path(path, opt) { + println!("{}: {error}", path.display()); + } +} + fn watch_and_compile(path: &Path, opt: &prqlc::Options) -> Result<()> { let cwd = std::env::current_dir().ok(); @@ -81,7 +91,7 @@ fn watch_and_compile(path: &Path, opt: &prqlc::Options) -> Result<()> { &path }; - let _ignore = compile_path(relative_path, opt); + compile_path_reporting_errors(relative_path, opt); } } @@ -154,7 +164,8 @@ mod tests { #[test] fn initial_compile_continues_past_a_failing_file() { let dir = TempDir::new().unwrap(); - // Named so that the failing file is walked before the second good one. + // Two good files, since `WalkDir` doesn't order entries: whichever + // side of the failing file the walk puts them on, both must compile. fs::write(dir.path().join("a_good.prql"), "from tracks\n").unwrap(); fs::write(dir.path().join("b_bad.prql"), "from tracks | filter\n").unwrap(); fs::write(dir.path().join("c_good.prql"), "from albums\n").unwrap(); From f87025e63ac59b24570fabb93e0a36ab38de722f Mon Sep 17 00:00:00 2001 From: prql-bot <107324867+prql-bot@users.noreply.github.com> Date: Mon, 14 Sep 2026 07:46:09 +0000 Subject: [PATCH 4/4] docs: cover the watch loop's silent errors in the changelog entry --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ac7c9a88d36..4b32acb191d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -122,8 +122,11 @@ - `prqlc watch` no longer exits when a `.prql` file in the watched tree fails to compile. The initial pass aborted on the first error, so the command never reached the watch loop — precisely the state watch mode exists to iterate out - of. It now reports the error and keeps watching, as it already did for errors - that appear after it starts. (@prql-bot, #6313) + of. Both the initial pass and the watch loop now print the failing path + alongside the error and carry on. The loop previously discarded every error it + hit, so a failure that produces no compiler diagnostic — an unwritable `.sql` + output path, say — left the watcher running silently and writing nothing. + (@prql-bot, #6313) **Documentation**: