Skip to content

ci: add uv lock --locked check to lint job (closes #60)#61

Merged
cmeans-claude-dev[bot] merged 1 commit into
mainfrom
chore/version-parity-check
May 2, 2026
Merged

ci: add uv lock --locked check to lint job (closes #60)#61
cmeans-claude-dev[bot] merged 1 commit into
mainfrom
chore/version-parity-check

Conversation

@cmeans-claude-dev

@cmeans-claude-dev cmeans-claude-dev Bot commented May 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a uv lock --locked step to the lint job in .github/workflows/ci.yml. Closes #60.

The v0.3.0 release commit (fdd4fc3) bumped pyproject.toml version = "0.2.0" → "0.3.0" but did not re-run uv lock, so uv.lock's self-version block stayed at 0.2.0. The drift was picked up days later by the weekly uv-lock-refresh.yml cron, which opened PR #59 with mis-framed CHANGELOG copy. PR #59 fixed the symptom; this PR prevents recurrence.

uv lock --locked exits 1 with "The lockfile at uv.lock needs to be updated, but --locked was provided" whenever pyproject.toml and uv.lock are not in agreement. With this step in place, a release commit that forgets the lockfile bump would have failed CI on its own PR before merge — structurally enforced rather than convention-enforced.

What this does NOT do

  • Does NOT check whether uv.lock is fresh against current PyPI. That remains uv-lock-refresh.yml's job (weekly Thursday cron). uv lock --locked only validates pyproject.toml-vs-lockfile consistency, so transitive churn upstream does not produce false positives here.
  • Does NOT change release flow itself. Cutting a release still means: bump pyproject.toml, run uv lock, stamp CHANGELOG, commit, tag, push. The new check is the safety net that catches a forgotten uv lock step.

Diff stat

 .github/workflows/ci.yml | 10 ++++++++++
 CHANGELOG.md             |  4 ++++
 2 files changed, 14 insertions(+)

Test plan

  • uv lock --locked passes locally on this branch (no drift).
  • uv lock --locked exits 1 locally when pyproject.toml version is mutated to mismatch (negative case verified before reverting).
  • uv sync --frozen --extra dev && uv run pytest passes (88 tests).
  • uv run ruff check and uv run ruff format --check src/ tests/ clean.
  • CI green on PR head (lint job picks up the new step on the bot's push).

Catches the v0.3.0-style regression where a release commit bumps
pyproject.toml `version` without re-running `uv lock`, leaving
uv.lock's self-version block on the previous release. PR #59
papered over the drift after the fact; this prevents recurrence.

The new step runs `uv lock --locked` early in the lint job and
fails fast on any pyproject.toml-vs-lockfile inconsistency. Does
not check lockfile-vs-PyPI freshness — that remains the weekly
uv-lock-refresh.yml cron's job.

Verified locally on branch: passes on consistent state, exits 1
when pyproject.toml version is mutated to mismatch.
@cmeans-claude-dev cmeans-claude-dev Bot added the Ready for QA Dev work complete — QA can begin review label May 1, 2026
@github-actions github-actions Bot added Awaiting CI Dev complete, waiting for CI/Codecov to pass before QA and removed Ready for QA Dev work complete — QA can begin review labels May 1, 2026
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@github-actions github-actions Bot added Ready for QA Dev work complete — QA can begin review and removed Awaiting CI Dev complete, waiting for CI/Codecov to pass before QA labels May 1, 2026
@cmeans cmeans added QA Active QA is actively reviewing; Dev should not push changes and removed Ready for QA Dev work complete — QA can begin review labels May 2, 2026

@cmeans cmeans left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

LGTM

@cmeans cmeans left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

QA review — round 1: PASS

PR head: 67d9e23 · branch: chore/version-parity-check · closes #60

Verification (in /tmp worktree off origin/chore/version-parity-check)

Check Result
uv lock --locked (positive — synced state) exit 0, "Resolved 47 packages"
uv lock --locked (negative — mutated pyproject.toml version to 0.4.0) exit 1, "The lockfile at `uv.lock` needs to be updated, but `--locked` was provided" — restored after
uv sync --frozen --extra dev clean
uv run pytest 88/88 pass
uv run ruff check . clean
uv run ruff format --check . 11 files already formatted
uv run mypy src/pypi_winnow_downloads/ clean (CI invocation)
CI status on 67d9e23 all green (lint, typecheck, test 3.11/3.12/3.13, deploy-smoke)

Issue scope check

Issue #60 was about the v0.3.0 release commit failing to bump uv.lock's self-version. The original suggestions were release-flow changes (option A) or cron-side guards (option B). This PR takes a structurally stronger approach — a CI gate that fails any PR with pyproject.toml ↔ uv.lock drift, including the kind that originally caused #60. Closure is well-justified: the v0.3.0-style regression cannot recur because the release PR itself would now fail lint before merge.

Workflow surface check

Grepped .github/workflows/*.yml for uv sync / uv pip:

  • ci.yml — gets the new check ✓
  • publish.yml, test-publish.yml — post-merge release-time workflows; gating in ci.yml already prevents drift from reaching them
  • uv-lock-refresh.yml — cron that regenerates uv.lock; doesn't consume --locked

ci.yml's lint job is the only correct surface to add this; PR is appropriately scoped.

Step placement

New step sits between Set up Python and Install dependencies, so failure happens on the cheap-to-run consistency check before the expensive uv sync. Comment block in the workflow file usefully cross-references issue #60 and the boundary with uv-lock-refresh.yml.

CHANGELOG

## [Unreleased] → ### Added — KaC ordering preserved (Added now leads, Changed follows). Bullet honestly describes both what the new step does and what it does NOT do (no PyPI freshness check). References #60.

Verdict

Ready for QA Signoff. Negative case verified by hand, all CI green, scope right.

No follow-up tickets.

Awaiting maintainer QA Approved.

@cmeans

cmeans commented May 2, 2026

Copy link
Copy Markdown
Owner

Audit: round 1 verification on 67d9e23 complete — positive + negative cases for uv lock --locked both confirmed (negative: mutated pyproject version to 0.4.0, got exit 1 with expected error, restored); pytest/ruff/mypy clean; CI all green; workflow surface check confirms ci.yml/lint is the right place; CHANGELOG ordering correct. No findings. Applying Ready for QA Signoff as final act.

@cmeans cmeans added Ready for QA Signoff QA passed — ready for maintainer final review and merge QA Approved Manual QA testing completed and passed and removed QA Active QA is actively reviewing; Dev should not push changes Ready for QA Signoff QA passed — ready for maintainer final review and merge labels May 2, 2026
@cmeans-claude-dev cmeans-claude-dev Bot merged commit 128b44b into main May 2, 2026
40 checks passed
@cmeans-claude-dev cmeans-claude-dev Bot deleted the chore/version-parity-check branch May 2, 2026 02:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

QA Approved Manual QA testing completed and passed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

release: v0.3.0 commit (fdd4fc3) did not update uv.lock self-version — caused mis-framed PR #59

2 participants