Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/api_contract_guardian/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ def check(
fail_on_dangerous: bool = typer.Option(
False, "--fail-on-dangerous/--allow-dangerous", help="Fail on dangerous changes",
),
max_breaking: int = typer.Option(0, "--max-breaking", help="Max allowed breaking changes (default 0)"),
max_dangerous: int = typer.Option(-1, "--max-dangerous", help="Max allowed dangerous changes (-1=unlimited)"),
max_breaking: int = typer.Option(-1, "--max-breaking", help="Max allowed breaking changes (-1=defer to flag, 0=none)"),
max_dangerous: int = typer.Option(-1, "--max-dangerous", help="Max allowed dangerous changes (-1=defer to flag, 0=none)"),
output: str | None = typer.Option(None, "--output", "-o", help="Output file path"),
) -> None:
"""Gate CI pipeline on breaking changes. Returns exit code 1 if gate fails."""
Expand Down
14 changes: 5 additions & 9 deletions src/api_contract_guardian/gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def check_gate(
*,
fail_on_breaking: bool = True,
fail_on_dangerous: bool = False,
max_breaking: int = 0,
max_breaking: int = -1,
max_dangerous: int = -1,
) -> GateResult:
"""Check if a diff result passes the CI gate.
Expand All @@ -52,21 +52,17 @@ def check_gate(
dangerous_count = len(result.dangerous_changes)

# Determine effective thresholds
# max_breaking >= 0 is an explicit ceiling — always honour it.
# When absent (-1, the default), fall back to fail_on_breaking flag.
if max_breaking >= 0:
if fail_on_breaking or max_breaking > 0: # noqa: SIM108
effective_max_breaking = max_breaking
else:
effective_max_breaking = -1 # unlimited
effective_max_breaking = max_breaking
elif fail_on_breaking:
effective_max_breaking = 0 # default: zero tolerance
else:
effective_max_breaking = -1 # unlimited

if max_dangerous >= 0:
if fail_on_dangerous or max_dangerous > 0: # noqa: SIM108
effective_max_dangerous = max_dangerous
else:
effective_max_dangerous = -1 # unlimited
effective_max_dangerous = max_dangerous
elif fail_on_dangerous:
effective_max_dangerous = 0 # default: zero tolerance
else:
Expand Down
12 changes: 12 additions & 0 deletions tests/test_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,15 @@ def test_fail_on_breaking_false_max_breaking_exceeded(self):
result = _make_result(breaking=3)
gate = check_gate(result, fail_on_breaking=False, max_breaking=1)
assert not gate.passed

def test_fail_on_breaking_false_max_breaking_zero_enforced(self):
"""max_breaking=0 should still fail even when fail_on_breaking=False."""
result = _make_result(breaking=1)
gate = check_gate(result, fail_on_breaking=False, max_breaking=0)
assert not gate.passed

def test_fail_on_dangerous_false_max_dangerous_zero_enforced(self):
"""max_dangerous=0 should still fail even when fail_on_dangerous=False."""
result = _make_result(dangerous=1)
gate = check_gate(result, fail_on_breaking=False, max_dangerous=0)
assert not gate.passed
Loading