- Add a Git action confirmation modal with live commit/push/PR progress states - Accept optional `commitMessage` input and skip AI message generation when provided - Expand server and contracts tests for custom commit message handling
Showing the changes to apps/server/src/gitManager.ts (1 of 5 files). Show all
Unified · Split
| @@ -106,6 +106,24 @@ function sanitizeCommitMessage( · 105 unmodified lines | |||
| 106 | }; | 106 | }; |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | function parseCustomCommitMessage(raw: string): CommitMessageGenerationResult | null { | ||
| 110 | const normalized = raw.replace(/\r\n/g, "\n").trim(); | ||
| 111 | if (normalized.length === 0) { | ||
| 112 | return null; | ||
| 113 | } | ||
| 114 | |||
| 115 | const [firstLine, ...rest] = normalized.split("\n"); | ||
| 116 | const subject = firstLine?.trim() ?? ""; | ||
| 117 | if (subject.length === 0) { | ||
| 118 | return null; | ||
| 119 | } | ||
| 120 | |||
| 121 | return { | ||
| 122 | subject, | ||
| 123 | body: rest.join("\n").trim(), | ||
| 124 | }; | ||
| 125 | } | ||
| 126 | |||
| 109 | function extractBranchFromRef(ref: string): string { | 127 | function extractBranchFromRef(ref: string): string { |
| 110 | const normalized = ref.trim(); | 128 | const normalized = ref.trim(); |
| 111 | 129 | ||
| @@ -222,7 +240,11 @@ export class GitManager { · 110 unmodified lines | |||
| 222 | throw new Error("Cannot create a pull request from detached HEAD."); | 240 | throw new Error("Cannot create a pull request from detached HEAD."); |
| 223 | } | 241 | } |
| 224 | 242 | ||
| 225 | const commit = await this.runCommitStep(input.cwd, initialStatus.branch); | 243 | const commit = await this.runCommitStep( |
| 244 | input.cwd, | ||
| 245 | initialStatus.branch, | ||
| 246 | input.commitMessage, | ||
| 247 | ); | ||
| 226 | 248 | ||
| 227 | const push = wantsPush | 249 | const push = wantsPush |
| 228 | ? await this.gitCore.pushCurrentBranch(input.cwd, initialStatus.branch) | 250 | ? await this.gitCore.pushCurrentBranch(input.cwd, initialStatus.branch) |
| @@ -243,6 +265,7 @@ export class GitManager { · 14 unmodified lines | |||
| 243 | private async runCommitStep( | 265 | private async runCommitStep( |
| 244 | cwd: string, | 266 | cwd: string, |
| 245 | branch: string | null, | 267 | branch: string | null, |
| 268 | commitMessage?: string, | ||
| 246 | ): Promise<{ | 269 | ): Promise<{ |
| 247 | status: "created" | "skipped_no_changes"; | 270 | status: "created" | "skipped_no_changes"; |
| 248 | commitSha?: string | undefined; | 271 | commitSha?: string | undefined; |
| @@ -253,18 +276,23 @@ export class GitManager { · 4 unmodified lines | |||
| 253 | return { status: "skipped_no_changes" }; | 276 | return { status: "skipped_no_changes" }; |
| 254 | } | 277 | } |
| 255 | 278 | ||
| 256 | let generated: CommitMessageGenerationResult; | 279 | let generated: CommitMessageGenerationResult | null = parseCustomCommitMessage( |
| 257 | try { | 280 | commitMessage ?? "", |
| 258 | generated = sanitizeCommitMessage( | 281 | ); |
| 259 | await this.textGenerator.generateCommitMessage({ | 282 | |
| 260 | cwd, | 283 | if (!generated) { |
| 261 | branch, | 284 | try { |
| 262 | stagedSummary: limitContext(context.stagedSummary, 8_000), | 285 | generated = sanitizeCommitMessage( |
| 263 | stagedPatch: limitContext(context.stagedPatch, 50_000), | 286 | await this.textGenerator.generateCommitMessage({ |
| 264 | }), | 287 | cwd, |
| 265 | ); | 288 | branch, |
| 266 | } catch (error) { | 289 | stagedSummary: limitContext(context.stagedSummary, 8_000), |
| 267 | throw asCommandNotFound("codex", error) ?? error; | 290 | stagedPatch: limitContext(context.stagedPatch, 50_000), |
| 291 | }), | ||
| 292 | ); | ||
| 293 | } catch (error) { | ||
| 294 | throw asCommandNotFound("codex", error) ?? error; | ||
| 295 | } | ||
| 268 | } | 296 | } |
| 269 | 297 | ||
| 270 | const { commitSha } = await this.gitCore.commit(cwd, generated.subject, generated.body); | 298 | const { commitSha } = await this.gitCore.commit(cwd, generated.subject, generated.body); |