/** * GSD Tools Test Helpers */ const { execSync, execFileSync } = require('child_process'); const fs = require('fs'); const path = require('path'); const TOOLS_PATH = path.join(__dirname, '..', 'get-shit-done', 'bin', 'gsd-tools.cjs'); /** * Run gsd-tools command. * * @param {string|string[]} args - Command string (shell-interpreted) or array * of arguments (shell-bypassed via execFileSync, safe for JSON and dollar signs). * @param {string} cwd - Working directory. * @param {object} [env] - Optional env overrides merged on top of process.env. * Pass { HOME: cwd } to sandbox ~/.gsd/ lookups in tests that assert concrete * config values that could be overridden by a developer's defaults.json. */ function runGsdTools(args, cwd = process.cwd(), env = {}) { try { let result; const childEnv = { ...process.env, ...env }; if (Array.isArray(args)) { result = execFileSync(process.execPath, [TOOLS_PATH, ...args], { cwd, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], env: childEnv, }); } else { result = execSync(`node "${TOOLS_PATH}" ${args}`, { cwd, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], env: childEnv, }); } return { success: true, output: result.trim() }; } catch (err) { return { success: false, output: err.stdout?.toString().trim() || '', error: err.stderr?.toString().trim() || err.message, }; } } // Create a bare temp directory (no .planning/ structure) function createTempDir(prefix = 'gsd-test-') { return fs.mkdtempSync(path.join(require('os').tmpdir(), prefix)); } // Create temp directory structure function createTempProject(prefix = 'gsd-test-') { const tmpDir = fs.mkdtempSync(path.join(require('os').tmpdir(), prefix)); fs.mkdirSync(path.join(tmpDir, '.planning', 'phases'), { recursive: true }); return tmpDir; } // Create temp directory with initialized git repo and at least one commit function createTempGitProject(prefix = 'gsd-test-') { const tmpDir = fs.mkdtempSync(path.join(require('os').tmpdir(), prefix)); fs.mkdirSync(path.join(tmpDir, '.planning', 'phases'), { recursive: true }); execSync('git init', { cwd: tmpDir, stdio: 'pipe' }); execSync('git config user.email "test@test.com"', { cwd: tmpDir, stdio: 'pipe' }); execSync('git config user.name "Test"', { cwd: tmpDir, stdio: 'pipe' }); execSync('git config commit.gpgsign false', { cwd: tmpDir, stdio: 'pipe' }); fs.writeFileSync( path.join(tmpDir, '.planning', 'PROJECT.md'), '# Project\n\nTest project.\n' ); execSync('git add -A', { cwd: tmpDir, stdio: 'pipe' }); execSync('git commit -m "initial commit"', { cwd: tmpDir, stdio: 'pipe' }); return tmpDir; } function cleanup(tmpDir) { fs.rmSync(tmpDir, { recursive: true, force: true }); } module.exports = { runGsdTools, createTempDir, createTempProject, createTempGitProject, cleanup, TOOLS_PATH };