From 0e2d50a62082aefb14249b85691cc500d4dd35dc Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Sun, 1 Mar 2026 11:07:27 -0800 Subject: [PATCH] Require ahead commits before offering Create PR on untracked branches - Change quick action to `Push` (not `Push & create PR`) when branch has no upstream and is not ahead - Keep `Create PR` menu item disabled until the branch has commits ahead - Add/adjust logic tests for both no-ahead and ahead scenarios --- .../GitActionsControl.logic.test.ts | 58 +++++++++++++++++-- .../src/components/GitActionsControl.logic.ts | 5 +- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/apps/web/src/components/GitActionsControl.logic.test.ts b/apps/web/src/components/GitActionsControl.logic.test.ts index c725da105a42680b0af4293438e5728952005015..35b5a48e322f048a4b29d65bb39e9f7440cad417 100644 --- a/apps/web/src/components/GitActionsControl.logic.test.ts +++ b/apps/web/src/components/GitActionsControl.logic.test.ts @@ -515,15 +515,15 @@ describe("when: HEAD is detached and there are no local changes", () => { }); describe("when: branch has no upstream configured", () => { - it("resolveQuickAction runs push and create PR when clean, no upstream, and no local commits are ahead", () => { + it("resolveQuickAction runs push when clean, no upstream, and no local commits are ahead", () => { const quick = resolveQuickAction( status({ hasUpstream: false, pr: null, aheadCount: 0 }), false, ); assert.deepInclude(quick, { kind: "run_action", - action: "commit_push_pr", - label: "Push & create PR", + action: "commit_push", + label: "Push", disabled: false, }); }); @@ -576,11 +576,61 @@ describe("when: branch has no upstream configured", () => { }); }); - it("buildMenuItems enables push and create PR to publish branch when no upstream exists", () => { + it("buildMenuItems enables push but keeps create PR disabled when no commits are ahead", () => { const items = buildMenuItems( status({ hasUpstream: false, pr: null, aheadCount: 0 }), false, ); + assert.deepEqual(items, [ + { + id: "commit", + label: "Commit", + disabled: true, + icon: "commit", + kind: "open_dialog", + dialogAction: "commit", + }, + { + id: "push", + label: "Push", + disabled: false, + icon: "push", + kind: "open_dialog", + dialogAction: "push", + }, + { + id: "pr", + label: "Create PR", + disabled: true, + icon: "pr", + kind: "open_dialog", + dialogAction: "create_pr", + }, + ]); + }); + + it("resolveQuickAction runs push and create PR when no upstream and commits are ahead", () => { + const quick = resolveQuickAction( + status({ + hasUpstream: false, + aheadCount: 2, + pr: null, + }), + false, + ); + assert.deepInclude(quick, { + kind: "run_action", + action: "commit_push_pr", + label: "Push & create PR", + disabled: false, + }); + }); + + it("buildMenuItems enables create PR when no upstream and commits are ahead", () => { + const items = buildMenuItems( + status({ hasUpstream: false, pr: null, aheadCount: 2 }), + false, + ); assert.deepEqual(items, [ { id: "commit", diff --git a/apps/web/src/components/GitActionsControl.logic.ts b/apps/web/src/components/GitActionsControl.logic.ts index bebdd2e072bdd75d5e30620c4ad2156dd004cf65..4c669d9d5045b27f7ddb487dd64c64edbcfed72a 100644 --- a/apps/web/src/components/GitActionsControl.logic.ts +++ b/apps/web/src/components/GitActionsControl.logic.ts @@ -124,7 +124,7 @@ export function buildMenuItems( hasBranch && !hasChanges && !hasOpenPr && - (gitStatus.aheadCount > 0 || canPublishUntrackedBranch) && + gitStatus.aheadCount > 0 && !isBehind; const canOpenPr = !isBusy && hasOpenPr; @@ -214,6 +214,9 @@ export function resolveQuickAction( if (hasOpenPr || isDefaultBranch) { return { label: "Push", disabled: false, kind: "run_action", action: "commit_push" }; } + if (!isAhead) { + return { label: "Push", disabled: false, kind: "run_action", action: "commit_push" }; + } return { label: "Push & create PR", disabled: false, -- 2.54.0