Skip to content
30 changes: 30 additions & 0 deletions apps/web/src/components/GitActionsControl.logic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,36 @@ describe("when: on default ref without open PR", () => {
});
});

describe("when: local changes are behind upstream", () => {
it("keeps the commit action available without pushing, with or without an open PR", () => {
const behind = status({ hasWorkingTreeChanges: true, behindCount: 2 });
const commit = {
label: "Commit",
disabled: false,
kind: "run_action",
action: "commit",
} as const;
assert.deepEqual(resolveQuickAction(behind, false), commit);
assert.deepEqual(
resolveQuickAction(
{
...behind,
pr: {
number: 13,
title: "Open PR",
url: "https://example.com/pr/13",
baseRef: "main",
headRef: "feature/test",
state: "open",
},
},
false,
),
commit,
);
});
});

describe("when: ref has no upstream configured", () => {
it("resolveQuickAction runs push and create PR when no upstream and commits are ahead", () => {
const quick = resolveQuickAction(
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/components/GitActionsControl.logic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ export function resolveQuickAction(
}

if (hasChanges) {
if (!gitStatus.hasUpstream && !hasPrimaryRemote) {
if (isBehind || (!gitStatus.hasUpstream && !hasPrimaryRemote)) {
return { label: "Commit", disabled: false, kind: "run_action", action: "commit" };
}
if (hasOpenPr || isDefaultRef) {
Expand Down
2 changes: 1 addition & 1 deletion packages/client-runtime/src/state/gitActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export function resolveQuickAction(
}

if (hasChanges) {
if (!gitStatus.hasUpstream && !hasOriginRemote) {
if (isBehind || (!gitStatus.hasUpstream && !hasOriginRemote)) {
return { label: "Commit", disabled: false, kind: "run_action", action: "commit" };
}
if (hasOpenPr || isDefaultBranch) {
Expand Down
46 changes: 46 additions & 0 deletions packages/client-runtime/src/state/vcs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
WS_METHODS,
VcsProcessExitError,
type VcsListRefsResult,
type VcsStatusResult,
} from "@t3tools/contracts";
import { describe, expect, it } from "@effect/vitest";
import * as Deferred from "effect/Deferred";
Expand Down Expand Up @@ -37,6 +38,7 @@ import {
commitVcsRefsRefresh,
createVcsEnvironmentAtoms,
makeCachedVcsRefsChanges,
resolveQuickAction,
} from "./vcs.ts";
import {
invalidateCachedVcsRefs,
Expand Down Expand Up @@ -617,3 +619,47 @@ const grantedSessions = Atom.family((_id: EnvironmentId) =>
}),
),
);

function status(overrides: Partial<VcsStatusResult> = {}): VcsStatusResult {
return {
isRepo: true,
hasPrimaryRemote: true,
isDefaultRef: false,
refName: "feature/test",
hasWorkingTreeChanges: false,
workingTree: {
files: [],
insertions: 0,
deletions: 0,
},
hasUpstream: true,
aheadCount: 0,
behindCount: 0,
pr: null,
...overrides,
};
}

describe("resolveQuickAction", () => {
it("commits local changes without pushing when the branch is behind upstream", () => {
const behind = status({ hasWorkingTreeChanges: true, behindCount: 2 });
const commit = { label: "Commit", disabled: false, kind: "run_action", action: "commit" };
expect(resolveQuickAction(behind, false)).toEqual(commit);
expect(
resolveQuickAction(
{
...behind,
pr: {
number: 13,
title: "Open PR",
url: "https://example.com/pr/13",
baseRef: "main",
headRef: "feature/test",
state: "open",
},
},
false,
),
).toEqual(commit);
});
});
Loading