// Проверки поиска файла post-commit для C5 observer-coverage-checker. // // Повод: 01.08.2026 сторож печатал «.git/hooks/post-commit not installed» // при коммите из рабочей папки ветки (git worktree). Там `.git` — не папка, // а файл-указатель, и проверка `<корень>/.git/hooks/post-commit` мимо цели. // Файл при этом лежит на месте, в общей папке репозитория. Ложная тревога. import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'fs'; import { join } from 'path'; import { tmpdir } from 'os'; import { postCommitInstalled } from './observer-coverage-checker.mjs'; let baza; beforeEach(() => { baza = mkdtempSync(join(tmpdir(), 'occ-')); }); afterEach(() => { rmSync(baza, { recursive: true, force: true }); }); describe('postCommitInstalled', () => { it('обычная папка репозитория: файл на месте — видит его', () => { const koren = join(baza, 'repo'); mkdirSync(join(koren, '.git', 'hooks'), { recursive: true }); writeFileSync(join(koren, '.git', 'hooks', 'post-commit'), '#!/bin/sh\n'); expect(postCommitInstalled(koren)).toBe(true); }); it('обычная папка репозитория: файла нет — так и говорит', () => { const koren = join(baza, 'repo'); mkdirSync(join(koren, '.git', 'hooks'), { recursive: true }); expect(postCommitInstalled(koren)).toBe(false); }); it('рабочая папка ветки: .git — файл-указатель, а хук лежит в общей папке', () => { const koren = join(baza, 'repo'); mkdirSync(join(koren, '.git', 'hooks'), { recursive: true }); writeFileSync(join(koren, '.git', 'hooks', 'post-commit'), '#!/bin/sh\n'); const svoya = join(koren, '.git', 'worktrees', 'vetka'); mkdirSync(svoya, { recursive: true }); writeFileSync(join(svoya, 'commondir'), '../..\n'); const vetka = join(baza, 'vetka'); mkdirSync(vetka, { recursive: true }); writeFileSync(join(vetka, '.git'), `gitdir: ${svoya}\n`); expect(postCommitInstalled(vetka)).toBe(true); }); it('рабочая папка ветки: хука нет и в общей папке — тревога честная', () => { const koren = join(baza, 'repo'); mkdirSync(join(koren, '.git', 'hooks'), { recursive: true }); const svoya = join(koren, '.git', 'worktrees', 'vetka'); mkdirSync(svoya, { recursive: true }); writeFileSync(join(svoya, 'commondir'), '../..\n'); const vetka = join(baza, 'vetka'); mkdirSync(vetka, { recursive: true }); writeFileSync(join(vetka, '.git'), `gitdir: ${svoya}\n`); expect(postCommitInstalled(vetka)).toBe(false); }); it('хуки перенесены настройкой core.hooksPath — смотрит туда', () => { const koren = join(baza, 'repo'); mkdirSync(join(koren, '.git', 'hooks'), { recursive: true }); const inye = join(koren, 'moi-huki'); mkdirSync(inye, { recursive: true }); writeFileSync(join(inye, 'post-commit'), '#!/bin/sh\n'); writeFileSync(join(koren, '.git', 'config'), '[core]\n\thooksPath = moi-huki\n'); expect(postCommitInstalled(koren)).toBe(true); }); });