Development¶
This guide is for contributors working on Agronomist itself. It covers environment setup, available tasks, code style, testing, and the contribution workflow.
If you are looking for usage instructions as an end user, see Getting Started. For internal design decisions and module descriptions, see Architecture.
Prerequisites¶
Before setting up the development environment, ensure you have:
- Python 3.10+ - Required by project (
pyproject.toml) - Poetry - Dependency and environment manager (https://python-poetry.org/)
- Git - Version control and required for git resolver testing
- Docker (optional) - For containerized builds using
make build-docker
Install Poetry¶
Then add Poetry to your PATH:
Development Setup¶
1. Clone and Install Dependencies¶
This installs:
- Core dependencies:
requests,pyyaml - Dev dependencies:
ruff,mypy,bandit,eradicate,pytest,pytest-cov,pytest-benchmark,pre-commit,taskipy,zensical
2. Verify Installation¶
Task Runner (taskipy)¶
Agronomist uses taskipy for convenient task management. All tasks are defined in pyproject.toml.
Available Tasks¶
| Task | Command | Description |
|---|---|---|
lint |
poetry run task lint |
Run ruff check, ruff format, and mypy |
format |
poetry run task format |
Auto-format code and remove dead code (ruff format + eradicate) |
test |
poetry run task test |
Run pytest test suite with coverage |
test-coverage |
poetry run task test-coverage |
Run pytest with strict coverage (no --exitfirst) |
security |
poetry run task security |
Run security checks (bandit + eradicate) |
check |
poetry run task check |
Run linters + security + tests (recommended before commit) |
bandit |
poetry run task bandit |
Run bandit security scanner |
mypy |
poetry run task mypy |
Run mypy static type checker |
pre-commit-install |
poetry run task pre-commit-install |
Install pre-commit hooks |
pre-commit-run |
poetry run task pre-commit-run |
Run pre-commit on all files |
pre-commit |
poetry run task pre-commit |
Install and run pre-commit hooks |
report |
poetry run task report |
Run agronomist on itself (example) |
update |
poetry run task update |
Update agronomist's own dependencies (example) |
Quick Start¶
# Run lint + security + tests
poetry run task check
# Install pre-commit hooks
poetry run task pre-commit-install
# Run tests only
poetry run task test
# Run tests with coverage report
poetry run task test-coverage
Linting and Formatting¶
Tools¶
- ruff - Fast Python linter and formatter (checks style, imports, bugs, and enforces consistent formatting)
- mypy - Static type checker (enforces type annotations)
- bandit - Security scanner (detects common vulnerabilities)
- eradicate - Dead code detector
Configuration¶
Tool settings are configured in pyproject.toml:
Manual Commands¶
# Check code style
poetry run ruff check .
# Auto-format with ruff
poetry run ruff format .
# Combined check and format (via task)
poetry run task check
Testing¶
Run All Tests¶
Run Specific Test¶
Run Tests with Coverage¶
Test Configuration¶
Tests use pytest. Configuration is managed in pyproject.toml (if present) or pytest defaults.
Pre-commit Hooks¶
Pre-commit hooks automatically run linters and formatters before each commit.
Install Hooks¶
This installs Git hooks defined in .pre-commit-config.yaml.
Run Hooks Manually¶
Bypass Hooks (not recommended)¶
CI/CD (Quality Checks)¶
The GitHub Actions workflow automatically runs quality checks:
- Trigger: On every push to
mainand pull requests - Command:
poetry run task check(linters + tests)
Local equivalent:
Always run this locally before pushing to ensure CI will pass.
Building¶
Using Make (Recommended)¶
Advantages:
- Isolated Docker environment (no local Python version conflicts)
- Consistent build across machines
- Cleans up automatically
Output: dist/agronomist-*.whl and dist/agronomist-*.tar.gz
Using Poetry Directly¶
Advantages:
- No Docker required
- Faster build
Output: Same as above
Build Artifacts¶
Both methods generate:
.whl- Wheel distribution (forpipx install).tar.gz- Source distribution
Documentation¶
Build Docs Locally¶
Starts a local server at http://localhost:8000 with live reloading.
Using Make¶
Features¶
- Built with MkDocs using the Material for MkDocs theme, served via the Zensical wrapper
- Source files:
docs/ - Navigation defined in
mkdocs.yml
Release Process¶
Prerequisites¶
- All tests must pass (
poetry run task check) - Changes committed and merged to
main - Version number decided (follow Semantic Versioning)
Steps¶
1. Update Version¶
Edit pyproject.toml:
2. Commit Version Bump¶
3. Create Release Tag¶
Or using Make:
GitHub Actions Release Workflow¶
Once the tag is pushed, .github/workflows/release.yml automatically:
- Runs
poetry build - Creates a GitHub Release
- Uploads artifacts (
.whland.tar.gz)
Result: Users can install the release:
# Download from https://github.com/Ops-Talks/agronomist/releases/latest
pipx install agronomist-X.Y.Z-py3-none-any.whl
Makefile Targets¶
Agronomist provides a Makefile with convenience targets:
make help # Show all available targets
make build # Build locally with Poetry
make build-docker # Build in Docker (recommended)
make clean # Remove build artifacts
make lint # Run linters (ruff check, ruff format, mypy)
make format # Format code and remove dead code
make test # Run tests
make coverage # Run tests with coverage report
make test-coverage # Alias for coverage
make run-tests # Alias for test
make security # Run security checks (bandit, eradicate)
make check # Run linters + security + tests
make docs-serve # Serve documentation locally
make pre-commit # Run pre-commit hooks
make release TAG=vX.Y.Z # Create release tag
Project Structure¶
agronomist/
├── src/
│ └── agronomist/
│ ├── __init__.py
│ ├── cli.py # CLI entry point
│ ├── config.py # Configuration loader (categories & blacklist)
│ ├── exceptions.py # Custom exception hierarchy
│ ├── fileutil.py # Shared file-writing utilities (atomic write)
│ ├── git.py # Git resolver
│ ├── github.py # GitHub API resolver
│ ├── gitlab.py # GitLab API resolver
│ ├── http.py # Shared HTTP session builder (retry & backoff)
│ ├── markdown.py # Markdown report generation
│ ├── models.py # Data models (SourceRef, UpdateEntry, Replacement)
│ ├── report.py # JSON report generation
│ ├── scanner.py # File scanner
│ └── updater.py # In-place file update application
├── test/
│ ├── fixtures/ # Test fixtures (report.json samples)
│ ├── integration/ # Shell integration tests
│ └── unit/
│ ├── python/ # Python test suite (pytest)
│ └── test_multi_pr.bats # BATS shell tests
├── docs/ # Documentation (MkDocs)
├── pyproject.toml # Project metadata and dependencies
├── Makefile # Build and development targets
├── Dockerfile # Docker build configuration
├── .github/workflows/ # GitHub Actions workflows
└── README.md
Code Style Guidelines¶
- Line length: 100 characters -- chosen over PEP 8's 79-character default to
reduce artificial line breaks in function signatures and long strings while still
fitting comfortably in side-by-side diffs and modern editor layouts. Both
ruffand the project formatter enforce this limit. - Imports: Organized via ruff (auto-formatted)
- Python version: 3.10+
- Type hints: Encouraged (Python 3.10+ supports modern syntax)
Contributing¶
- Create a branch from
main - Make changes and test:
poetry run task check - Push and open a pull request
- GitHub Actions CI will run automatically
- Once approved and green, merge to
main
Release tags are created manually after merging to trigger the release workflow.