Skip to content
Open
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
65 changes: 48 additions & 17 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,23 @@ permissions:
contents: read

jobs:
# Linux-only for PR feedback. Full platform matrix (incl. macOS + Windows) runs post-merge in build-release.yml.
# Combines unit tests + binary build into a single job to eliminate runner re-provisioning overhead.
build-and-test:
name: Build & Test (Linux)
# Fast lint gate -- runs in ~3s using Astral's ruff-action (no Python/uv setup needed).
# Fails fast on style, import, and complexity violations before the heavier build-and-test job.
lint:
name: Lint
runs-on: ubuntu-24.04
permissions:
contents: read

steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v6

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Ruff lint
run: uv run --extra dev ruff check src/ tests/

- name: Install uv
uses: astral-sh/setup-uv@v6
with:
enable-cache: true

- name: Install dependencies
run: uv sync --extra dev --extra build
- name: Ruff format check
run: uv run --extra dev ruff format --check src/ tests/

- name: Check YAML encoding safety
run: |
Expand All @@ -56,8 +50,18 @@ jobs:
exit 1
fi

- name: Run tests
run: uv run pytest tests/unit tests/test_console.py -n auto --dist worksteal
- name: File length guardrail
run: |
# Ruff has no max-module-lines rule. This check prevents new files from
# exceeding the current worst case. Tighten the threshold over time.
MAX_LINES=3000 # current max: 2917 (github_downloader.py)
VIOLATIONS=$(find src/ -name '*.py' -print0 | xargs -0 -I{} awk -v max="$MAX_LINES" \
'END { if (NR > max) printf "%s: %d lines (max %d)\n", FILENAME, NR, max }' {})
if [ -n "$VIOLATIONS" ]; then
echo "::error::Source files exceed $MAX_LINES-line limit:"
echo "$VIOLATIONS"
exit 1
fi

- name: Lint - no raw str(relative_to) patterns
run: |
Expand All @@ -67,6 +71,33 @@ jobs:
exit 1
fi

# Linux-only for PR feedback. Full platform matrix (incl. macOS + Windows) runs post-merge in build-release.yml.
# Combines unit tests + binary build into a single job to eliminate runner re-provisioning overhead.
build-and-test:
name: Build & Test (Linux)
runs-on: ubuntu-24.04
permissions:
contents: read

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}

- name: Install uv
uses: astral-sh/setup-uv@v6
with:
enable-cache: true

- name: Install dependencies
run: uv sync --extra dev --extra build

- name: Run tests
run: uv run pytest tests/unit tests/test_console.py -n auto --dist worksteal

- name: Install UPX
run: |
sudo apt-get update
Expand Down
9 changes: 9 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Optional: install with `uv run pre-commit install` for local lint feedback.
# CI (ci.yml lint job) is the authoritative gate -- pre-commit is a convenience.
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.12 # keep in sync with ruff version in uv.lock
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- Replace `black` + `isort` with Ruff for linting and formatting; add deterministic CI lint gate (~3s), configure 10 rule sets with strangler-fig complexity thresholds, and fix a Python 3.10 f-string compatibility bug in `audit_report.py` -- by @sergio-sisternes-epam (#999)

## [0.10.0] - 2026-04-27

### Added
Expand Down
21 changes: 16 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Enhancement suggestions are welcome! Please:
2. Create a new branch for your feature/fix: `git checkout -b feature/your-feature-name` or `git checkout -b fix/issue-description`.
3. Make your changes.
4. Run tests: `uv run pytest tests/unit tests/test_console.py -x`
5. Ensure your code follows our coding style (we use Black and isort).
5. Ensure your code passes linting: `uv run ruff check src/ tests/`
6. Commit your changes with a descriptive message.
7. Push to your fork.
8. Submit a pull request.
Expand Down Expand Up @@ -131,15 +131,26 @@ pytest tests/unit tests/test_console.py -x

This project follows:
- [PEP 8](https://pep8.org/) for Python style guidelines
- We use Black for code formatting and isort for import sorting
- We use [Ruff](https://docs.astral.sh/ruff/) for linting and formatting

You can run these tools with:
CI enforces all lint and formatting rules automatically. You can run them locally:

```bash
uv run black .
uv run isort .
uv run ruff check src/ tests/ # lint
uv run ruff check --fix src/ tests/ # lint with auto-fix
uv run ruff format src/ tests/ # format
```

### Optional: local pre-commit hooks

For instant feedback before pushing, install the pre-commit hooks:

```bash
uv run pre-commit install
```

This is optional -- CI is the authoritative gate. The pre-commit hook rev may lag behind the CI version; check `.pre-commit-config.yaml` against `uv.lock` if you see discrepancies.

## Documentation

If your changes affect how users interact with the project, update the documentation accordingly.
Expand Down
21 changes: 16 additions & 5 deletions docs/src/content/docs/contributing/development-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Enhancement suggestions are welcome! Please:
2. Create a new branch for your feature/fix: `git checkout -b feature/your-feature-name` or `git checkout -b fix/issue-description`.
3. Make your changes.
4. Run tests: `uv run pytest`
5. Ensure your code follows our coding style (we use Black and isort).
5. Ensure your code passes linting: `uv run ruff check src/ tests/`
6. Commit your changes with a descriptive message.
7. Push to your fork.
8. Submit a pull request.
Expand Down Expand Up @@ -104,15 +104,26 @@ pytest -q

This project follows:
- [PEP 8](https://pep8.org/) for Python style guidelines
- We use Black for code formatting and isort for import sorting
- We use [Ruff](https://docs.astral.sh/ruff/) for linting and formatting

You can run these tools with:
CI enforces all lint and formatting rules automatically. You can run them locally:

```bash
uv run black .
uv run isort .
uv run ruff check src/ tests/ # lint
uv run ruff check --fix src/ tests/ # lint with auto-fix
uv run ruff format src/ tests/ # format
```

### Optional: local pre-commit hooks

For instant feedback before pushing, install the pre-commit hooks:

```bash
uv run pre-commit install
```

This is optional -- CI is the authoritative gate. The pre-commit hook rev may lag behind the CI version; check `.pre-commit-config.yaml` against `uv.lock` if you see discrepancies.

## Documentation

If your changes affect how users interact with the project, update the documentation accordingly.
Expand Down
71 changes: 63 additions & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ dev = [
"pytest>=7.0.0",
"pytest-cov>=4.0.0",
"pytest-xdist>=3.0.0",
"black>=26.3.1; python_version>='3.10'",
"isort>=5.0.0",
"ruff>=0.11.0",
"mypy>=1.0.0",
]
build = [
Expand All @@ -58,13 +57,68 @@ apm = "apm_cli.cli:main"
where = ["src"]
include = ["apm_cli*"]

[tool.black]
line-length = 88
target-version = ["py312"]
[tool.ruff]
line-length = 100
target-version = "py310"

[tool.isort]
profile = "black"
line_length = 88
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"F", # pyflakes (unused imports, undefined names)
"I", # isort (import ordering)
"UP", # pyupgrade (Python modernisation)
"B", # bugbear (common bugs: mutable defaults, assert-false)
"SIM", # simplify (mechanical transformations)
"RUF", # ruff-specific patterns
"S", # bandit security checks
"PLR", # pylint refactor (complexity metrics)
"C90", # McCabe cyclomatic complexity
]
ignore = [
"PLR2004", # magic-value-comparison -- too noisy, especially in tests
"E501", # line-too-long -- ruff format handles code; remaining are strings/URLs
# --- Permanently ignored: intentional patterns in a CLI tool ---
"SIM117", # multiple-with-statements -- style preference, 65 violations
"S110", # try-except-pass -- intentional graceful degradation in CLI error handling
"S602", # subprocess-popen-with-shell -- intentional in CLI wrapping git/pip
# --- Deferred rules: enable in dedicated future PRs ---
"SIM102", # collapsible-if -- 28 violations, auto-fixable style improvement
"RUF003", # ambiguous-unicode-character-comment -- 14 violations, review against ASCII convention
"RUF002", # ambiguous-unicode-character-docstring -- 8 violations, same as above
]

[tool.ruff.lint.pylint]
# High initial thresholds set just above current codebase maximums.
# Prevents new code from exceeding the worst existing violations.
# Tighten these over time via dedicated refactoring PRs.
max-statements = 250 # current max: 244 (commands/install.py)
max-args = 18 # current max: 16 (commands/install.py)
max-branches = 70 # current max: 67 (commands/install.py)
max-returns = 18 # current max: 16 (marketplace/publisher.py)

[tool.ruff.lint.mccabe]
max-complexity = 65 # current max: 62 (install/validation.py)

[tool.ruff.lint.per-file-ignores]
# Subprocess calls are intentional in a CLI tool
"src/apm_cli/**" = ["S603", "S607"]
# Tests: assert is expected; security rules produce false positives on fixtures;
# F821 undefined-name from TYPE_CHECKING + PEP 563 deferred annotations
"tests/**" = ["S101", "S105", "S106", "S108", "S110", "S112", "S603", "S607"]
# Files using `from __future__ import annotations` with forward-reference-only
# type imports (PEP 563). Ruff cannot resolve these without a type checker.
"src/apm_cli/policy/ci_checks.py" = ["F821", "S603", "S607"]
"src/apm_cli/policy/policy_checks.py" = ["F821", "S603", "S607"]
"src/apm_cli/security/audit_report.py" = ["F821", "S603", "S607"]
"src/apm_cli/cli.py" = ["F821", "S603", "S607"]
"src/apm_cli/commands/audit.py" = ["F821", "S603", "S607"]
"src/apm_cli/commands/init.py" = ["F821", "S603", "S607"]
"src/apm_cli/install/pipeline.py" = ["F821", "S603", "S607"]
"src/apm_cli/integration/skill_integrator.py" = ["F821", "S603", "S607"]

[tool.ruff.format]
quote-style = "double"
indent-style = "space"

[tool.mypy]
python_version = "3.12"
Expand All @@ -79,3 +133,4 @@ markers = [
"slow: marks tests as slow running tests",
"benchmark: marks performance benchmark tests (deselected by default, run with -m benchmark)",
]

10 changes: 9 additions & 1 deletion src/apm_cli/adapters/client/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,15 @@ def get_current_config(self):
pass

@abstractmethod
def configure_mcp_server(self, server_url, server_name=None, enabled=True, env_overrides=None, server_info_cache=None, runtime_vars=None):
def configure_mcp_server(
self,
server_url,
server_name=None,
enabled=True,
env_overrides=None,
server_info_cache=None,
runtime_vars=None,
):
"""Configure an MCP server in the client configuration.

Args:
Expand Down
Loading
Loading