fix(win32): add git flags for snapshot operations and fix tests for cross-platform (#14890)
This commit is contained in:
@@ -64,6 +64,9 @@ export namespace Snapshot {
|
|||||||
.nothrow()
|
.nothrow()
|
||||||
// Configure git to not convert line endings on Windows
|
// Configure git to not convert line endings on Windows
|
||||||
await $`git --git-dir ${git} config core.autocrlf false`.quiet().nothrow()
|
await $`git --git-dir ${git} config core.autocrlf false`.quiet().nothrow()
|
||||||
|
await $`git --git-dir ${git} config core.longpaths true`.quiet().nothrow()
|
||||||
|
await $`git --git-dir ${git} config core.symlinks true`.quiet().nothrow()
|
||||||
|
await $`git --git-dir ${git} config core.fsmonitor false`.quiet().nothrow()
|
||||||
log.info("initialized")
|
log.info("initialized")
|
||||||
}
|
}
|
||||||
await add(git)
|
await add(git)
|
||||||
@@ -86,7 +89,7 @@ export namespace Snapshot {
|
|||||||
const git = gitdir()
|
const git = gitdir()
|
||||||
await add(git)
|
await add(git)
|
||||||
const result =
|
const result =
|
||||||
await $`git -c core.autocrlf=false -c core.quotepath=false --git-dir ${git} --work-tree ${Instance.worktree} diff --no-ext-diff --name-only ${hash} -- .`
|
await $`git -c core.autocrlf=false -c core.longpaths=true -c core.symlinks=true -c core.quotepath=false --git-dir ${git} --work-tree ${Instance.worktree} diff --no-ext-diff --name-only ${hash} -- .`
|
||||||
.quiet()
|
.quiet()
|
||||||
.cwd(Instance.directory)
|
.cwd(Instance.directory)
|
||||||
.nothrow()
|
.nothrow()
|
||||||
@@ -113,7 +116,7 @@ export namespace Snapshot {
|
|||||||
log.info("restore", { commit: snapshot })
|
log.info("restore", { commit: snapshot })
|
||||||
const git = gitdir()
|
const git = gitdir()
|
||||||
const result =
|
const result =
|
||||||
await $`git --git-dir ${git} --work-tree ${Instance.worktree} read-tree ${snapshot} && git --git-dir ${git} --work-tree ${Instance.worktree} checkout-index -a -f`
|
await $`git -c core.longpaths=true -c core.symlinks=true --git-dir ${git} --work-tree ${Instance.worktree} read-tree ${snapshot} && git -c core.longpaths=true -c core.symlinks=true --git-dir ${git} --work-tree ${Instance.worktree} checkout-index -a -f`
|
||||||
.quiet()
|
.quiet()
|
||||||
.cwd(Instance.worktree)
|
.cwd(Instance.worktree)
|
||||||
.nothrow()
|
.nothrow()
|
||||||
@@ -135,14 +138,15 @@ export namespace Snapshot {
|
|||||||
for (const file of item.files) {
|
for (const file of item.files) {
|
||||||
if (files.has(file)) continue
|
if (files.has(file)) continue
|
||||||
log.info("reverting", { file, hash: item.hash })
|
log.info("reverting", { file, hash: item.hash })
|
||||||
const result = await $`git --git-dir ${git} --work-tree ${Instance.worktree} checkout ${item.hash} -- ${file}`
|
const result =
|
||||||
.quiet()
|
await $`git -c core.longpaths=true -c core.symlinks=true --git-dir ${git} --work-tree ${Instance.worktree} checkout ${item.hash} -- ${file}`
|
||||||
.cwd(Instance.worktree)
|
.quiet()
|
||||||
.nothrow()
|
.cwd(Instance.worktree)
|
||||||
|
.nothrow()
|
||||||
if (result.exitCode !== 0) {
|
if (result.exitCode !== 0) {
|
||||||
const relativePath = path.relative(Instance.worktree, file)
|
const relativePath = path.relative(Instance.worktree, file)
|
||||||
const checkTree =
|
const checkTree =
|
||||||
await $`git --git-dir ${git} --work-tree ${Instance.worktree} ls-tree ${item.hash} -- ${relativePath}`
|
await $`git -c core.longpaths=true -c core.symlinks=true --git-dir ${git} --work-tree ${Instance.worktree} ls-tree ${item.hash} -- ${relativePath}`
|
||||||
.quiet()
|
.quiet()
|
||||||
.cwd(Instance.worktree)
|
.cwd(Instance.worktree)
|
||||||
.nothrow()
|
.nothrow()
|
||||||
@@ -164,7 +168,7 @@ export namespace Snapshot {
|
|||||||
const git = gitdir()
|
const git = gitdir()
|
||||||
await add(git)
|
await add(git)
|
||||||
const result =
|
const result =
|
||||||
await $`git -c core.autocrlf=false -c core.quotepath=false --git-dir ${git} --work-tree ${Instance.worktree} diff --no-ext-diff ${hash} -- .`
|
await $`git -c core.autocrlf=false -c core.longpaths=true -c core.symlinks=true -c core.quotepath=false --git-dir ${git} --work-tree ${Instance.worktree} diff --no-ext-diff ${hash} -- .`
|
||||||
.quiet()
|
.quiet()
|
||||||
.cwd(Instance.worktree)
|
.cwd(Instance.worktree)
|
||||||
.nothrow()
|
.nothrow()
|
||||||
@@ -201,7 +205,7 @@ export namespace Snapshot {
|
|||||||
const status = new Map<string, "added" | "deleted" | "modified">()
|
const status = new Map<string, "added" | "deleted" | "modified">()
|
||||||
|
|
||||||
const statuses =
|
const statuses =
|
||||||
await $`git -c core.autocrlf=false -c core.quotepath=false --git-dir ${git} --work-tree ${Instance.worktree} diff --no-ext-diff --name-status --no-renames ${from} ${to} -- .`
|
await $`git -c core.autocrlf=false -c core.longpaths=true -c core.symlinks=true -c core.quotepath=false --git-dir ${git} --work-tree ${Instance.worktree} diff --no-ext-diff --name-status --no-renames ${from} ${to} -- .`
|
||||||
.quiet()
|
.quiet()
|
||||||
.cwd(Instance.directory)
|
.cwd(Instance.directory)
|
||||||
.nothrow()
|
.nothrow()
|
||||||
@@ -215,7 +219,7 @@ export namespace Snapshot {
|
|||||||
status.set(file, kind)
|
status.set(file, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
for await (const line of $`git -c core.autocrlf=false -c core.quotepath=false --git-dir ${git} --work-tree ${Instance.worktree} diff --no-ext-diff --no-renames --numstat ${from} ${to} -- .`
|
for await (const line of $`git -c core.autocrlf=false -c core.longpaths=true -c core.symlinks=true -c core.quotepath=false --git-dir ${git} --work-tree ${Instance.worktree} diff --no-ext-diff --no-renames --numstat ${from} ${to} -- .`
|
||||||
.quiet()
|
.quiet()
|
||||||
.cwd(Instance.directory)
|
.cwd(Instance.directory)
|
||||||
.nothrow()
|
.nothrow()
|
||||||
@@ -225,13 +229,13 @@ export namespace Snapshot {
|
|||||||
const isBinaryFile = additions === "-" && deletions === "-"
|
const isBinaryFile = additions === "-" && deletions === "-"
|
||||||
const before = isBinaryFile
|
const before = isBinaryFile
|
||||||
? ""
|
? ""
|
||||||
: await $`git -c core.autocrlf=false --git-dir ${git} --work-tree ${Instance.worktree} show ${from}:${file}`
|
: await $`git -c core.autocrlf=false -c core.longpaths=true -c core.symlinks=true --git-dir ${git} --work-tree ${Instance.worktree} show ${from}:${file}`
|
||||||
.quiet()
|
.quiet()
|
||||||
.nothrow()
|
.nothrow()
|
||||||
.text()
|
.text()
|
||||||
const after = isBinaryFile
|
const after = isBinaryFile
|
||||||
? ""
|
? ""
|
||||||
: await $`git -c core.autocrlf=false --git-dir ${git} --work-tree ${Instance.worktree} show ${to}:${file}`
|
: await $`git -c core.autocrlf=false -c core.longpaths=true -c core.symlinks=true --git-dir ${git} --work-tree ${Instance.worktree} show ${to}:${file}`
|
||||||
.quiet()
|
.quiet()
|
||||||
.nothrow()
|
.nothrow()
|
||||||
.text()
|
.text()
|
||||||
@@ -256,7 +260,10 @@ export namespace Snapshot {
|
|||||||
|
|
||||||
async function add(git: string) {
|
async function add(git: string) {
|
||||||
await syncExclude(git)
|
await syncExclude(git)
|
||||||
await $`git --git-dir ${git} --work-tree ${Instance.worktree} add .`.quiet().cwd(Instance.directory).nothrow()
|
await $`git -c core.autocrlf=false -c core.longpaths=true -c core.symlinks=true --git-dir ${git} --work-tree ${Instance.worktree} add .`
|
||||||
|
.quiet()
|
||||||
|
.cwd(Instance.directory)
|
||||||
|
.nothrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function syncExclude(git: string) {
|
async function syncExclude(git: string) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { afterAll } from "bun:test"
|
|||||||
const dir = path.join(os.tmpdir(), "opencode-test-data-" + process.pid)
|
const dir = path.join(os.tmpdir(), "opencode-test-data-" + process.pid)
|
||||||
await fs.mkdir(dir, { recursive: true })
|
await fs.mkdir(dir, { recursive: true })
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
fsSync.rmSync(dir, { recursive: true, force: true })
|
fsSync.rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 500 })
|
||||||
})
|
})
|
||||||
|
|
||||||
process.env["XDG_DATA_HOME"] = path.join(dir, "share")
|
process.env["XDG_DATA_HOME"] = path.join(dir, "share")
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
import { test, expect } from "bun:test"
|
import { test, expect } from "bun:test"
|
||||||
import { $ } from "bun"
|
import { $ } from "bun"
|
||||||
import fs from "fs/promises"
|
import fs from "fs/promises"
|
||||||
|
import path from "path"
|
||||||
import { Snapshot } from "../../src/snapshot"
|
import { Snapshot } from "../../src/snapshot"
|
||||||
import { Instance } from "../../src/project/instance"
|
import { Instance } from "../../src/project/instance"
|
||||||
import { Filesystem } from "../../src/util/filesystem"
|
import { Filesystem } from "../../src/util/filesystem"
|
||||||
import { tmpdir } from "../fixture/fixture"
|
import { tmpdir } from "../fixture/fixture"
|
||||||
|
|
||||||
|
// Git always outputs /-separated paths internally. Snapshot.patch() joins them
|
||||||
|
// with path.join (which produces \ on Windows) then normalizes back to /.
|
||||||
|
// This helper does the same for expected values so assertions match cross-platform.
|
||||||
|
const fwd = (...parts: string[]) => path.join(...parts).replaceAll("\\", "/")
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
return tmpdir({
|
return tmpdir({
|
||||||
git: true,
|
git: true,
|
||||||
@@ -35,7 +41,7 @@ test("tracks deleted files correctly", async () => {
|
|||||||
|
|
||||||
await $`rm ${tmp.path}/a.txt`.quiet()
|
await $`rm ${tmp.path}/a.txt`.quiet()
|
||||||
|
|
||||||
expect((await Snapshot.patch(before!)).files).toContain(`${tmp.path}/a.txt`)
|
expect((await Snapshot.patch(before!)).files).toContain(fwd(tmp.path, "a.txt"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -143,7 +149,7 @@ test("binary file handling", async () => {
|
|||||||
await Filesystem.write(`${tmp.path}/image.png`, new Uint8Array([0x89, 0x50, 0x4e, 0x47]))
|
await Filesystem.write(`${tmp.path}/image.png`, new Uint8Array([0x89, 0x50, 0x4e, 0x47]))
|
||||||
|
|
||||||
const patch = await Snapshot.patch(before!)
|
const patch = await Snapshot.patch(before!)
|
||||||
expect(patch.files).toContain(`${tmp.path}/image.png`)
|
expect(patch.files).toContain(fwd(tmp.path, "image.png"))
|
||||||
|
|
||||||
await Snapshot.revert([patch])
|
await Snapshot.revert([patch])
|
||||||
expect(
|
expect(
|
||||||
@@ -164,9 +170,9 @@ test("symlink handling", async () => {
|
|||||||
const before = await Snapshot.track()
|
const before = await Snapshot.track()
|
||||||
expect(before).toBeTruthy()
|
expect(before).toBeTruthy()
|
||||||
|
|
||||||
await $`ln -s ${tmp.path}/a.txt ${tmp.path}/link.txt`.quiet()
|
await fs.symlink(`${tmp.path}/a.txt`, `${tmp.path}/link.txt`, "file")
|
||||||
|
|
||||||
expect((await Snapshot.patch(before!)).files).toContain(`${tmp.path}/link.txt`)
|
expect((await Snapshot.patch(before!)).files).toContain(fwd(tmp.path, "link.txt"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -181,7 +187,7 @@ test("large file handling", async () => {
|
|||||||
|
|
||||||
await Filesystem.write(`${tmp.path}/large.txt`, "x".repeat(1024 * 1024))
|
await Filesystem.write(`${tmp.path}/large.txt`, "x".repeat(1024 * 1024))
|
||||||
|
|
||||||
expect((await Snapshot.patch(before!)).files).toContain(`${tmp.path}/large.txt`)
|
expect((await Snapshot.patch(before!)).files).toContain(fwd(tmp.path, "large.txt"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -222,9 +228,9 @@ test("special characters in filenames", async () => {
|
|||||||
await Filesystem.write(`${tmp.path}/file_with_underscores.txt`, "UNDERSCORES")
|
await Filesystem.write(`${tmp.path}/file_with_underscores.txt`, "UNDERSCORES")
|
||||||
|
|
||||||
const files = (await Snapshot.patch(before!)).files
|
const files = (await Snapshot.patch(before!)).files
|
||||||
expect(files).toContain(`${tmp.path}/file with spaces.txt`)
|
expect(files).toContain(fwd(tmp.path, "file with spaces.txt"))
|
||||||
expect(files).toContain(`${tmp.path}/file-with-dashes.txt`)
|
expect(files).toContain(fwd(tmp.path, "file-with-dashes.txt"))
|
||||||
expect(files).toContain(`${tmp.path}/file_with_underscores.txt`)
|
expect(files).toContain(fwd(tmp.path, "file_with_underscores.txt"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -293,10 +299,10 @@ test("unicode filenames", async () => {
|
|||||||
expect(before).toBeTruthy()
|
expect(before).toBeTruthy()
|
||||||
|
|
||||||
const unicodeFiles = [
|
const unicodeFiles = [
|
||||||
{ path: `${tmp.path}/文件.txt`, content: "chinese content" },
|
{ path: fwd(tmp.path, "文件.txt"), content: "chinese content" },
|
||||||
{ path: `${tmp.path}/🚀rocket.txt`, content: "emoji content" },
|
{ path: fwd(tmp.path, "🚀rocket.txt"), content: "emoji content" },
|
||||||
{ path: `${tmp.path}/café.txt`, content: "accented content" },
|
{ path: fwd(tmp.path, "café.txt"), content: "accented content" },
|
||||||
{ path: `${tmp.path}/файл.txt`, content: "cyrillic content" },
|
{ path: fwd(tmp.path, "файл.txt"), content: "cyrillic content" },
|
||||||
]
|
]
|
||||||
|
|
||||||
for (const file of unicodeFiles) {
|
for (const file of unicodeFiles) {
|
||||||
@@ -329,8 +335,8 @@ test.skip("unicode filenames modification and restore", async () => {
|
|||||||
await Instance.provide({
|
await Instance.provide({
|
||||||
directory: tmp.path,
|
directory: tmp.path,
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
const chineseFile = `${tmp.path}/文件.txt`
|
const chineseFile = fwd(tmp.path, "文件.txt")
|
||||||
const cyrillicFile = `${tmp.path}/файл.txt`
|
const cyrillicFile = fwd(tmp.path, "файл.txt")
|
||||||
|
|
||||||
await Filesystem.write(chineseFile, "original chinese")
|
await Filesystem.write(chineseFile, "original chinese")
|
||||||
await Filesystem.write(cyrillicFile, "original cyrillic")
|
await Filesystem.write(cyrillicFile, "original cyrillic")
|
||||||
@@ -362,7 +368,7 @@ test("unicode filenames in subdirectories", async () => {
|
|||||||
expect(before).toBeTruthy()
|
expect(before).toBeTruthy()
|
||||||
|
|
||||||
await $`mkdir -p "${tmp.path}/目录/подкаталог"`.quiet()
|
await $`mkdir -p "${tmp.path}/目录/подкаталог"`.quiet()
|
||||||
const deepFile = `${tmp.path}/目录/подкаталог/文件.txt`
|
const deepFile = fwd(tmp.path, "目录", "подкаталог", "文件.txt")
|
||||||
await Filesystem.write(deepFile, "deep unicode content")
|
await Filesystem.write(deepFile, "deep unicode content")
|
||||||
|
|
||||||
const patch = await Snapshot.patch(before!)
|
const patch = await Snapshot.patch(before!)
|
||||||
@@ -388,7 +394,7 @@ test("very long filenames", async () => {
|
|||||||
expect(before).toBeTruthy()
|
expect(before).toBeTruthy()
|
||||||
|
|
||||||
const longName = "a".repeat(200) + ".txt"
|
const longName = "a".repeat(200) + ".txt"
|
||||||
const longFile = `${tmp.path}/${longName}`
|
const longFile = fwd(tmp.path, longName)
|
||||||
|
|
||||||
await Filesystem.write(longFile, "long filename content")
|
await Filesystem.write(longFile, "long filename content")
|
||||||
|
|
||||||
@@ -419,9 +425,9 @@ test("hidden files", async () => {
|
|||||||
await Filesystem.write(`${tmp.path}/.config`, "config content")
|
await Filesystem.write(`${tmp.path}/.config`, "config content")
|
||||||
|
|
||||||
const patch = await Snapshot.patch(before!)
|
const patch = await Snapshot.patch(before!)
|
||||||
expect(patch.files).toContain(`${tmp.path}/.hidden`)
|
expect(patch.files).toContain(fwd(tmp.path, ".hidden"))
|
||||||
expect(patch.files).toContain(`${tmp.path}/.gitignore`)
|
expect(patch.files).toContain(fwd(tmp.path, ".gitignore"))
|
||||||
expect(patch.files).toContain(`${tmp.path}/.config`)
|
expect(patch.files).toContain(fwd(tmp.path, ".config"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -436,12 +442,12 @@ test("nested symlinks", async () => {
|
|||||||
|
|
||||||
await $`mkdir -p ${tmp.path}/sub/dir`.quiet()
|
await $`mkdir -p ${tmp.path}/sub/dir`.quiet()
|
||||||
await Filesystem.write(`${tmp.path}/sub/dir/target.txt`, "target content")
|
await Filesystem.write(`${tmp.path}/sub/dir/target.txt`, "target content")
|
||||||
await $`ln -s ${tmp.path}/sub/dir/target.txt ${tmp.path}/sub/dir/link.txt`.quiet()
|
await fs.symlink(`${tmp.path}/sub/dir/target.txt`, `${tmp.path}/sub/dir/link.txt`, "file")
|
||||||
await $`ln -s ${tmp.path}/sub ${tmp.path}/sub-link`.quiet()
|
await fs.symlink(`${tmp.path}/sub`, `${tmp.path}/sub-link`, "dir")
|
||||||
|
|
||||||
const patch = await Snapshot.patch(before!)
|
const patch = await Snapshot.patch(before!)
|
||||||
expect(patch.files).toContain(`${tmp.path}/sub/dir/link.txt`)
|
expect(patch.files).toContain(fwd(tmp.path, "sub", "dir", "link.txt"))
|
||||||
expect(patch.files).toContain(`${tmp.path}/sub-link`)
|
expect(patch.files).toContain(fwd(tmp.path, "sub-link"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -476,7 +482,7 @@ test("circular symlinks", async () => {
|
|||||||
expect(before).toBeTruthy()
|
expect(before).toBeTruthy()
|
||||||
|
|
||||||
// Create circular symlink
|
// Create circular symlink
|
||||||
await $`ln -s ${tmp.path}/circular ${tmp.path}/circular`.quiet().nothrow()
|
await fs.symlink(`${tmp.path}/circular`, `${tmp.path}/circular`, "dir").catch(() => {})
|
||||||
|
|
||||||
const patch = await Snapshot.patch(before!)
|
const patch = await Snapshot.patch(before!)
|
||||||
expect(patch.files.length).toBeGreaterThanOrEqual(0) // Should not crash
|
expect(patch.files.length).toBeGreaterThanOrEqual(0) // Should not crash
|
||||||
@@ -499,11 +505,11 @@ test("gitignore changes", async () => {
|
|||||||
const patch = await Snapshot.patch(before!)
|
const patch = await Snapshot.patch(before!)
|
||||||
|
|
||||||
// Should track gitignore itself
|
// Should track gitignore itself
|
||||||
expect(patch.files).toContain(`${tmp.path}/.gitignore`)
|
expect(patch.files).toContain(fwd(tmp.path, ".gitignore"))
|
||||||
// Should track normal files
|
// Should track normal files
|
||||||
expect(patch.files).toContain(`${tmp.path}/normal.txt`)
|
expect(patch.files).toContain(fwd(tmp.path, "normal.txt"))
|
||||||
// Should not track ignored files (git won't see them)
|
// Should not track ignored files (git won't see them)
|
||||||
expect(patch.files).not.toContain(`${tmp.path}/test.ignored`)
|
expect(patch.files).not.toContain(fwd(tmp.path, "test.ignored"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -523,8 +529,8 @@ test("git info exclude changes", async () => {
|
|||||||
await Bun.write(`${tmp.path}/normal.txt`, "normal content")
|
await Bun.write(`${tmp.path}/normal.txt`, "normal content")
|
||||||
|
|
||||||
const patch = await Snapshot.patch(before!)
|
const patch = await Snapshot.patch(before!)
|
||||||
expect(patch.files).toContain(`${tmp.path}/normal.txt`)
|
expect(patch.files).toContain(fwd(tmp.path, "normal.txt"))
|
||||||
expect(patch.files).not.toContain(`${tmp.path}/ignored.txt`)
|
expect(patch.files).not.toContain(fwd(tmp.path, "ignored.txt"))
|
||||||
|
|
||||||
const after = await Snapshot.track()
|
const after = await Snapshot.track()
|
||||||
const diffs = await Snapshot.diffFull(before!, after!)
|
const diffs = await Snapshot.diffFull(before!, after!)
|
||||||
@@ -559,9 +565,9 @@ test("git info exclude keeps global excludes", async () => {
|
|||||||
await Bun.write(`${tmp.path}/normal.txt`, "normal content")
|
await Bun.write(`${tmp.path}/normal.txt`, "normal content")
|
||||||
|
|
||||||
const patch = await Snapshot.patch(before!)
|
const patch = await Snapshot.patch(before!)
|
||||||
expect(patch.files).toContain(`${tmp.path}/normal.txt`)
|
expect(patch.files).toContain(fwd(tmp.path, "normal.txt"))
|
||||||
expect(patch.files).not.toContain(`${tmp.path}/global.tmp`)
|
expect(patch.files).not.toContain(fwd(tmp.path, "global.tmp"))
|
||||||
expect(patch.files).not.toContain(`${tmp.path}/info.tmp`)
|
expect(patch.files).not.toContain(fwd(tmp.path, "info.tmp"))
|
||||||
} finally {
|
} finally {
|
||||||
if (prev) process.env.GIT_CONFIG_GLOBAL = prev
|
if (prev) process.env.GIT_CONFIG_GLOBAL = prev
|
||||||
else delete process.env.GIT_CONFIG_GLOBAL
|
else delete process.env.GIT_CONFIG_GLOBAL
|
||||||
@@ -610,7 +616,7 @@ test("snapshot state isolation between projects", async () => {
|
|||||||
const before1 = await Snapshot.track()
|
const before1 = await Snapshot.track()
|
||||||
await Filesystem.write(`${tmp1.path}/project1.txt`, "project1 content")
|
await Filesystem.write(`${tmp1.path}/project1.txt`, "project1 content")
|
||||||
const patch1 = await Snapshot.patch(before1!)
|
const patch1 = await Snapshot.patch(before1!)
|
||||||
expect(patch1.files).toContain(`${tmp1.path}/project1.txt`)
|
expect(patch1.files).toContain(fwd(tmp1.path, "project1.txt"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -620,10 +626,10 @@ test("snapshot state isolation between projects", async () => {
|
|||||||
const before2 = await Snapshot.track()
|
const before2 = await Snapshot.track()
|
||||||
await Filesystem.write(`${tmp2.path}/project2.txt`, "project2 content")
|
await Filesystem.write(`${tmp2.path}/project2.txt`, "project2 content")
|
||||||
const patch2 = await Snapshot.patch(before2!)
|
const patch2 = await Snapshot.patch(before2!)
|
||||||
expect(patch2.files).toContain(`${tmp2.path}/project2.txt`)
|
expect(patch2.files).toContain(fwd(tmp2.path, "project2.txt"))
|
||||||
|
|
||||||
// Ensure project1 files don't appear in project2
|
// Ensure project1 files don't appear in project2
|
||||||
expect(patch2.files).not.toContain(`${tmp1?.path}/project1.txt`)
|
expect(patch2.files).not.toContain(fwd(tmp1?.path ?? "", "project1.txt"))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -647,7 +653,7 @@ test("patch detects changes in secondary worktree", async () => {
|
|||||||
const before = await Snapshot.track()
|
const before = await Snapshot.track()
|
||||||
expect(before).toBeTruthy()
|
expect(before).toBeTruthy()
|
||||||
|
|
||||||
const worktreeFile = `${worktreePath}/worktree.txt`
|
const worktreeFile = fwd(worktreePath, "worktree.txt")
|
||||||
await Filesystem.write(worktreeFile, "worktree content")
|
await Filesystem.write(worktreeFile, "worktree content")
|
||||||
|
|
||||||
const patch = await Snapshot.patch(before!)
|
const patch = await Snapshot.patch(before!)
|
||||||
@@ -681,7 +687,7 @@ test("revert only removes files in invoking worktree", async () => {
|
|||||||
const before = await Snapshot.track()
|
const before = await Snapshot.track()
|
||||||
expect(before).toBeTruthy()
|
expect(before).toBeTruthy()
|
||||||
|
|
||||||
const worktreeFile = `${worktreePath}/worktree.txt`
|
const worktreeFile = fwd(worktreePath, "worktree.txt")
|
||||||
await Filesystem.write(worktreeFile, "worktree content")
|
await Filesystem.write(worktreeFile, "worktree content")
|
||||||
|
|
||||||
const patch = await Snapshot.patch(before!)
|
const patch = await Snapshot.patch(before!)
|
||||||
@@ -832,7 +838,7 @@ test("revert should not delete files that existed but were deleted in snapshot",
|
|||||||
await Filesystem.write(`${tmp.path}/a.txt`, "recreated content")
|
await Filesystem.write(`${tmp.path}/a.txt`, "recreated content")
|
||||||
|
|
||||||
const patch = await Snapshot.patch(snapshot2!)
|
const patch = await Snapshot.patch(snapshot2!)
|
||||||
expect(patch.files).toContain(`${tmp.path}/a.txt`)
|
expect(patch.files).toContain(fwd(tmp.path, "a.txt"))
|
||||||
|
|
||||||
await Snapshot.revert([patch])
|
await Snapshot.revert([patch])
|
||||||
|
|
||||||
@@ -861,8 +867,8 @@ test("revert preserves file that existed in snapshot when deleted then recreated
|
|||||||
await Filesystem.write(`${tmp.path}/newfile.txt`, "new")
|
await Filesystem.write(`${tmp.path}/newfile.txt`, "new")
|
||||||
|
|
||||||
const patch = await Snapshot.patch(snapshot!)
|
const patch = await Snapshot.patch(snapshot!)
|
||||||
expect(patch.files).toContain(`${tmp.path}/existing.txt`)
|
expect(patch.files).toContain(fwd(tmp.path, "existing.txt"))
|
||||||
expect(patch.files).toContain(`${tmp.path}/newfile.txt`)
|
expect(patch.files).toContain(fwd(tmp.path, "newfile.txt"))
|
||||||
|
|
||||||
await Snapshot.revert([patch])
|
await Snapshot.revert([patch])
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user