Skip to content

Commit 32723ae

Browse files
Merge pull request #113 from Emanuele-web04/dpcode/create-pr-availability-guard
Guard unavailable create PR actions
2 parents 94551c2 + 97b62d6 commit 32723ae

3 files changed

Lines changed: 98 additions & 7 deletions

File tree

apps/web/src/components/GitActionsControl.logic.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
requiresFeatureBranchForDefaultBranchAction,
77
requiresDefaultBranchConfirmation,
88
resolveAutoFeatureBranchName,
9+
resolveCreatePrActionAvailability,
910
resolveDefaultCreateBranchName,
1011
resolveDefaultBranchActionDialogCopy,
1112
resolveLiveThreadBranchUpdate,
@@ -322,6 +323,42 @@ describe("when: branch is clean, up to date, and has no open PR", () => {
322323
});
323324
});
324325

326+
it("resolveCreatePrActionAvailability blocks stale create-pr calls for default upstream", () => {
327+
const availability = resolveCreatePrActionAvailability({
328+
gitStatus: status({
329+
branch: "dpcode/pi-cleanup",
330+
upstreamBranch: "main",
331+
aheadCount: 0,
332+
behindCount: 0,
333+
pr: null,
334+
}),
335+
defaultBranchName: "main",
336+
});
337+
338+
assert.deepEqual(availability, {
339+
canRun: false,
340+
hint: "No branch changes to include in a PR.",
341+
});
342+
});
343+
344+
it("resolveCreatePrActionAvailability allows clean published feature branches", () => {
345+
const availability = resolveCreatePrActionAvailability({
346+
gitStatus: status({
347+
branch: "feature/test",
348+
upstreamBranch: "feature/test",
349+
aheadCount: 0,
350+
behindCount: 0,
351+
pr: null,
352+
}),
353+
defaultBranchName: "main",
354+
});
355+
356+
assert.deepEqual(availability, {
357+
canRun: true,
358+
hint: null,
359+
});
360+
});
361+
325362
it("buildMenuItems disables create PR when the branch tracks the default branch", () => {
326363
const items = buildMenuItems(
327364
status({

apps/web/src/components/GitActionsControl.logic.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export interface GitQuickAction {
2727
}
2828

2929
const FALLBACK_DEFAULT_BRANCH_NAMES = new Set(["main", "master"]);
30+
const CREATE_PR_UNAVAILABLE_HINT = "No branch changes to include in a PR.";
3031

3132
export interface DefaultBranchActionDialogCopy {
3233
title: string;
@@ -395,7 +396,7 @@ export function resolveQuickAction(
395396
label: "Create PR",
396397
disabled: true,
397398
kind: "show_hint",
398-
hint: "No branch changes to include in a PR.",
399+
hint: CREATE_PR_UNAVAILABLE_HINT,
399400
};
400401
}
401402

@@ -404,7 +405,7 @@ export function resolveQuickAction(
404405
label: "Create PR",
405406
disabled: true,
406407
kind: "show_hint",
407-
hint: "No branch changes to include in a PR.",
408+
hint: CREATE_PR_UNAVAILABLE_HINT,
408409
};
409410
}
410411

@@ -425,6 +426,32 @@ export function resolveQuickAction(
425426
};
426427
}
427428

429+
export function resolveCreatePrActionAvailability(input: {
430+
gitStatus: GitStatusResult | null;
431+
isDefaultBranch?: boolean;
432+
hasOriginRemote?: boolean;
433+
defaultBranchName?: string | null;
434+
}): { canRun: boolean; hint: string | null } {
435+
const quickAction = resolveQuickAction(
436+
input.gitStatus,
437+
false,
438+
input.isDefaultBranch ?? false,
439+
input.hasOriginRemote ?? true,
440+
false,
441+
input.defaultBranchName,
442+
);
443+
444+
const canRun =
445+
quickAction.kind === "run_action" &&
446+
quickAction.action === "create_pr" &&
447+
!quickAction.disabled;
448+
449+
return {
450+
canRun,
451+
hint: canRun ? null : (quickAction.hint ?? CREATE_PR_UNAVAILABLE_HINT),
452+
};
453+
}
454+
428455
export function shouldOfferCreateBranchPrompt(input: {
429456
activeWorktreePath: string | null;
430457
gitStatus: Pick<GitStatusResult, "branch" | "hasUpstream"> | null;

apps/web/src/components/GitActionsControl.tsx

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
resolveLiveThreadBranchUpdate,
3131
resolveDefaultCreateBranchName,
3232
resolveDefaultBranchActionDialogCopy,
33+
resolveCreatePrActionAvailability,
3334
resolveQuickAction,
3435
shouldOfferCreateBranchPrompt,
3536
summarizeGitResult,
@@ -653,6 +654,23 @@ export default function GitActionsControl({
653654
});
654655
return;
655656
}
657+
if (action === "create_pr" && !featureBranch) {
658+
const createPrAvailability = resolveCreatePrActionAvailability({
659+
gitStatus: actionStatus,
660+
isDefaultBranch: actionIsDefaultBranch,
661+
hasOriginRemote,
662+
defaultBranchName,
663+
});
664+
if (!createPrAvailability.canRun) {
665+
toastManager.add({
666+
type: "info",
667+
title: "Create PR unavailable",
668+
description: createPrAvailability.hint ?? "No branch changes to include in a PR.",
669+
data: threadToastData,
670+
});
671+
return;
672+
}
673+
}
656674
onConfirmed?.();
657675

658676
const progressStages = buildGitActionProgressStages({
@@ -743,18 +761,27 @@ export default function GitActionsControl({
743761
(!actionIsDefaultBranch ||
744762
result.pr.status === "created" ||
745763
result.pr.status === "opened_existing");
746-
const shouldOfferCreatePrCta =
747-
(action === "push" || action === "commit_push") &&
748-
!prUrl &&
749-
result.push.status === "pushed" &&
750-
!actionIsDefaultBranch;
751764
const postPushStatus = actionStatus
752765
? {
753766
...actionStatus,
754767
hasUpstream: true,
768+
upstreamBranch:
769+
actionStatus.upstreamBranch ??
770+
(!actionStatus.hasUpstream ? (result.push.branch ?? actionStatus.branch) : null),
755771
aheadCount: 0,
756772
}
757773
: null;
774+
const shouldOfferCreatePrCta =
775+
(action === "push" || action === "commit_push") &&
776+
!prUrl &&
777+
result.push.status === "pushed" &&
778+
!actionIsDefaultBranch &&
779+
resolveCreatePrActionAvailability({
780+
gitStatus: postPushStatus,
781+
isDefaultBranch: actionIsDefaultBranch,
782+
hasOriginRemote,
783+
defaultBranchName,
784+
}).canRun;
758785
const closeResultToast = () => {
759786
toastManager.close(resolvedProgressToastId);
760787
};

0 commit comments

Comments
 (0)