@henryqw/pi-pr 4.0.4 → 4.0.5

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/README.md CHANGED
@@ -74,7 +74,7 @@ Each footer entry is one linked `PR #number` plus one plain-language status: `N
74
74
  | No-action state | Report the state without taking action. |
75
75
  | Merge-ready pull request | Ask for final confirmation, recheck fresh state, and squash-merge if confirmed. |
76
76
 
77
- `pi-pr-create` selects its base in this order: the leading `/pr --base BRANCH`, one `branch.<branch>.gh-merge-base` value, then the default branch of validated `origin`. It captures the selected base OID and merge-base. Creation requires at least one committed change ahead. Dirty work alone does not enable creation.
77
+ `pi-pr-create` selects its base in this order: the leading `/pr --base BRANCH`, one `branch.<branch>.gh-merge-base` value, then the default branch of validated `origin`. It captures the selected base OID and merge-base. Creation requires at least one committed change ahead. Dirty work alone does not enable creation. If the current branch is the selected base, pi-pr stays silent because GitHub cannot create a pull request from a ref to itself.
78
78
 
79
79
  The base always comes from validated `origin`. The head may use that repository or a fork with the same GitHub source. Base and head must use the same GitHub host. Other fork relationships stop before mutation.
80
80
 
@@ -107,6 +107,10 @@ export type PullRequestCreationPreflight = {
107
107
  ahead: number;
108
108
  };
109
109
 
110
+ type CreationPreflightResult =
111
+ | { kind: "same-ref" }
112
+ | { kind: "distinct-ref"; preflight: PullRequestCreationPreflight };
113
+
110
114
  type CreationIdentity = {
111
115
  target: PullRequestTarget;
112
116
  head: string;
@@ -1104,19 +1108,18 @@ function parseCreationRepositoryLineage(output: string, expected: PushRepository
1104
1108
  return normalizeRepository(sourceName);
1105
1109
  }
1106
1110
 
1107
- async function assertCreationRepositoryRelation(
1111
+ async function inspectCreationRepositoryRelation(
1108
1112
  pi: Pick<ExtensionAPI, "exec">,
1109
1113
  context: PullRequestLoadContext,
1110
1114
  target: PullRequestTarget,
1111
1115
  origin: { repository: PushRepository },
1112
1116
  baseRef: string,
1113
- ): Promise<void> {
1117
+ ): Promise<"same-ref" | "distinct-ref"> {
1114
1118
  if (target.host !== origin.repository.host) {
1115
1119
  fail("Read creation repository", "base and head hosts do not match");
1116
1120
  }
1117
1121
  if (normalizeRepository(target.repository) === origin.repository.normalizedName) {
1118
- if (target.ref === baseRef) fail("Read creation repository", "head and base refs match");
1119
- return;
1122
+ return target.ref === baseRef ? "same-ref" : "distinct-ref";
1120
1123
  }
1121
1124
  const read = async (repository: PushRepository): Promise<string> => {
1122
1125
  const [owner, name] = repository.nameWithOwner.split("/");
@@ -1133,6 +1136,7 @@ async function assertCreationRepositoryRelation(
1133
1136
  host: target.host,
1134
1137
  });
1135
1138
  if (originSource !== targetSource) fail("Read creation repository", "base and head are unrelated");
1139
+ return "distinct-ref";
1136
1140
  }
1137
1141
 
1138
1142
  function parseCreationAhead(output: string): number {
@@ -1149,7 +1153,7 @@ async function preflightCreation(
1149
1153
  target: PullRequestTarget,
1150
1154
  explicitBaseRef: string | undefined,
1151
1155
  identity: CreationIdentity,
1152
- ): Promise<PullRequestCreationPreflight> {
1156
+ ): Promise<CreationPreflightResult> {
1153
1157
  const validatedTarget = validatedCreationTarget(target);
1154
1158
  if (!sameCreationTarget(identity.target, validatedTarget)) {
1155
1159
  fail("Read creation target", "target changed");
@@ -1160,7 +1164,8 @@ async function preflightCreation(
1160
1164
  ? await readConfiguredCreationBaseRef(pi, context, identity.target.branch)
1161
1165
  : await validateCreationRef(pi, context, explicitBaseRef);
1162
1166
  const baseRef = configuredBaseRef ?? await readDefaultCreationBaseRef(pi, context, origin);
1163
- await assertCreationRepositoryRelation(pi, context, identity.target, origin, baseRef);
1167
+ const relation = await inspectCreationRepositoryRelation(pi, context, identity.target, origin, baseRef);
1168
+ if (relation === "same-ref") return { kind: relation };
1164
1169
  const trackingRef = `refs/remotes/origin/${baseRef}`;
1165
1170
  await execute(pi, context, "Fetch creation base", "git", [
1166
1171
  "fetch", "--no-write-fetch-head", "--no-tags", "--no-recurse-submodules", "--",
@@ -1180,16 +1185,19 @@ async function preflightCreation(
1180
1185
  "rev-list", "--count", `${mergeBase}..${identity.head}`,
1181
1186
  ])).stdout);
1182
1187
  return {
1183
- head: identity.head,
1184
- base: {
1185
- host: origin.repository.host,
1186
- repository: origin.repository.nameWithOwner,
1187
- fetchSource: origin.fetchSource,
1188
- ref: baseRef,
1189
- oid: baseOid,
1190
- mergeBase,
1188
+ kind: relation,
1189
+ preflight: {
1190
+ head: identity.head,
1191
+ base: {
1192
+ host: origin.repository.host,
1193
+ repository: origin.repository.nameWithOwner,
1194
+ fetchSource: origin.fetchSource,
1195
+ ref: baseRef,
1196
+ oid: baseOid,
1197
+ mergeBase,
1198
+ },
1199
+ ahead,
1191
1200
  },
1192
- ahead,
1193
1201
  };
1194
1202
  }
1195
1203
 
@@ -1200,7 +1208,9 @@ export async function preflightPullRequestCreation(
1200
1208
  explicitBaseRef?: string,
1201
1209
  ): Promise<PullRequestCreationPreflight> {
1202
1210
  const identity = await captureCreationIdentity(pi, context, target);
1203
- return await preflightCreation(pi, context, target, explicitBaseRef, identity);
1211
+ const result = await preflightCreation(pi, context, target, explicitBaseRef, identity);
1212
+ if (result.kind === "same-ref") fail("Read creation repository", "head and base refs match");
1213
+ return result.preflight;
1204
1214
  }
1205
1215
 
1206
1216
  async function creationDiscovery(
@@ -1211,8 +1221,12 @@ async function creationDiscovery(
1211
1221
  identity?: CreationIdentity,
1212
1222
  ): Promise<CurrentPullRequestDiscovery> {
1213
1223
  const captured = identity ?? await captureCreationIdentity(pi, context, target);
1214
- const preflight = await preflightCreation(pi, context, target, explicitBaseRef, captured);
1215
- return { kind: "none", creationTarget: target, branch: { ahead: preflight.ahead } };
1224
+ const result = await preflightCreation(pi, context, target, explicitBaseRef, captured);
1225
+ return {
1226
+ kind: "none",
1227
+ creationTarget: target,
1228
+ branch: { ahead: result.kind === "same-ref" ? 0 : result.preflight.ahead },
1229
+ };
1216
1230
  }
1217
1231
 
1218
1232
  async function readRemoteAuthority(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@henryqw/pi-pr",
3
- "version": "4.0.4",
3
+ "version": "4.0.5",
4
4
  "description": "Run /pr to safely discover or link the current pull request, then create, update, address feedback, fix CI, or merge when ready.",
5
5
  "keywords": [
6
6
  "pi-package",