@webpieces/pr-gate 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +31 -0
- package/src/dashboard/dashboard.d.ts +27 -0
- package/src/dashboard/dashboard.js +155 -0
- package/src/dashboard/dashboard.js.map +1 -0
- package/src/index.d.ts +1 -0
- package/src/index.js +17 -0
- package/src/index.js.map +1 -0
- package/src/scripts/git-gatherInfo.d.ts +2 -0
- package/src/scripts/git-gatherInfo.js +98 -0
- package/src/scripts/git-gatherInfo.js.map +1 -0
- package/src/scripts/git-mergeComplete.d.ts +2 -0
- package/src/scripts/git-mergeComplete.js +77 -0
- package/src/scripts/git-mergeComplete.js.map +1 -0
- package/src/scripts/git-updateFromMain.d.ts +2 -0
- package/src/scripts/git-updateFromMain.js +157 -0
- package/src/scripts/git-updateFromMain.js.map +1 -0
- package/src/scripts/workflow/build-affected.d.ts +7 -0
- package/src/scripts/workflow/build-affected.js +22 -0
- package/src/scripts/workflow/build-affected.js.map +1 -0
- package/src/scripts/workflow/cleanTmp.d.ts +1 -0
- package/src/scripts/workflow/cleanTmp.js +57 -0
- package/src/scripts/workflow/cleanTmp.js.map +1 -0
- package/src/scripts/workflow/git-exec.d.ts +6 -0
- package/src/scripts/workflow/git-exec.js +17 -0
- package/src/scripts/workflow/git-exec.js.map +1 -0
- package/src/scripts/workflow/git-findForkPoint.d.ts +2 -0
- package/src/scripts/workflow/git-findForkPoint.js +120 -0
- package/src/scripts/workflow/git-findForkPoint.js.map +1 -0
- package/src/scripts/workflow/git-readAiBranchName.d.ts +2 -0
- package/src/scripts/workflow/git-readAiBranchName.js +20 -0
- package/src/scripts/workflow/git-readAiBranchName.js.map +1 -0
- package/src/scripts/workflow/git-validateUpToDate.d.ts +1 -0
- package/src/scripts/workflow/git-validateUpToDate.js +72 -0
- package/src/scripts/workflow/git-validateUpToDate.js.map +1 -0
- package/src/scripts/workflow/merge-state.d.ts +27 -0
- package/src/scripts/workflow/merge-state.js +88 -0
- package/src/scripts/workflow/merge-state.js.map +1 -0
- package/src/scripts/wp-build-affected.d.ts +2 -0
- package/src/scripts/wp-build-affected.js +20 -0
- package/src/scripts/wp-build-affected.js.map +1 -0
- package/src/scripts/wp-upsert-pr.d.ts +2 -0
- package/src/scripts/wp-upsert-pr.js +98 -0
- package/src/scripts/wp-upsert-pr.js.map +1 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.main = main;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const child_process_1 = require("child_process");
|
|
7
|
+
const fs = tslib_1.__importStar(require("fs"));
|
|
8
|
+
const path = tslib_1.__importStar(require("path"));
|
|
9
|
+
const git_readAiBranchName_1 = require("./workflow/git-readAiBranchName");
|
|
10
|
+
const git_gatherInfo_1 = require("./git-gatherInfo");
|
|
11
|
+
const cleanTmp_1 = require("./workflow/cleanTmp");
|
|
12
|
+
const git_exec_1 = require("./workflow/git-exec");
|
|
13
|
+
const merge_state_1 = require("./workflow/merge-state");
|
|
14
|
+
const SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n';
|
|
15
|
+
function detectPr(currentBranch) {
|
|
16
|
+
const result = (0, child_process_1.spawnSync)('gh', ['pr', 'list', '--head', currentBranch, '--json', 'number', '--jq', '.[0].number'], { encoding: 'utf8' });
|
|
17
|
+
return result.status === 0 ? (result.stdout ?? '').trim() : '';
|
|
18
|
+
}
|
|
19
|
+
function createBackup(currentBranch) {
|
|
20
|
+
process.stdout.write('\n' + SEP + '💾 Creating Incremental Backup\n' + SEP + '\n');
|
|
21
|
+
let n = 1;
|
|
22
|
+
while ((0, child_process_1.spawnSync)('git', ['show-ref', '--verify', '--quiet', `refs/heads/${currentBranch}Backup${n}`]).status === 0) {
|
|
23
|
+
n += 1;
|
|
24
|
+
}
|
|
25
|
+
const backupBranch = `${currentBranch}Backup${n}`;
|
|
26
|
+
(0, git_exec_1.runGitChecked)(['checkout', '-b', backupBranch], 'Failed to create backup branch');
|
|
27
|
+
(0, git_exec_1.runGitChecked)(['checkout', currentBranch], 'Failed to return to feature branch');
|
|
28
|
+
process.stdout.write(`✅ Backup created: ${backupBranch}\n\n`);
|
|
29
|
+
return backupBranch;
|
|
30
|
+
}
|
|
31
|
+
function saveConflictContext(conflictedFiles, mergeDir, forkPoint, featureHead, mainHead) {
|
|
32
|
+
for (const file of conflictedFiles) {
|
|
33
|
+
const safePath = file.replace(/\//g, '__');
|
|
34
|
+
const fileDir = path.join(mergeDir, `updatemain-${safePath}`);
|
|
35
|
+
fs.mkdirSync(fileDir, { recursive: true });
|
|
36
|
+
const fork = (0, child_process_1.spawnSync)('git', ['show', `${forkPoint}:${file}`], { encoding: 'utf8' });
|
|
37
|
+
fs.writeFileSync(path.join(fileDir, 'A-forkpoint.txt'), fork.status === 0 ? (fork.stdout ?? '') : '(file did not exist)\n');
|
|
38
|
+
const feature = (0, child_process_1.spawnSync)('git', ['show', `${featureHead}:${file}`], { encoding: 'utf8' });
|
|
39
|
+
fs.writeFileSync(path.join(fileDir, 'B-feature.txt'), feature.status === 0 ? (feature.stdout ?? '') : '(file did not exist)\n');
|
|
40
|
+
const main = (0, child_process_1.spawnSync)('git', ['show', `${mainHead}:${file}`], { encoding: 'utf8' });
|
|
41
|
+
fs.writeFileSync(path.join(fileDir, 'C-main.txt'), main.status === 0 ? (main.stdout ?? '') : '(file did not exist)\n');
|
|
42
|
+
const ba = (0, child_process_1.spawnSync)('git', ['diff', forkPoint, featureHead, '--', file], { encoding: 'utf8' });
|
|
43
|
+
fs.writeFileSync(path.join(fileDir, 'B-A.diff'), ba.stdout ?? '');
|
|
44
|
+
const ca = (0, child_process_1.spawnSync)('git', ['diff', forkPoint, mainHead, '--', file], { encoding: 'utf8' });
|
|
45
|
+
fs.writeFileSync(path.join(fileDir, 'C-A.diff'), ca.stdout ?? '');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function printConflictHandback(mergeDir, squashBranch, conflictedFiles) {
|
|
49
|
+
process.stdout.write('\n' + SEP + `⚠️ Conflicts in ${conflictedFiles.length} file(s) — handing control back to you\n` + SEP + '\n');
|
|
50
|
+
process.stdout.write(`You are on branch ${squashBranch} with conflicts in the working tree.\n`);
|
|
51
|
+
process.stdout.write(`3-point context per file in: ${mergeDir}/updatemain-<file>/\n`);
|
|
52
|
+
process.stdout.write(' A-forkpoint.txt (base) · B-feature.txt (yours) · C-main.txt (main) · B-A.diff · C-A.diff\n\n');
|
|
53
|
+
process.stdout.write('RESOLVE NOW (in the working tree):\n');
|
|
54
|
+
process.stdout.write(' 1. Edit each conflicted file, combining your changes (B−A) with main\'s (C−A).\n');
|
|
55
|
+
process.stdout.write(' 2. Do NOT git commit / git push / gh pr — these are blocked until validated.\n');
|
|
56
|
+
process.stdout.write(' 3. When every file is resolved, run: pnpm wp-git-merge-complete\n');
|
|
57
|
+
process.stdout.write(' (runs the conflict-marker scan + build; commits only if green)\n');
|
|
58
|
+
process.stdout.write(' 4. Then re-run pnpm wp-upsert-pr (or pnpm wp-git-update) to finalize & push.\n\n');
|
|
59
|
+
process.stdout.write('Conflicted files:\n');
|
|
60
|
+
for (const file of conflictedFiles)
|
|
61
|
+
process.stdout.write(` - ${file}\n`);
|
|
62
|
+
process.stdout.write('\n' + SEP);
|
|
63
|
+
}
|
|
64
|
+
function handleConflictsHandback(mergeDir, currentBranch, squashBranch, backupBranch, prNumber, hashes) {
|
|
65
|
+
const raw = (0, child_process_1.execSync)('git diff --name-only --diff-filter=U', { encoding: 'utf8' }).trim();
|
|
66
|
+
const conflictedFiles = raw.split('\n').filter((f) => f.trim() !== '');
|
|
67
|
+
fs.writeFileSync(path.join(mergeDir, 'updatemain-conflicted-files.txt'), raw + '\n');
|
|
68
|
+
saveConflictContext(conflictedFiles, mergeDir, hashes.hashForkPoint, hashes.hashFeatureHead, hashes.hashMainHead);
|
|
69
|
+
const marker = new merge_state_1.MergeMarker(currentBranch, squashBranch, backupBranch, prNumber, conflictedFiles, hashes.hashForkPoint, hashes.hashFeatureHead, hashes.hashMainHead, false);
|
|
70
|
+
(0, merge_state_1.writeMergeMarker)(mergeDir, marker);
|
|
71
|
+
printConflictHandback(mergeDir, squashBranch, conflictedFiles);
|
|
72
|
+
process.exit(2);
|
|
73
|
+
}
|
|
74
|
+
function finalizeBranch(currentBranch, squashBranch, backupBranch, prNumber) {
|
|
75
|
+
process.stdout.write('\n' + SEP + '🗑️ Finalizing\n' + SEP + '\n');
|
|
76
|
+
(0, git_exec_1.runGitChecked)(['branch', '-D', currentBranch], 'Failed to delete old feature branch');
|
|
77
|
+
const remoteExists = (0, child_process_1.spawnSync)('git', ['ls-remote', '--exit-code', '--heads', 'origin', currentBranch]).status === 0;
|
|
78
|
+
if (remoteExists) {
|
|
79
|
+
process.stdout.write(prNumber ? `Updating PR #${prNumber} (force-with-lease)...\n` : 'Updating remote branch (force-with-lease)...\n');
|
|
80
|
+
(0, git_exec_1.runGitChecked)(['push', '-u', '--force-with-lease', 'origin', `${squashBranch}:${currentBranch}`], 'Failed to push to origin');
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
process.stdout.write('No remote branch — local only.\n');
|
|
84
|
+
}
|
|
85
|
+
(0, git_exec_1.runGitChecked)(['checkout', squashBranch], 'Failed to checkout squash branch');
|
|
86
|
+
(0, git_exec_1.runGitChecked)(['branch', '-m', currentBranch], 'Failed to rename squash branch');
|
|
87
|
+
process.stdout.write(`\n✅ Branch ${currentBranch} updated from main. Backup: ${backupBranch}\n`);
|
|
88
|
+
process.stdout.write(` Delete backup when safe: git branch -D ${backupBranch}\n\n`);
|
|
89
|
+
}
|
|
90
|
+
async function handleResume(mergeDir, marker) {
|
|
91
|
+
if (!marker.validated) {
|
|
92
|
+
process.stdout.write('\n' + SEP + '⏸️ Merge in progress — not yet validated\n' + SEP + '\n');
|
|
93
|
+
process.stdout.write('Resolve the remaining conflicts in the working tree, then run:\n');
|
|
94
|
+
process.stdout.write(' pnpm wp-git-merge-complete\n\n');
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
process.stdout.write('Resuming: merge validated — finalizing.\n');
|
|
98
|
+
finalizeBranch(marker.currentBranch, marker.squashBranch, marker.backupBranch, marker.prNumber);
|
|
99
|
+
(0, merge_state_1.clearMergeMarker)(mergeDir);
|
|
100
|
+
await (0, cleanTmp_1.main)();
|
|
101
|
+
}
|
|
102
|
+
async function runFreshUpdate(mergeDir) {
|
|
103
|
+
const currentBranch = (0, child_process_1.execSync)('git branch --show-current', { encoding: 'utf8' }).trim();
|
|
104
|
+
if (currentBranch.endsWith('Squash')) {
|
|
105
|
+
process.stderr.write(`❌ On a leftover ${currentBranch} branch with no merge marker. Clean up: git branch -D ${currentBranch}\n`);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
process.stdout.write('\n' + SEP + '🔄 Squash-Merge Update from Main\n' + SEP + '\n');
|
|
109
|
+
await (0, git_gatherInfo_1.main)();
|
|
110
|
+
const hashes = JSON.parse(fs.readFileSync(path.join(mergeDir, 'updatemain-hashes.json'), 'utf8'));
|
|
111
|
+
const prNumber = detectPr(currentBranch);
|
|
112
|
+
process.stdout.write(prNumber ? `Existing PR #${prNumber} will be updated.\n` : 'No existing PR (one can be created later).\n');
|
|
113
|
+
const backupBranch = createBackup(currentBranch);
|
|
114
|
+
const squashBranch = `${currentBranch}Squash`;
|
|
115
|
+
if ((0, child_process_1.spawnSync)('git', ['show-ref', '--verify', '--quiet', `refs/heads/${squashBranch}`]).status === 0) {
|
|
116
|
+
process.stderr.write(`❌ Stale ${squashBranch} from a previous run. Delete it: git branch -D ${squashBranch}\n`);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
(0, git_exec_1.runGitChecked)(['checkout', 'main'], 'Failed to checkout main');
|
|
120
|
+
(0, git_exec_1.runGitChecked)(['pull', 'origin', 'main'], 'Failed to pull origin/main');
|
|
121
|
+
(0, git_exec_1.runGitChecked)(['checkout', '-b', squashBranch], 'Failed to create squash branch');
|
|
122
|
+
process.stdout.write('\n' + SEP + `🔀 Squash merging ${currentBranch}\n` + SEP + '\n');
|
|
123
|
+
const merge = (0, child_process_1.spawnSync)('git', ['merge', '--squash', currentBranch], { stdio: 'inherit' });
|
|
124
|
+
if (merge.status !== 0) {
|
|
125
|
+
handleConflictsHandback(mergeDir, currentBranch, squashBranch, backupBranch, prNumber, hashes);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const nothingStaged = (0, child_process_1.spawnSync)('git', ['diff-index', '--quiet', '--cached', 'HEAD', '--']).status === 0;
|
|
129
|
+
if (nothingStaged) {
|
|
130
|
+
process.stdout.write('ℹ️ Already up-to-date with main (nothing to merge).\n');
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
(0, git_exec_1.runGitChecked)(['commit', '-m', `Squash merge of ${currentBranch}`], 'Failed to commit squash merge');
|
|
134
|
+
}
|
|
135
|
+
finalizeBranch(currentBranch, squashBranch, backupBranch, prNumber);
|
|
136
|
+
await (0, cleanTmp_1.main)();
|
|
137
|
+
}
|
|
138
|
+
async function main() {
|
|
139
|
+
const repoRoot = (0, child_process_1.execSync)('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
|
|
140
|
+
const featureName = (0, git_readAiBranchName_1.getFeatureName)();
|
|
141
|
+
const mergeDir = (0, merge_state_1.mergeDirFor)(repoRoot, featureName);
|
|
142
|
+
fs.mkdirSync(mergeDir, { recursive: true });
|
|
143
|
+
const existing = (0, merge_state_1.readMergeMarker)(mergeDir);
|
|
144
|
+
if (existing) {
|
|
145
|
+
await handleResume(mergeDir, existing);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
await runFreshUpdate(mergeDir);
|
|
149
|
+
}
|
|
150
|
+
if (require.main === module) {
|
|
151
|
+
main().catch((err) => {
|
|
152
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
153
|
+
process.stderr.write(message + '\n');
|
|
154
|
+
process.exit(1);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=git-updateFromMain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-updateFromMain.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/scripts/git-updateFromMain.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\nimport { execSync, spawnSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { getFeatureName } from './workflow/git-readAiBranchName';\nimport { main as gatherInfo } from './git-gatherInfo';\nimport { main as cleanTmp } from './workflow/cleanTmp';\nimport { runGitChecked } from './workflow/git-exec';\nimport {\n MergeMarker,\n mergeDirFor,\n readMergeMarker,\n writeMergeMarker,\n clearMergeMarker,\n} from './workflow/merge-state';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\ninterface HashPoints {\n hashForkPoint: string;\n hashFeatureHead: string;\n hashMainHead: string;\n}\n\nfunction detectPr(currentBranch: string): string {\n const result = spawnSync(\n 'gh', ['pr', 'list', '--head', currentBranch, '--json', 'number', '--jq', '.[0].number'],\n { encoding: 'utf8' },\n );\n return result.status === 0 ? (result.stdout ?? '').trim() : '';\n}\n\nfunction createBackup(currentBranch: string): string {\n process.stdout.write('\\n' + SEP + '💾 Creating Incremental Backup\\n' + SEP + '\\n');\n let n = 1;\n while (spawnSync('git', ['show-ref', '--verify', '--quiet', `refs/heads/${currentBranch}Backup${n}`]).status === 0) {\n n += 1;\n }\n const backupBranch = `${currentBranch}Backup${n}`;\n runGitChecked(['checkout', '-b', backupBranch], 'Failed to create backup branch');\n runGitChecked(['checkout', currentBranch], 'Failed to return to feature branch');\n process.stdout.write(`✅ Backup created: ${backupBranch}\\n\\n`);\n return backupBranch;\n}\n\nfunction saveConflictContext(\n conflictedFiles: string[], mergeDir: string, forkPoint: string, featureHead: string, mainHead: string,\n): void {\n for (const file of conflictedFiles) {\n const safePath = file.replace(/\\//g, '__');\n const fileDir = path.join(mergeDir, `updatemain-${safePath}`);\n fs.mkdirSync(fileDir, { recursive: true });\n\n const fork = spawnSync('git', ['show', `${forkPoint}:${file}`], { encoding: 'utf8' });\n fs.writeFileSync(path.join(fileDir, 'A-forkpoint.txt'), fork.status === 0 ? (fork.stdout ?? '') : '(file did not exist)\\n');\n const feature = spawnSync('git', ['show', `${featureHead}:${file}`], { encoding: 'utf8' });\n fs.writeFileSync(path.join(fileDir, 'B-feature.txt'), feature.status === 0 ? (feature.stdout ?? '') : '(file did not exist)\\n');\n const main = spawnSync('git', ['show', `${mainHead}:${file}`], { encoding: 'utf8' });\n fs.writeFileSync(path.join(fileDir, 'C-main.txt'), main.status === 0 ? (main.stdout ?? '') : '(file did not exist)\\n');\n\n const ba = spawnSync('git', ['diff', forkPoint, featureHead, '--', file], { encoding: 'utf8' });\n fs.writeFileSync(path.join(fileDir, 'B-A.diff'), ba.stdout ?? '');\n const ca = spawnSync('git', ['diff', forkPoint, mainHead, '--', file], { encoding: 'utf8' });\n fs.writeFileSync(path.join(fileDir, 'C-A.diff'), ca.stdout ?? '');\n }\n}\n\nfunction printConflictHandback(mergeDir: string, squashBranch: string, conflictedFiles: string[]): void {\n process.stdout.write('\\n' + SEP + `⚠️ Conflicts in ${conflictedFiles.length} file(s) — handing control back to you\\n` + SEP + '\\n');\n process.stdout.write(`You are on branch ${squashBranch} with conflicts in the working tree.\\n`);\n process.stdout.write(`3-point context per file in: ${mergeDir}/updatemain-<file>/\\n`);\n process.stdout.write(' A-forkpoint.txt (base) · B-feature.txt (yours) · C-main.txt (main) · B-A.diff · C-A.diff\\n\\n');\n process.stdout.write('RESOLVE NOW (in the working tree):\\n');\n process.stdout.write(' 1. Edit each conflicted file, combining your changes (B−A) with main\\'s (C−A).\\n');\n process.stdout.write(' 2. Do NOT git commit / git push / gh pr — these are blocked until validated.\\n');\n process.stdout.write(' 3. When every file is resolved, run: pnpm wp-git-merge-complete\\n');\n process.stdout.write(' (runs the conflict-marker scan + build; commits only if green)\\n');\n process.stdout.write(' 4. Then re-run pnpm wp-upsert-pr (or pnpm wp-git-update) to finalize & push.\\n\\n');\n process.stdout.write('Conflicted files:\\n');\n for (const file of conflictedFiles) process.stdout.write(` - ${file}\\n`);\n process.stdout.write('\\n' + SEP);\n}\n\nfunction handleConflictsHandback(\n mergeDir: string, currentBranch: string, squashBranch: string,\n backupBranch: string, prNumber: string, hashes: HashPoints,\n): void {\n const raw = execSync('git diff --name-only --diff-filter=U', { encoding: 'utf8' }).trim();\n const conflictedFiles = raw.split('\\n').filter((f: string): boolean => f.trim() !== '');\n fs.writeFileSync(path.join(mergeDir, 'updatemain-conflicted-files.txt'), raw + '\\n');\n saveConflictContext(conflictedFiles, mergeDir, hashes.hashForkPoint, hashes.hashFeatureHead, hashes.hashMainHead);\n\n const marker = new MergeMarker(\n currentBranch, squashBranch, backupBranch, prNumber, conflictedFiles,\n hashes.hashForkPoint, hashes.hashFeatureHead, hashes.hashMainHead, false,\n );\n writeMergeMarker(mergeDir, marker);\n printConflictHandback(mergeDir, squashBranch, conflictedFiles);\n process.exit(2);\n}\n\nfunction finalizeBranch(\n currentBranch: string, squashBranch: string, backupBranch: string, prNumber: string,\n): void {\n process.stdout.write('\\n' + SEP + '🗑️ Finalizing\\n' + SEP + '\\n');\n runGitChecked(['branch', '-D', currentBranch], 'Failed to delete old feature branch');\n\n const remoteExists = spawnSync('git', ['ls-remote', '--exit-code', '--heads', 'origin', currentBranch]).status === 0;\n if (remoteExists) {\n process.stdout.write(prNumber ? `Updating PR #${prNumber} (force-with-lease)...\\n` : 'Updating remote branch (force-with-lease)...\\n');\n runGitChecked(['push', '-u', '--force-with-lease', 'origin', `${squashBranch}:${currentBranch}`], 'Failed to push to origin');\n } else {\n process.stdout.write('No remote branch — local only.\\n');\n }\n runGitChecked(['checkout', squashBranch], 'Failed to checkout squash branch');\n runGitChecked(['branch', '-m', currentBranch], 'Failed to rename squash branch');\n\n process.stdout.write(`\\n✅ Branch ${currentBranch} updated from main. Backup: ${backupBranch}\\n`);\n process.stdout.write(` Delete backup when safe: git branch -D ${backupBranch}\\n\\n`);\n}\n\nasync function handleResume(mergeDir: string, marker: MergeMarker): Promise<void> {\n if (!marker.validated) {\n process.stdout.write('\\n' + SEP + '⏸️ Merge in progress — not yet validated\\n' + SEP + '\\n');\n process.stdout.write('Resolve the remaining conflicts in the working tree, then run:\\n');\n process.stdout.write(' pnpm wp-git-merge-complete\\n\\n');\n process.exit(1);\n }\n process.stdout.write('Resuming: merge validated — finalizing.\\n');\n finalizeBranch(marker.currentBranch, marker.squashBranch, marker.backupBranch, marker.prNumber);\n clearMergeMarker(mergeDir);\n await cleanTmp();\n}\n\nasync function runFreshUpdate(mergeDir: string): Promise<void> {\n const currentBranch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();\n if (currentBranch.endsWith('Squash')) {\n process.stderr.write(`❌ On a leftover ${currentBranch} branch with no merge marker. Clean up: git branch -D ${currentBranch}\\n`);\n process.exit(1);\n }\n\n process.stdout.write('\\n' + SEP + '🔄 Squash-Merge Update from Main\\n' + SEP + '\\n');\n await gatherInfo();\n const hashes = JSON.parse(fs.readFileSync(path.join(mergeDir, 'updatemain-hashes.json'), 'utf8')) as HashPoints;\n\n const prNumber = detectPr(currentBranch);\n process.stdout.write(prNumber ? `Existing PR #${prNumber} will be updated.\\n` : 'No existing PR (one can be created later).\\n');\n\n const backupBranch = createBackup(currentBranch);\n const squashBranch = `${currentBranch}Squash`;\n if (spawnSync('git', ['show-ref', '--verify', '--quiet', `refs/heads/${squashBranch}`]).status === 0) {\n process.stderr.write(`❌ Stale ${squashBranch} from a previous run. Delete it: git branch -D ${squashBranch}\\n`);\n process.exit(1);\n }\n\n runGitChecked(['checkout', 'main'], 'Failed to checkout main');\n runGitChecked(['pull', 'origin', 'main'], 'Failed to pull origin/main');\n runGitChecked(['checkout', '-b', squashBranch], 'Failed to create squash branch');\n\n process.stdout.write('\\n' + SEP + `🔀 Squash merging ${currentBranch}\\n` + SEP + '\\n');\n const merge = spawnSync('git', ['merge', '--squash', currentBranch], { stdio: 'inherit' });\n if (merge.status !== 0) {\n handleConflictsHandback(mergeDir, currentBranch, squashBranch, backupBranch, prNumber, hashes);\n return;\n }\n\n const nothingStaged = spawnSync('git', ['diff-index', '--quiet', '--cached', 'HEAD', '--']).status === 0;\n if (nothingStaged) {\n process.stdout.write('ℹ️ Already up-to-date with main (nothing to merge).\\n');\n } else {\n runGitChecked(['commit', '-m', `Squash merge of ${currentBranch}`], 'Failed to commit squash merge');\n }\n finalizeBranch(currentBranch, squashBranch, backupBranch, prNumber);\n await cleanTmp();\n}\n\nexport async function main(): Promise<void> {\n const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();\n const featureName = getFeatureName();\n const mergeDir = mergeDirFor(repoRoot, featureName);\n fs.mkdirSync(mergeDir, { recursive: true });\n\n const existing = readMergeMarker(mergeDir);\n if (existing) {\n await handleResume(mergeDir, existing);\n return;\n }\n await runFreshUpdate(mergeDir);\n}\n\nif (require.main === module) {\n main().catch((err: Error) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(message + '\\n');\n process.exit(1);\n });\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const DEFAULT_BUILD_COMMAND = "pnpm nx affected --target=ci --base=origin/main";
|
|
2
|
+
/**
|
|
3
|
+
* Run the build gate. Returns the process exit code (0 = pass). `buildCommand` overrides
|
|
4
|
+
* the default (sourced from PrGateConfig.buildCommand by callers); empty/undefined uses the
|
|
5
|
+
* default affected-ci command.
|
|
6
|
+
*/
|
|
7
|
+
export declare function runBuildAffected(repoRoot: string, buildCommand?: string): number;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_BUILD_COMMAND = void 0;
|
|
4
|
+
exports.runBuildAffected = runBuildAffected;
|
|
5
|
+
const child_process_1 = require("child_process");
|
|
6
|
+
// Single source of truth for the build gate. Both `wp-build-affected` (CI + local) and the
|
|
7
|
+
// merge validation gate (`wp-git-merge-complete`) run THIS, so "what CI runs" and "what the
|
|
8
|
+
// PR command runs" can never drift. nx `affected` only rebuilds changed projects, so this
|
|
9
|
+
// stays fast on a large monorepo.
|
|
10
|
+
exports.DEFAULT_BUILD_COMMAND = 'pnpm nx affected --target=ci --base=origin/main';
|
|
11
|
+
/**
|
|
12
|
+
* Run the build gate. Returns the process exit code (0 = pass). `buildCommand` overrides
|
|
13
|
+
* the default (sourced from PrGateConfig.buildCommand by callers); empty/undefined uses the
|
|
14
|
+
* default affected-ci command.
|
|
15
|
+
*/
|
|
16
|
+
function runBuildAffected(repoRoot, buildCommand) {
|
|
17
|
+
const cmd = buildCommand !== undefined && buildCommand.trim() !== '' ? buildCommand : exports.DEFAULT_BUILD_COMMAND;
|
|
18
|
+
process.stdout.write(`\n▶ Build gate: ${cmd}\n\n`);
|
|
19
|
+
const result = (0, child_process_1.spawnSync)(cmd, { stdio: 'inherit', cwd: repoRoot, shell: true });
|
|
20
|
+
return result.status ?? 1;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=build-affected.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-affected.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/workflow/build-affected.ts"],"names":[],"mappings":";;;AAaA,4CAKC;AAlBD,iDAA0C;AAE1C,2FAA2F;AAC3F,4FAA4F;AAC5F,0FAA0F;AAC1F,kCAAkC;AACrB,QAAA,qBAAqB,GAAG,iDAAiD,CAAC;AAEvF;;;;GAIG;AACH,SAAgB,gBAAgB,CAAC,QAAgB,EAAE,YAAqB;IACpE,MAAM,GAAG,GAAG,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,6BAAqB,CAAC;IAC5G,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,GAAG,MAAM,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,IAAA,yBAAS,EAAC,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAChF,OAAO,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;AAC9B,CAAC","sourcesContent":["import { spawnSync } from 'child_process';\n\n// Single source of truth for the build gate. Both `wp-build-affected` (CI + local) and the\n// merge validation gate (`wp-git-merge-complete`) run THIS, so \"what CI runs\" and \"what the\n// PR command runs\" can never drift. nx `affected` only rebuilds changed projects, so this\n// stays fast on a large monorepo.\nexport const DEFAULT_BUILD_COMMAND = 'pnpm nx affected --target=ci --base=origin/main';\n\n/**\n * Run the build gate. Returns the process exit code (0 = pass). `buildCommand` overrides\n * the default (sourced from PrGateConfig.buildCommand by callers); empty/undefined uses the\n * default affected-ci command.\n */\nexport function runBuildAffected(repoRoot: string, buildCommand?: string): number {\n const cmd = buildCommand !== undefined && buildCommand.trim() !== '' ? buildCommand : DEFAULT_BUILD_COMMAND;\n process.stdout.write(`\\n▶ Build gate: ${cmd}\\n\\n`);\n const result = spawnSync(cmd, { stdio: 'inherit', cwd: repoRoot, shell: true });\n return result.status ?? 1;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function main(): Promise<void>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.main = main;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const child_process_1 = require("child_process");
|
|
6
|
+
const fs = tslib_1.__importStar(require("fs"));
|
|
7
|
+
const path = tslib_1.__importStar(require("path"));
|
|
8
|
+
const CUTOFF_DAYS = 30;
|
|
9
|
+
const SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n';
|
|
10
|
+
async function main() {
|
|
11
|
+
const repoRoot = (0, child_process_1.execSync)('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
|
|
12
|
+
const tmpBase = path.join(repoRoot, 'webpiecesTmp');
|
|
13
|
+
if (!fs.existsSync(tmpBase)) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
process.stdout.write('\n');
|
|
17
|
+
process.stdout.write(SEP);
|
|
18
|
+
process.stdout.write('🧹 Cleaning Old Temporary Directories\n');
|
|
19
|
+
process.stdout.write(SEP);
|
|
20
|
+
process.stdout.write('\n');
|
|
21
|
+
process.stdout.write(`Location: ${tmpBase}\n`);
|
|
22
|
+
process.stdout.write(`Retention: ${CUTOFF_DAYS} days\n`);
|
|
23
|
+
process.stdout.write('\n');
|
|
24
|
+
const cutoffMs = CUTOFF_DAYS * 24 * 60 * 60 * 1000;
|
|
25
|
+
const now = Date.now();
|
|
26
|
+
let deletedCount = 0;
|
|
27
|
+
const entries = fs.readdirSync(tmpBase);
|
|
28
|
+
for (const entry of entries) {
|
|
29
|
+
const fullPath = path.join(tmpBase, entry);
|
|
30
|
+
const stat = fs.statSync(fullPath);
|
|
31
|
+
if (!stat.isDirectory())
|
|
32
|
+
continue;
|
|
33
|
+
if (now - stat.mtimeMs < cutoffMs)
|
|
34
|
+
continue;
|
|
35
|
+
process.stdout.write(` 🗑️ Deleting: ${entry}\n`);
|
|
36
|
+
fs.rmSync(fullPath, { recursive: true, force: true });
|
|
37
|
+
deletedCount += 1;
|
|
38
|
+
}
|
|
39
|
+
if (deletedCount === 0) {
|
|
40
|
+
process.stdout.write(` ✅ No directories older than ${CUTOFF_DAYS} days found\n`);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
process.stdout.write('\n');
|
|
44
|
+
process.stdout.write(` ✅ Deleted ${deletedCount} old director${deletedCount === 1 ? 'y' : 'ies'}\n`);
|
|
45
|
+
}
|
|
46
|
+
process.stdout.write('\n');
|
|
47
|
+
process.stdout.write(SEP);
|
|
48
|
+
process.stdout.write('\n');
|
|
49
|
+
}
|
|
50
|
+
if (require.main === module) {
|
|
51
|
+
main().catch((err) => {
|
|
52
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
53
|
+
process.stderr.write(message + '\n');
|
|
54
|
+
process.exit(1);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=cleanTmp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleanTmp.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/workflow/cleanTmp.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nconst CUTOFF_DAYS = 30;\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\nexport async function main(): Promise<void> {\n const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();\n const tmpBase = path.join(repoRoot, 'webpiecesTmp');\n\n if (!fs.existsSync(tmpBase)) {\n return;\n }\n\n process.stdout.write('\\n');\n process.stdout.write(SEP);\n process.stdout.write('🧹 Cleaning Old Temporary Directories\\n');\n process.stdout.write(SEP);\n process.stdout.write('\\n');\n process.stdout.write(`Location: ${tmpBase}\\n`);\n process.stdout.write(`Retention: ${CUTOFF_DAYS} days\\n`);\n process.stdout.write('\\n');\n\n const cutoffMs = CUTOFF_DAYS * 24 * 60 * 60 * 1000;\n const now = Date.now();\n let deletedCount = 0;\n\n const entries = fs.readdirSync(tmpBase);\n for (const entry of entries) {\n const fullPath = path.join(tmpBase, entry);\n const stat = fs.statSync(fullPath);\n if (!stat.isDirectory()) continue;\n if (now - stat.mtimeMs < cutoffMs) continue;\n\n process.stdout.write(` 🗑️ Deleting: ${entry}\\n`);\n fs.rmSync(fullPath, { recursive: true, force: true });\n deletedCount += 1;\n }\n\n if (deletedCount === 0) {\n process.stdout.write(` ✅ No directories older than ${CUTOFF_DAYS} days found\\n`);\n } else {\n process.stdout.write('\\n');\n process.stdout.write(` ✅ Deleted ${deletedCount} old director${deletedCount === 1 ? 'y' : 'ies'}\\n`);\n }\n\n process.stdout.write('\\n');\n process.stdout.write(SEP);\n process.stdout.write('\\n');\n}\n\nif (require.main === module) {\n main().catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(message + '\\n');\n process.exit(1);\n });\n}\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run a git command that is expected to succeed; abort the process with a clear message
|
|
3
|
+
* if it fails. Used for fetch/pull/checkout/commit where silently continuing on failure
|
|
4
|
+
* would operate on stale or wrong state.
|
|
5
|
+
*/
|
|
6
|
+
export declare function runGitChecked(args: string[], errMsg: string): void;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runGitChecked = runGitChecked;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
/**
|
|
6
|
+
* Run a git command that is expected to succeed; abort the process with a clear message
|
|
7
|
+
* if it fails. Used for fetch/pull/checkout/commit where silently continuing on failure
|
|
8
|
+
* would operate on stale or wrong state.
|
|
9
|
+
*/
|
|
10
|
+
function runGitChecked(args, errMsg) {
|
|
11
|
+
const result = (0, child_process_1.spawnSync)('git', args, { stdio: 'inherit' });
|
|
12
|
+
if (result.status !== 0) {
|
|
13
|
+
process.stderr.write(`❌ ${errMsg} (git ${args.join(' ')} exited ${String(result.status)})\n`);
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=git-exec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-exec.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/workflow/git-exec.ts"],"names":[],"mappings":";;AAOA,sCAMC;AAbD,iDAA0C;AAE1C;;;;GAIG;AACH,SAAgB,aAAa,CAAC,IAAc,EAAE,MAAc;IACxD,MAAM,MAAM,GAAG,IAAA,yBAAS,EAAC,KAAK,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IAC5D,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,MAAM,SAAS,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC9F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;AACL,CAAC","sourcesContent":["import { spawnSync } from 'child_process';\n\n/**\n * Run a git command that is expected to succeed; abort the process with a clear message\n * if it fails. Used for fetch/pull/checkout/commit where silently continuing on failure\n * would operate on stale or wrong state.\n */\nexport function runGitChecked(args: string[], errMsg: string): void {\n const result = spawnSync('git', args, { stdio: 'inherit' });\n if (result.status !== 0) {\n process.stderr.write(`❌ ${errMsg} (git ${args.join(' ')} exited ${String(result.status)})\\n`);\n process.exit(1);\n }\n}\n"]}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findForkPoint = findForkPoint;
|
|
4
|
+
exports.main = main;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const child_process_1 = require("child_process");
|
|
7
|
+
const fs = tslib_1.__importStar(require("fs"));
|
|
8
|
+
const path = tslib_1.__importStar(require("path"));
|
|
9
|
+
const git_readAiBranchName_1 = require("./git-readAiBranchName");
|
|
10
|
+
const SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n';
|
|
11
|
+
function printMergeFromMainError(commit, parent, featureName, currentBranch) {
|
|
12
|
+
process.stderr.write('\n');
|
|
13
|
+
process.stderr.write(SEP);
|
|
14
|
+
process.stderr.write('❌ This branch merged main without pnpm wp-git-update\n');
|
|
15
|
+
process.stderr.write(SEP);
|
|
16
|
+
process.stderr.write('\n');
|
|
17
|
+
process.stderr.write(`Merge commit detected: ${commit}\n`);
|
|
18
|
+
process.stderr.write(`Parent from main: ${parent}\n`);
|
|
19
|
+
process.stderr.write('\n');
|
|
20
|
+
process.stderr.write('This prevents clean squash-merge. To recover, follow these steps:\n');
|
|
21
|
+
process.stderr.write('\n');
|
|
22
|
+
process.stderr.write('1. Switch to main branch:\n');
|
|
23
|
+
process.stderr.write(' git checkout main\n');
|
|
24
|
+
process.stderr.write('\n');
|
|
25
|
+
process.stderr.write('2. Pull latest changes:\n');
|
|
26
|
+
process.stderr.write(' git pull\n');
|
|
27
|
+
process.stderr.write('\n');
|
|
28
|
+
process.stderr.write('3. Create new branch with a new name:\n');
|
|
29
|
+
process.stderr.write(` git checkout -b ${featureName}-v2\n`);
|
|
30
|
+
process.stderr.write('\n');
|
|
31
|
+
process.stderr.write('4. Squash merge your old branch:\n');
|
|
32
|
+
process.stderr.write(` git merge --squash ${currentBranch}\n`);
|
|
33
|
+
process.stderr.write('\n');
|
|
34
|
+
process.stderr.write('5. Commit the squashed changes:\n');
|
|
35
|
+
process.stderr.write(` git add -A && git commit -m "Squashed from ${currentBranch}"\n`);
|
|
36
|
+
process.stderr.write('\n');
|
|
37
|
+
process.stderr.write('6. If you have an existing PR:\n');
|
|
38
|
+
process.stderr.write(` - Create a NEW PR for ${featureName}-v2\n`);
|
|
39
|
+
process.stderr.write(` - Close the old PR for ${currentBranch}\n`);
|
|
40
|
+
process.stderr.write('\n');
|
|
41
|
+
process.stderr.write(SEP);
|
|
42
|
+
process.stderr.write('\n');
|
|
43
|
+
}
|
|
44
|
+
function checkMergeCommits(mergeCommits, outputDir, prefix, featureName, currentBranch) {
|
|
45
|
+
process.stderr.write(`Found ${mergeCommits.length} merge commit(s) to check...\n`);
|
|
46
|
+
for (const commit of mergeCommits) {
|
|
47
|
+
const parentsResult = (0, child_process_1.spawnSync)('git', ['rev-list', '--parents', '-n', '1', commit], { encoding: 'utf8' });
|
|
48
|
+
const parents = (parentsResult.stdout ?? '').trim().split(' ').slice(1);
|
|
49
|
+
for (const parent of parents) {
|
|
50
|
+
const ancestorCheck = (0, child_process_1.spawnSync)('git', ['merge-base', '--is-ancestor', parent, 'origin/main']);
|
|
51
|
+
const reverseCheck = (0, child_process_1.spawnSync)('git', ['merge-base', '--is-ancestor', 'origin/main', parent]);
|
|
52
|
+
if (ancestorCheck.status === 0 && reverseCheck.status === 0) {
|
|
53
|
+
const errorJson = JSON.stringify({
|
|
54
|
+
error: 'Merge from main detected',
|
|
55
|
+
mergeCommit: commit,
|
|
56
|
+
parentFromMain: parent,
|
|
57
|
+
timestamp: new Date().toISOString(),
|
|
58
|
+
}, null, 2);
|
|
59
|
+
fs.writeFileSync(path.join(outputDir, `${prefix}forkpoint-error.json`), errorJson + '\n');
|
|
60
|
+
printMergeFromMainError(commit, parent, featureName, currentBranch);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
process.stderr.write('✅ No improper merges from main detected\n');
|
|
66
|
+
}
|
|
67
|
+
async function findForkPoint(workflow) {
|
|
68
|
+
if (workflow !== 'review' && workflow !== 'merge') {
|
|
69
|
+
process.stderr.write('ERROR: Workflow argument required\n');
|
|
70
|
+
process.stderr.write('Usage: git-findForkPoint <workflow>\n');
|
|
71
|
+
process.stderr.write(" workflow: 'review' or 'merge'\n");
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
const featureName = (0, git_readAiBranchName_1.getFeatureName)();
|
|
75
|
+
const currentBranch = (0, child_process_1.execSync)('git branch --show-current', { encoding: 'utf8' }).trim();
|
|
76
|
+
const repoRoot = (0, child_process_1.execSync)('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
|
|
77
|
+
const outputDir = path.join(repoRoot, 'webpiecesTmp', `${workflow}-${featureName}`);
|
|
78
|
+
const prefix = workflow === 'review' ? 'review-' : 'updatemain-';
|
|
79
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
80
|
+
(0, child_process_1.spawnSync)('git', ['fetch', 'origin', 'main'], { stdio: 'ignore' });
|
|
81
|
+
const featureHead = (0, child_process_1.execSync)('git rev-parse HEAD', { encoding: 'utf8' }).trim();
|
|
82
|
+
const originMain = (0, child_process_1.execSync)('git rev-parse origin/main', { encoding: 'utf8' }).trim();
|
|
83
|
+
process.stderr.write('Finding fork point using git merge-base...\n');
|
|
84
|
+
const forkPointResult = (0, child_process_1.spawnSync)('git', ['merge-base', 'origin/main', 'HEAD'], { encoding: 'utf8' });
|
|
85
|
+
const forkPoint = (forkPointResult.stdout ?? '').trim();
|
|
86
|
+
if (!forkPoint || forkPointResult.status !== 0) {
|
|
87
|
+
process.stderr.write('ERROR: Could not find common ancestor with origin/main\n');
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
process.stderr.write(`✅ Fork point found: ${forkPoint.slice(0, 7)}\n`);
|
|
91
|
+
process.stderr.write('Checking for improper merges from main...\n');
|
|
92
|
+
const mergeCommitsResult = (0, child_process_1.spawnSync)('git', ['log', `${forkPoint}..HEAD`, '--merges', '--format=%H'], { encoding: 'utf8' });
|
|
93
|
+
const mergeCommitsRaw = (mergeCommitsResult.stdout ?? '').trim();
|
|
94
|
+
const mergeCommits = mergeCommitsRaw ? mergeCommitsRaw.split('\n') : [];
|
|
95
|
+
if (mergeCommits.length > 0) {
|
|
96
|
+
checkMergeCommits(mergeCommits, outputDir, prefix, featureName, currentBranch);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
process.stderr.write('✅ No merge commits found (clean history)\n');
|
|
100
|
+
}
|
|
101
|
+
const hashesJson = JSON.stringify({
|
|
102
|
+
hashForkPoint: forkPoint,
|
|
103
|
+
hashFeatureHead: featureHead,
|
|
104
|
+
hashMainHead: originMain,
|
|
105
|
+
timestamp: new Date().toISOString(),
|
|
106
|
+
}, null, 2);
|
|
107
|
+
fs.writeFileSync(path.join(outputDir, `${prefix}hashes.json`), hashesJson + '\n');
|
|
108
|
+
process.stderr.write(`✅ Hash points written to: ${outputDir}/${prefix}hashes.json\n`);
|
|
109
|
+
}
|
|
110
|
+
async function main() {
|
|
111
|
+
await findForkPoint(process.argv[2] ?? '');
|
|
112
|
+
}
|
|
113
|
+
if (require.main === module) {
|
|
114
|
+
main().catch((err) => {
|
|
115
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
116
|
+
process.stderr.write(message + '\n');
|
|
117
|
+
process.exit(1);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=git-findForkPoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-findForkPoint.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/workflow/git-findForkPoint.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync, spawnSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { getFeatureName } from './git-readAiBranchName';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\nfunction printMergeFromMainError(commit: string, parent: string, featureName: string, currentBranch: string): void {\n process.stderr.write('\\n');\n process.stderr.write(SEP);\n process.stderr.write('❌ This branch merged main without pnpm wp-git-update\\n');\n process.stderr.write(SEP);\n process.stderr.write('\\n');\n process.stderr.write(`Merge commit detected: ${commit}\\n`);\n process.stderr.write(`Parent from main: ${parent}\\n`);\n process.stderr.write('\\n');\n process.stderr.write('This prevents clean squash-merge. To recover, follow these steps:\\n');\n process.stderr.write('\\n');\n process.stderr.write('1. Switch to main branch:\\n');\n process.stderr.write(' git checkout main\\n');\n process.stderr.write('\\n');\n process.stderr.write('2. Pull latest changes:\\n');\n process.stderr.write(' git pull\\n');\n process.stderr.write('\\n');\n process.stderr.write('3. Create new branch with a new name:\\n');\n process.stderr.write(` git checkout -b ${featureName}-v2\\n`);\n process.stderr.write('\\n');\n process.stderr.write('4. Squash merge your old branch:\\n');\n process.stderr.write(` git merge --squash ${currentBranch}\\n`);\n process.stderr.write('\\n');\n process.stderr.write('5. Commit the squashed changes:\\n');\n process.stderr.write(` git add -A && git commit -m \"Squashed from ${currentBranch}\"\\n`);\n process.stderr.write('\\n');\n process.stderr.write('6. If you have an existing PR:\\n');\n process.stderr.write(` - Create a NEW PR for ${featureName}-v2\\n`);\n process.stderr.write(` - Close the old PR for ${currentBranch}\\n`);\n process.stderr.write('\\n');\n process.stderr.write(SEP);\n process.stderr.write('\\n');\n}\n\nfunction checkMergeCommits(mergeCommits: string[], outputDir: string, prefix: string, featureName: string, currentBranch: string): void {\n process.stderr.write(`Found ${mergeCommits.length} merge commit(s) to check...\\n`);\n\n for (const commit of mergeCommits) {\n const parentsResult = spawnSync('git', ['rev-list', '--parents', '-n', '1', commit], { encoding: 'utf8' });\n const parents = (parentsResult.stdout ?? '').trim().split(' ').slice(1);\n\n for (const parent of parents) {\n const ancestorCheck = spawnSync('git', ['merge-base', '--is-ancestor', parent, 'origin/main']);\n const reverseCheck = spawnSync('git', ['merge-base', '--is-ancestor', 'origin/main', parent]);\n\n if (ancestorCheck.status === 0 && reverseCheck.status === 0) {\n const errorJson = JSON.stringify({\n error: 'Merge from main detected',\n mergeCommit: commit,\n parentFromMain: parent,\n timestamp: new Date().toISOString(),\n }, null, 2);\n\n fs.writeFileSync(path.join(outputDir, `${prefix}forkpoint-error.json`), errorJson + '\\n');\n printMergeFromMainError(commit, parent, featureName, currentBranch);\n process.exit(1);\n }\n }\n }\n process.stderr.write('✅ No improper merges from main detected\\n');\n}\n\nexport async function findForkPoint(workflow: string): Promise<void> {\n if (workflow !== 'review' && workflow !== 'merge') {\n process.stderr.write('ERROR: Workflow argument required\\n');\n process.stderr.write('Usage: git-findForkPoint <workflow>\\n');\n process.stderr.write(\" workflow: 'review' or 'merge'\\n\");\n process.exit(1);\n }\n\n const featureName = getFeatureName();\n const currentBranch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();\n const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();\n\n const outputDir = path.join(repoRoot, 'webpiecesTmp', `${workflow}-${featureName}`);\n const prefix = workflow === 'review' ? 'review-' : 'updatemain-';\n fs.mkdirSync(outputDir, { recursive: true });\n\n spawnSync('git', ['fetch', 'origin', 'main'], { stdio: 'ignore' });\n\n const featureHead = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim();\n const originMain = execSync('git rev-parse origin/main', { encoding: 'utf8' }).trim();\n\n process.stderr.write('Finding fork point using git merge-base...\\n');\n\n const forkPointResult = spawnSync('git', ['merge-base', 'origin/main', 'HEAD'], { encoding: 'utf8' });\n const forkPoint = (forkPointResult.stdout ?? '').trim();\n\n if (!forkPoint || forkPointResult.status !== 0) {\n process.stderr.write('ERROR: Could not find common ancestor with origin/main\\n');\n process.exit(1);\n }\n\n process.stderr.write(`✅ Fork point found: ${forkPoint.slice(0, 7)}\\n`);\n process.stderr.write('Checking for improper merges from main...\\n');\n\n const mergeCommitsResult = spawnSync('git', ['log', `${forkPoint}..HEAD`, '--merges', '--format=%H'], { encoding: 'utf8' });\n const mergeCommitsRaw = (mergeCommitsResult.stdout ?? '').trim();\n const mergeCommits = mergeCommitsRaw ? mergeCommitsRaw.split('\\n') : [];\n\n if (mergeCommits.length > 0) {\n checkMergeCommits(mergeCommits, outputDir, prefix, featureName, currentBranch);\n } else {\n process.stderr.write('✅ No merge commits found (clean history)\\n');\n }\n\n const hashesJson = JSON.stringify({\n hashForkPoint: forkPoint,\n hashFeatureHead: featureHead,\n hashMainHead: originMain,\n timestamp: new Date().toISOString(),\n }, null, 2);\n\n fs.writeFileSync(path.join(outputDir, `${prefix}hashes.json`), hashesJson + '\\n');\n process.stderr.write(`✅ Hash points written to: ${outputDir}/${prefix}hashes.json\\n`);\n}\n\nexport async function main(): Promise<void> {\n await findForkPoint(process.argv[2] ?? '');\n}\n\nif (require.main === module) {\n main().catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(message + '\\n');\n process.exit(1);\n });\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getFeatureName = getFeatureName;
|
|
4
|
+
exports.main = main;
|
|
5
|
+
const child_process_1 = require("child_process");
|
|
6
|
+
function getFeatureName() {
|
|
7
|
+
const branch = (0, child_process_1.execSync)('git branch --show-current', { encoding: 'utf8' }).trim();
|
|
8
|
+
return branch.replace(/\//g, '-').replace(/Squash$/, '');
|
|
9
|
+
}
|
|
10
|
+
async function main() {
|
|
11
|
+
process.stdout.write(getFeatureName() + '\n');
|
|
12
|
+
}
|
|
13
|
+
if (require.main === module) {
|
|
14
|
+
main().catch((err) => {
|
|
15
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
16
|
+
process.stderr.write(message + '\n');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=git-readAiBranchName.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-readAiBranchName.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/workflow/git-readAiBranchName.ts"],"names":[],"mappings":";;AAEA,wCAGC;AAED,oBAEC;AATD,iDAAyC;AAEzC,SAAgB,cAAc;IAC1B,MAAM,MAAM,GAAG,IAAA,wBAAQ,EAAC,2BAA2B,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAClF,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;AAC7D,CAAC;AAEM,KAAK,UAAU,IAAI;IACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,IAAI,CAAC,CAAC;AAClD,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC1B,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACjB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;AACP,CAAC","sourcesContent":["import { execSync } from 'child_process';\n\nexport function getFeatureName(): string {\n const branch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();\n return branch.replace(/\\//g, '-').replace(/Squash$/, '');\n}\n\nexport async function main(): Promise<void> {\n process.stdout.write(getFeatureName() + '\\n');\n}\n\nif (require.main === module) {\n main().catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(message + '\\n');\n process.exit(1);\n });\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function main(): Promise<void>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.main = main;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n';
|
|
6
|
+
async function main() {
|
|
7
|
+
const branch = (0, child_process_1.execSync)('git branch --show-current', { encoding: 'utf8' }).trim();
|
|
8
|
+
if (branch === 'main') {
|
|
9
|
+
process.stdout.write('✅ On main branch - no validation needed\n');
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
process.stdout.write('Validating branch is up to date with origin/main...\n');
|
|
13
|
+
process.stdout.write(`Current branch: ${branch}\n`);
|
|
14
|
+
process.stdout.write('\n');
|
|
15
|
+
process.stdout.write('Fetching latest from origin/main...\n');
|
|
16
|
+
(0, child_process_1.spawnSync)('git', ['fetch', 'origin', 'main', '--quiet'], { stdio: 'inherit' });
|
|
17
|
+
const isUpToDate = (0, child_process_1.spawnSync)('git', ['merge-base', '--is-ancestor', 'origin/main', 'HEAD']).status === 0;
|
|
18
|
+
if (isUpToDate) {
|
|
19
|
+
process.stdout.write('✅ Branch is up to date with origin/main\n');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const behindResult = (0, child_process_1.spawnSync)('git', ['rev-list', '--count', 'HEAD..origin/main'], { encoding: 'utf8' });
|
|
23
|
+
const commitsBehind = (behindResult.stdout ?? '').trim();
|
|
24
|
+
const recentResult = (0, child_process_1.spawnSync)('git', ['log', '--oneline', 'HEAD..origin/main'], { encoding: 'utf8' });
|
|
25
|
+
const recentLines = (recentResult.stdout ?? '').split('\n').filter((l) => l).slice(0, 5).join('\n');
|
|
26
|
+
process.stdout.write('\n');
|
|
27
|
+
process.stdout.write(SEP);
|
|
28
|
+
process.stdout.write('❌ ERROR: Branch is NOT up to date with origin/main\n');
|
|
29
|
+
process.stdout.write(SEP);
|
|
30
|
+
process.stdout.write('\n');
|
|
31
|
+
process.stdout.write(`Your branch is ${commitsBehind} commit(s) behind origin/main\n`);
|
|
32
|
+
process.stdout.write('\n');
|
|
33
|
+
process.stdout.write('Recent commits in origin/main not in your branch:\n');
|
|
34
|
+
process.stdout.write(recentLines + '\n');
|
|
35
|
+
process.stdout.write('\n');
|
|
36
|
+
process.stdout.write(SEP);
|
|
37
|
+
process.stdout.write('⚠️ CRITICAL: You must update your branch first!\n');
|
|
38
|
+
process.stdout.write(SEP);
|
|
39
|
+
process.stdout.write('\n');
|
|
40
|
+
process.stdout.write('1. Update your branch with latest main:\n');
|
|
41
|
+
process.stdout.write(' pnpm wp-git-update\n');
|
|
42
|
+
process.stdout.write('\n');
|
|
43
|
+
process.stdout.write('2. ⚠️ IMPORTANT: REVIEW THE CODE AFTER MERGE!\n');
|
|
44
|
+
process.stdout.write(' - Check for merge conflicts\n');
|
|
45
|
+
process.stdout.write(' - Review how your changes interact with new main code\n');
|
|
46
|
+
process.stdout.write(' - Test that everything still works\n');
|
|
47
|
+
process.stdout.write(' - This is where things often go wrong!\n');
|
|
48
|
+
process.stdout.write('\n');
|
|
49
|
+
process.stdout.write('3. After reviewing, run your command again\n');
|
|
50
|
+
process.stdout.write('\n');
|
|
51
|
+
process.stdout.write(SEP);
|
|
52
|
+
process.stdout.write('Why this matters:\n');
|
|
53
|
+
process.stdout.write(SEP);
|
|
54
|
+
process.stdout.write('\n');
|
|
55
|
+
process.stdout.write('- Your test plan should cover how your changes work with\n');
|
|
56
|
+
process.stdout.write(' the LATEST code from main, not outdated code\n');
|
|
57
|
+
process.stdout.write('- Merging main might introduce conflicts or integration\n');
|
|
58
|
+
process.stdout.write(' issues that need testing\n');
|
|
59
|
+
process.stdout.write('- Your changes might interact unexpectedly with new code\n');
|
|
60
|
+
process.stdout.write(' from main\n');
|
|
61
|
+
process.stdout.write('\n');
|
|
62
|
+
process.stdout.write(SEP);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
if (require.main === module) {
|
|
66
|
+
main().catch((err) => {
|
|
67
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
68
|
+
process.stderr.write(message + '\n');
|
|
69
|
+
process.exit(1);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=git-validateUpToDate.js.map
|