Skip to content

hrw4u: exit non-zero on compile errors - #13656

Merged
masaori335 merged 4 commits into
apache:masterfrom
masaori335:asf-master-hrw4u-check-0
Sep 22, 2026
Merged

masaori335 merged 4 commits into
apache:masterfrom
masaori335:asf-master-hrw4u-check-0

Conversation

@masaori335

@masaori335 masaori335 commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Fix #13618

The exit gate required tree is None, but ANTLR error recovery almost always yields a tree, so both syntax and semantic errors exited 0 while printing diagnostics and a partial .conf. Collecting every error and failing the build were mutually exclusive: only --stop-on-error exited 1. Sandbox denials were caught by the same gate, so the "denied" outcome the sandbox docs describe also exited 0.

generate_output now reports failure by return value and run_main owns the exit, so a bad file in a bulk run no longer aborts the files after it.

A failing compile still prints its partial .conf; the exit code now marks it untrustworthy. Suppressing those bytes would change behavior for existing pipelines and is left as a separate decision.

The exit gate required `tree is None`, but ANTLR error recovery almost
always yields a tree, so both syntax and semantic errors exited 0 while
printing diagnostics and a partial .conf. Collecting every error and
failing the build were mutually exclusive: only --stop-on-error exited 1.
Sandbox denials were caught by the same gate, so the "denied" outcome the
sandbox docs describe also exited 0.

generate_output now reports failure by return value and run_main owns the
exit, so a bad file in a bulk run no longer aborts the files after it.

A failing compile still prints its partial .conf; the exit code now marks
it untrustworthy. Suppressing those bytes would change behavior for
existing pipelines and is left as a separate decision.
@masaori335 masaori335 added this to the 11.0.0 milestone Sep 9, 2026
@masaori335 masaori335 self-assigned this Sep 9, 2026
Copilot AI lite review requested due to automatic review settings September 9, 2026 11:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Updates hrw4u to exit non-zero on any compile error (syntax/semantic), even when ANTLR recovers and produces a parse tree, while still processing all inputs in multi-file/bulk runs before deciding the final status.

Changes:

  • generate_output() now returns a boolean indicating whether errors occurred, instead of exiting directly.
  • run_main() accumulates per-input failures and exits 1 at the end of a multi-file/bulk run (or immediately for single-input paths).
  • Adds CLI/test coverage and documents the exit-status contract.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
tools/hrw4u/src/common.py Make generate_output() report errors via return value; accumulate failures in run_main() and exit non-zero appropriately.
tools/hrw4u/tests/test_common.py Update unit tests to validate the new boolean failure-reporting contract.
tools/hrw4u/tests/test_cli.py Add CLI integration tests asserting non-zero exit codes on syntax/semantic/multi-error and multi-file runs.
doc/admin-guide/configuration/hrw4u.en.rst Document exit status behavior and multi-input processing semantics.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tools/hrw4u/tests/test_cli.py
Comment thread tools/hrw4u/tests/test_common.py Outdated
The failure test passed parser_obj=None, which only worked because a
None tree short-circuits before the AST branch reads it. Parsing a real
input instead also pins the regression: the input parses, so the tree is
not None -- exactly what the old exit gate let through.
Copilot AI review requested due to automatic review settings September 10, 2026 04:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

A few correctness/coverage/documentation gaps remain (notably type-hint consistency, doc wording vs fatal I/O behavior, and u4wrh regression coverage) before the exit-code contract can be considered fully locked in.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

tools/hrw4u/src/common.py:239

  • generate_output() is annotated as requiring parser_obj: ParserProtocol, but it is intentionally called with parser_obj=None in tests (and the function’s AST path already tolerates it). Adjusting the type hints to allow None (and likewise for tree) keeps the annotations consistent with actual supported usage and avoids false-positive type-check failures.
  • Files reviewed: 4/4 changed files
  • Comments generated: 2
  • Review effort level: Lite

Comment thread doc/admin-guide/configuration/hrw4u.en.rst Outdated
Comment thread tools/hrw4u/tests/test_cli.py
u4wrh drives the same run_main(), so the contract regresses just as
easily there; verified the new test exits 0 against the pre-fix code.

The doc said every input is processed before the status is decided,
which reads as covering the fatal argument and I/O paths too -- those
still exit immediately.
Copilot AI review requested due to automatic review settings September 10, 2026 05:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The newly added exit-status documentation claims invalid CLI arguments return status 1, but argparse usage errors typically exit with status 2 unless explicitly normalized.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

doc/admin-guide/configuration/hrw4u.en.rst:126

  • The docs state exit status 1 for an invalid command line, but run_main() relies on argparse.ArgumentParser.parse_args() (default behavior), which exits with status 2 on usage/argument errors. The exit-status contract should document this (or adjust the code to normalize argparse failures to 1).
  • Files reviewed: 4/4 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

run_main() lets argparse handle the command line, so an unknown option,
a bad option value, or conflicting output modes exit 2, not the 1 the
table claimed. Normalizing them to 1 would merge "you typed the command
wrong" into "your rules did not compile", so the doc follows the code.

Row 1 now lists only what actually exits 1; the mixed bulk/stdout
rejection is caught after parsing and belongs there, not with argparse.
Copilot AI review requested due to automatic review settings September 17, 2026 08:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The reviewed changes are covered by tests and documented, with no unresolved blocking issues.

Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@cmcfarlen cmcfarlen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Good find — the old gate needed tree is None, which ANTLR error recovery almost never produces, so syntax errors, semantic errors and sandbox denials were all exiting 0.

I generated the parsers in a worktree and ran the suite (714 passed, including the 26 CLI tests) plus manual CLI probes. Every failure path now yields 1 and clean input yields 0: semantic error with and without --stop-on-error, syntax error, --ast plus syntax error, bulk a:out1 b:out2 with one bad input (1, and both outputs still written), warnings-only still 0. Sandbox denials route through ErrorCollector.add_error, so they are covered now too. failed is initialized on both the pair and plain branches, so the trailing if failed cannot hit an unbound name, and no non-test caller of generate_output depended on the old sys.exit.

Two non-blocking notes, both about the contract rather than the code:

  1. doc/admin-guide/configuration/hrw4u.en.rst:133 — "A compile error does not stop the run: every input is still processed" is stated unconditionally, but --stop-on-error does the opposite: create_parse_tree with collect_errors=False calls emit_fatal_error -> sys.exit(1), so hrw4u --stop-on-error bad.hrw4u good.hrw4u never processes good.hrw4u. That contradicts the flag's own help text. The same sentence's "The fatal problems above still abort immediately" is also a bit loose for the mixed-format case: the ":" not in pair check is inside the loop (src/common.py:371), so hrw4u a.hrw4u:a.conf plain.hrw4u writes a.conf before aborting — which your own test_cli_mixed_file_formats_exits_one exercises. Worth carving out --stop-on-error and softening "immediately".

  2. tools/hrw4u/src/common.py:286 — the old gate had not args.ast, so --ast always exited 0. The new unconditional return makes --ast exit 1 on a recoverable syntax error while still printing the tree. I think that is the right call (in --ast mode the visitor never runs, so only syntax errors can trigger it), but it is currently undocumented and untested — not in the PR description, not in the new exit-status table, and test_cli_ast_mode only uses a valid file. A test plus a doc line would nail it down.

@masaori335
masaori335 merged commit 915543f into apache:master Sep 22, 2026
14 checks passed
@github-project-automation github-project-automation Bot moved this to For v10.2.1 in ATS v10.2.x Sep 22, 2026
cmcfarlen pushed a commit that referenced this pull request Sep 23, 2026
* hrw4u: exit non-zero on compile errors

The exit gate required `tree is None`, but ANTLR error recovery almost
always yields a tree, so both syntax and semantic errors exited 0 while
printing diagnostics and a partial .conf. Collecting every error and
failing the build were mutually exclusive: only --stop-on-error exited 1.
Sandbox denials were caught by the same gate, so the "denied" outcome the
sandbox docs describe also exited 0.

generate_output now reports failure by return value and run_main owns the
exit, so a bad file in a bulk run no longer aborts the files after it.

A failing compile still prints its partial .conf; the exit code now marks
it untrustworthy. Suppressing those bytes would change behavior for
existing pipelines and is left as a separate decision.

* hrw4u: parse real input in generate_output return-value tests

The failure test passed parser_obj=None, which only worked because a
None tree short-circuits before the AST branch reads it. Parsing a real
input instead also pins the regression: the input parses, so the tree is
not None -- exactly what the old exit gate let through.

* hrw4u: cover u4wrh in the exit-code tests, scope the doc claim

u4wrh drives the same run_main(), so the contract regresses just as
easily there; verified the new test exits 0 against the pre-fix code.

The doc said every input is processed before the status is decided,
which reads as covering the fatal argument and I/O paths too -- those
still exit immediately.

* hrw4u: document exit status 2 for usage errors

run_main() lets argparse handle the command line, so an unknown option,
a bad option value, or conflicting output modes exit 2, not the 1 the
table claimed. Normalizing them to 1 would merge "you typed the command
wrong" into "your rules did not compile", so the doc follows the code.

Row 1 now lists only what actually exits 1; the mixed bulk/stdout
rejection is caught after parsing and belongs there, not with argparse.

(cherry picked from commit 915543f)
@cmcfarlen cmcfarlen moved this from For v10.2.1 to Picked v10.2.1 in ATS v10.2.x Sep 23, 2026
@cmcfarlen cmcfarlen modified the milestones: 11.0.0, 10.2.1 Sep 23, 2026
@cmcfarlen

Copy link
Copy Markdown
Contributor

Cherry-picked to the 10.2.x branch as 210980c for the 10.2.1 release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Picked v10.2.1

Development

Successfully merging this pull request may close these issues.

hrw4u: no non-zero exit status on errors unless --stop-on-error is given

3 participants