CI Fix Skill
This repo uses uv for all commands. The CI pipeline (.github/workflows/lint-and-test.yml)
runs these steps in order:
uv run ruff check src tests — lint
uv run ruff format --check src tests — format check
uv run ty check src tests — static type analysis
uv run pytest --tb=short — tests with coverage
Source code lives in src/campaign_ai/. Tests live in tests/.
Step 1 — Run the full CI pipeline locally
uv run ruff check src tests && \
uv run ruff format --check src tests && \
uv run ty check src tests && \
uv run pytest --tb=short
Step 2 — Fix lint errors (ruff)
Auto-fix safe lint issues:
uv run ruff check --fix src tests
Ruff rules enabled (see pyproject.toml): E, F, I (isort), UP (pyupgrade). E501 (line length) is ignored.
Common issues:
F401 unused import → remove the import
I001 import order → ruff check --fix sorts automatically
UP pyupgrade → use modern Python 3.13+ syntax (e.g. X | Y union types instead of Optional[X])
Auto-format all files:
uv run ruff format src tests
Then re-run uv run ruff format --check src tests to confirm no remaining issues.
Step 4 — Fix type errors (ty)
This project uses ty (not mypy). Run:
uv run ty check src tests
Key typing conventions in this codebase:
- All public functions and methods must have type annotations
- Use modern union syntax:
X | Y instead of Union[X, Y]
- Use
X | None instead of Optional[X]
- Prefer explicit Pydantic models (
TrendingTopicsReport, MarketingCampaign) over dict
- Async generators are typed as
AsyncGenerator[YieldType] (single type arg, Python 3.13+)
- Use
from __future__ import annotations only if needed for forward references
Common ty errors and fixes:
possibly-unbound → ensure variable is assigned in all code paths
invalid-return-type → check function return annotation matches actual return
missing-argument → provide all required arguments to function calls
Step 5 — Fix test failures (pytest)
Run tests with full output:
uv run pytest -v --tb=long
Run a single test file:
uv run pytest tests/test_<name>.py -v
Key testing conventions:
- Tests live in
tests/; file names follow test_<module>.py
pytest-asyncio is configured with asyncio_mode = "auto" — no @pytest.mark.asyncio needed
- Mock all AI/network calls — tests must pass without real API keys
- Coverage is auto-reported; target all public functions in
src/campaign_ai/
Run tests with coverage report:
uv run pytest --tb=short --cov=src/campaign_ai --cov-report=term-missing
Step 6 — Run pre-commit hooks (optional, full check)
uv run pre-commit run --all-files
This runs ruff lint, ruff format, and ty check on all staged and unstaged files.