fix(lanes,git): harden the lane git surface and fix client races in the Changes panel
Server (git-diff.js, git-ops.js, worktree.js, routes/lanes.js): - Every lane git call runs with GIT_LITERAL_PATHSPECS=1 and -z porcelain, so a file name is a file name, never a glob, and odd names parse correctly. - A lane that is a subdirectory of its repo sees and acts on ONLY its own paths (reads, stage/unstage/discard/commit, and gitFacts.files). - Any file named settings.local.json (the lane's router API key) is refused as 403 ESECRET on disk (symlinks resolved) and at every committed rev. - commit refuses with 400 ESTAGEDOUTSIDE while anything outside the lane is staged (checked with --no-renames, so a move into the lane is caught). - push resolves its remote (upstream → only remote → origin), else 400 ENOREMOTE; unstaging a rename unstages both halves. - Git writes serialize on the repo's git dir, not the lane id, so two lanes on one index cannot collide on index.lock. - git refusing an action (a numeric exit status) answers 409 EGIT with git's stderr instead of a 500 carrying a numeric code; one shared parseNumstat. Client: - Changes panel: no stale answer from a previous lane or an older quick-open query repaints the panel; discard disarms on lane switch; Enter on a file path opens it instead of folding; bounded tree expand-all. - Large diffs (> 500 rows) render only the visible rows, with stable width and in-sync split columns; mirrored split scroll is clamped. - Git bar: no "in sync" without counts, a clear no-remote message, branch list re-read after a switch, and no previous-lane facts after a lane switch. - Tooltips no longer flicker or close on unrelated scrolls.
This commit is contained in:
@@ -1022,6 +1022,22 @@ describe("the lane git surface: changes, branches, actions (issue #34)", () => {
|
||||
assert.equal(g(dir, "branch", "--list", "feat/sibling").trim(), "");
|
||||
});
|
||||
|
||||
it("maps a git exit status to 409 EGIT with git's stderr in the message", async () => {
|
||||
// A remote that is not a repository: `git push` exits 128, and execFile
|
||||
// reports that as a NUMERIC err.code. It must never reach the client as
|
||||
// `code: 128`, nor as a 500 — git refusing is not a server fault.
|
||||
g(dir, "remote", "add", "origin", path.join(ROOT, "no-such-remote"));
|
||||
try {
|
||||
const r = await request("POST", `/api/lanes/${laneId}/git/push`, {});
|
||||
assert.equal(r.status, 409, JSON.stringify(r.body));
|
||||
assert.equal(r.body.error.code, "EGIT");
|
||||
assert.match(r.body.error.message, /^git push failed\n/);
|
||||
assert.match(r.body.error.message, /no-such-remote/);
|
||||
} finally {
|
||||
g(dir, "remote", "remove", "origin");
|
||||
}
|
||||
});
|
||||
|
||||
it("404s every git route for a lane that does not exist", async () => {
|
||||
for (const url of [
|
||||
"/api/lanes/999999/git/changes",
|
||||
|
||||
Reference in New Issue
Block a user