fix(6245): a re-run of bind_repo(moved_from=…) finishes an earlier move
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 14s
CI & Build / TypeScript typecheck (push) Successful in 59s
CI & Build / integration (push) Successful in 1m25s
CI & Build / Python tests (push) Successful in 2m20s
CI & Build / Build & push image (push) Successful in 32s

Once the binding has moved, the old remote is no longer bound, and
move_binding refused. An install that renamed its repo before snippet
locations moved with it had no way to move them. When the old remote is
unbound and the new one is bound to this project, bind_repo now skips the
binding move and still moves the snippet locations that name the old
repo.

The snippet-move test gives each location its own path: rewritten to one
repo, identical locations merge into one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-22 16:21:19 -04:00
co-authored by Claude Opus 5.5
parent e89e6a24de
commit f77d18cb63
2 changed files with 45 additions and 5 deletions
+32 -1
View File
@@ -112,7 +112,12 @@ async def test_the_snippets_recorded_in_the_old_repo_move_with_it(bound):
note = await snippets_svc.create_snippet(
owner, name=name, code=f"def {name}():\n pass\n", language="python",
project_id=pid,
locations=[{"repo": r, "path": "src/app.py", "symbol": name} for r in repos],
# A path per location: rewritten to one repo, identical locations
# would merge into one.
locations=[
{"repo": r, "path": f"src/app{i}.py", "symbol": name}
for i, r in enumerate(repos)
],
)
return int(note.id)
@@ -132,3 +137,29 @@ async def test_the_snippets_recorded_in_the_old_repo_move_with_it(bound):
assert await repos(moved_one) == [NEW_KEY, NEW_KEY, NEW_KEY]
assert await repos(mixed) == [NEW_KEY, "elsewhere/gadget"]
assert await repos(untouched) == ["Gadget", "git.example.com/alice/oldnamesake"]
@pytest.mark.integration
async def test_running_the_move_again_finishes_what_an_earlier_one_left(bound):
from grimoire.mcp._context import _user_id_ctx
from grimoire.mcp.tools.repos import bind_repo
from grimoire.services import snippets as snippets_svc
owner, pid = bound["owner"], bound["pid"]
await svc.move_binding(owner, OLD, NEW, pid)
note = await snippets_svc.create_snippet(
owner, name="left_behind", code="def left_behind():\n pass\n",
language="python", project_id=pid,
locations=[{"repo": "OldName", "path": "src/app.py", "symbol": "left_behind"}],
)
token = _user_id_ctx.set(owner)
try:
out = await bind_repo(NEW, pid, moved_from=OLD)
finally:
_user_id_ctx.reset(token)
assert out["shapes_moved"] == 0
assert out["snippets_moved"] == [int(note.id)]
moved = await snippets_svc.get_snippet(owner, int(note.id))
assert snippets_svc.snippet_fields(moved)["locations"][0]["repo"] == NEW_KEY