@webpieces/pr-gate 0.3.188 → 0.3.189

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/pr-gate",
3
- "version": "0.3.188",
3
+ "version": "0.3.189",
4
4
  "description": "Gated PR system: 3-point squash-merge, merge validation gate, and red/yellow/green PR dashboard. Standalone scripts, no Nx dependency required.",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -22,7 +22,7 @@
22
22
  "directory": "packages/tooling/pr-gate"
23
23
  },
24
24
  "dependencies": {
25
- "@webpieces/rules-config": "0.3.188"
25
+ "@webpieces/rules-config": "0.3.189"
26
26
  },
27
27
  "publishConfig": {
28
28
  "access": "public"
@@ -66,9 +66,14 @@ async function main() {
66
66
  validateResolution(repoRoot, mergeDir, marker.conflictedFiles);
67
67
  (0, git_exec_1.runGitChecked)(['add', '-A'], 'Failed to stage resolved files');
68
68
  // Build gate (authoritative). Same configured command wp-upsert-pr uses — fast on a big monorepo.
69
+ const buildCommand = (0, build_affected_1.resolveBuildCommand)(repoRoot);
70
+ process.stdout.write(`\nRunning the build gate. To get it passing, run the SAME command yourself and fix everything it reports:\n\n` +
71
+ ` ${buildCommand}\n\n`);
69
72
  const buildCode = (0, build_affected_1.runConfiguredBuildGate)(repoRoot);
70
73
  if (buildCode !== 0) {
71
- process.stderr.write('\n❌ Build failed. Fix the build, then re-run: pnpm wp-git-merge-complete\n');
74
+ process.stderr.write(`\n❌ Build failed.\n\n` +
75
+ `Run THIS exact command to reproduce and fix all errors, then re-run pnpm wp-git-merge-complete:\n\n` +
76
+ ` ${buildCommand}\n\n`);
72
77
  process.exit(buildCode);
73
78
  return;
74
79
  }
@@ -1 +1 @@
1
- {"version":3,"file":"git-mergeComplete.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/scripts/git-mergeComplete.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 { runGitChecked } from './workflow/git-exec';\nimport { runConfiguredBuildGate } from './workflow/build-affected';\nimport { MERGE_EXPLANATION_FILE } from '@webpieces/rules-config';\nimport {\n mergeDirFor,\n perFileContextDir,\n readMergeMarker,\n writeMergeMarker,\n scanConflictMarkers,\n scanMergeExplanations,\n} from './workflow/merge-state';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\n// Validate the AI's resolution of the conflicted files — the part of the process the AI owns\n// (branch creation/finalization is the script's job, so it is not re-checked here). Exits the\n// process with a fix instruction on any failure; returns only when all three checks pass.\nfunction validateResolution(repoRoot: string, mergeDir: string, conflictedFiles: string[]): void {\n // 1. Scoped conflict-marker scan (only the conflicted files — O(conflicts), not O(repo)).\n const scan = scanConflictMarkers(repoRoot, conflictedFiles);\n if (!scan.clean) {\n process.stderr.write('❌ Unresolved conflict markers (<<<<<<< / ======= / >>>>>>>) remain in:\\n');\n for (const file of scan.filesWithMarkers) process.stderr.write(` - ${file}\\n`);\n process.stderr.write('\\nResolve them, then re-run: pnpm wp-git-merge-complete\\n');\n process.exit(1);\n }\n\n // 2. Ensure git itself has no remaining unmerged entries.\n const unmerged = execSync('git diff --name-only --diff-filter=U', { encoding: 'utf8' }).trim();\n if (unmerged !== '') {\n process.stderr.write('❌ Git still reports unmerged files:\\n' + unmerged + '\\n');\n process.stderr.write('\\nResolve and `git add` them, then re-run: pnpm wp-git-merge-complete\\n');\n process.exit(1);\n }\n process.stdout.write('✅ No conflict markers in resolved files.\\n');\n\n // 3. Explanation check — every conflicted file must have a non-empty merge-explanation.md in\n // its per-file context dir, proving the AI deliberately 3-point merged it (and recording how)\n // rather than blindly taking one side. A sidecar file works for any type, incl. JSON/deletes.\n const explanations = scanMergeExplanations(mergeDir, conflictedFiles);\n if (!explanations.clean) {\n process.stderr.write(`❌ Missing/empty merge explanation (${MERGE_EXPLANATION_FILE}) for:\\n`);\n for (const file of explanations.filesWithMarkers) {\n process.stderr.write(` - ${file}\\n → ${path.join(perFileContextDir(mergeDir, file), MERGE_EXPLANATION_FILE)}\\n`);\n }\n process.stderr.write(\n '\\nWrite a few sentences on how you resolved each (which side, what you combined, why),\\n' +\n 'then re-run: pnpm wp-git-merge-complete\\n',\n );\n process.exit(1);\n }\n process.stdout.write('✅ Merge explanations present for all resolved files.\\n');\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\n const marker = readMergeMarker(mergeDir);\n if (!marker) {\n process.stderr.write('❌ No merge in progress (no marker found). Nothing to complete.\\n');\n process.exit(1);\n return;\n }\n if (marker.validated) {\n process.stdout.write('✅ Merge already validated. Run pnpm wp-git-update (or wp-upsert-pr) to finalize.\\n');\n return;\n }\n\n process.stdout.write('\\n' + SEP + '🔎 Validating Merge Resolution\\n' + SEP + '\\n');\n\n validateResolution(repoRoot, mergeDir, marker.conflictedFiles);\n runGitChecked(['add', '-A'], 'Failed to stage resolved files');\n\n // Build gate (authoritative). Same configured command wp-upsert-pr uses — fast on a big monorepo.\n const buildCode = runConfiguredBuildGate(repoRoot);\n if (buildCode !== 0) {\n process.stderr.write('\\n❌ Build failed. Fix the build, then re-run: pnpm wp-git-merge-complete\\n');\n process.exit(buildCode);\n return;\n }\n process.stdout.write('\\n✅ Build passed.\\n');\n\n // Commit the resolved squash merge.\n const nothingStaged = spawnSync('git', ['diff-index', '--quiet', '--cached', 'HEAD', '--']).status === 0;\n if (!nothingStaged) {\n runGitChecked(\n ['commit', '-m', `Squash merge of ${marker.currentBranch} (conflicts resolved)`],\n 'Failed to commit resolved merge',\n );\n }\n\n // Flip the marker to validated + drop the proof file → unblocks the guard.\n marker.validated = true;\n writeMergeMarker(mergeDir, marker);\n fs.writeFileSync(path.join(mergeDir, 'conflicts-resolved'), '');\n\n process.stdout.write('\\n' + SEP + '✅ Merge validated and committed\\n' + SEP + '\\n');\n process.stdout.write('Finalize & push by running: pnpm wp-upsert-pr (or pnpm wp-git-update)\\n\\n');\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"]}
1
+ {"version":3,"file":"git-mergeComplete.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/scripts/git-mergeComplete.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 { runGitChecked } from './workflow/git-exec';\nimport { runConfiguredBuildGate, resolveBuildCommand } from './workflow/build-affected';\nimport { MERGE_EXPLANATION_FILE } from '@webpieces/rules-config';\nimport {\n mergeDirFor,\n perFileContextDir,\n readMergeMarker,\n writeMergeMarker,\n scanConflictMarkers,\n scanMergeExplanations,\n} from './workflow/merge-state';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\n// Validate the AI's resolution of the conflicted files — the part of the process the AI owns\n// (branch creation/finalization is the script's job, so it is not re-checked here). Exits the\n// process with a fix instruction on any failure; returns only when all three checks pass.\nfunction validateResolution(repoRoot: string, mergeDir: string, conflictedFiles: string[]): void {\n // 1. Scoped conflict-marker scan (only the conflicted files — O(conflicts), not O(repo)).\n const scan = scanConflictMarkers(repoRoot, conflictedFiles);\n if (!scan.clean) {\n process.stderr.write('❌ Unresolved conflict markers (<<<<<<< / ======= / >>>>>>>) remain in:\\n');\n for (const file of scan.filesWithMarkers) process.stderr.write(` - ${file}\\n`);\n process.stderr.write('\\nResolve them, then re-run: pnpm wp-git-merge-complete\\n');\n process.exit(1);\n }\n\n // 2. Ensure git itself has no remaining unmerged entries.\n const unmerged = execSync('git diff --name-only --diff-filter=U', { encoding: 'utf8' }).trim();\n if (unmerged !== '') {\n process.stderr.write('❌ Git still reports unmerged files:\\n' + unmerged + '\\n');\n process.stderr.write('\\nResolve and `git add` them, then re-run: pnpm wp-git-merge-complete\\n');\n process.exit(1);\n }\n process.stdout.write('✅ No conflict markers in resolved files.\\n');\n\n // 3. Explanation check — every conflicted file must have a non-empty merge-explanation.md in\n // its per-file context dir, proving the AI deliberately 3-point merged it (and recording how)\n // rather than blindly taking one side. A sidecar file works for any type, incl. JSON/deletes.\n const explanations = scanMergeExplanations(mergeDir, conflictedFiles);\n if (!explanations.clean) {\n process.stderr.write(`❌ Missing/empty merge explanation (${MERGE_EXPLANATION_FILE}) for:\\n`);\n for (const file of explanations.filesWithMarkers) {\n process.stderr.write(` - ${file}\\n → ${path.join(perFileContextDir(mergeDir, file), MERGE_EXPLANATION_FILE)}\\n`);\n }\n process.stderr.write(\n '\\nWrite a few sentences on how you resolved each (which side, what you combined, why),\\n' +\n 'then re-run: pnpm wp-git-merge-complete\\n',\n );\n process.exit(1);\n }\n process.stdout.write('✅ Merge explanations present for all resolved files.\\n');\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\n const marker = readMergeMarker(mergeDir);\n if (!marker) {\n process.stderr.write('❌ No merge in progress (no marker found). Nothing to complete.\\n');\n process.exit(1);\n return;\n }\n if (marker.validated) {\n process.stdout.write('✅ Merge already validated. Run pnpm wp-git-update (or wp-upsert-pr) to finalize.\\n');\n return;\n }\n\n process.stdout.write('\\n' + SEP + '🔎 Validating Merge Resolution\\n' + SEP + '\\n');\n\n validateResolution(repoRoot, mergeDir, marker.conflictedFiles);\n runGitChecked(['add', '-A'], 'Failed to stage resolved files');\n\n // Build gate (authoritative). Same configured command wp-upsert-pr uses — fast on a big monorepo.\n const buildCommand = resolveBuildCommand(repoRoot);\n process.stdout.write(\n `\\nRunning the build gate. To get it passing, run the SAME command yourself and fix everything it reports:\\n\\n` +\n ` ${buildCommand}\\n\\n`,\n );\n const buildCode = runConfiguredBuildGate(repoRoot);\n if (buildCode !== 0) {\n process.stderr.write(\n `\\n❌ Build failed.\\n\\n` +\n `Run THIS exact command to reproduce and fix all errors, then re-run pnpm wp-git-merge-complete:\\n\\n` +\n ` ${buildCommand}\\n\\n`,\n );\n process.exit(buildCode);\n return;\n }\n process.stdout.write('\\n✅ Build passed.\\n');\n\n // Commit the resolved squash merge.\n const nothingStaged = spawnSync('git', ['diff-index', '--quiet', '--cached', 'HEAD', '--']).status === 0;\n if (!nothingStaged) {\n runGitChecked(\n ['commit', '-m', `Squash merge of ${marker.currentBranch} (conflicts resolved)`],\n 'Failed to commit resolved merge',\n );\n }\n\n // Flip the marker to validated + drop the proof file → unblocks the guard.\n marker.validated = true;\n writeMergeMarker(mergeDir, marker);\n fs.writeFileSync(path.join(mergeDir, 'conflicts-resolved'), '');\n\n process.stdout.write('\\n' + SEP + '✅ Merge validated and committed\\n' + SEP + '\\n');\n process.stdout.write('Finalize & push by running: pnpm wp-upsert-pr (or pnpm wp-git-update)\\n\\n');\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"]}
@@ -1,4 +1,10 @@
1
1
  export declare const DEFAULT_BUILD_COMMAND = "pnpm nx affected --target=ci --base=origin/main";
2
+ /**
3
+ * Resolve the exact build command this gate will run for a repo: the project's configured
4
+ * PrGateConfig.buildCommand, or the default affected-ci command when none is set. Callers
5
+ * print this so the AI knows precisely which command to run locally to get the gate passing.
6
+ */
7
+ export declare function resolveBuildCommand(repoRoot: string): string;
2
8
  /**
3
9
  * Run the build gate. Returns the process exit code (0 = pass). `buildCommand` overrides
4
10
  * the default (sourced from PrGateConfig.buildCommand by callers); empty/undefined uses the
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DEFAULT_BUILD_COMMAND = void 0;
4
+ exports.resolveBuildCommand = resolveBuildCommand;
4
5
  exports.runBuildAffected = runBuildAffected;
5
6
  exports.runConfiguredBuildGate = runConfiguredBuildGate;
6
7
  const child_process_1 = require("child_process");
@@ -10,6 +11,15 @@ const rules_config_1 = require("@webpieces/rules-config");
10
11
  // PR command runs" can never drift. nx `affected` only rebuilds changed projects, so this
11
12
  // stays fast on a large monorepo.
12
13
  exports.DEFAULT_BUILD_COMMAND = 'pnpm nx affected --target=ci --base=origin/main';
14
+ /**
15
+ * Resolve the exact build command this gate will run for a repo: the project's configured
16
+ * PrGateConfig.buildCommand, or the default affected-ci command when none is set. Callers
17
+ * print this so the AI knows precisely which command to run locally to get the gate passing.
18
+ */
19
+ function resolveBuildCommand(repoRoot) {
20
+ const configured = (0, rules_config_1.loadPrGateConfig)(repoRoot).buildCommand;
21
+ return configured !== undefined && configured.trim() !== '' ? configured : exports.DEFAULT_BUILD_COMMAND;
22
+ }
13
23
  /**
14
24
  * Run the build gate. Returns the process exit code (0 = pass). `buildCommand` overrides
15
25
  * the default (sourced from PrGateConfig.buildCommand by callers); empty/undefined uses the
@@ -1 +1 @@
1
- {"version":3,"file":"build-affected.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/workflow/build-affected.ts"],"names":[],"mappings":";;;AAcA,4CAKC;AAQD,wDAEC;AA7BD,iDAA0C;AAC1C,0DAA2D;AAE3D,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;AAED;;;;;GAKG;AACH,SAAgB,sBAAsB,CAAC,QAAgB;IACnD,OAAO,gBAAgB,CAAC,QAAQ,EAAE,IAAA,+BAAgB,EAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC;AAC/E,CAAC","sourcesContent":["import { spawnSync } from 'child_process';\nimport { loadPrGateConfig } from '@webpieces/rules-config';\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\n/**\n * Run the build gate using the project's configured command (PrGateConfig.buildCommand). The\n * merge-complete gate and wp-upsert-pr both call THIS so they provably build with the same\n * command — the resolution the AI validates is built exactly as the PR command builds it.\n * Returns the exit code; callers print their own re-run hint.\n */\nexport function runConfiguredBuildGate(repoRoot: string): number {\n return runBuildAffected(repoRoot, loadPrGateConfig(repoRoot).buildCommand);\n}\n"]}
1
+ {"version":3,"file":"build-affected.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/workflow/build-affected.ts"],"names":[],"mappings":";;;AAcA,kDAGC;AAOD,4CAKC;AAQD,wDAEC;AAvCD,iDAA0C;AAC1C,0DAA2D;AAE3D,2FAA2F;AAC3F,4FAA4F;AAC5F,0FAA0F;AAC1F,kCAAkC;AACrB,QAAA,qBAAqB,GAAG,iDAAiD,CAAC;AAEvF;;;;GAIG;AACH,SAAgB,mBAAmB,CAAC,QAAgB;IAChD,MAAM,UAAU,GAAG,IAAA,+BAAgB,EAAC,QAAQ,CAAC,CAAC,YAAY,CAAC;IAC3D,OAAO,UAAU,KAAK,SAAS,IAAI,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,6BAAqB,CAAC;AACrG,CAAC;AAED;;;;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;AAED;;;;;GAKG;AACH,SAAgB,sBAAsB,CAAC,QAAgB;IACnD,OAAO,gBAAgB,CAAC,QAAQ,EAAE,IAAA,+BAAgB,EAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC;AAC/E,CAAC","sourcesContent":["import { spawnSync } from 'child_process';\nimport { loadPrGateConfig } from '@webpieces/rules-config';\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 * Resolve the exact build command this gate will run for a repo: the project's configured\n * PrGateConfig.buildCommand, or the default affected-ci command when none is set. Callers\n * print this so the AI knows precisely which command to run locally to get the gate passing.\n */\nexport function resolveBuildCommand(repoRoot: string): string {\n const configured = loadPrGateConfig(repoRoot).buildCommand;\n return configured !== undefined && configured.trim() !== '' ? configured : DEFAULT_BUILD_COMMAND;\n}\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\n/**\n * Run the build gate using the project's configured command (PrGateConfig.buildCommand). The\n * merge-complete gate and wp-upsert-pr both call THIS so they provably build with the same\n * command — the resolution the AI validates is built exactly as the PR command builds it.\n * Returns the exit code; callers print their own re-run hint.\n */\nexport function runConfiguredBuildGate(repoRoot: string): number {\n return runBuildAffected(repoRoot, loadPrGateConfig(repoRoot).buildCommand);\n}\n"]}
@@ -79,10 +79,16 @@ function main() {
79
79
  const repoRoot = (0, child_process_1.execSync)('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
80
80
  runUpdateFromMain();
81
81
  ensurePushed((0, child_process_1.execSync)('git branch --show-current', { encoding: 'utf8' }).trim());
82
+ const buildCommand = (0, build_affected_1.resolveBuildCommand)(repoRoot);
82
83
  process.stdout.write('\n' + SEP + '② Build gate (nx affected)\n' + SEP + '\n');
84
+ process.stdout.write(`This gate runs the build command below. To get it passing BEFORE this command runs it,\n` +
85
+ `run the SAME command yourself first and fix everything it reports:\n\n` +
86
+ ` ${buildCommand}\n\n`);
83
87
  const buildCode = (0, build_affected_1.runConfiguredBuildGate)(repoRoot);
84
88
  if (buildCode !== 0) {
85
- process.stderr.write('\n❌ Build failed — no PR created/updated. Fix and re-run pnpm wp-upsert-pr.\n');
89
+ process.stderr.write(`\n❌ Build failed — no PR created/updated.\n\n` +
90
+ `Run THIS exact command to reproduce and fix all errors, then re-run pnpm wp-upsert-pr:\n\n` +
91
+ ` ${buildCommand}\n\n`);
86
92
  process.exit(buildCode);
87
93
  }
88
94
  process.stdout.write('\n' + SEP + '③ Dashboard + PR\n' + SEP + '\n');
@@ -1 +1 @@
1
- {"version":3,"file":"wp-upsert-pr.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/scripts/wp-upsert-pr.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 { loadPrGateConfig, WEBPIECES_TMP_DIR } from '@webpieces/rules-config';\nimport { getFeatureName } from './workflow/git-readAiBranchName';\nimport { runConfiguredBuildGate } from './workflow/build-affected';\nimport { runGitChecked } from './workflow/git-exec';\nimport {\n computeGateResults,\n countAddedDisables,\n renderDashboard,\n DashboardInput,\n} from '../dashboard/dashboard';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\nfunction gitOut(args: string[]): string {\n const result = spawnSync('git', args, { encoding: 'utf8' });\n return result.status === 0 ? (result.stdout ?? '').trim() : '';\n}\n\n// Step A — bring the branch up to date with main via the 3-point engine (child process, so\n// its conflict handback / guard interplay is unaffected by this command's hook context).\nfunction runUpdateFromMain(): void {\n process.stdout.write('\\n' + SEP + '① Updating branch from main\\n' + SEP + '\\n');\n const result = spawnSync('pnpm', ['wp-git-update'], { stdio: 'inherit' });\n if (result.status === 2) {\n process.stdout.write('\\n⏸️ Conflicts — resolve them, run pnpm wp-git-merge-complete, then re-run pnpm wp-upsert-pr.\\n');\n process.exit(2);\n }\n if (result.status !== 0) {\n process.stderr.write('\\n❌ Branch update failed — see output above.\\n');\n process.exit(result.status ?? 1);\n }\n}\n\nfunction ensurePushed(currentBranch: string): void {\n const remoteExists = spawnSync('git', ['ls-remote', '--exit-code', '--heads', 'origin', currentBranch]).status === 0;\n if (remoteExists) {\n runGitChecked(['push', '--force-with-lease', 'origin', `HEAD:${currentBranch}`], 'Failed to push branch');\n } else {\n runGitChecked(['push', '-u', 'origin', `HEAD:${currentBranch}`], 'Failed to push new branch');\n }\n}\n\nfunction buildDashboard(repoRoot: string, buildPassed: boolean): string {\n const config = loadPrGateConfig(repoRoot);\n const forkPoint = gitOut(['merge-base', 'origin/main', 'HEAD']);\n const featureHead = gitOut(['rev-parse', 'HEAD']);\n const mainHead = gitOut(['rev-parse', 'origin/main']);\n const range = `${forkPoint}..${featureHead}`;\n const changedFiles = gitOut(['diff', range, '--name-only']).split('\\n').filter((f: string): boolean => f.trim() !== '');\n const patch = gitOut(['diff', range]);\n const title = gitOut(['log', '-1', '--format=%s']);\n\n const gateResults = computeGateResults(config.gates, changedFiles);\n const disables = countAddedDisables(patch);\n const input = new DashboardInput(title, gateResults, disables, buildPassed, forkPoint, featureHead, mainHead, '');\n return renderDashboard(input);\n}\n\nfunction upsertPr(repoRoot: string, currentBranch: string, body: string): void {\n const prDir = path.join(repoRoot, WEBPIECES_TMP_DIR, `pr-${getFeatureName()}`);\n fs.mkdirSync(prDir, { recursive: true });\n const bodyFile = path.join(prDir, 'pr-body.md');\n fs.writeFileSync(bodyFile, body + '\\n');\n\n const existing = gitOut(['log', '-1', '--format=%s']); // title fallback\n const prNumber = spawnSync(\n 'gh', ['pr', 'list', '--head', currentBranch, '--json', 'number', '--jq', '.[0].number'],\n { encoding: 'utf8' },\n );\n const num = prNumber.status === 0 ? (prNumber.stdout ?? '').trim() : '';\n\n if (num === '') {\n process.stdout.write('Creating PR...\\n');\n const create = spawnSync('gh', ['pr', 'create', '--head', currentBranch, '--base', 'main', '--title', existing, '--body-file', bodyFile], { stdio: 'inherit' });\n if (create.status !== 0) {\n process.stderr.write('⚠️ gh pr create failed — create the PR manually with the body in:\\n ' + bodyFile + '\\n');\n return;\n }\n } else {\n process.stdout.write(`Updating PR #${num}...\\n`);\n spawnSync('gh', ['pr', 'edit', num, '--body-file', bodyFile], { stdio: 'inherit' });\n }\n spawnSync('gh', ['pr', 'merge', currentBranch, '--auto', '--squash'], { stdio: 'inherit' });\n}\n\nexport function main(): void {\n const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();\n\n runUpdateFromMain();\n ensurePushed(execSync('git branch --show-current', { encoding: 'utf8' }).trim());\n\n process.stdout.write('\\n' + SEP + '② Build gate (nx affected)\\n' + SEP + '\\n');\n const buildCode = runConfiguredBuildGate(repoRoot);\n if (buildCode !== 0) {\n process.stderr.write('\\n❌ Build failed — no PR created/updated. Fix and re-run pnpm wp-upsert-pr.\\n');\n process.exit(buildCode);\n }\n\n process.stdout.write('\\n' + SEP + '③ Dashboard + PR\\n' + SEP + '\\n');\n const currentBranch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();\n const body = buildDashboard(repoRoot, true);\n upsertPr(repoRoot, currentBranch, body);\n process.stdout.write('\\n✅ Done.\\n');\n}\n\nif (require.main === module) {\n main();\n}\n"]}
1
+ {"version":3,"file":"wp-upsert-pr.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/scripts/wp-upsert-pr.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 { loadPrGateConfig, WEBPIECES_TMP_DIR } from '@webpieces/rules-config';\nimport { getFeatureName } from './workflow/git-readAiBranchName';\nimport { runConfiguredBuildGate, resolveBuildCommand } from './workflow/build-affected';\nimport { runGitChecked } from './workflow/git-exec';\nimport {\n computeGateResults,\n countAddedDisables,\n renderDashboard,\n DashboardInput,\n} from '../dashboard/dashboard';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\nfunction gitOut(args: string[]): string {\n const result = spawnSync('git', args, { encoding: 'utf8' });\n return result.status === 0 ? (result.stdout ?? '').trim() : '';\n}\n\n// Step A — bring the branch up to date with main via the 3-point engine (child process, so\n// its conflict handback / guard interplay is unaffected by this command's hook context).\nfunction runUpdateFromMain(): void {\n process.stdout.write('\\n' + SEP + '① Updating branch from main\\n' + SEP + '\\n');\n const result = spawnSync('pnpm', ['wp-git-update'], { stdio: 'inherit' });\n if (result.status === 2) {\n process.stdout.write('\\n⏸️ Conflicts — resolve them, run pnpm wp-git-merge-complete, then re-run pnpm wp-upsert-pr.\\n');\n process.exit(2);\n }\n if (result.status !== 0) {\n process.stderr.write('\\n❌ Branch update failed — see output above.\\n');\n process.exit(result.status ?? 1);\n }\n}\n\nfunction ensurePushed(currentBranch: string): void {\n const remoteExists = spawnSync('git', ['ls-remote', '--exit-code', '--heads', 'origin', currentBranch]).status === 0;\n if (remoteExists) {\n runGitChecked(['push', '--force-with-lease', 'origin', `HEAD:${currentBranch}`], 'Failed to push branch');\n } else {\n runGitChecked(['push', '-u', 'origin', `HEAD:${currentBranch}`], 'Failed to push new branch');\n }\n}\n\nfunction buildDashboard(repoRoot: string, buildPassed: boolean): string {\n const config = loadPrGateConfig(repoRoot);\n const forkPoint = gitOut(['merge-base', 'origin/main', 'HEAD']);\n const featureHead = gitOut(['rev-parse', 'HEAD']);\n const mainHead = gitOut(['rev-parse', 'origin/main']);\n const range = `${forkPoint}..${featureHead}`;\n const changedFiles = gitOut(['diff', range, '--name-only']).split('\\n').filter((f: string): boolean => f.trim() !== '');\n const patch = gitOut(['diff', range]);\n const title = gitOut(['log', '-1', '--format=%s']);\n\n const gateResults = computeGateResults(config.gates, changedFiles);\n const disables = countAddedDisables(patch);\n const input = new DashboardInput(title, gateResults, disables, buildPassed, forkPoint, featureHead, mainHead, '');\n return renderDashboard(input);\n}\n\nfunction upsertPr(repoRoot: string, currentBranch: string, body: string): void {\n const prDir = path.join(repoRoot, WEBPIECES_TMP_DIR, `pr-${getFeatureName()}`);\n fs.mkdirSync(prDir, { recursive: true });\n const bodyFile = path.join(prDir, 'pr-body.md');\n fs.writeFileSync(bodyFile, body + '\\n');\n\n const existing = gitOut(['log', '-1', '--format=%s']); // title fallback\n const prNumber = spawnSync(\n 'gh', ['pr', 'list', '--head', currentBranch, '--json', 'number', '--jq', '.[0].number'],\n { encoding: 'utf8' },\n );\n const num = prNumber.status === 0 ? (prNumber.stdout ?? '').trim() : '';\n\n if (num === '') {\n process.stdout.write('Creating PR...\\n');\n const create = spawnSync('gh', ['pr', 'create', '--head', currentBranch, '--base', 'main', '--title', existing, '--body-file', bodyFile], { stdio: 'inherit' });\n if (create.status !== 0) {\n process.stderr.write('⚠️ gh pr create failed — create the PR manually with the body in:\\n ' + bodyFile + '\\n');\n return;\n }\n } else {\n process.stdout.write(`Updating PR #${num}...\\n`);\n spawnSync('gh', ['pr', 'edit', num, '--body-file', bodyFile], { stdio: 'inherit' });\n }\n spawnSync('gh', ['pr', 'merge', currentBranch, '--auto', '--squash'], { stdio: 'inherit' });\n}\n\nexport function main(): void {\n const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();\n\n runUpdateFromMain();\n ensurePushed(execSync('git branch --show-current', { encoding: 'utf8' }).trim());\n\n const buildCommand = resolveBuildCommand(repoRoot);\n process.stdout.write('\\n' + SEP + '② Build gate (nx affected)\\n' + SEP + '\\n');\n process.stdout.write(\n `This gate runs the build command below. To get it passing BEFORE this command runs it,\\n` +\n `run the SAME command yourself first and fix everything it reports:\\n\\n` +\n ` ${buildCommand}\\n\\n`,\n );\n const buildCode = runConfiguredBuildGate(repoRoot);\n if (buildCode !== 0) {\n process.stderr.write(\n `\\n❌ Build failed — no PR created/updated.\\n\\n` +\n `Run THIS exact command to reproduce and fix all errors, then re-run pnpm wp-upsert-pr:\\n\\n` +\n ` ${buildCommand}\\n\\n`,\n );\n process.exit(buildCode);\n }\n\n process.stdout.write('\\n' + SEP + '③ Dashboard + PR\\n' + SEP + '\\n');\n const currentBranch = execSync('git branch --show-current', { encoding: 'utf8' }).trim();\n const body = buildDashboard(repoRoot, true);\n upsertPr(repoRoot, currentBranch, body);\n process.stdout.write('\\n✅ Done.\\n');\n}\n\nif (require.main === module) {\n main();\n}\n"]}