Skip to content

Contributing

Thank you for your interest in contributing to AAP Bridge!

Code of Conduct

This project follows the AAP Bridge Code of Conduct. By participating, you are expected to uphold this code.

How to Contribute

Reporting Bugs

Before submitting a bug report:

  1. Search existing issues to avoid duplicates
  2. Try the latest version from the main branch
  3. Gather information:
  4. AAP Bridge version (aap-bridge --version)
  5. Source/Target AAP versions
  6. Error messages and logs (scrubbed of secrets!)

When opening an issue:

  • Use a clear, descriptive title
  • Describe steps to reproduce
  • Include expected vs actual behavior
  • Attach relevant logs

Suggesting Features

Open an issue with:

  • Clear description of the feature
  • Use case / problem it solves
  • Proposed implementation (if you have ideas)

Pull Requests

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Make your changes
  4. Run tests and checks: make check
  5. Commit your changes (pre-commit hooks run automatically after make setup)
  6. Push to your fork: git push origin feature/amazing-feature
  7. Open a Pull Request

CI also runs the quality gates on every PR (see Pre-commit and CI below). Do not rely on skipping hooks locally — CI will still fail.

Development Setup

Prerequisites

  • Python 3.12 (required)
  • uv (recommended) or pip with the stdlib venv module (python3.12-venv on Debian/Ubuntu)
  • PostgreSQL (for integration tests)
  • For Ansible lint / ephemeral AAP work: ansible-core >= 2.16.14 and ansible-lint >= 26.1 (installed via make setup / requirements-dev.txt). Collections in tests/integration/requirements.yml are for running the harness (make run-pair, etc.), not required for ansible-lint --offline.
  • For the Web UI: Node.js 20+ (optional unless you change web/)

Setup

make setup creates .venv, installs dev dependencies, seeds .env, and installs git pre-commit hooks. It prefers uv when installed; pass USE_UV=0 to use pip instead.

# Clone your fork
git clone https://github.com/YOUR_USERNAME/aap-bridge.git
cd aap-bridge

make setup

# Interactive CLI usage only — make test/lint/etc. use .venv/bin directly
source .venv/bin/activate

Pre-commit and CI

After make setup, hooks run on every git commit. They cover:

Hook What it does
Hygiene trailing whitespace, EOF, YAML, merge conflicts, large files
CHANGELOG periods each bullet in CHANGELOG.md and docs/reference/changelog.md ends with . (tools/check_changelog_periods.py)
kacl-verify Keep a Changelog structure on CHANGELOG.md (python-kacl; see .kacl.yml)
gitleaks secret scanning (dedicated CI job + local pre-commit)
black / isort / ruff format and lint Python under src/ and tests/
pytest unit pytest tests/unit (fast; no AAP containers)
ansible-lint offline lint of tests/integration/ when those YAML files change
web-build / web-vitest npm run build + vitest run when web/ changes (needs make web-install)

Run all hooks manually:

make pre-commit
# or: .venv/bin/pre-commit run --all-files

GitHub Actions (.github/workflows/ci.yml) runs four jobs on every PR/push to main:

  • Secretspre-commit run gitleaks --all-files (dedicated status check)
  • Python — remaining pre-commit hooks with SKIP=gitleaks,ansible-lint,web-build,web-vitest (includes changelog trailing-period checks and kacl-verify)
  • Ansible — path-filtered ansible-lint --offline when tests/integration/ changes
  • Web — path-filtered npm ci, npm run build, and npm run test:unit when web/ changes

mypy is still part of make check / make typecheck but is not in pre-commit or CI yet (tracked in issue #158). Prefer fixing type errors before merge when you touch typed code.

Escape hatches (SKIP=... git commit or --no-verify) are discouraged; CI still blocks the PR.

Running Tests

# All tests
make test

# Unit tests only (fast)
make test-unit

# With coverage
make test-cov

# Specific test file
.venv/bin/pytest tests/unit/test_exporter.py -v

Ephemeral AAP integration testing

For end-to-end migration testing against real AAP instances (golden images, source/target pairs, make test-bridge), see Testing with Ephemeral AAP Instances. That workflow uses podman on the host and does not require a local Python install for the AAP side of the stack.

Preview documentation

User-facing docs live under docs/ and are built with MkDocs Material. Most readers use GitHub (or the published site); local serve is for contributors editing docs.

# Live reload (recommended while editing)
make docs-serve
# Open http://127.0.0.1:8001

# Or default MkDocs bind
mkdocs serve
# Open http://127.0.0.1:8000

# Static build only (writes site/; does not start a server)
make docs
# Optional: python -m http.server 8000 --directory site

Lint the integration Ansible harness:

make ansible-lint
# cd tests/integration && ansible-lint --offline

Web UI

make web-install   # npm ci in web/ (required once before web hooks/tests)
make web-dev       # Vite dev server
make web-build     # tsc + production build (same as pre-commit web-build)
make web-test      # vitest unit tests (same as pre-commit web-vitest)

Frontend unit tests live next to source (*.test.ts / *.test.tsx), using the Vitest + Testing Library setup already wired in web/vitest.config.ts. Commit hooks for web only run when web/ files are staged; CI enforces build + unit tests on web path changes.

Code Quality

Before submitting:

# Format code
make format

# Run linter
make lint

# Type checking (local; not yet in CI — see issue #158)
make typecheck

# All checks (format + lint + typecheck + test)
make check

# Integration Ansible (when changing tests/integration/)
make ansible-lint

# Web build (when changing web/)
make web-build
make web-test

Code Style

Python Style

  • Formatter: black (line length: 100)
  • Linter: ruff
  • Type checker: mypy

Naming Conventions

  • snake_case for functions and variables
  • PascalCase for classes
  • UPPER_CASE for constants
  • Descriptive names over abbreviations

Documentation

  • Docstrings for all public functions/classes
  • Type hints for all function signatures
  • Comments for complex logic

Example

async def import_resources(
    self,
    resources: list[dict[str, Any]],
    progress_callback: Callable[[int, int], None] | None = None,
) -> list[dict[str, Any]]:
    """Import resources to target AAP.

    Args:
        resources: List of resource dictionaries to import
        progress_callback: Optional callback for progress updates

    Returns:
        List of successfully imported resources

    Raises:
        APIError: If API request fails
    """
    ...

Git Commit Messages

  • Use present tense: "Add feature" not "Added feature"
  • Use imperative mood: "Move cursor" not "Moves cursor"
  • First line: 72 characters or less
  • Reference issues: "Fix #123: Handle edge case"

Good Examples

Add bulk import support for hosts

Implement bulk host creation using AAP's /bulk/host_create endpoint.
This improves import performance by ~10x for large inventories.

Fixes #45

Fix rate limiting during export

- Add exponential backoff on 429 responses
- Respect Retry-After header
- Add configurable rate limit settings

Adding New Features

Adding a New Resource Type

See Adding Resource Types for the complete guide.

Adding a New Command

  1. Create command file in src/aap_migration/cli/commands/
  2. Register in src/aap_migration/cli/main.py
  3. Add tests in tests/unit/cli/
  4. Document in docs/user-guide/cli-reference.md

Testing Guidelines

Unit Tests

  • Test individual functions in isolation
  • Mock external dependencies
  • Fast execution (< 1 second per test)

Integration Tests

  • Test with real AAP instances (when available)
  • Mark with @pytest.mark.integration
  • Use fixtures for setup/teardown

Test Coverage

Aim for high coverage but prioritize meaningful tests:

# Check coverage
make test-cov

# View HTML report
open htmlcov/index.html

Release Process

  1. Update version in pyproject.toml
  2. Update CHANGELOG.md
  3. Create a PR with version bump
  4. After merge, tag the release: git tag v0.2.0
  5. Push tags: git push --tags

Getting Help

  • Open an issue for questions
  • Join discussions on GitHub
  • Check existing documentation

License

By contributing, you agree that your contributions will be licensed under the GPL-3.0 License.