Skip to main content

Development

This guide covers how to set up a development environment for infrahub-sync, contribute to the project, and publish releases.

Prerequisites​

  • Python 3.10–3.13 (3.12 recommended)
  • uv for dependency management
  • Git

Setting up your development environment​

Clone the repository​

git clone https://github.com/opsmill/infrahub-sync.git
cd infrahub-sync

Install uv​

If you don't have uv installed, you can install it with:

curl -LsSf https://astral.sh/uv/install.sh | sh

Or see the uv installation guide for other options.

Install dependencies​

uv sync --group dev

This installs all runtime and development dependencies defined in pyproject.toml.

Verify your setup​

uv run infrahub-sync --help
uv run infrahub-sync list --directory examples/

Development workflow​

Before committing any changes, run the following commands in order:

uv run invoke format # Format code with ruff
uv run invoke lint # Lint code with ruff and pylint
uv run mypy infrahub_sync/ --ignore-missing-imports

Validate the CLI​

After making changes, verify the CLI still works:

uv run infrahub-sync --help
uv run infrahub-sync list --directory examples/
uv run infrahub-sync generate --name from-netbox --directory examples/

Running tests​

uv run pytest -q

Code standards​

Python style​

  • Python 3.10–3.13 compatible
  • Type hints on new or changed code
  • Ruff-formatted and lint-clean
  • Mypy-checked (do not increase existing error count)
  • Public functions and classes require documentation strings
  • Raise specific exceptions; avoid broad except Exception:

Line length​

  • Maximum line length: 120 characters (configured in pyproject.toml)

Documentation​

If you make user-facing changes (CLI flags, configuration options, new adapters), update the documentation.

Generate command-line documentation​

uv run invoke docs.generate

Build documentation site​

First-time setup (requires Node.js):

cd docs && npm install

Build the site:

uv run invoke docs.docusaurus

Lint markdown files​

npx markdownlint-cli "docs/docs/**/*.{md,mdx}"
npx markdownlint-cli --fix "docs/docs/**/*.{md,mdx}"

Adding a new adapter​

  1. Create infrahub_sync/adapters/<name>.py following existing adapter patterns
  2. Add connection configuration schema and an example under examples/
  3. Provide list and diff pathways before enabling sync
  4. Document required environment variables and expected error cases
  5. Create a documentation page in docs/docs/adapters/
  6. Add the adapter to the sidebar in docs/sidebars.ts

Invoke tasks​

View all available tasks:

uv run invoke --list

Common tasks:

TaskDescription
linter.format-ruffFormat Python code with ruff
linter.lint-ruffLint Python code with ruff
linter.lint-pylintLint Python code with pylint
linter.lint-yamlLint YAML files with yamllint
docs.generateGenerate CLI documentation
docs.docusaurusBuild documentation website
formatAlias for ruff format
lintRun all linters

Publishing a release​

This section documents how to publish new releases of infrahub-sync to PyPI.

Overview​

The project uses an automated release system powered by GitHub Actions. There are three ways to publish a release:

  1. Automated release (recommended for regular releases)
  2. Manual GitHub release (for controlled releases)
  3. Manual workflow dispatch (for emergency or custom releases)

Prerequisites​

Before publishing, ensure:

  • You have write access to the repository
  • The PYPI_TOKEN secret is configured in repository settings
  • The GH_INFRAHUB_BOT_TOKEN secret is configured (for automated releases)

This is the standard release flow. Releases are triggered automatically when PRs are merged to main or stable branches.

Step 1: Label your pull requests​

Apply appropriate labels to PRs before merging. Labels determine the version bump:

LabelVersion BumpUse When
changes/major, type/breaking-changeMajor (1.0.0 β†’ 2.0.0)Breaking API changes
changes/minor, type/feature, type/refactoringMinor (1.0.0 β†’ 1.1.0)New features, refactoring
changes/patch, type/bug, type/housekeeping, type/documentationPatch (1.0.0 β†’ 1.0.1)Bug fixes, docs, maintenance

Auto-labeling rules are configured in .github/release-drafter.yml but require a separate workflow trigger to activate. For now, apply labels manually:

PR Title PatternRecommended Label
Contains fixtype/bug
Contains enhance, improve, featuretype/feature
Contains choreci/skip-changelog
Contains deprecattype/deprecated

Step 2: Merge to main​

Merge your labeled PR to the main branch. The automation will:

  1. Calculate the next version based on PR labels
  2. Update pyproject.toml with the new version (and regenerate uv.lock)
  3. Commit changes as chore(release): v{VERSION} [skip ci]
  4. Create/update a draft GitHub Release with auto-generated release notes

Step 3: Publish the GitHub release​

  1. Navigate to the repository's Releases page
  2. Find the draft release created by Release Drafter
  3. Review the auto-generated release notes
  4. Edit if needed (add context, highlights, migration notes)
  5. Click Publish release

Publishing the release triggers the PyPI upload automatically.

Method 2: Manual GitHub release​

Use this method when you want full control over the release timing and notes.

Step 1: Update the version​

Update the version in pyproject.toml:

# Edit pyproject.toml and update the version field
uv lock

Commit and push the changes:

git add pyproject.toml uv.lock
git commit -m "chore(release): vX.Y.Z"
git push origin main

Step 2: Create a GitHub release​

  1. Go to Releases β†’ Draft a new release
  2. Click Choose a tag and create a new tag matching your version (for example, 1.6.0)
  3. Set the target to main branch
  4. Add a release title (for example, 1.6.0)
  5. Write release notes describing the changes
  6. Click Publish release

This triggers the trigger-release.yml workflow, which publishes to PyPI.

Method 3: Manual workflow dispatch​

Use this for emergency releases or when you need to bypass the standard flow.

Using the GitHub UI​

  1. Go to Actions β†’ Publish Infrahub Sync Package
  2. Click Run workflow
  3. Configure the inputs:
    • version: The version string (for example, 1.6.0) - optional, for labeling
    • publish: Set to true to publish to PyPI (default: false)
    • runs-on: OS for the runner (default: ubuntu-22.04)
  4. Click Run workflow

Using the GitHub CLI​

gh workflow run workflow-publish.yml \
--field version="1.6.0" \
--field publish=true

Important: When using workflow dispatch, ensure pyproject.toml already has the correct version, as this method builds from the current code state.

Release notes​

Release notes are auto-generated based on merged PRs and their labels:

CategoryLabels
Breaking Changeschanges/major
Minor Changeschanges/minor, type/feature, type/refactoring
Patch & Bug Fixestype/bug, changes/patch
Documentation Changetype/documentation

PRs with these labels are excluded from release notes:

  • ci/skip-changelog
  • type/duplicate

Verifying a release​

After publishing:

  1. Check PyPI: Visit pypi.org/project/infrahub-sync to confirm the new version is available
  2. Check GitHub Actions: Ensure the publish workflow completed successfully
  3. Test Installation:
pip install infrahub-sync==<new-version>
infrahub-sync --version

Troubleshooting​

Release workflow skipped​

The automated release is skipped when:

  • The commit author is opsmill-bot with a chore prefix (prevents recursive releases)
  • No version bump is detected (no labeled PRs since last release)
  • Changes are only in the docs/ directory

The PyPI upload failed​

Common causes:

  • PYPI_TOKEN secret is missing or invalid
  • Version already exists on PyPI (versions cannot be overwritten)
  • Network issues during upload

To retry, use the manual workflow dispatch method.

Version not bumped correctly​

Ensure PRs have appropriate labels before merging. If labels are missing, the version drafter may not calculate a new version.

Workflow files reference​

WorkflowTypePurpose
trigger-push-stable.ymlPush to main/stableCalculates version, bumps pyproject.toml, triggers release draft
workflow-release-drafter.ymlReusable (workflow_call)Creates/updates GitHub Release draft; invoked by trigger-release.yml
trigger-release.ymlGitHub Release publishedOrchestrates release: invokes release drafter and publish workflows
workflow-publish.ymlReusable (workflow_dispatch)Builds and publishes package to PyPI; invoked by trigger-release.yml