Files
superwork/vscode/test/git/worktreeFromRemote.test.ts

89 lines
3.6 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { execFileSync } from 'node:child_process'
import { existsSync, promises as fsp, rmSync, writeFileSync } from 'node:fs'
import * as os from 'node:os'
import * as path from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
import { ensureWorktreeFromRemote } from '../../src/git/worktree'
const gitEnv: NodeJS.ProcessEnv = {
...process.env,
GIT_CONFIG_NOSYSTEM: '1',
GIT_CONFIG_GLOBAL: '/dev/null',
GIT_TERMINAL_PROMPT: '0',
GIT_AUTHOR_NAME: 'remote-test',
GIT_AUTHOR_EMAIL: 'remote@test.local',
GIT_COMMITTER_NAME: 'remote-test',
GIT_COMMITTER_EMAIL: 'remote@test.local',
}
function git(cwd: string, args: string[]): string {
return execFileSync('git', ['-C', cwd, ...args], { encoding: 'utf8', env: gitEnv }).trim()
}
interface Fixture { root: string, origin: string, repo: string, templatePath: string }
/** originbare)← 同事的 clone push feature 分支;repo 是接管方的 clone,只有 main。 */
async function setup(): Promise<Fixture> {
const root = await fsp.mkdtemp(path.join(os.tmpdir(), 'sw-remote-'))
const origin = path.join(root, 'origin.git')
git(root, ['init', '--bare', '-b', 'main', origin])
const peer = path.join(root, 'peer')
git(root, ['clone', origin, peer])
writeFileSync(path.join(peer, 'README.md'), 'hello\n')
git(peer, ['add', 'README.md'])
git(peer, ['commit', '-m', 'init'])
git(peer, ['push', '-u', 'origin', 'main'])
git(peer, ['checkout', '-b', 'feature/x'])
writeFileSync(path.join(peer, 'x.txt'), 'x\n')
git(peer, ['add', 'x.txt'])
git(peer, ['commit', '-m', 'feat x'])
git(peer, ['push', '-u', 'origin', 'feature/x'])
const repo = path.join(root, 'repo')
git(root, ['clone', origin, repo])
const templatePath = path.join(root, 'wt', 'x')
return { root, origin, repo, templatePath }
}
let fx: Fixture | undefined
afterEach(() => {
if (fx)
rmSync(fx.root, { recursive: true, force: true })
fx = undefined
})
describe('ensureWorktreeFromRemote', () => {
it('从 origin 分支建 worktree,本地分支跟踪远端', async () => {
fx = await setup()
const out = await ensureWorktreeFromRemote({ workspaceRoot: fx.repo, worktreePath: fx.templatePath, branch: 'feature/x' })
expect(out).toBe(fx.templatePath)
expect(existsSync(path.join(fx.templatePath, 'x.txt'))).toBe(true)
expect(git(fx.templatePath, ['rev-parse', '--abbrev-ref', 'HEAD'])).toBe('feature/x')
expect(git(fx.templatePath, ['rev-parse', '--abbrev-ref', '@{u}'])).toBe('origin/feature/x')
})
it('该分支已有 live worktree 时直接复用', async () => {
fx = await setup()
const first = await ensureWorktreeFromRemote({ workspaceRoot: fx.repo, worktreePath: fx.templatePath, branch: 'feature/x' })
const other = path.join(fx.root, 'wt', 'other')
const second = await ensureWorktreeFromRemote({ workspaceRoot: fx.repo, worktreePath: other, branch: 'feature/x' })
expect(second).toBe(first)
expect(existsSync(other)).toBe(false)
})
it('模板路径被非 worktree 目录占着 → 删掉重建', async () => {
fx = await setup()
await fsp.mkdir(fx.templatePath, { recursive: true })
writeFileSync(path.join(fx.templatePath, 'junk'), '')
await ensureWorktreeFromRemote({ workspaceRoot: fx.repo, worktreePath: fx.templatePath, branch: 'feature/x' })
expect(existsSync(path.join(fx.templatePath, 'junk'))).toBe(false)
expect(existsSync(path.join(fx.templatePath, 'x.txt'))).toBe(true)
})
it('远端没有该分支 → 抛错', async () => {
fx = await setup()
await expect(
ensureWorktreeFromRemote({ workspaceRoot: fx.repo, worktreePath: fx.templatePath, branch: 'feature/none' }),
).rejects.toThrow(/feature\/none/)
})
})