| author | |
| committer | |
| log | 9ea443d73afc72cf9fa617bdc1344e67913e4c63 |
| tree | 6ef41cc03f794a7a26968d9ef8d240d0647a78cb |
| parent | 60f7ae86bbeaa95ebdfeb0fd83edc564119258df |
| signature | Signed by PGP key B5690EEEBB952194 |
4 files changed, 61 insertions(+), 7 deletions(-)
apps/server/src/git/Layers/GitManager.test.ts+11-1| ... | @@ -2739,7 +2739,17 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { | ... | @@ -2739,7 +2739,17 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { |
| 2739 | expect.objectContaining({ | 2739 | expect.objectContaining({ |
| 2740 | kind: "phase_started", | 2740 | kind: "phase_started", |
| 2741 | phase: "pr", | 2741 | phase: "pr", |
| 2742 | label: "Creating PR...", | 2742 | label: "Preparing PR...", |
| 2743 | }), | ||
| 2744 | expect.objectContaining({ | ||
| 2745 | kind: "phase_started", | ||
| 2746 | phase: "pr", | ||
| 2747 | label: "Generating PR content...", | ||
| 2748 | }), | ||
| 2749 | expect.objectContaining({ | ||
| 2750 | kind: "phase_started", | ||
| 2751 | phase: "pr", | ||
| 2752 | label: "Creating GitHub pull request...", | ||
| 2743 | }), | 2753 | }), |
| 2744 | ]); | 2754 | ]); |
| 2745 | }), | 2755 | }), |
apps/server/src/git/Layers/GitManager.ts+16-2| ... | @@ -37,6 +37,7 @@ const STATUS_RESULT_CACHE_TTL = Duration.seconds(1); | ... | @@ -37,6 +37,7 @@ const STATUS_RESULT_CACHE_TTL = Duration.seconds(1); |
| 37 | const STATUS_RESULT_CACHE_CAPACITY = 2_048; | 37 | const STATUS_RESULT_CACHE_CAPACITY = 2_048; |
| 38 | type StripProgressContext<T> = T extends any ? Omit<T, "actionId" | "cwd" | "action"> : never; | 38 | type StripProgressContext<T> = T extends any ? Omit<T, "actionId" | "cwd" | "action"> : never; |
| 39 | type GitActionProgressPayload = StripProgressContext<GitActionProgressEvent>; | 39 | type GitActionProgressPayload = StripProgressContext<GitActionProgressEvent>; |
| 40 | type GitActionProgressEmitter = (event: GitActionProgressPayload) => Effect.Effect<void, never>; | ||
| 40 | 41 | ||
| 41 | interface OpenPrInfo { | 42 | interface OpenPrInfo { |
| 42 | number: number; | 43 | number: number; |
| ... | @@ -1200,6 +1201,7 @@ export const makeGitManager = Effect.fn("makeGitManager")(function* () { | ... | @@ -1200,6 +1201,7 @@ export const makeGitManager = Effect.fn("makeGitManager")(function* () { |
| 1200 | modelSelection: ModelSelection, | 1201 | modelSelection: ModelSelection, |
| 1201 | cwd: string, | 1202 | cwd: string, |
| 1202 | fallbackBranch: string | null, | 1203 | fallbackBranch: string | null, |
| 1204 | emit: GitActionProgressEmitter, | ||
| 1203 | ) { | 1205 | ) { |
| 1204 | const details = yield* gitCore.statusDetails(cwd); | 1206 | const details = yield* gitCore.statusDetails(cwd); |
| 1205 | const branch = details.branch ?? fallbackBranch; | 1207 | const branch = details.branch ?? fallbackBranch; |
| ... | @@ -1234,6 +1236,11 @@ export const makeGitManager = Effect.fn("makeGitManager")(function* () { | ... | @@ -1234,6 +1236,11 @@ export const makeGitManager = Effect.fn("makeGitManager")(function* () { |
| 1234 | } | 1236 | } |
| 1235 | 1237 | ||
| 1236 | const baseBranch = yield* resolveBaseBranch(cwd, branch, details.upstreamRef, headContext); | 1238 | const baseBranch = yield* resolveBaseBranch(cwd, branch, details.upstreamRef, headContext); |
| 1239 | yield* emit({ | ||
| 1240 | kind: "phase_started", | ||
| 1241 | phase: "pr", | ||
| 1242 | label: "Generating PR content...", | ||
| 1243 | }); | ||
| 1237 | const rangeContext = yield* gitCore.readRangeContext(cwd, baseBranch); | 1244 | const rangeContext = yield* gitCore.readRangeContext(cwd, baseBranch); |
| 1238 | 1245 | ||
| 1239 | const generated = yield* textGeneration.generatePrContent({ | 1246 | const generated = yield* textGeneration.generatePrContent({ |
| ... | @@ -1254,6 +1261,11 @@ export const makeGitManager = Effect.fn("makeGitManager")(function* () { | ... | @@ -1254,6 +1261,11 @@ export const makeGitManager = Effect.fn("makeGitManager")(function* () { |
| 1254 | gitManagerError("runPrStep", "Failed to write pull request body temp file.", cause), | 1261 | gitManagerError("runPrStep", "Failed to write pull request body temp file.", cause), |
| 1255 | ), | 1262 | ), |
| 1256 | ); | 1263 | ); |
| 1264 | yield* emit({ | ||
| 1265 | kind: "phase_started", | ||
| 1266 | phase: "pr", | ||
| 1267 | label: "Creating GitHub pull request...", | ||
| 1268 | }); | ||
| 1257 | yield* gitHubCli | 1269 | yield* gitHubCli |
| 1258 | .createPullRequest({ | 1270 | .createPullRequest({ |
| 1259 | cwd, | 1271 | cwd, |
| ... | @@ -1612,11 +1624,13 @@ export const makeGitManager = Effect.fn("makeGitManager")(function* () { | ... | @@ -1612,11 +1624,13 @@ export const makeGitManager = Effect.fn("makeGitManager")(function* () { |
| 1612 | .emit({ | 1624 | .emit({ |
| 1613 | kind: "phase_started", | 1625 | kind: "phase_started", |
| 1614 | phase: "pr", | 1626 | phase: "pr", |
| 1615 | label: "Creating PR...", | 1627 | label: "Preparing PR...", |
| 1616 | }) | 1628 | }) |
| 1617 | .pipe( | 1629 | .pipe( |
| 1618 | Effect.tap(() => Ref.set(currentPhase, Option.some("pr"))), | 1630 | Effect.tap(() => Ref.set(currentPhase, Option.some("pr"))), |
| 1619 | Effect.flatMap(() => runPrStep(modelSelection, input.cwd, currentBranch)), | 1631 | Effect.flatMap(() => |
| 1632 | runPrStep(modelSelection, input.cwd, currentBranch, progress.emit), | ||
| 1633 | ), | ||
| 1620 | ) | 1634 | ) |
| 1621 | : { status: "skipped_not_requested" as const }; | 1635 | : { status: "skipped_not_requested" as const }; |
| 1622 | 1636 |
apps/web/src/components/GitActionsControl.logic.test.ts+27-2| ... | @@ -877,7 +877,12 @@ describe("buildGitActionProgressStages", () => { | ... | @@ -877,7 +877,12 @@ describe("buildGitActionProgressStages", () => { |
| 877 | pushTarget: "origin/feature/test", | 877 | pushTarget: "origin/feature/test", |
| 878 | shouldPushBeforePr: true, | 878 | shouldPushBeforePr: true, |
| 879 | }); | 879 | }); |
| 880 | assert.deepEqual(stages, ["Pushing to origin/feature/test...", "Creating PR..."]); | 880 | assert.deepEqual(stages, [ |
| 881 | "Pushing to origin/feature/test...", | ||
| 882 | "Preparing PR...", | ||
| 883 | "Generating PR content...", | ||
| 884 | "Creating GitHub pull request...", | ||
| 885 | ]); | ||
| 881 | }); | 886 | }); |
| 882 | 887 | ||
| 883 | it("shows only PR progress when create-pr can skip the push", () => { | 888 | it("shows only PR progress when create-pr can skip the push", () => { |
| ... | @@ -887,7 +892,11 @@ describe("buildGitActionProgressStages", () => { | ... | @@ -887,7 +892,11 @@ describe("buildGitActionProgressStages", () => { |
| 887 | hasWorkingTreeChanges: false, | 892 | hasWorkingTreeChanges: false, |
| 888 | shouldPushBeforePr: false, | 893 | shouldPushBeforePr: false, |
| 889 | }); | 894 | }); |
| 890 | assert.deepEqual(stages, ["Creating PR..."]); | 895 | assert.deepEqual(stages, [ |
| 896 | "Preparing PR...", | ||
| 897 | "Generating PR content...", | ||
| 898 | "Creating GitHub pull request...", | ||
| 899 | ]); | ||
| 891 | }); | 900 | }); |
| 892 | 901 | ||
| 893 | it("includes commit stages for commit+push when working tree is dirty", () => { | 902 | it("includes commit stages for commit+push when working tree is dirty", () => { |
| ... | @@ -903,6 +912,22 @@ describe("buildGitActionProgressStages", () => { | ... | @@ -903,6 +912,22 @@ describe("buildGitActionProgressStages", () => { |
| 903 | "Pushing to origin/feature/test...", | 912 | "Pushing to origin/feature/test...", |
| 904 | ]); | 913 | ]); |
| 905 | }); | 914 | }); |
| 915 | |||
| 916 | it("includes granular PR stages for commit+push+PR actions", () => { | ||
| 917 | const stages = buildGitActionProgressStages({ | ||
| 918 | action: "commit_push_pr", | ||
| 919 | hasCustomCommitMessage: true, | ||
| 920 | hasWorkingTreeChanges: true, | ||
| 921 | pushTarget: "origin/feature/test", | ||
| 922 | }); | ||
| 923 | assert.deepEqual(stages, [ | ||
| 924 | "Committing...", | ||
| 925 | "Pushing to origin/feature/test...", | ||
| 926 | "Preparing PR...", | ||
| 927 | "Generating PR content...", | ||
| 928 | "Creating GitHub pull request...", | ||
| 929 | ]); | ||
| 930 | }); | ||
| 906 | }); | 931 | }); |
| 907 | 932 | ||
| 908 | describe("resolveThreadBranchUpdate", () => { | 933 | describe("resolveThreadBranchUpdate", () => { |
apps/web/src/components/GitActionsControl.logic.ts+7-2| ... | @@ -47,12 +47,17 @@ export function buildGitActionProgressStages(input: { | ... | @@ -47,12 +47,17 @@ export function buildGitActionProgressStages(input: { |
| 47 | }): string[] { | 47 | }): string[] { |
| 48 | const branchStages = input.featureBranch ? ["Preparing feature branch..."] : []; | 48 | const branchStages = input.featureBranch ? ["Preparing feature branch..."] : []; |
| 49 | const pushStage = input.pushTarget ? `Pushing to ${input.pushTarget}...` : "Pushing..."; | 49 | const pushStage = input.pushTarget ? `Pushing to ${input.pushTarget}...` : "Pushing..."; |
| 50 | const prStages = [ | ||
| 51 | "Preparing PR...", | ||
| 52 | "Generating PR content...", | ||
| 53 | "Creating GitHub pull request...", | ||
| 54 | ]; | ||
| 50 | 55 | ||
| 51 | if (input.action === "push") { | 56 | if (input.action === "push") { |
| 52 | return [pushStage]; | 57 | return [pushStage]; |
| 53 | } | 58 | } |
| 54 | if (input.action === "create_pr") { | 59 | if (input.action === "create_pr") { |
| 55 | return input.shouldPushBeforePr ? [pushStage, "Creating PR..."] : ["Creating PR..."]; | 60 | return input.shouldPushBeforePr ? [pushStage, ...prStages] : prStages; |
| 56 | } | 61 | } |
| 57 | 62 | ||
| 58 | const shouldIncludeCommitStages = input.action === "commit" || input.hasWorkingTreeChanges; | 63 | const shouldIncludeCommitStages = input.action === "commit" || input.hasWorkingTreeChanges; |
| ... | @@ -67,7 +72,7 @@ export function buildGitActionProgressStages(input: { | ... | @@ -67,7 +72,7 @@ export function buildGitActionProgressStages(input: { |
| 67 | if (input.action === "commit_push") { | 72 | if (input.action === "commit_push") { |
| 68 | return [...branchStages, ...commitStages, pushStage]; | 73 | return [...branchStages, ...commitStages, pushStage]; |
| 69 | } | 74 | } |
| 70 | return [...branchStages, ...commitStages, pushStage, "Creating PR..."]; | 75 | return [...branchStages, ...commitStages, pushStage, ...prStages]; |
| 71 | } | 76 | } |
| 72 | 77 | ||
| 73 | export function buildMenuItems( | 78 | export function buildMenuItems( |