const fs = require('fs'); const path = require('path'); const managedStart = '# >>> aidop-managed-pre-push >>>'; const managedEnd = '# <<< aidop-managed-pre-push <<<'; function findGitRoot(startDir) { let current = startDir; while (true) { const gitDir = path.join(current, '.git'); if (fs.existsSync(gitDir)) return current; const parent = path.dirname(current); if (parent === current) return null; current = parent; } } function ensureDir(dir) { if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); } function toPosix(p) { return p.replace(/\\/g, '/'); } const webDir = path.resolve(__dirname, '..'); const gitRoot = findGitRoot(webDir); if (!gitRoot) { console.log('[hooks] Skip: .git not found from Web directory upward.'); process.exit(0); } const webRel = toPosix(path.relative(gitRoot, webDir)); const coreCsprojRel = toPosix(path.relative(gitRoot, path.join(webDir, '..', 'server', 'Admin.NET.Core', 'Admin.NET.Core.csproj'))); const hookDir = path.join(gitRoot, '.git', 'hooks'); const hookFile = path.join(hookDir, 'pre-push'); ensureDir(hookDir); const block = `${managedStart} set -e changed_files="" while read local_ref local_sha remote_ref remote_sha do if [ -z "$local_sha" ]; then continue fi if [ "$remote_sha" = "0000000000000000000000000000000000000000" ]; then diff_files=$(git diff-tree --no-commit-id --name-only -r "$local_sha" || true) else diff_files=$(git diff --name-only "$remote_sha" "$local_sha" || true) fi changed_files="$changed_files $diff_files" done need_frontend=0 need_backend=0 if [ -n "$AIDOP_VERIFY_ALL" ]; then need_frontend=1 need_backend=1 fi if [ "$need_frontend" -eq 0 ] && printf "%s\\n" "$changed_files" | grep -qE '^${webRel}/'; then need_frontend=1 fi if [ "$need_backend" -eq 0 ] && printf "%s\\n" "$changed_files" | grep -qE '^server/'; then need_backend=1 fi if [ "$need_frontend" -eq 0 ] && [ "$need_backend" -eq 0 ]; then echo "[aidop hook] no Web or server/ code changes detected, skip build checks" exit 0 fi if [ "$need_frontend" -eq 1 ]; then echo "[aidop hook] verify frontend build" export NODE_OPTIONS="\${NODE_OPTIONS:+\$NODE_OPTIONS }--max-old-space-size=16384" if command -v pnpm >/dev/null 2>&1; then pnpm -C "${webRel}" build else npm --prefix "${webRel}" run build fi fi if [ "$need_backend" -eq 1 ]; then echo "[aidop hook] verify backend core build" dotnet build "${coreCsprojRel}" --framework net8.0 fi ${managedEnd} `; let content = '#!/usr/bin/env sh\n'; if (fs.existsSync(hookFile)) { content = fs.readFileSync(hookFile, 'utf8'); if (!content.startsWith('#!/usr/bin/env sh')) content = '#!/usr/bin/env sh\n' + content; const start = content.indexOf(managedStart); const end = content.indexOf(managedEnd); if (start >= 0 && end > start) { const afterEnd = end + managedEnd.length; content = content.slice(0, start) + block + content.slice(afterEnd); } else { content = content.trimEnd() + '\n\n' + block; } } else { content += '\n' + block; } fs.writeFileSync(hookFile, content, { encoding: 'utf8' }); try { fs.chmodSync(hookFile, 0o755); } catch (_) { // ignore chmod failures on Windows } console.log(`[hooks] pre-push installed at ${hookFile}`);