fix(2136): add missing bash hooks to MANAGED_HOOKS staleness check (#2141)
* test(2136): add failing test for MANAGED_HOOKS missing bash hooks Asserts that every gsd-*.js and gsd-*.sh file shipped in hooks/ appears in the MANAGED_HOOKS array inside gsd-check-update.js. The three bash hooks (gsd-phase-boundary.sh, gsd-session-state.sh, gsd-validate-commit.sh) were absent, causing this test to fail before the fix. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(2136): add gsd-phase-boundary.sh, gsd-session-state.sh, gsd-validate-commit.sh to MANAGED_HOOKS The MANAGED_HOOKS array in gsd-check-update.js only listed the 6 JS hooks. The 3 bash hooks were never checked for staleness after a GSD update, meaning users could run stale shell hooks indefinitely without any warning. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -86,9 +86,12 @@ const child = spawn(process.execPath, ['-e', `
|
||||
const MANAGED_HOOKS = [
|
||||
'gsd-check-update.js',
|
||||
'gsd-context-monitor.js',
|
||||
'gsd-phase-boundary.sh',
|
||||
'gsd-prompt-guard.js',
|
||||
'gsd-read-guard.js',
|
||||
'gsd-session-state.sh',
|
||||
'gsd-statusline.js',
|
||||
'gsd-validate-commit.sh',
|
||||
'gsd-workflow-guard.js',
|
||||
];
|
||||
let staleHooks = [];
|
||||
|
||||
74
tests/managed-hooks.test.cjs
Normal file
74
tests/managed-hooks.test.cjs
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Regression tests for bug #2136
|
||||
*
|
||||
* gsd-check-update.js contains a MANAGED_HOOKS array used to detect stale
|
||||
* hooks after a GSD update. It must list every hook file that GSD ships so
|
||||
* that all deployed hooks are checked for staleness — not just the .js ones.
|
||||
*
|
||||
* The original bug: the 3 bash hooks (gsd-phase-boundary.sh,
|
||||
* gsd-session-state.sh, gsd-validate-commit.sh) were missing from
|
||||
* MANAGED_HOOKS, so they would never be detected as stale after an update.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const { describe, test } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const HOOKS_DIR = path.join(__dirname, '..', 'hooks');
|
||||
const CHECK_UPDATE_FILE = path.join(HOOKS_DIR, 'gsd-check-update.js');
|
||||
|
||||
describe('bug #2136: MANAGED_HOOKS must include all shipped hook files', () => {
|
||||
let src;
|
||||
let managedHooks;
|
||||
let shippedHooks;
|
||||
|
||||
// Read once — all tests share the same source snapshot
|
||||
src = fs.readFileSync(CHECK_UPDATE_FILE, 'utf-8');
|
||||
|
||||
// Extract the MANAGED_HOOKS array entries from the source
|
||||
// The array is defined as a multi-line array literal of quoted strings
|
||||
const match = src.match(/const MANAGED_HOOKS\s*=\s*\[([\s\S]*?)\]/);
|
||||
assert.ok(match, 'MANAGED_HOOKS array not found in gsd-check-update.js');
|
||||
|
||||
managedHooks = match[1]
|
||||
.split('\n')
|
||||
.map(line => line.trim().replace(/^['"]|['"],?$/g, ''))
|
||||
.filter(s => s.length > 0 && !s.startsWith('//'));
|
||||
|
||||
// List all GSD-managed hook files in hooks/ (names starting with "gsd-")
|
||||
shippedHooks = fs.readdirSync(HOOKS_DIR)
|
||||
.filter(f => f.startsWith('gsd-') && (f.endsWith('.js') || f.endsWith('.sh')));
|
||||
|
||||
test('every shipped gsd-*.js hook is in MANAGED_HOOKS', () => {
|
||||
const jsHooks = shippedHooks.filter(f => f.endsWith('.js'));
|
||||
for (const hookFile of jsHooks) {
|
||||
assert.ok(
|
||||
managedHooks.includes(hookFile),
|
||||
`${hookFile} is shipped in hooks/ but missing from MANAGED_HOOKS in gsd-check-update.js`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('every shipped gsd-*.sh hook is in MANAGED_HOOKS', () => {
|
||||
const shHooks = shippedHooks.filter(f => f.endsWith('.sh'));
|
||||
for (const hookFile of shHooks) {
|
||||
assert.ok(
|
||||
managedHooks.includes(hookFile),
|
||||
`${hookFile} is shipped in hooks/ but missing from MANAGED_HOOKS in gsd-check-update.js`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('MANAGED_HOOKS contains no entries for hooks that do not exist', () => {
|
||||
for (const entry of managedHooks) {
|
||||
const exists = fs.existsSync(path.join(HOOKS_DIR, entry));
|
||||
assert.ok(
|
||||
exists,
|
||||
`MANAGED_HOOKS entry '${entry}' has no corresponding file in hooks/ — remove stale entry`
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user