@webpieces/pr-gate 0.4.454 → 0.4.455

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.4.454",
3
+ "version": "0.4.455",
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",
@@ -9,7 +9,8 @@
9
9
  "wp-start-upsert-pr": "./src/scripts/wp-start-upsert-pr.js",
10
10
  "wp-start-update": "./src/scripts/wp-start-update.js",
11
11
  "wp-finish-update": "./src/scripts/wp-finish-update.js",
12
- "wp-cleanup": "./src/scripts/wp-cleanup.js"
12
+ "wp-cleanup": "./src/scripts/wp-cleanup.js",
13
+ "wp-land-pr": "./src/scripts/wp-land-pr.js"
13
14
  },
14
15
  "files": [
15
16
  "src/**/*"
@@ -22,7 +23,7 @@
22
23
  "directory": "packages/tooling/pr-gate"
23
24
  },
24
25
  "dependencies": {
25
- "@webpieces/rules-config": "0.4.454",
26
+ "@webpieces/rules-config": "0.4.455",
26
27
  "@inversifyjs/binding-decorators": "1.1.5",
27
28
  "inversify": "7.10.4",
28
29
  "reflect-metadata": "0.2.2"
@@ -0,0 +1,28 @@
1
+ import { RepoRootFinder } from '@webpieces/rules-config';
2
+ import { AiBranchName } from '../workflow/git-readAiBranchName';
3
+ import { BranchNaming } from '../workflow/branch-naming';
4
+ import { PrMerger } from '../workflow/pr-merger';
5
+ /**
6
+ * `wp-land-pr`: squash-merge THIS branch's already-posted PR into main with the compact commit body.
7
+ *
8
+ * It exists because a merge clicked in the GitHub UI cannot produce that body. A UI merge is limited
9
+ * to the repo's squash_merge_commit_title/message settings, and none of their values yields the
10
+ * shortened risk/flags summary — only an explicit `gh pr merge --subject --body-file` does. So when a
11
+ * merge has to happen outside `wp-finish-upsert-pr` (a mergeMode=NONE repo, or a PR whose checks were
12
+ * still running when finish ran), this is the command that keeps main's history consistent.
13
+ *
14
+ * It deliberately does NOT re-run the build gate or re-render the dashboard: `wp-finish-upsert-pr`
15
+ * already did both and left `merge-commit-body.md` on disk. Landing is a separate, later act, and
16
+ * rebuilding here would mean a second authoritative gate whose result nobody reads. If that file is
17
+ * missing, the honest answer is that finish has not run — so this fails and says so, rather than
18
+ * inventing a body that would not match the PR.
19
+ */
20
+ export declare class LandPrCommand {
21
+ private readonly repoRootFinder;
22
+ private readonly aiBranchName;
23
+ private readonly branchNaming;
24
+ private readonly prMerger;
25
+ constructor(repoRootFinder: RepoRootFinder, aiBranchName: AiBranchName, branchNaming: BranchNaming, prMerger: PrMerger);
26
+ run(): Promise<void>;
27
+ private prNumberAndTitle;
28
+ }
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LandPrCommand = void 0;
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 rules_config_1 = require("@webpieces/rules-config");
9
+ const inversify_1 = require("inversify");
10
+ const git_readAiBranchName_1 = require("../workflow/git-readAiBranchName");
11
+ const branch_naming_1 = require("../workflow/branch-naming");
12
+ const pr_merger_1 = require("../workflow/pr-merger");
13
+ const SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n';
14
+ /**
15
+ * `wp-land-pr`: squash-merge THIS branch's already-posted PR into main with the compact commit body.
16
+ *
17
+ * It exists because a merge clicked in the GitHub UI cannot produce that body. A UI merge is limited
18
+ * to the repo's squash_merge_commit_title/message settings, and none of their values yields the
19
+ * shortened risk/flags summary — only an explicit `gh pr merge --subject --body-file` does. So when a
20
+ * merge has to happen outside `wp-finish-upsert-pr` (a mergeMode=NONE repo, or a PR whose checks were
21
+ * still running when finish ran), this is the command that keeps main's history consistent.
22
+ *
23
+ * It deliberately does NOT re-run the build gate or re-render the dashboard: `wp-finish-upsert-pr`
24
+ * already did both and left `merge-commit-body.md` on disk. Landing is a separate, later act, and
25
+ * rebuilding here would mean a second authoritative gate whose result nobody reads. If that file is
26
+ * missing, the honest answer is that finish has not run — so this fails and says so, rather than
27
+ * inventing a body that would not match the PR.
28
+ */
29
+ let LandPrCommand = class LandPrCommand {
30
+ repoRootFinder;
31
+ aiBranchName;
32
+ branchNaming;
33
+ prMerger;
34
+ constructor(repoRootFinder, aiBranchName, branchNaming, prMerger) {
35
+ this.repoRootFinder = repoRootFinder;
36
+ this.aiBranchName = aiBranchName;
37
+ this.branchNaming = branchNaming;
38
+ this.prMerger = prMerger;
39
+ }
40
+ async run() {
41
+ const repoRoot = this.repoRootFinder.resolveRepoRoot(process.cwd());
42
+ const base = this.branchNaming.baseBranchName((0, child_process_1.execSync)('git branch --show-current', { encoding: 'utf8' }).trim());
43
+ const prDir = (0, rules_config_1.prDirFor)(repoRoot, this.aiBranchName.getFeatureName());
44
+ const mergeBodyFile = path.join(prDir, 'merge-commit-body.md');
45
+ if (!fs.existsSync(mergeBodyFile)) {
46
+ throw new rules_config_1.InformAiError('\n' + SEP + '❌ Nothing to land — no rendered merge body\n' + SEP + '\n' +
47
+ `Expected the compact squash-commit body at:\n ${mergeBodyFile}\n\n` +
48
+ 'That file is written by `pnpm wp-finish-upsert-pr`, which is also what posts the PR.\n' +
49
+ 'Its absence means finish has not run on this branch, so there is no reviewed PR to\n' +
50
+ 'land. Run the gated flow first:\n\n' +
51
+ ' pnpm wp-start-upsert-pr # update from main, push, build gate\n' +
52
+ ' # write .webpieces/review.json\n' +
53
+ ' pnpm wp-finish-upsert-pr # build gate, dashboard, create/update the PR\n\n' +
54
+ 'Then re-run `pnpm wp-land-pr` if the PR still needs landing.\n' + SEP);
55
+ }
56
+ const ref = this.prNumberAndTitle(base);
57
+ if (ref === null) {
58
+ throw new rules_config_1.InformAiError('\n' + SEP + '❌ No open PR found for this branch\n' + SEP + '\n' +
59
+ `No open PR has head branch "${base}". Nothing to land.\n` +
60
+ 'If the PR is already merged, run `pnpm wp-cleanup`.\n' + SEP);
61
+ }
62
+ process.stdout.write('\n' + SEP + `🚀 Landing PR #${ref.number}\n` + SEP + '\n');
63
+ // Reuse the SAME merge logic wp-finish-upsert-pr uses, so a PR lands identically whichever
64
+ // command lands it — including the auto-merge fallback when the checks are still running.
65
+ // MERGE_MODE_AUTO is passed explicitly: running this command IS the intent to merge, so it is
66
+ // not gated on pr-gate.mergeMode (a NONE repo runs this precisely to land one PR by hand).
67
+ const outcome = this.prMerger.merge(base, `${ref.title} (#${ref.number})`, mergeBodyFile, rules_config_1.MERGE_MODE_AUTO);
68
+ const policy = (0, rules_config_1.loadAndValidate)(repoRoot).prGate.mergeMode;
69
+ process.stdout.write('\n' + SEP + (outcome.merged ? '✅ Landed\n' : 'ℹ️ Not landed yet\n') + SEP + '\n' +
70
+ ` ${outcome.message}\n` +
71
+ (outcome.merged ? ' Next: `pnpm wp-cleanup` to delete the merged branch.\n' : '') +
72
+ (policy === rules_config_1.MERGE_MODE_AUTO
73
+ ? ''
74
+ : ` (pr-gate.mergeMode is ${policy} — wp-finish-upsert-pr will keep leaving PRs for a human.)\n`) +
75
+ '\n');
76
+ }
77
+ // The open PR's number + title for this head branch, or null when there is none. The TITLE comes
78
+ // from the PR itself, not review.json, so the squash subject matches what a reviewer approved even
79
+ // if review.json was edited afterwards.
80
+ prNumberAndTitle(baseBranch) {
81
+ const result = (0, child_process_1.spawnSync)('gh', ['pr', 'view', baseBranch, '--json', 'number,title', '--jq', '"\\(.number)\\t\\(.title)"'], { encoding: 'utf8' });
82
+ if (result.status !== 0)
83
+ return null;
84
+ const parts = (result.stdout ?? '').trim().split('\t');
85
+ if ((parts[0] ?? '') === '')
86
+ return null;
87
+ return new PrIdentity(parts[0] ?? '', parts[1] ?? '');
88
+ }
89
+ };
90
+ exports.LandPrCommand = LandPrCommand;
91
+ exports.LandPrCommand = LandPrCommand = tslib_1.__decorate([
92
+ (0, inversify_1.injectable)(inversify_1.bindingScopeValues.Singleton),
93
+ tslib_1.__metadata("design:paramtypes", [rules_config_1.RepoRootFinder,
94
+ git_readAiBranchName_1.AiBranchName,
95
+ branch_naming_1.BranchNaming,
96
+ pr_merger_1.PrMerger])
97
+ ], LandPrCommand);
98
+ // The open PR's number + title, as read back from GitHub.
99
+ class PrIdentity {
100
+ number;
101
+ title;
102
+ constructor(number, title) {
103
+ this.number = number;
104
+ this.title = title;
105
+ }
106
+ }
107
+ //# sourceMappingURL=land-pr-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"land-pr-command.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/pr-gate/src/scripts/commands/land-pr-command.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 { prDirFor, InformAiError, RepoRootFinder, MERGE_MODE_AUTO, loadAndValidate } from '@webpieces/rules-config';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { AiBranchName } from '../workflow/git-readAiBranchName';\nimport { BranchNaming } from '../workflow/branch-naming';\nimport { PrMerger } from '../workflow/pr-merger';\n\nconst SEP = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n';\n\n/**\n * `wp-land-pr`: squash-merge THIS branch's already-posted PR into main with the compact commit body.\n *\n * It exists because a merge clicked in the GitHub UI cannot produce that body. A UI merge is limited\n * to the repo's squash_merge_commit_title/message settings, and none of their values yields the\n * shortened risk/flags summary — only an explicit `gh pr merge --subject --body-file` does. So when a\n * merge has to happen outside `wp-finish-upsert-pr` (a mergeMode=NONE repo, or a PR whose checks were\n * still running when finish ran), this is the command that keeps main's history consistent.\n *\n * It deliberately does NOT re-run the build gate or re-render the dashboard: `wp-finish-upsert-pr`\n * already did both and left `merge-commit-body.md` on disk. Landing is a separate, later act, and\n * rebuilding here would mean a second authoritative gate whose result nobody reads. If that file is\n * missing, the honest answer is that finish has not run — so this fails and says so, rather than\n * inventing a body that would not match the PR.\n */\n@injectable(bindingScopeValues.Singleton)\nexport class LandPrCommand {\n constructor(\n private readonly repoRootFinder: RepoRootFinder,\n private readonly aiBranchName: AiBranchName,\n private readonly branchNaming: BranchNaming,\n private readonly prMerger: PrMerger,\n ) {}\n\n async run(): Promise<void> {\n const repoRoot = this.repoRootFinder.resolveRepoRoot(process.cwd());\n const base = this.branchNaming.baseBranchName(execSync('git branch --show-current', { encoding: 'utf8' }).trim());\n const prDir = prDirFor(repoRoot, this.aiBranchName.getFeatureName());\n const mergeBodyFile = path.join(prDir, 'merge-commit-body.md');\n\n if (!fs.existsSync(mergeBodyFile)) {\n throw new InformAiError(\n '\\n' + SEP + '❌ Nothing to land — no rendered merge body\\n' + SEP + '\\n' +\n `Expected the compact squash-commit body at:\\n ${mergeBodyFile}\\n\\n` +\n 'That file is written by `pnpm wp-finish-upsert-pr`, which is also what posts the PR.\\n' +\n 'Its absence means finish has not run on this branch, so there is no reviewed PR to\\n' +\n 'land. Run the gated flow first:\\n\\n' +\n ' pnpm wp-start-upsert-pr # update from main, push, build gate\\n' +\n ' # write .webpieces/review.json\\n' +\n ' pnpm wp-finish-upsert-pr # build gate, dashboard, create/update the PR\\n\\n' +\n 'Then re-run `pnpm wp-land-pr` if the PR still needs landing.\\n' + SEP,\n );\n }\n\n const ref = this.prNumberAndTitle(base);\n if (ref === null) {\n throw new InformAiError(\n '\\n' + SEP + '❌ No open PR found for this branch\\n' + SEP + '\\n' +\n `No open PR has head branch \"${base}\". Nothing to land.\\n` +\n 'If the PR is already merged, run `pnpm wp-cleanup`.\\n' + SEP,\n );\n }\n\n process.stdout.write('\\n' + SEP + `🚀 Landing PR #${ref.number}\\n` + SEP + '\\n');\n // Reuse the SAME merge logic wp-finish-upsert-pr uses, so a PR lands identically whichever\n // command lands it — including the auto-merge fallback when the checks are still running.\n // MERGE_MODE_AUTO is passed explicitly: running this command IS the intent to merge, so it is\n // not gated on pr-gate.mergeMode (a NONE repo runs this precisely to land one PR by hand).\n const outcome = this.prMerger.merge(base, `${ref.title} (#${ref.number})`, mergeBodyFile, MERGE_MODE_AUTO);\n\n const policy = loadAndValidate(repoRoot).prGate.mergeMode;\n process.stdout.write(\n '\\n' + SEP + (outcome.merged ? '✅ Landed\\n' : 'ℹ️ Not landed yet\\n') + SEP + '\\n' +\n ` ${outcome.message}\\n` +\n (outcome.merged ? ' Next: `pnpm wp-cleanup` to delete the merged branch.\\n' : '') +\n (policy === MERGE_MODE_AUTO\n ? ''\n : ` (pr-gate.mergeMode is ${policy} — wp-finish-upsert-pr will keep leaving PRs for a human.)\\n`) +\n '\\n',\n );\n }\n\n // The open PR's number + title for this head branch, or null when there is none. The TITLE comes\n // from the PR itself, not review.json, so the squash subject matches what a reviewer approved even\n // if review.json was edited afterwards.\n private prNumberAndTitle(baseBranch: string): PrIdentity | null {\n const result = spawnSync(\n 'gh', ['pr', 'view', baseBranch, '--json', 'number,title', '--jq', '\"\\\\(.number)\\\\t\\\\(.title)\"'],\n { encoding: 'utf8' },\n );\n if (result.status !== 0) return null;\n const parts = (result.stdout ?? '').trim().split('\\t');\n if ((parts[0] ?? '') === '') return null;\n return new PrIdentity(parts[0] ?? '', parts[1] ?? '');\n }\n}\n\n// The open PR's number + title, as read back from GitHub.\nclass PrIdentity {\n number: string;\n title: string;\n\n constructor(number: string, title: string) {\n this.number = number;\n this.title = title;\n }\n}\n"]}
@@ -3,9 +3,10 @@ import { FinishUpdateCommand } from './commands/finish-update-command';
3
3
  import { StartUpsertPrCommand } from './commands/start-upsert-pr-command';
4
4
  import { FinishUpsertPrCommand } from './commands/finish-upsert-pr-command';
5
5
  import { CleanupCommand } from './commands/cleanup-command';
6
+ import { LandPrCommand } from './commands/land-pr-command';
6
7
  /**
7
- * The pr-gate application root. `container.get(PrGateApp)` resolves the entire workflow DAG (the 4
8
- * command classes → the injected git/merge/dashboard services). `@DocumentDesign` marks it the
8
+ * The pr-gate application root. `container.get(PrGateApp)` resolves the entire workflow DAG (the command
9
+ * classes → the injected git/merge/dashboard services). `@DocumentDesign` marks it the
9
10
  * top-of-DAG the DI-design analyzer roots on, so `role:app` pr-gate draws its design. Each `bin/*`
10
11
  * entry resolves THIS and calls the matching command method.
11
12
  */
@@ -15,7 +16,8 @@ export declare class PrGateApp {
15
16
  private readonly startUpsertPrCommand;
16
17
  private readonly finishUpsertPrCommand;
17
18
  private readonly cleanupCommand;
18
- constructor(startUpdateCommand: StartUpdateCommand, finishUpdateCommand: FinishUpdateCommand, startUpsertPrCommand: StartUpsertPrCommand, finishUpsertPrCommand: FinishUpsertPrCommand, cleanupCommand: CleanupCommand);
19
+ private readonly landPrCommand;
20
+ constructor(startUpdateCommand: StartUpdateCommand, finishUpdateCommand: FinishUpdateCommand, startUpsertPrCommand: StartUpsertPrCommand, finishUpsertPrCommand: FinishUpsertPrCommand, cleanupCommand: CleanupCommand, landPrCommand: LandPrCommand);
19
21
  /** `wp-start-update`: 3-point squash-update from main (no PR). */
20
22
  startUpdate(): Promise<void>;
21
23
  /** `wp-finish-update`: validate + finalize a resolved 3-point merge (no PR). */
@@ -26,4 +28,6 @@ export declare class PrGateApp {
26
28
  finishUpsertPr(): Promise<void>;
27
29
  /** `wp-cleanup`: delete local branches whose PR is already merged (or that hold no commits). */
28
30
  cleanup(): Promise<void>;
31
+ /** `wp-land-pr`: squash-merge this branch's PR into main with the compact commit body. */
32
+ landPr(): Promise<void>;
29
33
  }
@@ -9,9 +9,10 @@ const finish_update_command_1 = require("./commands/finish-update-command");
9
9
  const start_upsert_pr_command_1 = require("./commands/start-upsert-pr-command");
10
10
  const finish_upsert_pr_command_1 = require("./commands/finish-upsert-pr-command");
11
11
  const cleanup_command_1 = require("./commands/cleanup-command");
12
+ const land_pr_command_1 = require("./commands/land-pr-command");
12
13
  /**
13
- * The pr-gate application root. `container.get(PrGateApp)` resolves the entire workflow DAG (the 4
14
- * command classes → the injected git/merge/dashboard services). `@DocumentDesign` marks it the
14
+ * The pr-gate application root. `container.get(PrGateApp)` resolves the entire workflow DAG (the command
15
+ * classes → the injected git/merge/dashboard services). `@DocumentDesign` marks it the
15
16
  * top-of-DAG the DI-design analyzer roots on, so `role:app` pr-gate draws its design. Each `bin/*`
16
17
  * entry resolves THIS and calls the matching command method.
17
18
  */
@@ -21,12 +22,14 @@ let PrGateApp = class PrGateApp {
21
22
  startUpsertPrCommand;
22
23
  finishUpsertPrCommand;
23
24
  cleanupCommand;
24
- constructor(startUpdateCommand, finishUpdateCommand, startUpsertPrCommand, finishUpsertPrCommand, cleanupCommand) {
25
+ landPrCommand;
26
+ constructor(startUpdateCommand, finishUpdateCommand, startUpsertPrCommand, finishUpsertPrCommand, cleanupCommand, landPrCommand) {
25
27
  this.startUpdateCommand = startUpdateCommand;
26
28
  this.finishUpdateCommand = finishUpdateCommand;
27
29
  this.startUpsertPrCommand = startUpsertPrCommand;
28
30
  this.finishUpsertPrCommand = finishUpsertPrCommand;
29
31
  this.cleanupCommand = cleanupCommand;
32
+ this.landPrCommand = landPrCommand;
30
33
  }
31
34
  /** `wp-start-update`: 3-point squash-update from main (no PR). */
32
35
  startUpdate() {
@@ -48,6 +51,10 @@ let PrGateApp = class PrGateApp {
48
51
  cleanup() {
49
52
  return this.cleanupCommand.run();
50
53
  }
54
+ /** `wp-land-pr`: squash-merge this branch's PR into main with the compact commit body. */
55
+ landPr() {
56
+ return this.landPrCommand.run();
57
+ }
51
58
  };
52
59
  exports.PrGateApp = PrGateApp;
53
60
  exports.PrGateApp = PrGateApp = tslib_1.__decorate([
@@ -57,6 +64,7 @@ exports.PrGateApp = PrGateApp = tslib_1.__decorate([
57
64
  finish_update_command_1.FinishUpdateCommand,
58
65
  start_upsert_pr_command_1.StartUpsertPrCommand,
59
66
  finish_upsert_pr_command_1.FinishUpsertPrCommand,
60
- cleanup_command_1.CleanupCommand])
67
+ cleanup_command_1.CleanupCommand,
68
+ land_pr_command_1.LandPrCommand])
61
69
  ], PrGateApp);
62
70
  //# sourceMappingURL=pr-gate-app.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pr-gate-app.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/scripts/pr-gate-app.ts"],"names":[],"mappings":";;;;AAAA,0DAAyD;AACzD,yCAA2D;AAC3D,0EAAqE;AACrE,4EAAuE;AACvE,gFAA0E;AAC1E,kFAA4E;AAC5E,gEAA4D;AAE5D;;;;;GAKG;AAGI,IAAM,SAAS,GAAf,MAAM,SAAS;IAEG;IACA;IACA;IACA;IACA;IALrB,YACqB,kBAAsC,EACtC,mBAAwC,EACxC,oBAA0C,EAC1C,qBAA4C,EAC5C,cAA8B;QAJ9B,uBAAkB,GAAlB,kBAAkB,CAAoB;QACtC,wBAAmB,GAAnB,mBAAmB,CAAqB;QACxC,yBAAoB,GAApB,oBAAoB,CAAsB;QAC1C,0BAAqB,GAArB,qBAAqB,CAAuB;QAC5C,mBAAc,GAAd,cAAc,CAAgB;IAChD,CAAC;IAEJ,kEAAkE;IAClE,WAAW;QACP,OAAO,IAAI,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC;IACzC,CAAC;IAED,gFAAgF;IAChF,YAAY;QACR,OAAO,IAAI,CAAC,mBAAmB,CAAC,GAAG,EAAE,CAAC;IAC1C,CAAC;IAED,+FAA+F;IAC/F,aAAa;QACT,OAAO,IAAI,CAAC,oBAAoB,CAAC,GAAG,EAAE,CAAC;IAC3C,CAAC;IAED,oGAAoG;IACpG,cAAc;QACV,OAAO,IAAI,CAAC,qBAAqB,CAAC,GAAG,EAAE,CAAC;IAC5C,CAAC;IAED,gGAAgG;IAChG,OAAO;QACH,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC;IACrC,CAAC;CACJ,CAAA;AAjCY,8BAAS;oBAAT,SAAS;IAFrB,IAAA,6BAAc,GAAE;IAChB,IAAA,sBAAU,EAAC,8BAAkB,CAAC,SAAS,CAAC;6CAGI,yCAAkB;QACjB,2CAAmB;QAClB,8CAAoB;QACnB,gDAAqB;QAC5B,gCAAc;GAN1C,SAAS,CAiCrB","sourcesContent":["import { DocumentDesign } from '@webpieces/rules-config';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { StartUpdateCommand } from './commands/start-update-command';\nimport { FinishUpdateCommand } from './commands/finish-update-command';\nimport { StartUpsertPrCommand } from './commands/start-upsert-pr-command';\nimport { FinishUpsertPrCommand } from './commands/finish-upsert-pr-command';\nimport { CleanupCommand } from './commands/cleanup-command';\n\n/**\n * The pr-gate application root. `container.get(PrGateApp)` resolves the entire workflow DAG (the 4\n * command classes → the injected git/merge/dashboard services). `@DocumentDesign` marks it the\n * top-of-DAG the DI-design analyzer roots on, so `role:app` pr-gate draws its design. Each `bin/*`\n * entry resolves THIS and calls the matching command method.\n */\n@DocumentDesign()\n@injectable(bindingScopeValues.Singleton)\nexport class PrGateApp {\n constructor(\n private readonly startUpdateCommand: StartUpdateCommand,\n private readonly finishUpdateCommand: FinishUpdateCommand,\n private readonly startUpsertPrCommand: StartUpsertPrCommand,\n private readonly finishUpsertPrCommand: FinishUpsertPrCommand,\n private readonly cleanupCommand: CleanupCommand,\n ) {}\n\n /** `wp-start-update`: 3-point squash-update from main (no PR). */\n startUpdate(): Promise<void> {\n return this.startUpdateCommand.run();\n }\n\n /** `wp-finish-update`: validate + finalize a resolved 3-point merge (no PR). */\n finishUpdate(): Promise<void> {\n return this.finishUpdateCommand.run();\n }\n\n /** `wp-start-upsert-pr`: update from main, push, advisory build gate, hand off review.json. */\n startUpsertPr(): Promise<void> {\n return this.startUpsertPrCommand.run();\n }\n\n /** `wp-finish-upsert-pr`: finalize merge, authoritative build gate, dashboard, create/update PR. */\n finishUpsertPr(): Promise<void> {\n return this.finishUpsertPrCommand.run();\n }\n\n /** `wp-cleanup`: delete local branches whose PR is already merged (or that hold no commits). */\n cleanup(): Promise<void> {\n return this.cleanupCommand.run();\n }\n}\n"]}
1
+ {"version":3,"file":"pr-gate-app.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/scripts/pr-gate-app.ts"],"names":[],"mappings":";;;;AAAA,0DAAyD;AACzD,yCAA2D;AAC3D,0EAAqE;AACrE,4EAAuE;AACvE,gFAA0E;AAC1E,kFAA4E;AAC5E,gEAA4D;AAC5D,gEAA2D;AAE3D;;;;;GAKG;AAGI,IAAM,SAAS,GAAf,MAAM,SAAS;IAEG;IACA;IACA;IACA;IACA;IACA;IANrB,YACqB,kBAAsC,EACtC,mBAAwC,EACxC,oBAA0C,EAC1C,qBAA4C,EAC5C,cAA8B,EAC9B,aAA4B;QAL5B,uBAAkB,GAAlB,kBAAkB,CAAoB;QACtC,wBAAmB,GAAnB,mBAAmB,CAAqB;QACxC,yBAAoB,GAApB,oBAAoB,CAAsB;QAC1C,0BAAqB,GAArB,qBAAqB,CAAuB;QAC5C,mBAAc,GAAd,cAAc,CAAgB;QAC9B,kBAAa,GAAb,aAAa,CAAe;IAC9C,CAAC;IAEJ,kEAAkE;IAClE,WAAW;QACP,OAAO,IAAI,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC;IACzC,CAAC;IAED,gFAAgF;IAChF,YAAY;QACR,OAAO,IAAI,CAAC,mBAAmB,CAAC,GAAG,EAAE,CAAC;IAC1C,CAAC;IAED,+FAA+F;IAC/F,aAAa;QACT,OAAO,IAAI,CAAC,oBAAoB,CAAC,GAAG,EAAE,CAAC;IAC3C,CAAC;IAED,oGAAoG;IACpG,cAAc;QACV,OAAO,IAAI,CAAC,qBAAqB,CAAC,GAAG,EAAE,CAAC;IAC5C,CAAC;IAED,gGAAgG;IAChG,OAAO;QACH,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC;IACrC,CAAC;IAED,0FAA0F;IAC1F,MAAM;QACF,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC;IACpC,CAAC;CACJ,CAAA;AAvCY,8BAAS;oBAAT,SAAS;IAFrB,IAAA,6BAAc,GAAE;IAChB,IAAA,sBAAU,EAAC,8BAAkB,CAAC,SAAS,CAAC;6CAGI,yCAAkB;QACjB,2CAAmB;QAClB,8CAAoB;QACnB,gDAAqB;QAC5B,gCAAc;QACf,+BAAa;GAPxC,SAAS,CAuCrB","sourcesContent":["import { DocumentDesign } from '@webpieces/rules-config';\nimport { injectable, bindingScopeValues } from 'inversify';\nimport { StartUpdateCommand } from './commands/start-update-command';\nimport { FinishUpdateCommand } from './commands/finish-update-command';\nimport { StartUpsertPrCommand } from './commands/start-upsert-pr-command';\nimport { FinishUpsertPrCommand } from './commands/finish-upsert-pr-command';\nimport { CleanupCommand } from './commands/cleanup-command';\nimport { LandPrCommand } from './commands/land-pr-command';\n\n/**\n * The pr-gate application root. `container.get(PrGateApp)` resolves the entire workflow DAG (the command\n * classes → the injected git/merge/dashboard services). `@DocumentDesign` marks it the\n * top-of-DAG the DI-design analyzer roots on, so `role:app` pr-gate draws its design. Each `bin/*`\n * entry resolves THIS and calls the matching command method.\n */\n@DocumentDesign()\n@injectable(bindingScopeValues.Singleton)\nexport class PrGateApp {\n constructor(\n private readonly startUpdateCommand: StartUpdateCommand,\n private readonly finishUpdateCommand: FinishUpdateCommand,\n private readonly startUpsertPrCommand: StartUpsertPrCommand,\n private readonly finishUpsertPrCommand: FinishUpsertPrCommand,\n private readonly cleanupCommand: CleanupCommand,\n private readonly landPrCommand: LandPrCommand,\n ) {}\n\n /** `wp-start-update`: 3-point squash-update from main (no PR). */\n startUpdate(): Promise<void> {\n return this.startUpdateCommand.run();\n }\n\n /** `wp-finish-update`: validate + finalize a resolved 3-point merge (no PR). */\n finishUpdate(): Promise<void> {\n return this.finishUpdateCommand.run();\n }\n\n /** `wp-start-upsert-pr`: update from main, push, advisory build gate, hand off review.json. */\n startUpsertPr(): Promise<void> {\n return this.startUpsertPrCommand.run();\n }\n\n /** `wp-finish-upsert-pr`: finalize merge, authoritative build gate, dashboard, create/update PR. */\n finishUpsertPr(): Promise<void> {\n return this.finishUpsertPrCommand.run();\n }\n\n /** `wp-cleanup`: delete local branches whose PR is already merged (or that hold no commits). */\n cleanup(): Promise<void> {\n return this.cleanupCommand.run();\n }\n\n /** `wp-land-pr`: squash-merge this branch's PR into main with the compact commit body. */\n landPr(): Promise<void> {\n return this.landPrCommand.run();\n }\n}\n"]}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import 'reflect-metadata';
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ require("reflect-metadata");
5
+ const inversify_1 = require("inversify");
6
+ const rules_config_1 = require("@webpieces/rules-config");
7
+ const pr_gate_app_1 = require("./pr-gate-app");
8
+ // Composition root: build the container and resolve the app so inversify constructs the whole DAG.
9
+ (0, rules_config_1.runMain)(async () => {
10
+ // autobind self-binds every @injectable(Singleton) tooling class (replaces the buildProviderModule registry scan)
11
+ const container = new inversify_1.Container({ autobind: true });
12
+ // Reject `--help`/bogus flags BEFORE the app touches git — an ignored flag must never start the flow.
13
+ container.get(rules_config_1.CliArgs).assertNoArgs(new rules_config_1.CliUsage('wp-land-pr', "Squash-merge this branch's PR into main with the compact risk/flags commit body."));
14
+ await container.get(pr_gate_app_1.PrGateApp).landPr();
15
+ });
16
+ //# sourceMappingURL=wp-land-pr.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wp-land-pr.js","sourceRoot":"","sources":["../../../../../../packages/tooling/pr-gate/src/scripts/wp-land-pr.ts"],"names":[],"mappings":";;;AACA,4BAA0B;AAC1B,yCAAsC;AACtC,0DAAqE;AACrE,+CAA0C;AAE1C,mGAAmG;AACnG,IAAA,sBAAO,EAAC,KAAK,IAAmB,EAAE;IAC9B,kHAAkH;IAClH,MAAM,SAAS,GAAG,IAAI,qBAAS,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,sGAAsG;IACtG,SAAS,CAAC,GAAG,CAAC,sBAAO,CAAC,CAAC,YAAY,CAAC,IAAI,uBAAQ,CAC5C,YAAY,EAAE,kFAAkF,CAAC,CAAC,CAAC;IACvG,MAAM,SAAS,CAAC,GAAG,CAAC,uBAAS,CAAC,CAAC,MAAM,EAAE,CAAC;AAC5C,CAAC,CAAC,CAAC","sourcesContent":["#!/usr/bin/env node\nimport 'reflect-metadata';\nimport { Container } from 'inversify';\nimport { runMain, CliArgs, CliUsage } from '@webpieces/rules-config';\nimport { PrGateApp } from './pr-gate-app';\n\n// Composition root: build the container and resolve the app so inversify constructs the whole DAG.\nrunMain(async (): Promise<void> => {\n // autobind self-binds every @injectable(Singleton) tooling class (replaces the buildProviderModule registry scan)\n const container = new Container({ autobind: true });\n // Reject `--help`/bogus flags BEFORE the app touches git — an ignored flag must never start the flow.\n container.get(CliArgs).assertNoArgs(new CliUsage(\n 'wp-land-pr', \"Squash-merge this branch's PR into main with the compact risk/flags commit body.\"));\n await container.get(PrGateApp).landPr();\n});\n"]}