feat(exit-codes): implement Robot Framework-style exit codes (#469)#553
feat(exit-codes): implement Robot Framework-style exit codes (#469)#553oboehmer merged 14 commits intorelease/pyats-integration-v1.1-betafrom
Conversation
…ource of truth for exit codes ## Summary Removed the legacy errorhandler system that was interfering with proper exit code behavior. Exit codes are now handled exclusively through CombinedResults.exit_code, providing a single, predictable source of truth that follows Robot Framework conventions. ## Key Changes **Errorhandler Removal:** - Eliminated errorhandler dependency that was causing logger.error() calls to override intended exit codes - Restored proper logger.error() usage throughout the codebase (no more workarounds with logger.warning()) - Developers can now use logger.error() naturally without unintended side effects on exit codes **Single Source of Truth:** - CombinedResults.exit_code is now the only exit code calculation method - Removed unused TestResults.exit_code method that was never called in production - Simplified architecture: exit codes are purely a CLI aggregation concern, not individual framework concern ## Benefits - **Predictable Behavior**: Exit codes come from one clear path (CombinedResults → CLI) - **No Hidden Side Effects**: Logging levels don't accidentally change exit codes - **Cleaner Architecture**: No duplicate exit code logic across TestResults and CombinedResults - **Developer Friendly**: logger.error() works as expected without exit code interference ## Tests - **New CLI exit code tests**: Comprehensive test suite for main.py exit code behavior (9 tests) - **Removed**: Unused TestResults.exit_code tests that tested non-production code paths - All existing integration and E2E tests continue to pass The errorhandler was a legacy mechanism from before CombinedResults existed. With proper structured error handling now in place, the errorhandler created more problems than it solved by interfering with the intended graduated exit code system.
Introduce symbolic exit code constants in nac_test/core/constants.py following Robot Framework conventions: EXIT_FAILURE_CAP = 250 # max test failure count reported EXIT_INVALID_ARGS = 252 # invalid RF args or no tests found EXIT_INTERRUPTED = 253 # Ctrl+C / interrupted execution EXIT_ERROR = 255 # infrastructure/execution errors EXIT_SUCCESS (0) is deliberately not defined — it is a universal POSIX convention that never changes, so a named constant adds no clarity. Removed the spuriously added __all__ from constants.py. Also fix template rendering error handling: instead of propagating exceptions in render-only mode (which leaked as exit code 1, violating the "1-250 = test failure count" convention), rendering failures are now converted to TestResults.from_error() objects with descriptive messages. main.py inspects the resulting CombinedResults.has_errors to exit with EXIT_ERROR (255) and display an actionable "❌ Template rendering failed: <reason>" message, consistent with all other infrastructure failures. Updated all tests to use the new constants instead of magic numbers, except where literals are derived directly from test input (e.g. `failed=3` → `assert exit_code == 3`) and therefore more readable as literals.
…t (252) EXIT_INVALID_ARGS was previously 252 (Robot Framework convention). This was confusing because nac-test's own CLI argument errors should follow POSIX/Typer conventions (exit code 2) rather than RF conventions. Split into two distinct constants: - EXIT_INVALID_ARGS = 2 (nac-test CLI arg errors, aligns with POSIX/Typer) - EXIT_INVALID_ROBOT_ARGS = 252 (Robot Framework invalid args / no tests found) This allows CI/CD to unambiguously distinguish exit code 2 from a bad CLI invocation vs. 2 test failures (which would produce artifacts). Updated all production code, tests, and README accordingly.
…type-safe exit code determination Replace fragile string-based error detection (ERROR_MARKER_*) with a typed ErrorType enum approach. This enables compile-time checking and explicit exit code priority handling. Changes: - Add ErrorType enum (GENERIC, INVALID_ROBOT_ARGS, INTERRUPTED) - Add error_type field to TestResults dataclass - Update from_error() to accept optional error_type parameter - Fix exit code priority: 253 (interrupted) > 252 (invalid args) > 255 (generic) - Remove ERROR_MARKER_* constants from constants.py - Add unit tests for ErrorType and exit code priority
Move all user-facing error/success output to main.py: - Display ❌ for errors,⚠️ for warnings, ✅ for success - Route all error messages to stderr consistently Remove redundant error output from orchestrators: - robot/orchestrator.py: remove typer.echo calls (-15 lines) - combined_orchestrator.py: simplify exception handler (-17 lines) Orchestrators now only log errors and store them in TestResults, following single-responsibility principle.
Tests previously expected exit code 1 for controller detection failures. With the new exit code scheme, infrastructure errors return EXIT_ERROR (255).
aitestino
left a comment
There was a problem hiding this comment.
Hey Oliver, @oboehmer - good work with this. Thank you.
A couple of things at quick glance that stood out to me:
1. Unused ERROR_TYPE_EXIT_CODES Dict
Location: nac_test/core/types.py:44-50
The ERROR_TYPE_EXIT_CODES mapping is defined but never used. The CombinedResults.exit_code property uses inline if/elif checks instead of looking up from this dict:
# Dict is defined but unused:
ERROR_TYPE_EXIT_CODES: dict[ErrorType, int] = {
ErrorType.INVALID_ROBOT_ARGS: EXIT_INVALID_ROBOT_ARGS,
ErrorType.INTERRUPTED: EXIT_INTERRUPTED,
ErrorType.GENERIC: EXIT_ERROR,
}
# exit_code property doesn't use it:
if ErrorType.INTERRUPTED in error_types:
return EXIT_INTERRUPTED
if ErrorType.INVALID_ROBOT_ARGS in error_types:
return EXIT_INVALID_ROBOT_ARGS
return EXIT_ERRORThis creates two sources of truth that could drift. Two options:
- Remove the dict (my preference) - With only 3 error types, the explicit
ifchain is more readable and the priority ordering is immediately visible. The dict would only add value if we had many error types; with three, it's unnecessary indirection that adds a maintenance burden without improving clarity. - Use the dict - Replace the if/elif chain with a priority-ordered lookup
What's your thinking on keeping vs. removing this mapping?
2. errorhandler Dependency in pyproject.toml
Location: pyproject.toml:52
All imports and usages of errorhandler have been removed from the code, but errorhandler>=2.0 is still in pyproject.toml. This should be removed to avoid shipping an unused dependency.
Minor Observations (Non-Blocking)
Naming: EXIT_INVALID_ROBOT_ARGS Dual Purpose
The constant is used for both "invalid Robot arguments" AND "no tests found" (via is_empty check in CombinedResults.exit_code). The name suggests it's exclusively about invalid arguments. Consider renaming to EXIT_DATA_ERROR (matching Robot Framework's naming) or adding a clarifying comment. Not critical since the docstring explains the dual meaning.
Priority Ordering Documentation
The docstring says "Priority: 253 > 252 > 255" which looks counterintuitive numerically. A brief note about why this ordering (interrupted = most actionable signal for CI/CD) would help future maintainers who might assume lower numbers = higher priority.
P.S. — This comment was drafted using voice-to-text via Claude Code. If the tone comes across as overly direct or terse, please know that's just how it tends to phrase things. No offense or criticism is intended — this is purely an objective technical review of the PR. Thanks for understanding! 🙂
With only 3 error types, the explicit if chain in CombinedResults.exit_code is more readable and makes priority ordering immediately visible. The dict was defined but never used, creating two sources of truth that could drift.
The errorhandler package is no longer used in the codebase after centralizing exit code handling in CombinedResults.exit_code.
Rename to match Robot Framework's naming convention for exit code 252. This constant serves dual purpose: invalid Robot arguments AND no tests found (via is_empty check), so the more generic name is more accurate.
…cstring Add explanation for why priority is 253 > 252 > 255 (counterintuitive numerically): interrupted is most actionable for CI/CD, data errors indicate config issues, generic errors may be transient.
…69-exit-code Resolve merge conflict in combined_orchestrator.py: - Keep render_only check from base branch (skip controller detection in render-only mode) - Use EXIT_ERROR constant instead of hardcoded 1 for consistent exit codes
|
thanks for the catches in your review, I addressed all comments, please re-review, @aitestino |
…eta' into feat/469-exit-code
aitestino
left a comment
There was a problem hiding this comment.
Thanks! Great job. I upon a 2nd glance spotted these but they are truly nitpicks, opened the issues as to not look the other way...but this is good to merge imo:
P.S. — This comment was drafted using voice-to-text. If the tone comes across as overly direct or terse, please know that's just how it tends to phrase things. No offense or criticism is intended — this is purely an objective technical review of the PR. Thanks for understanding! 🙂
53b1447
into
release/pyats-integration-v1.1-beta
…553) * refactor: remove legacy errorhandler, use CombinedResults as single source of truth for exit codes ## Summary Removed the legacy errorhandler system that was interfering with proper exit code behavior. Exit codes are now handled exclusively through CombinedResults.exit_code, providing a single, predictable source of truth that follows Robot Framework conventions. ## Key Changes **Errorhandler Removal:** - Eliminated errorhandler dependency that was causing logger.error() calls to override intended exit codes - Restored proper logger.error() usage throughout the codebase (no more workarounds with logger.warning()) - Developers can now use logger.error() naturally without unintended side effects on exit codes **Single Source of Truth:** - CombinedResults.exit_code is now the only exit code calculation method - Removed unused TestResults.exit_code method that was never called in production - Simplified architecture: exit codes are purely a CLI aggregation concern, not individual framework concern ## Benefits - **Predictable Behavior**: Exit codes come from one clear path (CombinedResults → CLI) - **No Hidden Side Effects**: Logging levels don't accidentally change exit codes - **Cleaner Architecture**: No duplicate exit code logic across TestResults and CombinedResults - **Developer Friendly**: logger.error() works as expected without exit code interference ## Tests - **New CLI exit code tests**: Comprehensive test suite for main.py exit code behavior (9 tests) - **Removed**: Unused TestResults.exit_code tests that tested non-production code paths - All existing integration and E2E tests continue to pass The errorhandler was a legacy mechanism from before CombinedResults existed. With proper structured error handling now in place, the errorhandler created more problems than it solved by interfering with the intended graduated exit code system. * refactor(exit-codes): replace hardcoded exit codes with named constants Introduce symbolic exit code constants in nac_test/core/constants.py following Robot Framework conventions: EXIT_FAILURE_CAP = 250 # max test failure count reported EXIT_INVALID_ARGS = 252 # invalid RF args or no tests found EXIT_INTERRUPTED = 253 # Ctrl+C / interrupted execution EXIT_ERROR = 255 # infrastructure/execution errors EXIT_SUCCESS (0) is deliberately not defined — it is a universal POSIX convention that never changes, so a named constant adds no clarity. Removed the spuriously added __all__ from constants.py. Also fix template rendering error handling: instead of propagating exceptions in render-only mode (which leaked as exit code 1, violating the "1-250 = test failure count" convention), rendering failures are now converted to TestResults.from_error() objects with descriptive messages. main.py inspects the resulting CombinedResults.has_errors to exit with EXIT_ERROR (255) and display an actionable "❌ Template rendering failed: <reason>" message, consistent with all other infrastructure failures. Updated all tests to use the new constants instead of magic numbers, except where literals are derived directly from test input (e.g. `failed=3` → `assert exit_code == 3`) and therefore more readable as literals. * refactor(exit-codes): split EXIT_INVALID_ARGS into POSIX (2) and Robot (252) EXIT_INVALID_ARGS was previously 252 (Robot Framework convention). This was confusing because nac-test's own CLI argument errors should follow POSIX/Typer conventions (exit code 2) rather than RF conventions. Split into two distinct constants: - EXIT_INVALID_ARGS = 2 (nac-test CLI arg errors, aligns with POSIX/Typer) - EXIT_INVALID_ROBOT_ARGS = 252 (Robot Framework invalid args / no tests found) This allows CI/CD to unambiguously distinguish exit code 2 from a bad CLI invocation vs. 2 test failures (which would produce artifacts). Updated all production code, tests, and README accordingly. * refactor(exit-codes): replace string markers with ErrorType enum for type-safe exit code determination Replace fragile string-based error detection (ERROR_MARKER_*) with a typed ErrorType enum approach. This enables compile-time checking and explicit exit code priority handling. Changes: - Add ErrorType enum (GENERIC, INVALID_ROBOT_ARGS, INTERRUPTED) - Add error_type field to TestResults dataclass - Update from_error() to accept optional error_type parameter - Fix exit code priority: 253 (interrupted) > 252 (invalid args) > 255 (generic) - Remove ERROR_MARKER_* constants from constants.py - Add unit tests for ErrorType and exit code priority * refactor(exit-codes): centralize error reporting in main.py Move all user-facing error/success output to main.py: - Display ❌ for errors,⚠️ for warnings, ✅ for success - Route all error messages to stderr consistently Remove redundant error output from orchestrators: - robot/orchestrator.py: remove typer.echo calls (-15 lines) - combined_orchestrator.py: simplify exception handler (-17 lines) Orchestrators now only log errors and store them in TestResults, following single-responsibility principle. * test: update controller detection tests to expect EXIT_ERROR (255) Tests previously expected exit code 1 for controller detection failures. With the new exit code scheme, infrastructure errors return EXIT_ERROR (255). * Fix test comment with correct expected exit code * refactor(exit-codes): remove unused ERROR_TYPE_EXIT_CODES dict With only 3 error types, the explicit if chain in CombinedResults.exit_code is more readable and makes priority ordering immediately visible. The dict was defined but never used, creating two sources of truth that could drift. * chore(deps): remove unused errorhandler dependency The errorhandler package is no longer used in the codebase after centralizing exit code handling in CombinedResults.exit_code. * refactor(exit-codes): rename EXIT_INVALID_ROBOT_ARGS to EXIT_DATA_ERROR Rename to match Robot Framework's naming convention for exit code 252. This constant serves dual purpose: invalid Robot arguments AND no tests found (via is_empty check), so the more generic name is more accurate. * docs(exit-codes): explain priority ordering rationale in exit_code docstring Add explanation for why priority is 253 > 252 > 255 (counterintuitive numerically): interrupted is most actionable for CI/CD, data errors indicate config issues, generic errors may be transient. * tests: add defaults.apic.version to e2e fixtures to make ACI defaults check happy
…553) * refactor: remove legacy errorhandler, use CombinedResults as single source of truth for exit codes ## Summary Removed the legacy errorhandler system that was interfering with proper exit code behavior. Exit codes are now handled exclusively through CombinedResults.exit_code, providing a single, predictable source of truth that follows Robot Framework conventions. ## Key Changes **Errorhandler Removal:** - Eliminated errorhandler dependency that was causing logger.error() calls to override intended exit codes - Restored proper logger.error() usage throughout the codebase (no more workarounds with logger.warning()) - Developers can now use logger.error() naturally without unintended side effects on exit codes **Single Source of Truth:** - CombinedResults.exit_code is now the only exit code calculation method - Removed unused TestResults.exit_code method that was never called in production - Simplified architecture: exit codes are purely a CLI aggregation concern, not individual framework concern ## Benefits - **Predictable Behavior**: Exit codes come from one clear path (CombinedResults → CLI) - **No Hidden Side Effects**: Logging levels don't accidentally change exit codes - **Cleaner Architecture**: No duplicate exit code logic across TestResults and CombinedResults - **Developer Friendly**: logger.error() works as expected without exit code interference ## Tests - **New CLI exit code tests**: Comprehensive test suite for main.py exit code behavior (9 tests) - **Removed**: Unused TestResults.exit_code tests that tested non-production code paths - All existing integration and E2E tests continue to pass The errorhandler was a legacy mechanism from before CombinedResults existed. With proper structured error handling now in place, the errorhandler created more problems than it solved by interfering with the intended graduated exit code system. * refactor(exit-codes): replace hardcoded exit codes with named constants Introduce symbolic exit code constants in nac_test/core/constants.py following Robot Framework conventions: EXIT_FAILURE_CAP = 250 # max test failure count reported EXIT_INVALID_ARGS = 252 # invalid RF args or no tests found EXIT_INTERRUPTED = 253 # Ctrl+C / interrupted execution EXIT_ERROR = 255 # infrastructure/execution errors EXIT_SUCCESS (0) is deliberately not defined — it is a universal POSIX convention that never changes, so a named constant adds no clarity. Removed the spuriously added __all__ from constants.py. Also fix template rendering error handling: instead of propagating exceptions in render-only mode (which leaked as exit code 1, violating the "1-250 = test failure count" convention), rendering failures are now converted to TestResults.from_error() objects with descriptive messages. main.py inspects the resulting CombinedResults.has_errors to exit with EXIT_ERROR (255) and display an actionable "❌ Template rendering failed: <reason>" message, consistent with all other infrastructure failures. Updated all tests to use the new constants instead of magic numbers, except where literals are derived directly from test input (e.g. `failed=3` → `assert exit_code == 3`) and therefore more readable as literals. * refactor(exit-codes): split EXIT_INVALID_ARGS into POSIX (2) and Robot (252) EXIT_INVALID_ARGS was previously 252 (Robot Framework convention). This was confusing because nac-test's own CLI argument errors should follow POSIX/Typer conventions (exit code 2) rather than RF conventions. Split into two distinct constants: - EXIT_INVALID_ARGS = 2 (nac-test CLI arg errors, aligns with POSIX/Typer) - EXIT_INVALID_ROBOT_ARGS = 252 (Robot Framework invalid args / no tests found) This allows CI/CD to unambiguously distinguish exit code 2 from a bad CLI invocation vs. 2 test failures (which would produce artifacts). Updated all production code, tests, and README accordingly. * refactor(exit-codes): replace string markers with ErrorType enum for type-safe exit code determination Replace fragile string-based error detection (ERROR_MARKER_*) with a typed ErrorType enum approach. This enables compile-time checking and explicit exit code priority handling. Changes: - Add ErrorType enum (GENERIC, INVALID_ROBOT_ARGS, INTERRUPTED) - Add error_type field to TestResults dataclass - Update from_error() to accept optional error_type parameter - Fix exit code priority: 253 (interrupted) > 252 (invalid args) > 255 (generic) - Remove ERROR_MARKER_* constants from constants.py - Add unit tests for ErrorType and exit code priority * refactor(exit-codes): centralize error reporting in main.py Move all user-facing error/success output to main.py: - Display ❌ for errors,⚠️ for warnings, ✅ for success - Route all error messages to stderr consistently Remove redundant error output from orchestrators: - robot/orchestrator.py: remove typer.echo calls (-15 lines) - combined_orchestrator.py: simplify exception handler (-17 lines) Orchestrators now only log errors and store them in TestResults, following single-responsibility principle. * test: update controller detection tests to expect EXIT_ERROR (255) Tests previously expected exit code 1 for controller detection failures. With the new exit code scheme, infrastructure errors return EXIT_ERROR (255). * Fix test comment with correct expected exit code * refactor(exit-codes): remove unused ERROR_TYPE_EXIT_CODES dict With only 3 error types, the explicit if chain in CombinedResults.exit_code is more readable and makes priority ordering immediately visible. The dict was defined but never used, creating two sources of truth that could drift. * chore(deps): remove unused errorhandler dependency The errorhandler package is no longer used in the codebase after centralizing exit code handling in CombinedResults.exit_code. * refactor(exit-codes): rename EXIT_INVALID_ROBOT_ARGS to EXIT_DATA_ERROR Rename to match Robot Framework's naming convention for exit code 252. This constant serves dual purpose: invalid Robot arguments AND no tests found (via is_empty check), so the more generic name is more accurate. * docs(exit-codes): explain priority ordering rationale in exit_code docstring Add explanation for why priority is 253 > 252 > 255 (counterintuitive numerically): interrupted is most actionable for CI/CD, data errors indicate config issues, generic errors may be transient. * tests: add defaults.apic.version to e2e fixtures to make ACI defaults check happy
…553) * refactor: remove legacy errorhandler, use CombinedResults as single source of truth for exit codes ## Summary Removed the legacy errorhandler system that was interfering with proper exit code behavior. Exit codes are now handled exclusively through CombinedResults.exit_code, providing a single, predictable source of truth that follows Robot Framework conventions. ## Key Changes **Errorhandler Removal:** - Eliminated errorhandler dependency that was causing logger.error() calls to override intended exit codes - Restored proper logger.error() usage throughout the codebase (no more workarounds with logger.warning()) - Developers can now use logger.error() naturally without unintended side effects on exit codes **Single Source of Truth:** - CombinedResults.exit_code is now the only exit code calculation method - Removed unused TestResults.exit_code method that was never called in production - Simplified architecture: exit codes are purely a CLI aggregation concern, not individual framework concern ## Benefits - **Predictable Behavior**: Exit codes come from one clear path (CombinedResults → CLI) - **No Hidden Side Effects**: Logging levels don't accidentally change exit codes - **Cleaner Architecture**: No duplicate exit code logic across TestResults and CombinedResults - **Developer Friendly**: logger.error() works as expected without exit code interference ## Tests - **New CLI exit code tests**: Comprehensive test suite for main.py exit code behavior (9 tests) - **Removed**: Unused TestResults.exit_code tests that tested non-production code paths - All existing integration and E2E tests continue to pass The errorhandler was a legacy mechanism from before CombinedResults existed. With proper structured error handling now in place, the errorhandler created more problems than it solved by interfering with the intended graduated exit code system. * refactor(exit-codes): replace hardcoded exit codes with named constants Introduce symbolic exit code constants in nac_test/core/constants.py following Robot Framework conventions: EXIT_FAILURE_CAP = 250 # max test failure count reported EXIT_INVALID_ARGS = 252 # invalid RF args or no tests found EXIT_INTERRUPTED = 253 # Ctrl+C / interrupted execution EXIT_ERROR = 255 # infrastructure/execution errors EXIT_SUCCESS (0) is deliberately not defined — it is a universal POSIX convention that never changes, so a named constant adds no clarity. Removed the spuriously added __all__ from constants.py. Also fix template rendering error handling: instead of propagating exceptions in render-only mode (which leaked as exit code 1, violating the "1-250 = test failure count" convention), rendering failures are now converted to TestResults.from_error() objects with descriptive messages. main.py inspects the resulting CombinedResults.has_errors to exit with EXIT_ERROR (255) and display an actionable "❌ Template rendering failed: <reason>" message, consistent with all other infrastructure failures. Updated all tests to use the new constants instead of magic numbers, except where literals are derived directly from test input (e.g. `failed=3` → `assert exit_code == 3`) and therefore more readable as literals. * refactor(exit-codes): split EXIT_INVALID_ARGS into POSIX (2) and Robot (252) EXIT_INVALID_ARGS was previously 252 (Robot Framework convention). This was confusing because nac-test's own CLI argument errors should follow POSIX/Typer conventions (exit code 2) rather than RF conventions. Split into two distinct constants: - EXIT_INVALID_ARGS = 2 (nac-test CLI arg errors, aligns with POSIX/Typer) - EXIT_INVALID_ROBOT_ARGS = 252 (Robot Framework invalid args / no tests found) This allows CI/CD to unambiguously distinguish exit code 2 from a bad CLI invocation vs. 2 test failures (which would produce artifacts). Updated all production code, tests, and README accordingly. * refactor(exit-codes): replace string markers with ErrorType enum for type-safe exit code determination Replace fragile string-based error detection (ERROR_MARKER_*) with a typed ErrorType enum approach. This enables compile-time checking and explicit exit code priority handling. Changes: - Add ErrorType enum (GENERIC, INVALID_ROBOT_ARGS, INTERRUPTED) - Add error_type field to TestResults dataclass - Update from_error() to accept optional error_type parameter - Fix exit code priority: 253 (interrupted) > 252 (invalid args) > 255 (generic) - Remove ERROR_MARKER_* constants from constants.py - Add unit tests for ErrorType and exit code priority * refactor(exit-codes): centralize error reporting in main.py Move all user-facing error/success output to main.py: - Display ❌ for errors,⚠️ for warnings, ✅ for success - Route all error messages to stderr consistently Remove redundant error output from orchestrators: - robot/orchestrator.py: remove typer.echo calls (-15 lines) - combined_orchestrator.py: simplify exception handler (-17 lines) Orchestrators now only log errors and store them in TestResults, following single-responsibility principle. * test: update controller detection tests to expect EXIT_ERROR (255) Tests previously expected exit code 1 for controller detection failures. With the new exit code scheme, infrastructure errors return EXIT_ERROR (255). * Fix test comment with correct expected exit code * refactor(exit-codes): remove unused ERROR_TYPE_EXIT_CODES dict With only 3 error types, the explicit if chain in CombinedResults.exit_code is more readable and makes priority ordering immediately visible. The dict was defined but never used, creating two sources of truth that could drift. * chore(deps): remove unused errorhandler dependency The errorhandler package is no longer used in the codebase after centralizing exit code handling in CombinedResults.exit_code. * refactor(exit-codes): rename EXIT_INVALID_ROBOT_ARGS to EXIT_DATA_ERROR Rename to match Robot Framework's naming convention for exit code 252. This constant serves dual purpose: invalid Robot arguments AND no tests found (via is_empty check), so the more generic name is more accurate. * docs(exit-codes): explain priority ordering rationale in exit_code docstring Add explanation for why priority is 253 > 252 > 255 (counterintuitive numerically): interrupted is most actionable for CI/CD, data errors indicate config issues, generic errors may be transient. * tests: add defaults.apic.version to e2e fixtures to make ACI defaults check happy
Description
Implement Robot Framework-style exit codes for nac-test CLI to provide meaningful feedback for CI/CD pipelines. Exit codes now follow Robot Framework conventions: 0=pass, 1-249=failed test count, 250=250+ failures, 252=invalid Robot args/no tests, 253=interrupted, 255=internal error.
This also aligns to current nac-test 1.x behaviour
Closes
Related Issue(s)
Type of Change
Test Framework Affected
Network as Code (NaC) Architecture Affected
Platform Tested
Key Changes
Testing Done
Test Commands Used
Checklist
Screenshots (if applicable)
N/A
Additional Notes
Exit Code Summary Table (from README):
Deviation from Robot Framework convention: