ReviewOS

also looking at this

stacks/gitlint

fix: support linked Git worktrees

#551
Merged chris wants to merge agent/worktree-git-paths into main
4 files +122 -13
test/worktree.test.tsadded+67-0
Changes to test/worktree.test.ts
@@ -0,0 +1,67 @@
1import { afterEach, describe, expect, it } from 'bun:test'
2import { execFileSync } from 'node:child_process'
3import fs from 'node:fs'
4import os from 'node:os'
5import path from 'node:path'
6import { installGitHooks, resolveHooksDirectory, uninstallGitHooks } from '../src/hooks'
7import { readCommitMessageFromFile, resolveCommitMessagePath } from '../src/utils'
8
9const temporaryRoots: string[] = []
10
11function git(cwd: string, ...args: string[]): string {
12 return execFileSync('git', args, { cwd, encoding: 'utf8' }).trim()
13}
14
15function linkedWorktree(): { repository: string, worktree: string } {
16 const root = fs.mkdtempSync(path.join(os.tmpdir(), 'gitlint-worktree-'))
17 temporaryRoots.push(root)
18 const repository = path.join(root, 'repository')
19 const worktree = path.join(root, 'linked')
20 fs.mkdirSync(repository)
21 git(repository, 'init', '--initial-branch=main')
22 git(repository, 'config', 'user.name', 'Gitlint Test')
23 git(repository, 'config', 'user.email', 'gitlint@example.com')
24 fs.writeFileSync(path.join(repository, 'README.md'), '# fixture\n')
25 git(repository, 'add', 'README.md')
26 git(repository, 'commit', '-m', 'chore: initialize fixture')
27 git(repository, 'worktree', 'add', '-b', 'test-worktree', worktree)
28 return { repository, worktree }
29}
30
31afterEach(() => {
32 for (const root of temporaryRoots.splice(0)) fs.rmSync(root, { recursive: true, force: true })
33})
34
35describe('linked worktree support', () => {
36 it('resolves .git commit message paths through Git', () => {
37 const { worktree } = linkedWorktree()
38 expect(fs.statSync(path.join(worktree, '.git')).isFile()).toBeTrue()
39 const actualPath = path.resolve(worktree, git(worktree, 'rev-parse', '--git-path', 'COMMIT_EDITMSG'))
40 fs.writeFileSync(actualPath, 'feat: support linked worktrees\n')
41
42 expect(resolveCommitMessagePath('.git/COMMIT_EDITMSG', worktree)).toBe(actualPath)
43 expect(readCommitMessageFromFile('.git/COMMIT_EDITMSG', worktree)).toBe('feat: support linked worktrees\n')
44 })
45
46 it('installs and removes hooks in the effective Git hooks directory', () => {
47 const { worktree } = linkedWorktree()
48 const hooksDirectory = path.resolve(worktree, git(worktree, 'rev-parse', '--git-path', 'hooks'))
49 const hookPath = path.join(hooksDirectory, 'commit-msg')
50
51 expect(resolveHooksDirectory(worktree)).toBe(hooksDirectory)
52 expect(installGitHooks(true, worktree)).toBeTrue()
53 expect(fs.readFileSync(hookPath, 'utf8')).toContain('gitlint --edit "$1"')
54 expect(uninstallGitHooks(worktree)).toBeTrue()
55 expect(fs.existsSync(hookPath)).toBeFalse()
56 })
57
58 it('preserves ordinary absolute and relative paths', () => {
59 const { worktree } = linkedWorktree()
60 const relativePath = 'message.txt'
61 const absolutePath = path.join(worktree, relativePath)
62 fs.writeFileSync(absolutePath, 'fix: ordinary path\n')
63
64 expect(resolveCommitMessagePath(relativePath, worktree)).toBe(absolutePath)
65 expect(resolveCommitMessagePath(absolutePath, worktree)).toBe(absolutePath)
66 })
67})