chore: add dependency cache for fork PR CI support #1
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
| # Warm Python Dependency Cache | ||
| # | ||
| # Pre-downloads all Python dependencies via JFrog Artifactory and saves them | ||
| # to the GitHub Actions cache. PR workflows (including fork PRs, which cannot | ||
| # authenticate to JFrog) restore this cache and build fully offline. | ||
| # | ||
| # Triggers: | ||
| # - push to main when dependency files change (keeps cache fresh) | ||
| # - daily schedule (prevents 7-day GitHub Actions cache eviction) | ||
| # - manual dispatch (with optional PR number to warm cache for a fork's deps) | ||
| name: Warm Python Dependency Cache | ||
| on: | ||
| push: | ||
| branches: [main] | ||
| paths: | ||
| - "uv.lock" | ||
| - "pyproject.toml" | ||
| - ".pre-commit-config.yaml" | ||
| schedule: | ||
| - cron: "0 6 * * *" # Daily at 06:00 UTC | ||
| workflow_dispatch: | ||
| inputs: | ||
| pr_number: | ||
| description: "PR number to warm cache for (reads lockfiles from the PR branch). Leave empty to warm from main." | ||
| required: false | ||
| type: string | ||
| permissions: | ||
| id-token: write | ||
| contents: read | ||
| pull-requests: read | ||
| jobs: | ||
| warm-cache: | ||
| runs-on: | ||
| group: databricks-protected-runner-group | ||
| labels: linux-ubuntu-latest | ||
| env: | ||
| UV_FROZEN: "1" | ||
| steps: | ||
| - name: Checkout PR dependency files (sparse) | ||
| if: inputs.pr_number != '' | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| PR_DATA=$(curl -sLS \ | ||
| -H "Accept: application/vnd.github+json" \ | ||
| -H "Authorization: Bearer ${{ github.token }}" \ | ||
| "https://api.github.com/repos/${{ github.repository }}/pulls/${{ inputs.pr_number }}") | ||
| FORK_REPO=$(echo "$PR_DATA" | jq -r '.head.repo.full_name') | ||
| FORK_REF=$(echo "$PR_DATA" | jq -r '.head.ref') | ||
| echo "Warming cache for PR #${{ inputs.pr_number }} from ${FORK_REPO}@${FORK_REF}" | ||
| # Sparse checkout: only dependency files and CI actions (no source code from fork) | ||
| git init . | ||
| git remote add fork "https://github.com/${FORK_REPO}.git" | ||
| git config core.sparseCheckout true | ||
| cat > .git/info/sparse-checkout << 'EOF' | ||
| uv.lock | ||
| pyproject.toml | ||
| .pre-commit-config.yaml | ||
| .github/actions/ | ||
| EOF | ||
| git fetch --depth=1 fork "${FORK_REF}" | ||
| git checkout FETCH_HEAD | ||
| - name: Checkout main branch | ||
| if: inputs.pr_number == '' | ||
| uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | ||
| - name: Setup JFrog PyPI Proxy | ||
| uses: ./.github/actions/setup-jfrog-pypi | ||
| - name: Set up Python | ||
| uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 | ||
| with: | ||
| python-version: "3.10" | ||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@38f3f104447c67c051c4a08e39b64a148898af3a # v4 | ||
| - name: Install Hatch | ||
| uses: pypa/hatch@257e27e51a6a5616ed08a39a408a21c35c9931bc # install | ||
| - name: Install Python versions for test matrix | ||
| run: uv python install 3.10 3.11 3.12 3.13 | ||
| - name: Create all hatch environments (populates uv cache) | ||
| run: | | ||
| set -euo pipefail | ||
| hatch env create default | ||
| hatch env create test.py3.10 | ||
| hatch env create test.py3.11 | ||
| hatch env create test.py3.12 | ||
| hatch env create test.py3.13 | ||
| hatch env create verify | ||
| - name: Warm pre-commit cache | ||
| run: pre-commit install-hooks | ||
| - name: Build and warm pip cache for verify environment | ||
| run: | | ||
| set -euo pipefail | ||
| hatch -v build | ||
| # Run verify to populate ~/.cache/pip/ with runtime transitive deps. | ||
| # Allow failure — we only care about populating the cache. | ||
| hatch run verify:check-all || true | ||
| - name: Generate cache key | ||
| id: cache-key | ||
| shell: bash | ||
| run: | | ||
| # Timestamp ensures each run creates a new immutable cache entry. | ||
| # restore-keys prefix matching in consumers picks the latest. | ||
| TIMESTAMP=$(date -u +%Y%m%d%H%M%S) | ||
| LOCK_HASH=${{ hashFiles('uv.lock', 'pyproject.toml') }} | ||
| echo "python-deps-key=python-deps-${TIMESTAMP}-${LOCK_HASH}" >> $GITHUB_OUTPUT | ||
| PRECOMMIT_HASH=${{ hashFiles('.pre-commit-config.yaml') }} | ||
| echo "pre-commit-key=pre-commit-deps-${TIMESTAMP}-${PRECOMMIT_HASH}" >> $GITHUB_OUTPUT | ||
| - name: Save uv and pip cache | ||
| uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 | ||
| with: | ||
| path: | | ||
| ~/.cache/uv | ||
| ~/.cache/pip | ||
| key: ${{ steps.cache-key.outputs.python-deps-key }} | ||
| - name: Save pre-commit cache | ||
| uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 | ||
| with: | ||
| path: ~/.cache/pre-commit | ||
| key: ${{ steps.cache-key.outputs.pre-commit-key }} | ||