Skip to content

fix(pyproject): track uv.lock relative to target workdir#9266

Open
nguyeda wants to merge 1 commit into
updatecli:mainfrom
nguyeda:fix/pyproject-subdir-lockfile-path
Open

fix(pyproject): track uv.lock relative to target workdir#9266
nguyeda wants to merge 1 commit into
updatecli:mainfrom
nguyeda:fix/pyproject-subdir-lockfile-path

Conversation

@nguyeda

@nguyeda nguyeda commented Jun 25, 2026

Copy link
Copy Markdown

Current Behavior

The pyproject autodiscovery crawler generates a broken shell target for any pyproject.toml discovered in a subdirectory. The generated target sets:

  • workdir: <subdir> — the uv lock command runs here and succeeds, and
  • a changedif (file/checksum) tracking <subdir>/uv.lock.

Because the shell resource resolves changedif files relative to workdir, the path doubles (e.g. foo/bar/foo/bar/uv.lock). That path doesn't exist, so the post-command file check reports Missing files and the target fails — even though uv lock succeeded. Projects at the scan root are unaffected because workdir is ..

Fix

Record the lockfile path relative to the target's own workdir (just uv.lock) instead of joining workdir into it. The workdir is already emitted into the target, and the shell resource prepends it, so joining it twice was the bug. This also matches how sibling crawlers (golang, npm, cargo) reference their lock files as plain literals.

-	relLockFile := filepath.Join(workdir, "uv.lock")
-	...
-		LockFile:                   relLockFile,
+		LockFile:                   "uv.lock",

Tests

Added a regression scenario (Scenario 12) using a nested subdirectory project (testdata/subdir_project/foo/bar) to prove the fix holds at arbitrary depth. With the bug present this scenario fails (files: - "foo/bar/uv.lock"); with the fix it passes (files: - "uv.lock", workdir: 'foo/bar'). Existing scan-root scenarios are unchanged.

Verified end-to-end against a real subdirectory project: updatecli apply runs uv lock in the subdir and rewrites <subdir>/uv.lock correctly, with no <subdir>/<subdir>/ ever created.

Fixes #9265

🤖 Generated with Claude Code

The pyproject autodiscovery crawler generated a broken shell target for any
pyproject.toml discovered in a subdirectory. The target set both
`workdir: <subdir>` and a changedif file of `<subdir>/uv.lock`. Since the shell
resource resolves changedif files relative to workdir, the path doubled (e.g.
`foo/bar/foo/bar/uv.lock`), so the post-command file check reported
"Missing files" and the target failed even though `uv lock` succeeded. Projects
at the scan root were unaffected because workdir is `.`.

Record the lockfile path relative to the target's own workdir (`uv.lock`),
matching how sibling crawlers (golang, npm, cargo) reference their lock files.

Add a regression test with a nested subdirectory project (foo/bar) to cover
arbitrary depth; existing scan-root scenarios are unchanged.

Fixes updatecli#9265

Signed-off-by: David Nguyen <david@nguyen.eu>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BSdDmyipsijMHvW4myvcEW

@loispostula loispostula left a comment

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 @nguyeda for your first contribution!

Lgtm

@mergify

mergify Bot commented Jun 25, 2026

Copy link
Copy Markdown

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

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.

pyproject autodiscovery: uv.lock path is doubled for projects in subdirectories, target fails with "Missing files"

2 participants