feat(6243): move_path carries a moved path's snippets with its shapes
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 17s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 1m9s
CI & Build / Python tests (push) Successful in 2m12s
CI & Build / Build & push image (push) Successful in 31s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 17s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 1m9s
CI & Build / Python tests (push) Successful in 2m12s
CI & Build / Build & push image (push) Successful in 31s
Snippet locations are keyed by path too, so a snippet recorded under a moved directory reads `missing` at its next check. The tool is now move_path(project_id, from_path, to_path). It moves the ledger rows as before, and re-paths the project's snippet locations under from_path through update_snippet, so each body and its indexed mirror stay one record. A snippet the caller can only read is listed in snippets_read_only. The tool refuses only when nothing at all is recorded under from_path. The path test is the one snippets already uses (_path_touches), and the plugin version is minted for the skill edit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -115,12 +115,35 @@ async def test_a_judgment_already_at_the_new_path_stands(seeded):
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
async def test_overlapping_empty_and_unwritable_moves_are_refused(seeded):
|
||||
async def test_overlapping_and_unwritable_moves_are_refused(seeded):
|
||||
owner, other, pid = seeded["owner"], seeded["other"], seeded["pid"]
|
||||
with pytest.raises(ValueError, match="overlap"):
|
||||
await move_shapes(owner, pid, "src/old", "src/old/inner")
|
||||
with pytest.raises(ValueError, match="no shapes under"):
|
||||
await move_shapes(owner, pid, "src/gone", "src/new")
|
||||
assert await move_shapes(owner, pid, "src/gone", "src/new") == {
|
||||
"moved": 0, "replaced": 0, "kept": [],
|
||||
}
|
||||
with pytest.raises(ValueError, match="no write access"):
|
||||
await move_shapes(other, pid, "src/old", "src/new")
|
||||
assert ("src/old/app.py", "make_app") in await _ledger(pid)
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
async def test_the_snippets_recorded_there_move_with_it(seeded):
|
||||
from grimoire.services import snippets as snippets_svc
|
||||
|
||||
owner, pid = seeded["owner"], seeded["pid"]
|
||||
note = await snippets_svc.create_snippet(
|
||||
owner, name="move_helper", code="def helper():\n pass\n",
|
||||
language="python", project_id=pid, locations=[
|
||||
{"repo": "Widget", "path": "src/old/sub/util.py", "symbol": "helper"},
|
||||
{"repo": "Widget", "path": "src/older/keep.py", "symbol": "untouched"},
|
||||
],
|
||||
)
|
||||
|
||||
result = await snippets_svc.move_locations(owner, pid, "src/old", "src/new")
|
||||
|
||||
assert result == {"moved": [int(note.id)], "read_only": []}
|
||||
moved = await snippets_svc.get_snippet(owner, int(note.id))
|
||||
assert [loc["path"] for loc in snippets_svc.snippet_fields(moved)["locations"]] == [
|
||||
"src/new/sub/util.py", "src/older/keep.py",
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user