From 5be3a5d709fca200cc45e1d21bd01d8498c38fb9 Mon Sep 17 00:00:00 2001 From: CEO Agent Date: Tue, 23 Jun 2026 01:41:30 -0400 Subject: [PATCH 1/3] docs: add AGENTS.md for agent discoverability --- .gitignore | 1 - AGENTS.md | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 AGENTS.md diff --git a/.gitignore b/.gitignore index 0fb7c58..23abba5 100644 --- a/.gitignore +++ b/.gitignore @@ -74,6 +74,5 @@ fixtures/generated/ .ruff_cache/ # Local opencode config -AGENTS.md .agents/ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..2c0cd05 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,25 @@ +# API Contract Guardian + +## Purpose +CLI tool that monitors OpenAPI schema diffs, detects breaking changes, generates migration guides, and gates CI pipelines on contract violations. + +## Build & Test Commands +- Install: `pip install -e .` or `pip install git+https://github.com/Coding-Dev-Tools/api-contract-guardian.git` +- Test: `pytest` +- Lint: `ruff check .` +- Build: `pip wheel . --wheel-dir dist/` + +## Architecture +Key directories: +- `src/api_contract_guardian/` — Main package (CLI, diff engine, migration guide generator) +- `tests/` — Test suite +- `.github/workflows/` — CI/CD (4 workflows) + +## Conventions +- Language: Python 3.10+ +- Test framework: pytest +- CI: GitHub Actions (4 workflows) +- Formatting: ruff (line-length 120) +- Type checking: py.typed included +- Package: setuptools with src layout +- CLI framework: typer \ No newline at end of file From bdea59e6298decaa6c774a325c7598e52bb1f1d4 Mon Sep 17 00:00:00 2001 From: CEO Agent Date: Tue, 23 Jun 2026 12:13:48 -0400 Subject: [PATCH 2/3] improve: update dependency versions to latest compatible --- pyproject.toml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e16eec9..5c68557 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,11 +22,11 @@ classifiers = [ "Programming Language :: Python :: 3.13", ] dependencies = [ - "typer>=0.9.0", - "rich>=13.0.0", + "typer>=0.26.0", + "rich>=15.0.0", "pyyaml>=6.0", "jsonschema>=4.17.0", - "deepdiff>=6.0.0", + "deepdiff>=9.0.0", ] [project.urls] @@ -38,21 +38,21 @@ Changelog = "https://github.com/Coding-Dev-Tools/api-contract-guardian/releases" [project.optional-dependencies] dev = [ - "pytest>=7.0.0", - "pytest-cov>=4.0.0", - "ruff>=0.4.0", + "pytest>=9.0.0", + "pytest-cov>=7.0.0", + "ruff>=0.15.0", ] license = ["revenueholdings-license>=0.1.0"] [project.scripts] api-contract-guardian = "api_contract_guardian.cli:app" -[tool.setuptools.packages.find] -where = ["src"] - [tool.setuptools] include-package-data = true +[tool.setuptools.packages.find] +where = ["src"] + [tool.setuptools.package-data] api_contract_guardian = ["py.typed"] @@ -69,4 +69,4 @@ select = ["E", "F", "W", "I", "UP", "B", "SIM"] ignore = ["E501"] [tool.ruff.lint.isort] -known-first-party = ["api_contract_guardian"] +known-first-party = ["api_contract_guardian"] \ No newline at end of file From 536b02d0c1089f579ca32c08415ae652c8ff73d9 Mon Sep 17 00:00:00 2001 From: CEO Agent Date: Tue, 23 Jun 2026 12:14:56 -0400 Subject: [PATCH 3/3] fix: lint fixes and exception chaining by reviewer-A --- src/api_contract_guardian/cli.py | 8 ++++++-- tests/test_cli.py | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/api_contract_guardian/cli.py b/src/api_contract_guardian/cli.py index 3a8d4d3..7f8933d 100644 --- a/src/api_contract_guardian/cli.py +++ b/src/api_contract_guardian/cli.py @@ -2,10 +2,11 @@ from __future__ import annotations -import typer from pathlib import Path from typing import Any +import typer + # Lazy imports — jwt+cryptography+deepdiff+yaml add ~200ms at module level. # Deferring heavy deps to command execution cuts cold start from ~440ms to ~180ms. @@ -70,7 +71,7 @@ def _load_and_validate(path: str) -> dict: except SpecLoadError as e: from rich.console import Console Console().print(f"[red]Error loading: {e}[/red]") - raise typer.Exit(code=1) + raise typer.Exit(code=1) from e def _print_result(result: Any) -> None: @@ -121,6 +122,7 @@ def diff( ) -> None: """Compare two OpenAPI specs and show all detected changes.""" import json + import yaml from .diff import diff_specs @@ -180,6 +182,7 @@ def check( ) -> None: """Gate CI pipeline on breaking changes. Returns exit code 1 if gate fails.""" import json + import yaml from .diff import diff_specs @@ -243,6 +246,7 @@ def migrate( ) -> None: """Generate a migration guide between two OpenAPI spec versions.""" import json + import yaml from .diff import diff_specs diff --git a/tests/test_cli.py b/tests/test_cli.py index 89dabfe..6d18c91 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -639,7 +639,7 @@ def test_main_module_version(self): # carry over to a separate process). from revenueholdings_license.rate_limiter import RateLimiter RateLimiter().reset("api-contract-guardian") - from revenueholdings_license import generate_license_key, Tier + from revenueholdings_license import Tier, generate_license_key env = os.environ.copy() env["REVENUEHOLDINGS_LICENSE_KEY"] = generate_license_key(Tier.PRO) # Ensure all environment variables are string keys and string values to prevent Popen TypeError on Windows