fix(cli): fix invariant add scope handling (#6331)
CI / benchmark-publish (pull_request) Has been skipped
CI / helm (pull_request) Successful in 28s
CI / push-validation (pull_request) Successful in 29s
CI / lint (pull_request) Failing after 31s
CI / build (pull_request) Successful in 33s
CI / quality (pull_request) Successful in 42s
CI / typecheck (pull_request) Successful in 53s
CI / security (pull_request) Successful in 58s
CI / coverage (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Has been skipped
CI / integration_tests (pull_request) Successful in 4m5s
CI / e2e_tests (pull_request) Successful in 4m10s
CI / unit_tests (pull_request) Successful in 5m31s
CI / docker (pull_request) Has been skipped
CI / status-check (pull_request) Failing after 1s

Ensure invariant add enforces explicit scope selection and covers missing flag error in CLI tests.\n\nISSUES CLOSED: #6331
This commit is contained in:
2026-04-09 21:31:25 +00:00
parent fc9c730670
commit c41a479069
3 changed files with 30 additions and 10 deletions
+8 -3
View File
@@ -25,10 +25,9 @@ Feature: Invariant CLI commands coverage
Then the resolved invariant scope should be "action"
And the resolved invariant source name should be "deploy-service"
Scenario: Resolve scope with no flags defaults to GLOBAL
Scenario: Resolve scope with no flags raises BadParameter
When I resolve invariant scope with no flags
Then the resolved invariant scope should be "global"
And the resolved invariant source name should be "system"
Then a BadParameter error should be raised for invariant scope
Scenario: Resolve scope with conflicting flags raises BadParameter
When I resolve invariant scope with global and project flags
@@ -65,6 +64,12 @@ Feature: Invariant CLI commands coverage
Then the invariant CLI exit code should be 0
And the invariant CLI output should contain "Invariant added"
Scenario: Add invariant without scope flag via CLI
Given a mocked InvariantService for invariant CLI add
When I invoke invariant add without scope flags and text "Missing scope flag"
Then the invariant CLI exit code should be non-zero
And the invariant CLI output should contain "Exactly one scope flag is required"
Scenario: Add invariant with --format json via CLI
Given a mocked InvariantService for invariant CLI add
When I invoke invariant add with "--global --format json" and text "JSON constraint"
@@ -91,9 +91,11 @@ def step_resolve_scope_action(context, action):
@when("I resolve invariant scope with no flags")
def step_resolve_scope_default(context):
context.resolved_scope, context.resolved_source = _resolve_scope(
is_global=False, project=None, plan=None, action=None
)
context.inv_bad_parameter_raised = False
try:
_resolve_scope(is_global=False, project=None, plan=None, action=None)
except typer.BadParameter:
context.inv_bad_parameter_raised = True
@when("I resolve invariant scope with global and project flags")
@@ -214,6 +216,11 @@ def step_run_add(context, flags, text):
context.inv_result = _runner.invoke(app, args)
@when('I invoke invariant add without scope flags and text "{text}"')
def step_run_add_no_flags(context, text):
context.inv_result = _runner.invoke(app, ["add", text])
@then("the invariant CLI exit code should be 0")
def step_check_exit_zero(context):
assert context.inv_result.exit_code == 0, (
+12 -4
View File
@@ -20,7 +20,7 @@ Each invariant belongs to exactly one scope. Pass the matching flag:
- ``--action ACTION``: Action-template invariant
- ``--plan PLAN_ID``: Plan-specific invariant
If no scope flag is given, ``--global`` is assumed.
Exactly one scope flag must be provided; commands error when omitted.
## Examples
@@ -81,11 +81,17 @@ def _resolve_scope(
flags_set = sum(
[is_global, project is not None, plan is not None, action is not None]
)
if flags_set == 0:
raise typer.BadParameter(
"Exactly one scope flag is required: --global, --project, --plan, or --action"
)
if flags_set > 1:
raise typer.BadParameter(
"Specify at most one scope flag: --global, --project, --plan, or --action"
"Specify only one scope flag: --global, --project, --plan, or --action"
)
if is_global:
return InvariantScope.GLOBAL, "system"
if project is not None:
return InvariantScope.PROJECT, project
if plan is not None:
@@ -93,8 +99,10 @@ def _resolve_scope(
if action is not None:
return InvariantScope.ACTION, action
# Default to global
return InvariantScope.GLOBAL, "system"
# This line is unreachable because flags_set == 0 already raises BadParameter.
raise typer.BadParameter(
"Exactly one scope flag is required: --global, --project, --plan, or --action"
)
def _invariant_dict(inv: Invariant) -> dict[str, object]: