Skip to content

Add import lint workflow and lock-sync hook - #5

Open
gkennos wants to merge 8 commits into
mainfrom
lint-imports
Open

Add import lint workflow and lock-sync hook#5
gkennos wants to merge 8 commits into
mainfrom
lint-imports

Conversation

@gkennos

@gkennos gkennos commented Aug 11, 2026

Copy link
Copy Markdown
Member

Closes #1.
Closes #4.
Fixes #3.

Summary

  • Add a reusable lint-imports.yml workflow for package-owned import-linter contracts
  • Document the lint-imports workflow and add it to the MkDocs workflow index
  • Add dependency-range guidance for sibling CaVa packages during repo onboarding
  • Add .githooks/pre-commit template for uv.lock refreshes when dependency lines change in pyproject.toml
  • Fix the hook dependency-name extraction so it is portable on macOS/BSD tooling and exits cleanly when a staged pyproject.toml change has no dependency-line candidates

Notes

This PR now combines the import-boundary workflow from #4 with the lock-sync hook work currently represented in #2. It does not add the earlier lowest-direct resolution input or Dependabot template approach.

nicoloesch and others added 7 commits July 23, 2026 00:43
Adds an optional `resolution` input (default `highest`) to build-test.yml
and build-test-postgres.yml, forwarded to `uv sync --resolution`, so
consumers can add a second CI job verifying that a declared dependency
floor is actually sufficient (not just the latest resolvable version).

Adds a canonical templates/dependabot.yml scoped to the CAVA sibling packages, pre-labelled `dependencies` so opened PRs flow through the existing label-gate/release-drafter pipeline.

Not yet merged to main. Being piloted on a branch against cava-ci-test
first per the CAVA dependency-range-bump plan.
Without this, Dependabot's default versioning strategy rewrites the
manifest's lower-bound constraint to match whatever it just bumped to,
not just uv.lock -- silently collapsing every declared range down to
"whatever was last merged" and making lowest-direct floor-testing
meaningless. Confirmed via the cava-ci-test pilot (round 1 exhibited
this exact bug; round 2 verifies the fix).
- build-test-postgres.md was missing the resolution input added earlier
  to build-test-postgres.yml itself -- brings it in line with build-test.md.
- docs/index.md component table now lists templates/dependabot.yml.
- setup-new-repo.md gets a new step 4 covering when/how to widen a sibling
  dependency to a range, add Dependabot (with the required
  versioning-strategy: lockfile-only), and add the lowest-direct CI job.
  Subsequent steps renumbered 5-7.
uv sync --resolution <mode> tags the lock with that resolution mode, but
a plain `uv run <cmd>` with no --resolution flag defaults to expecting
`highest` -- it treats a lowest-direct-tagged lock as stale and silently
re-resolves everything back to highest before running the command.

Confirmed directly: after `uv sync --resolution lowest-direct` installed
ruff==0.4.0, a subsequent `uv run ruff --version` logged "Ignoring
existing lockfile due to change in resolution mode: lowest-direct vs.
highest" and ended up on a completely different ruff version.

This meant the lowest-direct job never actually tested the floor -- every
step after the initial sync silently upgraded back to highest, making it
a redundant, no-op duplicate of the regular highest job. Fixes it by
passing --resolution explicitly to the ty/ruff/pytest uv run steps too.
…ommit hook

Reassessed the compatibility-verification approach: the lowest-direct CI
job never caught a real cross-package incompatibility (only bugs in its
own scaffolding -- the versioning-strategy and --resolution propagation
issues fixed earlier), and duplicates a signal already available for free
from any regular Dependabot bump PR's normal CI run. Floor-testing matters
far more for widely-distributed public libraries than a closed internal
chain with full release control.

- build-test.yml / build-test-postgres.yml: drop the resolution input and
  all --resolution flags; install with `uv sync --frozen` instead, so CI
  tests exactly what's committed in uv.lock, no implicit re-resolution.
- Remove templates/dependabot.yml. CVE coverage now comes from the
  Dependabot security-updates repo setting alone (no dependabot.yml
  needed -- confirmed the `allow` list required for scoped version
  updates silently blocks security-update PRs for anything not listed,
  a known GitHub gotcha with no clean workaround).
- Add templates/githooks/pre-commit: keeps uv.lock in sync with
  pyproject.toml locally, before a commit is ever made. Diffs staged
  pyproject.toml for the specific dependency line(s) that changed and
  runs `uv lock --upgrade-package <name>` for just those -- confirmed
  directly this touches only the named package, never an unrelated one.
- docs: setup-new-repo.md step 4 trimmed to just the range-widening
  guidance; new step 5 documents installing the pre-commit hook;
  build-test.md/build-test-postgres.md/index.md references removed.
--frozen blindly trusts uv.lock with no validation against pyproject.toml
at all. Confirmed directly: raising a dependency floor in pyproject.toml
without updating uv.lock still passed --frozen silently (exit 0), meaning
a forgotten or bypassed pre-commit hook could leave a floor completely
untested indefinitely with no signal anywhere.

Plain uv sync is the better fit: it prefers the committed lock when still
valid (so no gratuitous bumps just because something newer shipped
upstream, confirmed separately), but re-resolves and fails loudly the
moment the lock can no longer satisfy pyproject.toml (confirmed with the
same raised-floor scenario -- "No solution found", not a silent pass).
--locked/uv lock --check were also ruled out: they fail on any staleness
at all, not just genuine inconsistency, reintroducing exactly the
forced-update-just-because-something-shipped nagging this whole design
was trying to avoid.
@gkennos
gkennos requested a review from nicoloesch August 11, 2026 02:53
@gkennos gkennos changed the title Lint imports Add import lint workflow and lock-sync hook Aug 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants