diff --git a/.gitignore b/.gitignore index 5934074..4659a71 100644 --- a/.gitignore +++ b/.gitignore @@ -71,6 +71,7 @@ Thumbs.db research/ fixtures/generated/ .ruff_cache/ +.secrets.baseline # Merge artifacts and cache (added by workspace stabilization) *.pyc diff --git a/AGENTS.md b/AGENTS.md index 7d5daf3..7c39a1e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -16,6 +16,7 @@ Key directories: - `tests/` — Test suite - `.github/workflows/` — CI/CD (auto-code-review.yml, ci.yml, pages.yml, publish.yml) - `dist/` — Built distributions +- `scripts/` — Automation scripts ## Conventions - Language: Python 3.10+ @@ -26,4 +27,9 @@ Key directories: - Package layout: src/ layout - Dependencies: click, rich, pyyaml, tomli, jinja2 - CLI entry point: deploydiff.cli:cli -- Default branch: main \ No newline at end of file +- Default branch: main +- Versioning: Semantic versioning (semver) +- Documentation: Markdown + +## Contributing +See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed contribution guidelines and development workflow. \ No newline at end of file diff --git a/src/deploydiff/cli.py b/src/deploydiff/cli.py index 091cbd9..f84d6e1 100644 --- a/src/deploydiff/cli.py +++ b/src/deploydiff/cli.py @@ -252,8 +252,7 @@ def mcp() -> None: from .mcp_server import run_for_app except ImportError as exc: console.print( - "[red]Error: click-to-mcp is not installed.[/red]\n" - "Install it with: [bold]pip install click-to-mcp[/bold]" + "[red]Error: click-to-mcp is not installed.[/red]\nInstall it with: [bold]pip install click-to-mcp[/bold]" ) raise SystemExit(1) from exc diff --git a/src/deploydiff/cost_estimator.py b/src/deploydiff/cost_estimator.py index d405305..0c3faa4 100644 --- a/src/deploydiff/cost_estimator.py +++ b/src/deploydiff/cost_estimator.py @@ -247,7 +247,7 @@ def _load_pricing( if not path.exists(): return DEFAULT_PRICING.copy() - with open(path) as f: + with path.open() as f: custom = json.load(f) # Merge with defaults (custom overrides) diff --git a/src/deploydiff/mcp_server.py b/src/deploydiff/mcp_server.py index 150f3d6..a59135e 100644 --- a/src/deploydiff/mcp_server.py +++ b/src/deploydiff/mcp_server.py @@ -19,8 +19,7 @@ def run_mcp() -> None: import sys print( - "Error: click-to-mcp is not installed. " - "Install it with: pip install click-to-mcp", + "Error: click-to-mcp is not installed. Install it with: pip install click-to-mcp", file=sys.stderr, ) sys.exit(1) @@ -38,8 +37,7 @@ def run_for_app(app: object) -> None: import sys print( - "Error: click-to-mcp is not installed. " - "Install it with: pip install click-to-mcp", + "Error: click-to-mcp is not installed. Install it with: pip install click-to-mcp", file=sys.stderr, ) sys.exit(1) diff --git a/src/deploydiff/pulumi_parser.py b/src/deploydiff/pulumi_parser.py index 07970f4..5802b69 100644 --- a/src/deploydiff/pulumi_parser.py +++ b/src/deploydiff/pulumi_parser.py @@ -3,6 +3,7 @@ from __future__ import annotations import json +from pathlib import Path from typing import Any from .models import ChangeAction, ChangeSource, DeployPlan, ResourceChange @@ -39,7 +40,7 @@ def parse_pulumi_preview(preview_json: str | dict[str, Any]) -> DeployPlan: try: data = json.loads(preview_json) except json.JSONDecodeError: - with open(preview_json) as f: + with Path(preview_json).open() as f: data = json.load(f) else: data = preview_json diff --git a/src/deploydiff/terraform_parser.py b/src/deploydiff/terraform_parser.py index 4308898..68fd890 100644 --- a/src/deploydiff/terraform_parser.py +++ b/src/deploydiff/terraform_parser.py @@ -3,6 +3,7 @@ from __future__ import annotations import json +from pathlib import Path from typing import Any from .models import ChangeAction, ChangeSource, DeployPlan, ResourceChange @@ -33,7 +34,7 @@ def parse_terraform_plan(plan_json: str | dict[str, Any]) -> DeployPlan: data = json.loads(plan_json) except json.JSONDecodeError: # Try as file path - with open(plan_json) as f: + with Path(plan_json).open() as f: data = json.load(f) else: data = plan_json @@ -72,9 +73,7 @@ def parse_terraform_plan(plan_json: str | dict[str, Any]) -> DeployPlan: else set() ) after_sensitive = ( - set(change.get("after_sensitive", {}).keys()) - if isinstance(change.get("after_sensitive"), dict) - else set() + set(change.get("after_sensitive", {}).keys()) if isinstance(change.get("after_sensitive"), dict) else set() ) resource_change = ResourceChange( diff --git a/tests/conftest.py b/tests/conftest.py index 38b2915..1bcbe3c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -17,9 +17,5 @@ @pytest.fixture(autouse=True) def _mock_license(monkeypatch): """Ensure license checks stay mocked even if a test reimports.""" - monkeypatch.setattr( - "revenueholdings_license.require_license", MagicMock(return_value=None) - ) - monkeypatch.setattr( - "revenueholdings_license.require_tier", MagicMock(return_value=None) - ) + monkeypatch.setattr("revenueholdings_license.require_license", MagicMock(return_value=None)) + monkeypatch.setattr("revenueholdings_license.require_tier", MagicMock(return_value=None))