feat: add package model foundation with env-root discovery #472
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| pull_request: | |
| branches: [main] | |
| types: [opened, synchronize, reopened, labeled] | |
| workflow_dispatch: | |
| workflow_call: | |
| permissions: | |
| contents: read | |
| jobs: | |
| setup: | |
| # Skip CI if triggered by a label event that isn't 'full-matrix' | |
| if: github.event.action != 'labeled' || github.event.label.name == 'full-matrix' | |
| runs-on: ubuntu-latest | |
| outputs: | |
| matrix: ${{ steps.set-matrix.outputs.matrix }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| sparse-checkout: .github/python-versions.json | |
| sparse-checkout-cone-mode: false | |
| - name: Set matrix based on config and label | |
| id: set-matrix | |
| run: | | |
| # Read config | |
| oldest=$(jq -r '.oldest' .github/python-versions.json) | |
| newest=$(jq -r '.newest' .github/python-versions.json) | |
| oldest_minor=${oldest#3.} | |
| newest_minor=${newest#3.} | |
| if [[ "${{ github.event.label.name }}" == "full-matrix" ]]; then | |
| # Middle versions only (bookends already tested) | |
| versions="" | |
| for ((i=oldest_minor+1; i<newest_minor; i++)); do | |
| if [[ -n "$versions" ]]; then | |
| versions="$versions," | |
| fi | |
| versions="$versions\"3.$i\"" | |
| done | |
| if [[ -z "$versions" ]]; then | |
| echo "No middle versions to test (oldest=$oldest, newest=$newest)" | |
| echo 'matrix={"include":[]}' >> $GITHUB_OUTPUT | |
| else | |
| echo "Middle versions: $versions" | |
| echo "matrix={\"python-version\":[$versions]}" >> $GITHUB_OUTPUT | |
| fi | |
| else | |
| # Bookend versions (oldest + newest) | |
| echo "Bookend versions: $oldest, $newest" | |
| echo "matrix={\"python-version\":[\"$oldest\",\"$newest\"]}" >> $GITHUB_OUTPUT | |
| fi | |
| test: | |
| needs: setup | |
| if: ${{ needs.setup.outputs.matrix != '{"include":[]}' }} | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{ fromJson(needs.setup.outputs.matrix) }} | |
| env: | |
| UV_CACHE_DIR: ${{ github.workspace }}/.uv-cache | |
| INFRAFOUNDRY_SKIP_SOPS_CHECK: '1' | |
| HYPOTHESIS_PROFILE: ci | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - uses: astral-sh/setup-uv@v7 | |
| with: | |
| version: "latest" | |
| - name: Cache uv dependencies | |
| uses: actions/cache@v5 | |
| with: | |
| path: ${{ env.UV_CACHE_DIR }} | |
| key: ${{ runner.os }}-uv-${{ hashFiles('uv.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-uv- | |
| - name: Install dependencies | |
| run: uv sync --all-extras --dev | |
| - name: Install Terraform | |
| uses: hashicorp/setup-terraform@v4 | |
| with: | |
| terraform_wrapper: false | |
| - name: Install OpenTofu | |
| uses: opentofu/setup-opentofu@v1 | |
| with: | |
| tofu_wrapper: false | |
| - name: Install system tools (age, sops) | |
| run: | | |
| mkdir -p ~/.local/bin | |
| # age + age-keygen | |
| AGE_VERSION=$(curl -s https://api.github.com/repos/FiloSottile/age/releases/latest -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" | jq -r .tag_name) | |
| curl -sL "https://github.com/FiloSottile/age/releases/download/${AGE_VERSION}/age-${AGE_VERSION}-linux-amd64.tar.gz" | tar xz -C /tmp | |
| mv /tmp/age/age /tmp/age/age-keygen ~/.local/bin/ | |
| # sops | |
| SOPS_VERSION=$(curl -s https://api.github.com/repos/getsops/sops/releases/latest -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" | jq -r .tag_name) | |
| curl -sL "https://github.com/getsops/sops/releases/download/${SOPS_VERSION}/sops-${SOPS_VERSION}.linux.amd64" -o ~/.local/bin/sops | |
| chmod +x ~/.local/bin/sops | |
| - name: Check code formatting | |
| run: uv run ruff format --check src/ tests/ | |
| - name: Run linting | |
| run: uv run ruff check src/ tests/ | |
| - name: Run type checking | |
| run: uv run mypy src/ | |
| - name: Run security scan | |
| run: uv run bandit -c pyproject.toml -r src/ | |
| - name: Run spell check | |
| run: uv run codespell src/ tests/ docs/ README.md | |
| - name: Run dependency audit | |
| continue-on-error: true | |
| run: uv run pip-audit --skip-editable | |
| - name: Run tests with coverage | |
| run: uv run pytest --cov=infrafoundry --cov-report=xml:tmp/coverage.xml --cov-report=term -v | |
| - name: Upload coverage to Codecov | |
| if: matrix.python-version == '3.12' | |
| uses: codecov/codecov-action@v5 | |
| with: | |
| file: ./tmp/coverage.xml | |
| flags: unittests | |
| name: codecov-umbrella | |
| fail_ci_if_error: false | |
| env: | |
| CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} | |
| ci-complete: | |
| # Always run unless this is a non-full-matrix label event | |
| if: always() && (github.event.action != 'labeled' || github.event.label.name == 'full-matrix') | |
| needs: [setup, test] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check CI status | |
| run: | | |
| setup_result="${{ needs.setup.result }}" | |
| test_result="${{ needs.test.result }}" | |
| echo "Setup result: $setup_result" | |
| echo "Test result: $test_result" | |
| # Setup must succeed | |
| if [[ "$setup_result" != "success" ]]; then | |
| echo "Setup job failed" | |
| exit 1 | |
| fi | |
| # Test must succeed or be skipped (skipped = no middle versions) | |
| if [[ "$test_result" != "success" && "$test_result" != "skipped" ]]; then | |
| echo "Test job failed" | |
| exit 1 | |
| fi | |
| echo "CI completed successfully" |