fix(cli): require at least one scope flag for invariant add per spec
The invariant add command was silently defaulting to global scope when no scope flag was provided, violating the specification which requires at least one scope flag (--global, --project, --plan, or --action). This fix: - Updates _resolve_scope() to raise typer.BadParameter when no flags are set - Updates the docstring to reflect the requirement - Adds a new BDD scenario to test the missing scope flag error - Updates the existing scenario that expected default to global behavior
This commit is contained in:
@@ -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
|
||||
@@ -71,6 +70,12 @@ Feature: Invariant CLI commands coverage
|
||||
Then the invariant CLI exit code should be 0
|
||||
And the invariant CLI output should contain "JSON constraint"
|
||||
|
||||
Scenario: Add invariant without scope flag raises error
|
||||
Given a mocked InvariantService for invariant CLI add
|
||||
When I invoke invariant add with no scope flags and text "Missing scope"
|
||||
Then the invariant CLI exit code should be non-zero
|
||||
And the invariant CLI output should contain "At least one scope flag is required"
|
||||
|
||||
Scenario: Add invariant handles CleverAgentsError
|
||||
Given a mocked InvariantService that raises CleverAgentsError on add
|
||||
When I invoke invariant add with "--global" and text "will fail"
|
||||
|
||||
@@ -91,9 +91,13 @@ 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:
|
||||
context.resolved_scope, context.resolved_source = _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 +218,12 @@ def step_run_add(context, flags, text):
|
||||
context.inv_result = _runner.invoke(app, args)
|
||||
|
||||
|
||||
@when('I invoke invariant add with no scope flags and text "{text}"')
|
||||
def step_run_add_no_scope(context, text):
|
||||
args = ["add", text]
|
||||
context.inv_result = _runner.invoke(app, args)
|
||||
|
||||
|
||||
@then("the invariant CLI exit code should be 0")
|
||||
def step_check_exit_zero(context):
|
||||
assert context.inv_result.exit_code == 0, (
|
||||
|
||||
@@ -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.
|
||||
At least one scope flag must be provided.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -86,6 +86,12 @@ def _resolve_scope(
|
||||
"Specify at most one scope flag: --global, --project, --plan, or --action"
|
||||
)
|
||||
|
||||
if flags_set == 0:
|
||||
raise typer.BadParameter(
|
||||
"At least one scope flag is required: --global, --project, --plan, "
|
||||
"or --action"
|
||||
)
|
||||
|
||||
if project is not None:
|
||||
return InvariantScope.PROJECT, project
|
||||
if plan is not None:
|
||||
@@ -93,7 +99,6 @@ def _resolve_scope(
|
||||
if action is not None:
|
||||
return InvariantScope.ACTION, action
|
||||
|
||||
# Default to global
|
||||
return InvariantScope.GLOBAL, "system"
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user