8f00449615
Работа 1 промта от 01.08 — оживление сторожей текста. По ходу вскрылся отдельный дефект в нашем собственном скрипте. observer-coverage-checker при коммите из рабочей папки ветки печатал ".git/hooks/post-commit not installed". Файл при этом лежал на месте. Причина: в рабочей папке ветки .git не папка, а файл-указатель, и проверка пути <корень>/.git/hooks/post-commit смотрела мимо цели. Плюс настройка core.hooksPath, которая в этом репозитории задана, вообще не учитывалась. Класс беды тот же, что уже дважды записан в память: сторож, не умеющий отличить "нет" от "лежит в другом месте", штампует ложные тревоги. Рядом в той же строке живёт правдивая жалоба про неподключённый обработчик - и ложная половина приучает не читать всю строку целиком. Что сделано: - добавлена postCommitInstalled: сначала ищет общую папку репозитория (для обычной копии это сам .git, для рабочей папки ветки - по указателю gitdir и файлу commondir рядом с ним), затем учитывает core.hooksPath из config и только потом смотрит наличие файла; - чистое чтение файлов, без запуска сторонних команд - требование Security Guidance 40 для этого скрипта соблюдено. Порядок работы соблюдён. Пять проверок написаны ДО правки и покраснели на отсутствующей функции. Разобраны обе стороны каждой развилки: обычная копия с хуком и без, рабочая папка ветки с хуком и без, перенос хуков настройкой. Живой прогон по настоящему репозиторию: из рабочей папки ветки ложная половина ушла, правдивая осталась. Прогоны: набор проверок инструментов 14 файлов, 66 проверок, все зелёные. Отдельно, без правок в git: node_modules был в состоянии оборванной установки - 121 временная папка распаковки, 90 пакетов без главного файла, у tinyglobby файл обрезан посреди строки. Причина обрыва - падение сборки better-sqlite3. Пересобрано начисто из списка версий без сборочных сценариев; package.json и package-lock.json не тронуты, проверено хешем. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
79 lines
3.4 KiB
JavaScript
79 lines
3.4 KiB
JavaScript
// Проверки поиска файла 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);
|
|
});
|
|
});
|