UN-1929 [FIX] Skip uv locking when lockfiles are already up to date - #2244
Open
Deepak-Kesavan wants to merge 1 commit into
Open
UN-1929 [FIX] Skip uv locking when lockfiles are already up to date#2244Deepak-Kesavan wants to merge 1 commit into
Deepak-Kesavan wants to merge 1 commit into
Conversation
The lock automation gated on "did pyproject.toml change vs origin/main?", which is a proxy for the question it actually wanted to ask. A PR that already carries correct lockfiles still tripped the gate and re-ran a full `uv sync` for every affected directory. Gate on `uv lock --check` instead, which is the authoritative staleness test and covers transitive local path dependencies (verified: editing unstract/core/pyproject.toml marks backend/uv.lock stale). Directories whose lockfiles are already correct are now a real no-op. Also swap `uv sync` for `uv lock`. The workflow only ever commits uv.lock, so building a virtualenv and installing every package was wasted work and the largest source of failures in this job. Add a per-branch concurrency group. Two pushes in quick succession started overlapping runs that raced each other's auto-commit, and the loser failed the job with "failed to push some refs" — 3 of the last 30 runs. Auto-commit behaviour is unchanged.
|
Contributor
|
| Filename | Overview |
|---|---|
| .github/workflows/uv-lock-automation.yaml | Adds branch-scoped cancellation to prevent overlapping lockfile auto-commit runs; no actionable defect was established. |
| docker/scripts/uv-lock-gen/uv-lock.sh | Replaces Git-diff-based gating and full environment synchronization with authoritative lock checks and lock-only regeneration while preserving failure propagation. |
Reviews (1): Last reviewed commit: "UN-1929 [FIX] Skip uv locking when lockf..." | Re-trigger Greptile
Contributor
Unstract test resultsPer-group results
Critical paths
|
chandrasekharan-zipstack
approved these changes
Aug 18, 2026
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



What
Makes the
uv.lockautomation a genuine no-op when the lockfiles in a PR are already correct, and stops the job failing when two runs overlap on the same branch.Three changes:
uv lock --checkinstead of "didpyproject.tomlchange vsorigin/main?"uv sync→uv lockconcurrencygroup on the workflowAuto-commit behaviour is deliberately unchanged — the bot still commits lockfiles back to the PR branch exactly as before.
Why
1. The staleness gate asked the wrong question.
has_dependency_changes()checked whetherpyproject.toml(or a local path dependency'spyproject.toml) differed fromorigin/main. That is a proxy for the real question, "isuv.lockstale?", and it is wrong in exactly the case UN-1929 describes: a contributor (or their AI assistant) already ranuv lockand pushed correct lockfiles, butpyproject.tomlstill differs from main, so the gate trips and the job re-resolves everything anyway.uv lock --checkis the authoritative test — it is what uv exposes for this precise question.2.
uv syncdid far more than needed. The workflow only ever commitsuv.lock.uv syncadditionally creates a virtualenv and installs every package in it — pure waste, and by far the largest failure surface in the job (network, sdist builds).uv lockresolves and writes the lockfile and nothing else.3. The job's actual failure mode today is a push race. Reviewing the last 30 runs of this workflow, the failures are not re-lock failures at all:
There was no
concurrency:block, so two pushes in quick succession start two overlapping runs, both of which try to auto-commit to the same branch; the loser fails the whole job and puts a red X on the PR. This accounted for 3 of the last 30 runs (e.g. branchUN-3987-fix-line-splitter-strategy-key, three overlapping runs within four minutes).How
docker/scripts/uv-lock-gen/uv-lock.shget_local_dep_pyprojects()andhas_dependency_changes()(~45 lines).uv lock --checksubsumes both, including the transitive local-path-dependency walk they hand-rolled.update_lockfile()now runsuv lock --check; if it passes, the directory is skipped entirely. Otherwise it runsuv lock.cdis scoped, replacing the manualcd/cd -dance.git fetch origin main— nothing compares againstorigin/mainany more. (This fetch was also responsible for the large* [new branch]dumps in the job logs.).github/workflows/uv-lock-automation.yamlgithub.head_refis empty onworkflow_dispatch, hence thegithub.reffallback.Net: -46 lines, and the common case now does no dependency resolution at all.
Can this PR break any existing features. If yes, please list possible items. If no, please explain why.
No. This only touches the lockfile-automation CI job — no application code, no runtime path, no shipped artifact. Considered risks, each checked:
uv lock --checkunder-reports staleness. The one real concern was transitive local path dependencies, which the old code walked by hand. Verified explicitly (see Notes on Testing): editingunstract/core/pyproject.tomlmakesbackend'suv lock --checkexit non-zero. No regression in coverage.uv lockproduce a different lockfile thanuv syncdid? No —uv synclocks and then installs. The lockfile-producing step is identical; only the install is dropped.cancel-in-progressdrop a needed run? No. A run is only cancelled when a newer run in the same group starts, and that newer run operates on a strictly newer tree. If a subsequent push does not touch apyproject.toml, thepaths:filter means no new run starts, so the in-flight run is not cancelled and still completes.Database Migrations
Env Config
Relevant Docs
uv lock --check— "Check if the lockfile is up-to-date"Related Issues or PRs
Dependencies Versions
uvstays pinned at0.6.14;uv lock --checkis available in that version (confirmed against the pinned version locally).Notes on Testing
CI-only change with no UI or runtime surface, so this was verified by running the modified script directly against this repo with the same
uv 0.6.14that the workflow pins.1. No-op path — the UN-1929 scenario. Clean tree, lockfiles already correct:
Exit 0, 0.69s for three directories, working tree untouched. Previously each of these would have run a full
uv sync.2. Stale path still works. Added
tabulatetounstract/flags/pyproject.toml:unstract/flags/uv.lockupdated correctly (+46/-35).3. Idempotency — re-running with the now-correct lock. This is the exact ticket scenario (lockfile already pushed):
Second run touched nothing. This is what the ticket asked for.
4. Transitive local path dependencies — the main regression risk. Added a dependency to
unstract/core/pyproject.toml, then checkedbackend(which consumes it via[tool.uv.sources] unstract-core = { path = "../unstract/core" }):So
uv lock --checkcovers whatget_local_dep_pyprojects()walked manually.5. Failure propagation. With an unresolvable dependency pinned in
unstract/flags/pyproject.toml, the script exits 1, so genuinely broken dependency changes still fail the job.All test edits were reverted;
backend/unstract/flagslockfiles confirmed current afterwards.Follow-up spotted while in here (not fixed in this PR)
The hardcoded
directorieslist inuv-lock.shhas drifted. It covers 10 directories, but 14 have auv.lock. These four are never maintained by the automation:tool-sidecarunstract/sdk1unstract/tool-registryunstract/tool-sandboxDeliberately left out of scope — this PR is about doing less, and adding four directories is a behaviour change that deserves its own review. Worth noting that the
uv lock --checkgate makes adding them much cheaper than before, since up-to-date directories now cost effectively nothing. Happy to raise a follow-up ticket, or fold it in here if reviewers prefer.Screenshots
N/A — CI-only change, no UI surface.
Checklist
I have read and understood the Contribution Guidelines.