Skip to content

Commit ab55bd7

Browse files
author
Revenue Holdings
committed
fix: ruff lint fixes, add ruff CI step, CONTRIBUTING.md, remove BOM from config files
1 parent b9918b0 commit ab55bd7

9 files changed

Lines changed: 65 additions & 23 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,13 @@ jobs:
2626
python -m pip install --upgrade pip
2727
pip install -e ".[dev]"
2828
29+
- name: Lint with ruff
30+
run: pip install ruff && ruff check src/ --target-version py310
2931
- name: Run tests
3032
run: |
3133
python -m pytest tests/ -v --tb=short
3234
3335
- name: Check CLI works
3436
run: |
3537
api-contract-guardian --help
38+

.github/workflows/publish.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,4 @@ jobs:
5151
TWINE_PASSWORD: \${{ secrets.TEST_PYPI_API_TOKEN }}
5252
run: |
5353
twine upload --repository testpypi dist/* --verbose
54+

CONTRIBUTING.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Contributing
2+
3+
Thanks for your interest in contributing!
4+
5+
## Development Setup
6+
7+
1. Fork and clone the repo
8+
2. Create a virtual environment: python -m venv .venv && source .venv/bin/activate
9+
3. Install dev dependencies: pip install -e ".[dev]"
10+
4. Run tests: pytest tests/ -v
11+
5. Lint: uff check src/
12+
13+
## Pull Requests
14+
15+
- Fork the repo and create a feature branch
16+
- Add tests for any new functionality
17+
- Ensure all existing tests pass
18+
- Run uff check src/ --fix before committing
19+
- Keep PRs focused on a single change
20+
21+
## Reporting Issues
22+
23+
- Use GitHub Issues
24+
- Include Python version, OS, and steps to reproduce
25+
- Include relevant error output
26+
27+
## Code Style
28+
29+
- Python 3.10+
30+
- Type hints where practical
31+
- Follow ruff defaults (Black-compatible formatting)
32+
33+
## License
34+
35+
By contributing, you agree your work will be licensed under the same license as this project.

pyproject.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,14 @@ where = ["src"]
4545
[tool.pytest.ini_options]
4646
testpaths = ["tests"]
4747
addopts = "-v --tb=short"
48+
49+
[tool.ruff]
50+
target-version = "py310"
51+
line-length = 120
52+
53+
[tool.ruff.lint]
54+
select = ["E", "F", "W", "I", "UP", "B", "SIM"]
55+
ignore = ["E501"]
56+
57+
[tool.ruff.lint.isort]
58+
known-first-party = ["*"]

src/api_contract_guardian/cli.py

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,18 @@
33
from __future__ import annotations
44

55
import json
6-
import sys
7-
from pathlib import Path
8-
from typing import Optional
9-
106
import typer
7+
from pathlib import Path
118
from rich.console import Console
129
from rich.table import Table
13-
from rich.panel import Panel
14-
from rich.text import Text
1510

1611
try:
1712
from revenueholdings_license import require_license
1813
except ImportError:
1914
require_license = None
2015

21-
from .diff import DiffResult, Severity, diff_specs
22-
from .gate import GateResult, check_gate
16+
from .diff import DiffResult, diff_specs
17+
from .gate import check_gate
2318
from .loader import SpecLoadError, load_spec, validate_openapi_version
2419
from .migration import generate_migration_guide, generate_migration_guide_json
2520

@@ -86,7 +81,7 @@ def _print_result(result: DiffResult) -> None:
8681
def diff(
8782
old: str = typer.Argument(..., help="Path to old (baseline) OpenAPI spec"),
8883
new: str = typer.Argument(..., help="Path to new (proposed) OpenAPI spec"),
89-
output: Optional[str] = typer.Option(None, "--output", "-o", help="Output file path"),
84+
output: str | None = typer.Option(None, "--output", "-o", help="Output file path"),
9085
format: str = typer.Option("rich", "--format", "-f", help="Output format: rich, json, markdown"),
9186
) -> None:
9287
"""Compare two OpenAPI specs and show all detected changes."""
@@ -127,7 +122,7 @@ def check(
127122
fail_on_dangerous: bool = typer.Option(False, "--fail-on-dangerous/--allow-dangerous", help="Fail on dangerous changes"),
128123
max_breaking: int = typer.Option(0, "--max-breaking", help="Max allowed breaking changes (default 0)"),
129124
max_dangerous: int = typer.Option(-1, "--max-dangerous", help="Max allowed dangerous changes (-1=unlimited)"),
130-
output: Optional[str] = typer.Option(None, "--output", "-o", help="Output file path"),
125+
output: str | None = typer.Option(None, "--output", "-o", help="Output file path"),
131126
) -> None:
132127
"""Gate CI pipeline on breaking changes. Returns exit code 1 if gate fails."""
133128
if require_license:
@@ -167,7 +162,7 @@ def check(
167162
def migrate(
168163
old: str = typer.Argument(..., help="Path to old (baseline) OpenAPI spec"),
169164
new: str = typer.Argument(..., help="Path to new (proposed) OpenAPI spec"),
170-
output: Optional[str] = typer.Option(None, "--output", "-o", help="Output file path"),
165+
output: str | None = typer.Option(None, "--output", "-o", help="Output file path"),
171166
format: str = typer.Option("markdown", "--format", "-f", help="Output format: markdown, json"),
172167
) -> None:
173168
"""Generate a migration guide between two OpenAPI spec versions."""

src/api_contract_guardian/diff.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
from enum import Enum
77
from typing import Any
88

9-
from deepdiff import DeepDiff
10-
119

1210
class Severity(str, Enum):
1311
BREAKING = "breaking"

src/api_contract_guardian/gate.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from dataclasses import dataclass
66
from typing import Any
77

8-
from .diff import DiffResult, Severity
8+
from .diff import DiffResult
99

1010

1111
@dataclass
@@ -53,20 +53,20 @@ def check_gate(
5353

5454
# Determine effective thresholds
5555
if max_breaking >= 0:
56-
if fail_on_breaking or max_breaking > 0:
56+
if fail_on_breaking or max_breaking > 0: # noqa: SIM108
5757
effective_max_breaking = max_breaking
5858
else:
59-
effective_max_breaking = -1 # unlimited
59+
effective_max_breaking = -1 # unlimited
6060
elif fail_on_breaking:
6161
effective_max_breaking = 0 # default: zero tolerance
6262
else:
6363
effective_max_breaking = -1 # unlimited
6464

6565
if max_dangerous >= 0:
66-
if fail_on_dangerous or max_dangerous > 0:
66+
if fail_on_dangerous or max_dangerous > 0: # noqa: SIM108
6767
effective_max_dangerous = max_dangerous
6868
else:
69-
effective_max_dangerous = -1 # unlimited
69+
effective_max_dangerous = -1 # unlimited
7070
elif fail_on_dangerous:
7171
effective_max_dangerous = 0 # default: zero tolerance
7272
else:

src/api_contract_guardian/loader.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@
33
from __future__ import annotations
44

55
import json
6+
import yaml
67
from pathlib import Path
78
from typing import Any
89

9-
import yaml
10-
1110

1211
class SpecLoadError(Exception):
1312
"""Raised when a spec file cannot be loaded or parsed."""

src/api_contract_guardian/migration.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from typing import Any
66

7-
from .diff import Change, DiffResult, Severity
7+
from .diff import Change, DiffResult
88

99

1010
def generate_migration_guide(result: DiffResult) -> str:
@@ -27,8 +27,8 @@ def generate_migration_guide(result: DiffResult) -> str:
2727
summary = result.to_dict()["summary"]
2828
lines.append("## Summary")
2929
lines.append("")
30-
lines.append(f"| Severity | Count |")
31-
lines.append(f"|----------|-------|")
30+
lines.append("| Severity | Count |")
31+
lines.append("|----------|-------|")
3232
lines.append(f"| Breaking | {summary['breaking']} |")
3333
lines.append(f"| Dangerous | {summary['dangerous']} |")
3434
lines.append(f"| Non-breaking | {summary['non_breaking']} |")

0 commit comments

Comments
 (0)