fix: avoid duplicate JSON in combined output when hotspot has no Git repo (#294)#297
Merged
BartWaardenburg merged 1 commit intofallow-rs:mainfrom May 6, 2026
Conversation
…ow-rs#294) Combined-mode `--format json` could write two top-level JSON values to stdout when run outside a git repository: first a `{ "error": true, "message": "hotspot analysis requires a git repository", ... }` blob emitted by the hotspot pipeline, then the normal combined report. That broke `fallow --format json | jq .` and any agent or CI parser that expects a single document — `failed to parse JSON: trailing characters at line 6 column 1` was the typical symptom. `fetch_churn_data` already returns `None` for the no-git case, and the caller already renders an empty hotspot section when that happens, so the JSON emission was the only side effect that ever made it to stdout. Drop the JSON emission in favor of a single stderr note (gated by `--quiet`); standalone `fallow health --hotspots --format json` outside a git repo now emits one well-formed health report with empty hotspots and exits 0, matching the issue's preferred resolution. Adds `combined_json_outside_git_repo_emits_single_document` to `exit_code_tests.rs`. The test builds a minimal TS project in a tempdir (no parent `.git`), strips inherited `GIT_DIR` / `GIT_WORK_TREE`, runs combined mode with `--format json`, and asserts stdout parses as exactly one JSON value with `schema_version` set and no top-level `error` key.
BartWaardenburg
added a commit
that referenced
this pull request
May 6, 2026
CHANGELOG entry under [Unreleased] documenting the behavior change for the next release: combined-mode --format json now emits exactly one JSON document outside a git repository, and standalone fallow health --hotspots exits 0 with empty hotspot fields instead of exit 2 with a JSON error. docs/backwards-compatibility.md gains a 'Notable behavior changes within v2' section so CI scripts that depended on the exit-2 signal have a documented migration path (inspect hotspot_summary instead).
BartWaardenburg
added a commit
to fallow-rs/docs
that referenced
this pull request
May 6, 2026
Updates the --hotspots and --ownership flag rows and the warning panel in cli/health.mdx to reflect the v2.66.x behavior change: outside a git repository the hotspot section now degrades to empty (with a stderr note) and exits 0 instead of erroring, so combined-mode --format json always emits a single JSON document. Tracks fallow-rs/fallow#297.
Collaborator
|
Released in v2.66.1. Thanks @ChrisJr404. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #294.
Combined-mode
--format jsonwrites two top-level JSON documents to stdout when the project is outside a Git repository: first a{ "error": true, "message": "hotspot analysis requires a git repository", ... }blob, then the normal combined report. That breaksfallow --format json | jq .and any agent or CI parser that assumes a single document. The nixpkgs build of 2.65.0 hit this in five combined-mode integration tests whose temp fixtures live outside any Git checkout.Where the second blob comes from
crates/cli/src/health/hotspots.rs::fetch_churn_datais called from inside the health pipeline. Whenis_git_repo(opts.root)returns false it does:emit_errorwithOutputFormat::Jsonprintln!s a structured error object to stdout regardless of who called it. The function then returnsNone, which the caller already handles gracefully ((Vec::new(), None)for hotspots — seecrates/cli/src/health/mod.rs:520). Combined mode then continues, builds the combined report, andprint_combined_jsonprintln!s it. Two documents on stdout, one well-formed parser per side.Fix
Treat a missing Git repo as unavailable hotspot data rather than a hard error. The hotspot pipeline already silently degrades to an empty section when
fetch_churn_datareturnsNone, so dropping the JSON emission lets combined mode keep its single-document contract. A non-fatalnote: hotspot analysis skipped — no git repository found at project rootgoes to stderr unless--quietis set.This also fixes standalone
fallow health --hotspots --format jsonoutside a Git repo: it now emits one well-formed health report with empty hotspots and exits 0, which lines up with the first acceptable resolution suggested in the issue ("treat missing Git history for hotspot analysis as unavailable data in the combined report").The other
emit_errorpaths infetch_churn_datacover--sincemalformed input — those are user-error invariants and are not reachable from combined mode (build_health_optshard-codessince: None), so they keep their existing exit-2 contract.Test
Adds
combined_json_outside_git_repo_emits_single_documenttocrates/cli/tests/exit_code_tests.rs. The test:/tmp/...), sois_git_repowalks up and returns false.GIT_DIR/GIT_WORK_TREEand pointsGIT_CONFIG_GLOBAL/GIT_CONFIG_SYSTEMat/dev/nullso a parent-process git env can't redirect rev-parse upward (this matches the isolation pattern already used byhealth_tests.rs::git).fallow --root <tempdir> --format json --quiet(combined mode).serde_json::Value(the original failure modefailed to parse JSON: trailing characters at line 6 column 1reproduces here without the fix).schema_versionand no top-levelerrorkey.I confirmed the test fails on
mainand passes with the patch applied locally.Verification
cargo test -p fallow-extract -p fallow-cli --bin fallow— 1755 pass, 0 failcargo test -p fallow-cli --test exit_code_tests— 16 pass, 0 fail (includes the new case)cargo test -p fallow-cli --test health_tests— 30 pass, 0 failcargo test -p fallow-cli --lib— 1226 pass, 0 failcargo test -p fallow-extract --lib— 1392 pass, 0 failcargo clippy -p fallow-cli --bin fallow --tests— cleancargo fmt --check— clean