Skip to content

Commit a9ef179

Browse files
authored
fix(ci): keep uv.lock in step with the release version bump (#699)
The release job bumps `version` in `pyproject.toml` but commits only that file, so `uv.lock` — which carries the project's own version — goes stale after every release, and the next contributor to run `make install` picks up an unrelated bump in their PR. Nothing caught it: `uv sync --frozen` takes the lock as-is, and at tag `v0.26.0` it installed `redisvl==0.26.0` from a lock that still said `0.25.1`. The release job now bumps both files and verifies the edit before anything is committed or pushed: one changed line per file, and the new version on the `redisvl` entry specifically. It edits that one field rather than running `uv lock`, which re-serializes the whole file (258 lines of marker churn here) right after `canary-build` validated the old one. A new `lock` job in `lint.yml` runs `uv lock --check` so drift fails on the PR — note that a PR editing dependency specifiers without re-locking will now fail it; fix is `uv lock`. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches the auto-release job that commits to main and tags/publishes, so a bad sed or check could stall or mis-bump a release. Lock-check is otherwise low-risk CI. > > **Overview** > Stops the release bot from leaving `uv.lock` stale after it bumps `pyproject.toml`. The project's own version in the lock is edited in place (not a full `uv lock` re-serialize), then checked: one version line per file, the `redisvl` entry specifically, and `uv lock --check`. Both files are committed together. > > Lint CI gains a `lock` job that runs `uv lock --check` so dependency-spec changes without a re-lock fail on the PR. CONTRIBUTING notes that contributors should run `uv lock` when changing deps. This PR also aligns the lock's `redisvl` version to `0.26.0`. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 53aa941. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 6cb3f92 commit a9ef179

3 files changed

Lines changed: 84 additions & 5 deletions

File tree

.github/workflows/auto-release.yml

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,26 +183,75 @@ jobs:
183183
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
184184
echo "Resolved version: $VERSION"
185185
186-
- name: Apply release version to pyproject.toml
186+
# Only the bump needs uv. Kept after the `auto` calls, which resolve the
187+
# release version today without the env setup-python/setup-uv export.
188+
- name: Install Python
189+
uses: actions/setup-python@v6
190+
with:
191+
python-version: ${{ env.PYTHON_VERSION }}
192+
193+
- name: Install uv
194+
uses: astral-sh/setup-uv@v10.0.0
195+
with:
196+
version: ${{ env.UV_VERSION }}
197+
enable-cache: true
198+
python-version: ${{ env.PYTHON_VERSION }}
199+
cache-dependency-glob: |
200+
pyproject.toml
201+
uv.lock
202+
203+
- name: Apply release version to pyproject.toml and uv.lock
187204
run: |
188205
set -euo pipefail
189206
VERSION="${{ steps.latest_release.outputs.version }}"
190207
sed -i "s/^version = \".*\"$/version = \"${VERSION}\"/" pyproject.toml
208+
# uv.lock carries the project's own version. Edit that one field rather
209+
# than running `uv lock`, which re-serializes the whole file.
210+
sed -i "/^name = \"redisvl\"$/{n;s/^version = \".*\"$/version = \"${VERSION}\"/;}" uv.lock
191211
grep '^version = ' pyproject.toml
212+
grep -A1 '^name = "redisvl"$' uv.lock
213+
214+
- name: Verify the version bump
215+
run: |
216+
set -euo pipefail
217+
VERSION="${{ steps.latest_release.outputs.version }}"
218+
219+
fail() { echo "::error::$1"; exit 1; }
220+
221+
# Catch a sed that matched the wrong line, before anything is pushed or
222+
# published. No change is fine: a re-run of an already-bumped commit.
223+
for f in pyproject.toml uv.lock; do
224+
stat="$(git diff --numstat -- "$f" | cut -f1,2)"
225+
if [ -n "$stat" ] && [ "$stat" != "$(printf '1\t1')" ]; then
226+
fail "$f: expected a single-line version change, got $(git diff --shortstat -- "$f")"
227+
fi
228+
other="$(git diff -U0 -- "$f" | grep -E '^[-+][^-+]' | grep -vE '^[-+]version = "' || true)"
229+
if [ -n "$other" ]; then
230+
fail "$f: changed something other than a version line: $other"
231+
fi
232+
done
233+
234+
# In uv.lock it has to be the project's own entry, not a dependency's pin.
235+
grep -qx "version = \"${VERSION}\"" pyproject.toml \
236+
|| fail "pyproject.toml does not carry ${VERSION}"
237+
grep -A1 '^name = "redisvl"$' uv.lock | grep -qx "version = \"${VERSION}\"" \
238+
|| fail "uv.lock: the redisvl entry does not carry ${VERSION}"
239+
240+
uv lock --check
192241
193242
- name: Commit and push version bump
194243
env:
195244
GH_TOKEN: ${{ steps.app_token.outputs.token }}
196245
run: |
197246
set -euo pipefail
198-
if git diff --quiet -- pyproject.toml; then
199-
echo "No pyproject version change to commit."
247+
if git diff --quiet -- pyproject.toml uv.lock; then
248+
echo "No version change to commit."
200249
else
201250
git config user.name "${RELEASE_BOT_NAME}"
202251
git config user.email "${RELEASE_BOT_EMAIL}"
203-
git add pyproject.toml
252+
git add pyproject.toml uv.lock
204253
# Include [skip ci] to avoid running the workflow again on this bot commit.
205-
git commit -m "chore(release): set pyproject version to ${{ steps.latest_release.outputs.version }} [skip ci]"
254+
git commit -m "chore(release): set version to ${{ steps.latest_release.outputs.version }} [skip ci]"
206255
git push origin HEAD:main
207256
fi
208257

.github/workflows/lint.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,28 @@ env:
1010
UV_VERSION: "0.12.3"
1111

1212
jobs:
13+
lock:
14+
name: Check uv.lock is up to date
15+
runs-on: ubuntu-latest
16+
17+
steps:
18+
- name: Check out repository
19+
uses: actions/checkout@v6
20+
21+
- name: Install uv
22+
uses: astral-sh/setup-uv@v10.0.0
23+
with:
24+
version: ${{ env.UV_VERSION }}
25+
enable-cache: true
26+
cache-dependency-glob: |
27+
pyproject.toml
28+
uv.lock
29+
30+
# Fails a pyproject.toml change that was never locked, before the drift
31+
# lands on main and dirties the next contributor's tree.
32+
- name: Check lockfile
33+
run: uv lock --check
34+
1335
check:
1436
name: Style-check ${{ matrix.python-version }}
1537
runs-on: ubuntu-latest

CONTRIBUTING.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ uv sync --all-extras
8181

8282
This will create a virtual environment and install all necessary dependencies for development.
8383

84+
### Changing Dependencies
85+
86+
`uv.lock` is checked in, and CI verifies it matches `pyproject.toml`. If you add, remove, or re-bound a dependency, re-lock and commit the result:
87+
88+
```bash
89+
uv lock
90+
```
91+
8492
## Using the Makefile
8593

8694
We provide a comprehensive Makefile to streamline common development tasks. Here are the available commands:

0 commit comments

Comments
 (0)