mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-28 06:22:22 +00:00
Some checks failed
Devcontainer Smoke / Config-transform unit tests (push) Has been cancelled
Devcontainer Smoke / Build devcontainer image (default) (push) Has been cancelled
Publish Development Images / publish (core) (push) Has been cancelled
Publish Development Images / publish (ui) (push) Has been cancelled
Devcontainer Smoke / Build devcontainer image (ui) (push) Has been cancelled
CodeQL / Analyze (python) (push) Waiting to run
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
Gitleaks / gitleaks (push) Waiting to run
Publish / ci (push) Blocked by required conditions
Publish / Classify release event (push) Waiting to run
Publish / RC guard (marker + release-PR skip) (push) Blocked by required conditions
Publish / Publish to npm (push) Blocked by required conditions
Publish / Build & Push RC Docker images (push) Blocked by required conditions
Scorecard / Scorecard analysis (push) Waiting to run
Skill copy sync / shipped skills drift guard (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-cli) (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-web) (push) Waiting to run
158 lines
6.4 KiB
JavaScript
158 lines
6.4 KiB
JavaScript
'use strict';
|
|
|
|
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const os = require('node:os');
|
|
const path = require('node:path');
|
|
const { execFileSync, spawnSync } = require('node:child_process');
|
|
|
|
const verifier = path.join(__dirname, 'verify-git-hooks.cjs');
|
|
const husky = path.resolve(__dirname, '../node_modules/husky/bin.js');
|
|
|
|
function fixture(t, install = true) {
|
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'gn-husky-'));
|
|
t.after(() => fs.rmSync(root, { recursive: true, force: true }));
|
|
const globalConfig = path.join(root, 'global-gitconfig');
|
|
fs.writeFileSync(globalConfig, '');
|
|
const env = {
|
|
...process.env,
|
|
HUSKY: '',
|
|
GIT_CONFIG_GLOBAL: globalConfig,
|
|
GIT_CONFIG_NOSYSTEM: '1',
|
|
GIT_CONFIG_COUNT: '0',
|
|
XDG_CONFIG_HOME: path.join(root, 'xdg'),
|
|
};
|
|
for (const key of ['GIT_DIR', 'GIT_COMMON_DIR', 'GIT_WORK_TREE', 'GIT_INDEX_FILE'])
|
|
delete env[key];
|
|
const options = { cwd: root, env, encoding: 'utf8' };
|
|
const git = (...args) => execFileSync('git', args, options);
|
|
git('init', '-q');
|
|
git('config', 'user.name', 'Husky test');
|
|
git('config', 'user.email', 'husky-test@example.invalid');
|
|
fs.mkdirSync(path.join(root, '.husky'));
|
|
fs.copyFileSync(
|
|
path.resolve(__dirname, '../.husky/pre-commit'),
|
|
path.join(root, '.husky/pre-commit'),
|
|
);
|
|
if (install) execFileSync(process.execPath, [husky], options);
|
|
const verify = (overrides = {}) =>
|
|
spawnSync(process.execPath, [verifier], { ...options, env: { ...env, ...overrides } });
|
|
const commit = () => spawnSync('git', ['commit', '--allow-empty', '-m', 'hook test'], options);
|
|
const tool = (file, status) => {
|
|
const target = path.join(root, file);
|
|
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
fs.writeFileSync(target, `#!/bin/sh\nprintf called > "$0.called"\nexit ${status}\n`, {
|
|
mode: 0o755,
|
|
});
|
|
return `${target}.called`;
|
|
};
|
|
return { root, git, verify, commit, tool };
|
|
}
|
|
|
|
test('Husky verification accepts a real installation', (t) => {
|
|
const repo = fixture(t);
|
|
const result = repo.verify();
|
|
assert.equal(result.status, 0, result.stderr);
|
|
assert.match(result.stdout, /installed and enabled/);
|
|
});
|
|
|
|
test('Husky verification rejects missing Git hook configuration', (t) => {
|
|
const repo = fixture(t, false);
|
|
assert.equal(repo.verify().status, 1);
|
|
});
|
|
|
|
test('Husky verification rejects a cleared cache without removing the tracked hook', (t) => {
|
|
const repo = fixture(t);
|
|
fs.rmSync(path.join(repo.root, '.husky/_'), { recursive: true });
|
|
assert.equal(repo.verify().status, 1);
|
|
assert.ok(fs.existsSync(path.join(repo.root, '.husky/pre-commit')));
|
|
});
|
|
|
|
test('Husky verification rejects hooks redirected elsewhere', (t) => {
|
|
const repo = fixture(t);
|
|
repo.git('config', 'core.hooksPath', 'other-hooks');
|
|
assert.equal(repo.verify().status, 1);
|
|
});
|
|
|
|
test('Husky verification rejects a missing tracked pre-commit script', (t) => {
|
|
const repo = fixture(t);
|
|
fs.rmSync(path.join(repo.root, '.husky/pre-commit'));
|
|
assert.equal(repo.verify().status, 1);
|
|
});
|
|
|
|
test('Husky verification rejects a non-executable Git hook', (t) => {
|
|
const repo = fixture(t);
|
|
fs.chmodSync(path.join(repo.root, '.husky/_/pre-commit'), 0o644);
|
|
assert.equal(repo.verify().status, 1);
|
|
});
|
|
|
|
test('Husky verification rejects an explicitly disabled hook', (t) => {
|
|
const repo = fixture(t);
|
|
const result = repo.verify({ HUSKY: '0' });
|
|
assert.equal(result.status, 1);
|
|
assert.match(result.stderr, /HUSKY=0 disables/);
|
|
});
|
|
|
|
for (const init of ['export HUSKY=0\n', 'exit 0\n']) {
|
|
test(`Husky verification rejects startup configuration ${init.trim()}`, (t) => {
|
|
const repo = fixture(t);
|
|
const marker = repo.tool('node_modules/.bin/lint-staged', 1);
|
|
fs.mkdirSync(path.join(repo.root, 'xdg/husky'), { recursive: true });
|
|
fs.writeFileSync(path.join(repo.root, 'xdg/husky/init.sh'), init);
|
|
const result = repo.verify();
|
|
assert.equal(result.status, 1);
|
|
assert.match(result.stderr, /startup configuration disables or skips/);
|
|
// Demonstrate why the verifier must fail: real Git would skip the formatter.
|
|
assert.equal(repo.commit().status, 0);
|
|
assert.equal(fs.existsSync(marker), false);
|
|
});
|
|
}
|
|
|
|
test('Husky probe accepts enabled startup configuration without running the tracked hook', (t) => {
|
|
const repo = fixture(t);
|
|
const marker = repo.tool('node_modules/.bin/lint-staged', 1);
|
|
fs.mkdirSync(path.join(repo.root, 'xdg/husky'), { recursive: true });
|
|
fs.writeFileSync(path.join(repo.root, 'xdg/husky/init.sh'), 'export HUSKY=1\nprintf startup\n');
|
|
assert.equal(repo.verify().status, 0);
|
|
assert.equal(fs.existsSync(marker), false);
|
|
assert.equal(repo.commit().status, 1);
|
|
assert.equal(fs.existsSync(marker), true);
|
|
});
|
|
|
|
test('Git rejects a commit when the actual pre-commit formatter fails', (t) => {
|
|
const repo = fixture(t);
|
|
const marker = repo.tool('node_modules/.bin/lint-staged', 1);
|
|
assert.equal(repo.verify().status, 0);
|
|
const result = repo.commit();
|
|
assert.equal(result.status, 1, result.stderr);
|
|
assert.match(result.stdout + result.stderr, /pre-commit: formatting staged files/);
|
|
assert.equal(fs.readFileSync(marker, 'utf8'), 'called');
|
|
assert.throws(() => repo.git('rev-parse', '--verify', 'HEAD'));
|
|
});
|
|
|
|
for (const pkg of ['gitnexus', 'gitnexus-web']) {
|
|
test(`Git rejects a commit when the actual ${pkg} pre-commit typecheck fails`, (t) => {
|
|
const repo = fixture(t);
|
|
repo.tool('node_modules/.bin/lint-staged', 0);
|
|
const marker = repo.tool(`${pkg}/node_modules/.bin/tsc`, 1);
|
|
fs.writeFileSync(path.join(repo.root, pkg, 'change.ts'), 'export const value = 1;\n');
|
|
repo.git('add', `${pkg}/change.ts`);
|
|
assert.equal(repo.verify().status, 0);
|
|
const result = repo.commit();
|
|
assert.equal(result.status, 1, result.stderr);
|
|
assert.match(result.stdout + result.stderr, new RegExp(`pre-commit: typechecking ${pkg}`));
|
|
assert.equal(fs.readFileSync(marker, 'utf8'), 'called');
|
|
assert.throws(() => repo.git('rev-parse', '--verify', 'HEAD'));
|
|
});
|
|
}
|
|
|
|
test('Git accepts a commit when the actual pre-commit checks pass', (t) => {
|
|
const repo = fixture(t);
|
|
repo.tool('node_modules/.bin/lint-staged', 0);
|
|
assert.equal(repo.verify().status, 0);
|
|
const result = repo.commit();
|
|
assert.equal(result.status, 0, result.stderr);
|
|
assert.match(result.stdout + result.stderr, /pre-commit: all checks passed/);
|
|
assert.ok(repo.git('rev-parse', '--verify', 'HEAD').trim());
|
|
});
|