Skip to content
Merged
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/file-filters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ development_files: &development_files
- "development/**"
- "tasks/**"

poetry_files: &poetry_files
uv_files: &uv_files
- "pyproject.toml"
- "poetry.lock"
- "uv.lock"

doc_files: &doc_files
- "docs/**"
Expand All @@ -24,7 +24,7 @@ doc_files: &doc_files

python_all: &python_all
- "**/*.py"
- *poetry_files
- *uv_files
- *ci_config
- *coverage_config

Expand Down
93 changes: 45 additions & 48 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
helm: ${{ steps.changes.outputs.helm_all }}
python: ${{ steps.changes.outputs.python_all }}
yaml: ${{ steps.changes.outputs.yaml_all }}
poetry_files: ${{ steps.changes.outputs.poetry_files }}
uv_files: ${{ steps.changes.outputs.uv_files }}
github_workflows: ${{ steps.changes.outputs.github_workflows }}
steps:
- name: "Check out repository code"
Expand Down Expand Up @@ -129,7 +129,7 @@ jobs:
!contains(needs.*.result, 'failure') &&
!contains(needs.*.result, 'cancelled') &&
needs.files-changed.outputs.documentation == 'true'
needs: ["files-changed", "yaml-lint", "python-lint"]
needs: ["prepare-environment", "files-changed", "yaml-lint", "python-lint"]
runs-on: "ubuntu-22.04"
timeout-minutes: 5
steps:
Expand All @@ -145,10 +145,18 @@ jobs:
cache-dependency-path: docs/package-lock.json
- name: "Install dependencies"
run: npm install
- name: "Setup Python environment"
run: "pip install invoke"
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install UV
uses: astral-sh/setup-uv@v4
with:
version: "${{ needs.prepare-environment.outputs.UV_VERSION }}"
- name: Install dependencies
run: uv sync --all-groups --all-extras
- name: "Build docs website"
run: "invoke docs"
run: "uv run invoke docs"

validate-generated-documentation:
if: |
Expand All @@ -168,17 +176,14 @@ jobs:
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: "Setup Python environment"
run: |
pipx install poetry==${{ needs.prepare-environment.outputs.POETRY_VERSION }}
poetry config virtualenvs.create true --local
poetry env use 3.12
- name: "Install dependencies"
run: "poetry install --no-interaction --no-ansi --extras ctl"
- name: "Setup environment"
run: "poetry run pip install invoke"
- name: "Validate generated documentation"
run: "poetry run invoke docs-validate"
- name: Install UV
uses: astral-sh/setup-uv@v4
with:
version: "${{ needs.prepare-environment.outputs.UV_VERSION }}"
- name: Install dependencies
run: uv sync --all-groups --all-extras
- name: Validate generated documentation
run: uv run invoke docs-validate

validate-documentation-style:
if: |
Expand Down Expand Up @@ -232,24 +237,19 @@ jobs:
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: "Setup environment"
run: |
pipx install poetry==${{ needs.prepare-environment.outputs.POETRY_VERSION }} --python python${{ matrix.python-version }}
poetry config virtualenvs.create true --local
pip install invoke codecov
- name: "Install tomli for Python < 3.11"
if: matrix.python-version == '3.9' || matrix.python-version == '3.10'
run: |
pip install tomli
- name: "Install Package"
run: "poetry install --all-extras"
- name: "Mypy Tests"
run: "poetry run mypy --show-error-codes infrahub_sdk/"
- name: "Unit Tests"
run: "poetry run pytest --cov infrahub_sdk tests/unit/"
- name: Install UV
uses: astral-sh/setup-uv@v4
with:
version: "${{ needs.prepare-environment.outputs.UV_VERSION }}"
- name: Install dependencies
run: uv sync --all-groups --all-extras
- name: Mypy Tests
run: uv run mypy --show-error-codes infrahub_sdk/
- name: Unit Tests
run: uv run pytest --cov infrahub_sdk tests/unit/
- name: "Upload coverage to Codecov"
run: |
codecov --flags python-${{ matrix.python-version }}
uv run codecov --flags python-${{ matrix.python-version }}
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

Expand All @@ -259,11 +259,10 @@ jobs:
- name: "Report coverage for pytest-plugin"
if: matrix.python-version == '3.12'
run: |
source $(poetry env info --path)/bin/activate
coverage run --source=infrahub_sdk -m pytest tests/unit/pytest_plugin
coverage report -m
coverage xml
codecov --flags python-filler-${{ matrix.python-version }}
uv run coverage run --source=infrahub_sdk -m pytest tests/unit/pytest_plugin
uv run coverage report -m
uv run coverage xml
uv run codecov --flags python-filler-${{ matrix.python-version }}
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

Expand All @@ -289,19 +288,17 @@ jobs:
run: |
RUNNER_NAME=$(echo "${{ runner.name }}" | grep -o 'ghrunner[0-9]\+' | sed 's/ghrunner\([0-9]\+\)/ghrunner_\1/')
echo "PYTEST_DEBUG_TEMPROOT=/var/lib/github/${RUNNER_NAME}/_temp" >> $GITHUB_ENV
- name: "Setup environment"
run: |
pipx install poetry==${{ needs.prepare-environment.outputs.POETRY_VERSION }}
poetry config virtualenvs.create true --local
pip install invoke codecov
- name: "Install Package"
run: "poetry install --all-extras"
- name: "Integration Tests"
run: |
poetry run pytest --cov infrahub_sdk tests/integration/
- name: Install UV
uses: astral-sh/setup-uv@v4
with:
version: "${{ needs.prepare-environment.outputs.UV_VERSION }}"
- name: Install dependencies
run: uv sync --all-groups --all-extras
- name: Integration Tests
run: uv run pytest --cov infrahub_sdk tests/integration/
- name: "Upload coverage to Codecov"
run: |
codecov --flags integration-tests
uv run codecov --flags integration-tests
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/define-versions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ name: "Define versions"
on:
workflow_call:
outputs:
POETRY_VERSION:
value: "2.1.3"
UV_VERSION:
value: "0.9.8"

jobs:
prepare:
Expand Down
41 changes: 19 additions & 22 deletions .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,39 +41,36 @@ jobs:
with:
python-version: "3.12"

- name: "Install Poetry"
uses: "snok/install-poetry@v1"
- name: Install UV
uses: astral-sh/setup-uv@v4
with:
version: ${{ needs.prepare-environment.outputs.POETRY_VERSION }}
virtualenvs-create: true
virtualenvs-in-project: true
installer-parallel: true
version: ${{ needs.prepare-environment.outputs.UV_VERSION }}

- name: "Check out repository code"
- name: Check out repository code
uses: "actions/checkout@v5"
with:
submodules: true

- name: "Cache poetry venv"
- name: Cache UV dependencies
uses: "actions/cache@v4"
id: "cached-poetry-dependencies"
id: "cached-uv-dependencies"
with:
path: "./python_sdk/.venv"
key: "venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }}"
path: ".venv"
key: "venv-${{ runner.os }}-${{ hashFiles('uv.lock') }}"

- name: "Install Dependencies"
run: "poetry install"
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
- name: Install Dependencies
run: uv sync --all-groups --all-extras
if: steps.cached-uv-dependencies.outputs.cache-hit != 'true'

- name: "Add PyPI secret"
run: "poetry config pypi-token.pypi ${{ secrets.PYPI_TOKEN }}"
- name: Add PyPI secret
run: uv config token pypi ${{ secrets.PYPI_TOKEN }}

- name: "Poetry build"
run: "poetry build"
- name: Build package
run: uv build

- name: "show output"
run: "ls -la dist/"
- name: Show output
run: ls -la dist/

- name: "Poetry push PyPI"
- name: Publish to PyPI
if: ${{ inputs.publish }}
run: "poetry publish"
run: uv publish
38 changes: 18 additions & 20 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,28 +30,22 @@ jobs:
with:
python-version: "3.12"

- name: "Install Poetry"
uses: "snok/install-poetry@v1"
- name: Install UV
uses: astral-sh/setup-uv@v4
with:
version: ${{ needs.prepare-environment.outputs.POETRY_VERSION }}
virtualenvs-create: true
virtualenvs-in-project: true
installer-parallel: true
version: "${{ needs.prepare-environment.outputs.UV_VERSION }}"

- name: "Setup Python environment"
run: |
poetry config virtualenvs.create true --local
poetry env use 3.12
- name: "Install dependencies"
run: "poetry install --no-interaction --no-ansi"
- name: Install dependencies
run: uv sync --all-groups --all-extras

- name: "Check prerelease type"
- name: Check prerelease type
id: release
run: |
echo is_prerelease=$(poetry run python -c "from packaging.version import Version; print(int(Version('$(poetry version -s)').is_prerelease))") >> "$GITHUB_OUTPUT"
echo is_devrelease=$(poetry run python -c "from packaging.version import Version; print(int(Version('$(poetry version -s)').is_devrelease))") >> "$GITHUB_OUTPUT"
echo "version=$(poetry version -s)" >> "$GITHUB_OUTPUT"
echo major_minor_version=$(poetry run python -c "from packaging.version import Version; print(f\"{Version('$(poetry version -s)').major}.{Version('$(poetry version -s)').minor}\")") >> "$GITHUB_OUTPUT"
VERSION=$(uv version --short)
echo is_prerelease=$(uv run python -c "from packaging.version import Version; print(int(Version('$VERSION').is_prerelease))") >> "$GITHUB_OUTPUT"
echo is_devrelease=$(uv run python -c "from packaging.version import Version; print(int(Version('$VERSION').is_devrelease))") >> "$GITHUB_OUTPUT"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo major_minor_version=$(uv run python -c "from packaging.version import Version; v = Version('$VERSION'); print(f'{v.major}.{v.minor}')") >> "$GITHUB_OUTPUT"
Comment on lines +44 to +48
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Critical: uv version --short returns the UV tool version, not the project version.

Line 44 uses uv version --short to extract the project VERSION, but this command returns the UV tool version (e.g., "0.4.28"), not the Python project version. This will:

  1. Break tag validation (line 58-59): the workflow will expect tag "v0.4.28" but the release tag is "v<project_version>"
  2. Invalidate prerelease/devrelease checks (lines 45-46) based on wrong version
  3. Cause the release workflow to fail

To fix, extract the project version from pyproject.toml or via Python. For example:

- VERSION=$(uv version --short)
+ VERSION=$(uv run python -c "from importlib.metadata import version; print(version('infrahub-sdk'))")

Or, if the project defines __version__ in its package:

- VERSION=$(uv version --short)
+ VERSION=$(uv run python -c "import infrahub_sdk; print(infrahub_sdk.__version__)")

Please verify the correct approach with the project's structure and confirm this resolves the version mismatch.


I need to verify the critical claim in this review comment about uv version --short. Let me inspect the repository structure and the workflow file.


---

🏁 Script executed:

```shell
#!/bin/bash
# Check repository structure and find pyproject.toml
fd -t f "pyproject.toml|setup.py|setup.cfg|__init__.py" -x ls -la {} \;

Length of output: 2236


🏁 Script executed:

#!/bin/bash
# View the complete release.yml workflow for context
cat .github/workflows/release.yml

Length of output: 3677


🏁 Script executed:

#!/bin/bash
# Search for __version__ definitions in the codebase
rg -n "__version__" --type py -A2 -B2

Length of output: 653


🏁 Script executed:

#!/bin/bash
# Check what uv version actually returns by examining documentation or similar workflows
rg -n "uv version" --type yml -C5

Length of output: 27


Let me check the pyproject.toml to confirm the project name and verify the fix is correct.


---

🏁 Script executed:

```shell
#!/bin/bash
# Extract project name from pyproject.toml
head -50 pyproject.toml | grep -A 5 "\[project\]"

Length of output: 169


🏁 Script executed:

#!/bin/bash
# Check for any version field in pyproject.toml
rg -n "version\s*=" pyproject.toml | head -10

Length of output: 20


Critical: uv version --short returns the UV tool version, not the project version.

Line 44 uses uv version --short to extract the project VERSION, but this command returns the UV tool version (e.g., "0.4.28"), not the Python project version ("1.15.0"). This breaks the workflow:

  1. Tag validation (lines 58-59) fails: the workflow expects tag "v0.4.28" but the release tag is "v1.15.0"
  2. Prerelease/devrelease checks (lines 45-46) evaluate the wrong version
  3. Release workflow fails with validation error

Fix by extracting the project version from package metadata:

- VERSION=$(uv version --short)
+ VERSION=$(uv run python -c "from importlib.metadata import version; print(version('infrahub-sdk'))")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
VERSION=$(uv version --short)
echo is_prerelease=$(uv run python -c "from packaging.version import Version; print(int(Version('$VERSION').is_prerelease))") >> "$GITHUB_OUTPUT"
echo is_devrelease=$(uv run python -c "from packaging.version import Version; print(int(Version('$VERSION').is_devrelease))") >> "$GITHUB_OUTPUT"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo major_minor_version=$(uv run python -c "from packaging.version import Version; v = Version('$VERSION'); print(f'{v.major}.{v.minor}')") >> "$GITHUB_OUTPUT"
VERSION=$(uv run python -c "from importlib.metadata import version; print(version('infrahub-sdk'))")
echo is_prerelease=$(uv run python -c "from packaging.version import Version; print(int(Version('$VERSION').is_prerelease))") >> "$GITHUB_OUTPUT"
echo is_devrelease=$(uv run python -c "from packaging.version import Version; print(int(Version('$VERSION').is_devrelease))") >> "$GITHUB_OUTPUT"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo major_minor_version=$(uv run python -c "from packaging.version import Version; v = Version('$VERSION'); print(f'{v.major}.{v.minor}')") >> "$GITHUB_OUTPUT"

echo latest_tag=$(curl -L \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ github.token }}" \
Expand All @@ -60,10 +54,14 @@ jobs:
| jq -r '.tag_name') >> "$GITHUB_OUTPUT"

- name: Check tag version
if: github.event.release.tag_name != format('v{0}', steps.release.outputs.version)
run: |
echo "Tag version does not match python project version"
exit 1
EXPECTED_TAG="v${{ steps.release.outputs.version }}"
if [ "${{ github.event.release.tag_name }}" != "$EXPECTED_TAG" ]; then
echo "Tag version does not match python project version"
echo "Expected: $EXPECTED_TAG"
echo "Got: ${{ github.event.release.tag_name }}"
exit 1
fi

- name: Check prerelease and project version
if: github.event.release.prerelease == true && steps.release.outputs.is_prerelease == 0 && steps.release.outputs.is_devrelease == 0
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ script.py
.vscode/settings.json
.DS_Store
.python-version
.venv/
.venv
.ruff_cache
**/.ruff_cache
**/.idea/**
Expand Down
32 changes: 19 additions & 13 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,45 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

```bash
# Install dependencies
poetry install --with dev --all-extras
uv sync --all-groups --all-extras

# Install specific groups
uv sync --group tests # Testing dependencies only
uv sync --group lint # Linting dependencies only
uv sync --extra ctl # CLI dependencies only
uv sync --all-groups --all-extras # All optional dependencies

# Format code
poetry run invoke format
uv run invoke format

# Run linting (ruff + mypy + yamllint + markdownlint)
poetry run invoke lint
uv run invoke lint

# Run unit tests with coverage
poetry run pytest --cov infrahub_sdk tests/unit/
uv run pytest --cov infrahub_sdk tests/unit/

# Run integration tests
poetry run pytest tests/integration/
uv run pytest tests/integration/

# Generate documentation
poetry run invoke docs
uv run invoke docs

# Validate documentation
poetry run invoke docs-validate
uv run invoke docs-validate
```

### Testing Specific Components

```bash
# Run tests for specific modules
poetry run pytest tests/unit/test_client.py
poetry run pytest tests/unit/test_node.py
uv run pytest tests/unit/test_client.py
uv run pytest tests/unit/test_node.py

# Run with verbose output
poetry run pytest -v tests/unit/
uv run pytest -v tests/unit/

# Run with parallel execution
poetry run pytest -n 4 tests/unit/
uv run pytest -n 4 tests/unit/
```

## Architecture Overview
Expand Down Expand Up @@ -148,7 +154,7 @@ CLI commands are auto-documented and organized in `infrahub_sdk/ctl/`.

```bash
# Generate all docs
poetry run invoke docs
uv run invoke docs

# Start development server (requires Node.js)
cd docs && npm start
Expand All @@ -168,7 +174,7 @@ cd docs && npm start

GitHub Actions workflow runs:

1. Multi-version Python testing (3.9-3.13)
1. Multi-version Python testing (3.10-3.13)
2. Comprehensive linting pipeline
3. Documentation generation and validation
4. Integration testing with Infrahub containers
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,18 @@ Installs infrahub-sdk together with all the extras.
```bash
pip install 'infrahub-sdk[all]'
```

### Development setup with UV

If you're developing the SDK and using UV for dependency management, you can install specific dependency groups:

```bash
# Install development dependencies
uv sync --all-groups --all-extras

# Install specific groups
uv sync --group tests # Testing dependencies only
uv sync --group lint # Linting dependencies only
uv sync --group ctl # CLI dependencies only
uv sync --all-groups --all-extras # All optional dependencies
```
Loading