install-git-hooks.cjs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. const fs = require('fs');
  2. const path = require('path');
  3. const managedStart = '# >>> aidop-managed-pre-push >>>';
  4. const managedEnd = '# <<< aidop-managed-pre-push <<<';
  5. function findGitRoot(startDir) {
  6. let current = startDir;
  7. while (true) {
  8. const gitDir = path.join(current, '.git');
  9. if (fs.existsSync(gitDir)) return current;
  10. const parent = path.dirname(current);
  11. if (parent === current) return null;
  12. current = parent;
  13. }
  14. }
  15. function ensureDir(dir) {
  16. if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
  17. }
  18. function toPosix(p) {
  19. return p.replace(/\\/g, '/');
  20. }
  21. const webDir = path.resolve(__dirname, '..');
  22. const gitRoot = findGitRoot(webDir);
  23. if (!gitRoot) {
  24. console.log('[hooks] Skip: .git not found from Web directory upward.');
  25. process.exit(0);
  26. }
  27. const webRel = toPosix(path.relative(gitRoot, webDir));
  28. const coreCsprojRel = toPosix(path.relative(gitRoot, path.join(webDir, '..', 'server', 'Admin.NET.Core', 'Admin.NET.Core.csproj')));
  29. const hookDir = path.join(gitRoot, '.git', 'hooks');
  30. const hookFile = path.join(hookDir, 'pre-push');
  31. ensureDir(hookDir);
  32. const block = `${managedStart}
  33. set -e
  34. changed_files=""
  35. while read local_ref local_sha remote_ref remote_sha
  36. do
  37. if [ -z "$local_sha" ]; then
  38. continue
  39. fi
  40. if [ "$remote_sha" = "0000000000000000000000000000000000000000" ]; then
  41. diff_files=$(git diff-tree --no-commit-id --name-only -r "$local_sha" || true)
  42. else
  43. diff_files=$(git diff --name-only "$remote_sha" "$local_sha" || true)
  44. fi
  45. changed_files="$changed_files
  46. $diff_files"
  47. done
  48. need_frontend=0
  49. need_backend=0
  50. if [ -n "$AIDOP_VERIFY_ALL" ]; then
  51. need_frontend=1
  52. need_backend=1
  53. fi
  54. if [ "$need_frontend" -eq 0 ] && printf "%s\\n" "$changed_files" | grep -qE '^${webRel}/'; then
  55. need_frontend=1
  56. fi
  57. if [ "$need_backend" -eq 0 ] && printf "%s\\n" "$changed_files" | grep -qE '^server/'; then
  58. need_backend=1
  59. fi
  60. if [ "$need_frontend" -eq 0 ] && [ "$need_backend" -eq 0 ]; then
  61. echo "[aidop hook] no Web or server/ code changes detected, skip build checks"
  62. exit 0
  63. fi
  64. if [ "$need_frontend" -eq 1 ]; then
  65. echo "[aidop hook] verify frontend build"
  66. export NODE_OPTIONS="\${NODE_OPTIONS:+\$NODE_OPTIONS }--max-old-space-size=24576"
  67. if command -v pnpm >/dev/null 2>&1; then
  68. pnpm -C "${webRel}" build
  69. else
  70. npm --prefix "${webRel}" run build
  71. fi
  72. fi
  73. if [ "$need_backend" -eq 1 ]; then
  74. echo "[aidop hook] verify backend core build"
  75. dotnet build "${coreCsprojRel}" --framework net8.0
  76. fi
  77. ${managedEnd}
  78. `;
  79. let content = '#!/usr/bin/env sh\n';
  80. if (fs.existsSync(hookFile)) {
  81. content = fs.readFileSync(hookFile, 'utf8');
  82. if (!content.startsWith('#!/usr/bin/env sh')) content = '#!/usr/bin/env sh\n' + content;
  83. const start = content.indexOf(managedStart);
  84. const end = content.indexOf(managedEnd);
  85. if (start >= 0 && end > start) {
  86. const afterEnd = end + managedEnd.length;
  87. content = content.slice(0, start) + block + content.slice(afterEnd);
  88. } else {
  89. content = content.trimEnd() + '\n\n' + block;
  90. }
  91. } else {
  92. content += '\n' + block;
  93. }
  94. fs.writeFileSync(hookFile, content, { encoding: 'utf8' });
  95. try {
  96. fs.chmodSync(hookFile, 0o755);
  97. } catch (_) {
  98. // ignore chmod failures on Windows
  99. }
  100. console.log(`[hooks] pre-push installed at ${hookFile}`);