)]}'
{
  "commit": "34d3bb0d218c82dc50331b8ee4e03cef6fa01f34",
  "tree": "312f0d249ef404bd7035b76240acc969f656bfeb",
  "parents": [
    "381762af4e3e7d1c83e827aec9bb14b4c477f492"
  ],
  "author": {
    "name": "Ted Kaplan",
    "email": "ted.kaplan@bedrockrobotics.com",
    "time": "Mon Oct 05 01:56:45 2026 +0000"
  },
  "committer": {
    "name": "GitHub",
    "email": "noreply@github.com",
    "time": "Mon Oct 05 01:56:45 2026 +0000"
  },
  "message": "fix(pypi): build uv.lock git sources with pip (#4209)\n\n`pip.parse(uv_lock \u003d ...)` passes a git-sourced package\u0027s raw uv source\nstring (`https://host/repo?rev\u003d\u003cref\u003e#\u003ccommit\u003e`) to the Bazel downloader\nas a URL, which cannot fetch a git repository (#4139). #4086 fixed the\ninvalid repo name for these sources but kept the URL, so they still fail\nat fetch time.\n\nThis makes uv.lock git sources match how a `foo @ git+...` line from a\nrequirements file is already handled:\n\n- The src gets an empty `url` and `filename`, so `_whl_repo` takes the\nexisting pip path instead of the downloader.\n- The requirement line becomes a pip direct reference, `foo @ git+\u003crepo\nurl\u003e@\u003ccommit\u003e`, pinned to the commit uv resolved rather than the\nrequested `rev`/`tag`/`branch`. Before, it was `foo\u003d\u003d\u003cversion\u003e`, which\npip cannot satisfy for a VCS-only version such as `0.12.0a0+39be1c6`.\n- A `subdirectory` query parameter carries over as\n`#subdirectory\u003d\u003cdir\u003e`. uv percent-encodes it\n(`subdirectory\u003dpython%2Ffoo`) and pip reads the fragment as a literal\npath, so it is decoded. I checked both against uv 0.9.30 and pip 26.2.1:\npip fails on the encoded form with \"does not appear to be a Python\nproject\" and builds the decoded one.\n\nTests: updated `test_uv_lock_vcs_entry` for the new src shape and added\n`test_uv_lock_vcs_entry_subdirectory`.\n`//tests/pypi/parse_requirements/...` and `//tests/pypi/hub_builder/...`\npass. End to end, a large monorepo using `pip.parse(uv_lock \u003d ...)`\nbuilds its git-sourced `torchdata` dependency against this branch via\n`--override_module`; we have been carrying the same change as a patch on\n2.3.1.\n\nFixes #4139",
  "tree_diff": [
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "589812ea877d2132727607b486c8ff0da6748e92",
      "new_mode": 33188,
      "new_path": "news/4139.fixed.md"
    },
    {
      "type": "modify",
      "old_id": "580989e3ffc930ef4ebc7ce75d624d0752dc07bb",
      "old_mode": 33188,
      "old_path": "python/private/pypi/parse_requirements.bzl",
      "new_id": "2ac8b3724f5e41b517b43c6e3431b3e6a33b454e",
      "new_mode": 33188,
      "new_path": "python/private/pypi/parse_requirements.bzl"
    },
    {
      "type": "modify",
      "old_id": "f6b9d7e5a5be1c8eeeb0e3b9a6a368c39e0879b0",
      "old_mode": 33188,
      "old_path": "tests/pypi/parse_requirements/parse_requirements_tests.bzl",
      "new_id": "733abe42d42495d2d8aea9284f0ea776e2841fe1",
      "new_mode": 33188,
      "new_path": "tests/pypi/parse_requirements/parse_requirements_tests.bzl"
    }
  ]
}
