Skip to content

Cache uv dependencies to speed up PR checks#333

Open
chayac wants to merge 6 commits into
mainfrom
chayac/uv-cache-optimization
Open

Cache uv dependencies to speed up PR checks#333
chayac wants to merge 6 commits into
mainfrom
chayac/uv-cache-optimization

Conversation

@chayac
Copy link
Copy Markdown
Collaborator

@chayac chayac commented Feb 18, 2026

Description

  • New workflow to cache uv dependencies based on main branch's uv.lock
  • Migrate pytest workflow to use cached dependencies

Since we run all of our actions across multiple Python versions, this should speed up PR checks significantly. This only affects PRs - releases still refresh all dependencies when installing.

Reference: https://szeyusim.medium.com/optimizing-uv-in-github-actions-one-global-cache-to-rule-them-all-9c64b42aee7f

Comment on lines +14 to +44
name: build cache on ${{ matrix.python-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v7
with:
python-version: ${{ matrix.python-version }}
enable-cache: false

- name: Install dependencies and populate cache
run: |
echo "Building global UV cache..."
uv sync --all-packages --all-extras
echo "Cache populated successfully"

- name: Save uv caches
uses: actions/cache/save@v4
with:
path: |
~/.cache/uv
~/.local/share/uv
.venv
key: uv-main-${{ matrix.python-version }}-${{ hashFiles('uv.lock') }} No newline at end of file

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}

Copilot Autofix

AI 3 months ago

In general, the fix is to explicitly declare a restrictive permissions: block, either at the workflow root or at the job level, granting only the scopes required. For this workflow, the steps only need to read repository contents (for checkout) and do not need to write to the repo or interact with issues/PRs, so contents: read at the workflow level is sufficient. actions/cache/save uses dedicated cache APIs and does not require repo write permissions.

The best minimal fix without changing existing behavior is to add a root-level permissions: block just after the name: (before on:), specifying contents: read. This will apply to all jobs in this workflow (there is only build-cache). No other scopes (like pull-requests, issues, etc.) are necessary based on the current steps. No additional imports or code changes are needed; we only modify .github/workflows/cache-dependencies.yml.

Concretely: in .github/workflows/cache-dependencies.yml, insert:

permissions:
  contents: read

between line 1 (name: Build uv cache) and line 3 (on:). The rest of the workflow remains unchanged.

Suggested changeset 1
.github/workflows/cache-dependencies.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/cache-dependencies.yml b/.github/workflows/cache-dependencies.yml
--- a/.github/workflows/cache-dependencies.yml
+++ b/.github/workflows/cache-dependencies.yml
@@ -1,5 +1,8 @@
 name: Build uv cache
 
+permissions:
+  contents: read
+
 on:
   push:
     branches:
EOF
@@ -1,5 +1,8 @@
name: Build uv cache

permissions:
contents: read

on:
push:
branches:
Copilot is powered by AI and may make mistakes. Always verify output.
@chayac chayac committed this autofix suggestion 3 months ago.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

So I guess we need a top level:

permissions:
  contents: read

block. But to write to the cache, maybe we need read,write?

Might have to play with it. I'm not seeing cache-management explicitly discussed in this doc on workflow permissions syntax

Comment thread .github/workflows/cache-dependencies.yml Fixed
Comment thread .github/workflows/pytest-pr.yml Fixed
Comment thread .github/workflows/pytest-pr.yml Fixed
chayac and others added 3 commits February 18, 2026 14:32
…in permissions

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
@chayac chayac marked this pull request as ready for review February 18, 2026 22:44
Comment thread .github/workflows/check-pypi-release.yml Fixed
@davidharting davidharting self-requested a review February 20, 2026 16:49
Copy link
Copy Markdown
Contributor

@davidharting davidharting left a comment

Choose a reason for hiding this comment

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

This is awesome! Great find with that article. Will be really nice to not waste time on every PR building a bespoke cache.

strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice! Was wondering how our multi-python version stuff would make this differ from the post you linked.

Pretty simple - just run across all python versions and include python-version in the cache key!

Comment on lines +14 to +44
name: build cache on ${{ matrix.python-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v7
with:
python-version: ${{ matrix.python-version }}
enable-cache: false

- name: Install dependencies and populate cache
run: |
echo "Building global UV cache..."
uv sync --all-packages --all-extras
echo "Cache populated successfully"

- name: Save uv caches
uses: actions/cache/save@v4
with:
path: |
~/.cache/uv
~/.local/share/uv
.venv
key: uv-main-${{ matrix.python-version }}-${{ hashFiles('uv.lock') }} No newline at end of file
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

So I guess we need a top level:

permissions:
  contents: read

block. But to write to the cache, maybe we need read,write?

Might have to play with it. I'm not seeing cache-management explicitly discussed in this doc on workflow permissions syntax


- name: Install uv
uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # astral-sh/setup-uv@v3
uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

thanks for the upgrades!

.venv
key: uv-main-${{ matrix.python-version }}-${{ hashFiles('uv.lock') }}
restore-keys: |
uv-main-${{ matrix.python-version }}-
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm not really clear why restore-keys does not include the uv.lock hash

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Was this for your own debugging or is this something we want to keep around?

It looks like it overlaps somewhat with our noxfile tests

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants