Skip to content

Comments

feat(git): auto-append issue closing keywords to PR body#1044

Open
rabanspiegel wants to merge 4 commits intomainfrom
emdash/linear-5mc
Open

feat(git): auto-append issue closing keywords to PR body#1044
rabanspiegel wants to merge 4 commits intomainfrom
emdash/linear-5mc

Conversation

@rabanspiegel
Copy link
Contributor

@rabanspiegel rabanspiegel commented Feb 23, 2026

Summary

  • Adds injectIssueFooter utility that appends Fixes #<number> / Fixes <LINEAR-ID> lines to PR descriptions based on linked GitHub and Linear issue metadata stored on the task
  • Integrates the footer into both git:create-pr and git:merge-to-main IPC handlers so PRs automatically reference their source issues
  • Footer is wrapped in HTML comment markers for idempotent injection (re-injecting strips the old block first)

Changes

  • src/main/lib/prIssueFooter.ts (new): Standalone utility with injectIssueFooter(body, metadata) that builds a marker-delimited footer block from task metadata
  • src/main/ipc/gitIpc.ts:
    • git:create-pr handler now looks up the task by path and enriches the PR body with issue footer before submission
    • git:merge-to-main handler now creates a --body-file with the issue footer instead of using bare --fill, using execFileAsync for safer argument handling
  • src/test/main/prIssueFooter.test.ts (new): Tests covering appending, idempotency, stale replacement, and cleanup

Test plan

  • Run pnpm exec vitest run src/test/main/prIssueFooter.test.ts to verify footer logic
  • Create a task linked to a GitHub issue and/or Linear issue, then create a PR — verify the body contains Fixes #<number>
  • Create a PR via merge-to-main flow with a linked issue — verify footer is present
  • Re-generate PR content on an existing PR body that already has the footer — verify no duplication

Note

Medium Risk
Touches PR creation/merge automation and GitHub CLI invocation paths; mistakes could result in incorrect PR bodies or failed PR creation/edits, but changes are mostly additive with fallback/error handling and tests for new logic.

Overview
PR creation and merge-to-main flows now automatically enrich PR descriptions with issue-closing footers derived from task metadata (GitHub issue number and/or Linear identifier), using a marker-delimited block to stay idempotent.

git:create-pr now decides between --body-file, --fill, or post-create patching via a new getCreatePrBodyPlan, and when --fill is used without an explicit body it follows up with gh pr edit to append only the footer while preserving the filled body. git:merge-to-main similarly patches the existing/created PR body after gh pr create --fill, switching to execFile argument invocation for PR creation and adding best-effort footer patching.

Written by Cursor Bugbot for commit 16046d0. This will update automatically on new commits. Configure here.

@vercel
Copy link

vercel bot commented Feb 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment Feb 23, 2026 6:53am

Request Review

@greptile-apps
Copy link

greptile-apps bot commented Feb 23, 2026

Greptile Summary

Adds an injectIssueFooter utility that appends Fixes #<number> / Fixes <LINEAR-ID> lines (wrapped in HTML comment markers for idempotency) to PR descriptions based on linked issue metadata stored on the task. The utility is integrated into both git:create-pr and git:merge-to-main IPC handlers.

  • The new prIssueFooter.ts utility is well-designed: idempotent injection, stale-footer replacement, defensive type handling, and clean edge-case behavior. Test coverage is thorough.
  • The git:create-pr integration is clean — it enriches the user-provided body before submission and gracefully falls back on errors.
  • Issue: In git:merge-to-main, combining --fill with --body-file causes gh CLI to use the body-file content instead of the commit-message body that --fill would generate. This means the PR body will only contain the issue footer (e.g., Fixes #42) and lose the commit-message description.
  • The switch from execAsync to execFileAsync in the merge-to-main PR creation path is a good security improvement (avoids shell interpolation).

Confidence Score: 3/5

  • Mostly safe, but the merge-to-main flow has a behavioral regression where commit-message body content is silently dropped.
  • The core utility (prIssueFooter.ts) is solid and well-tested. The create-pr integration is clean. However, the merge-to-main handler has a logic issue where --fill + --body-file causes the commit-message-derived body to be replaced by just the issue footer, which is a user-visible behavioral regression. This isn't a crash or data-loss issue but will produce lower-quality PR descriptions for the merge-to-main flow.
  • Pay close attention to src/main/ipc/gitIpc.ts — specifically the git:merge-to-main handler's interaction between --fill and --body-file flags.

Important Files Changed

Filename Overview
src/main/ipc/gitIpc.ts Integrates injectIssueFooter into git:create-pr and git:merge-to-main handlers. The create-pr integration is clean, but the merge-to-main flow has a behavioral regression: combining --fill with --body-file causes commit-message body content to be dropped in favor of the footer-only content.
src/main/lib/prIssueFooter.ts Well-structured utility with idempotent injection using HTML comment markers. Handles edge cases (undefined body, stale footer replacement, deduplication) correctly. Type narrowing from unknown metadata is defensive and appropriate.
src/test/main/prIssueFooter.test.ts Good test coverage for the footer utility: appending, idempotency, stale replacement, cleanup, and undefined returns. Tests are clear and focused.

Sequence Diagram

sequenceDiagram
    participant Renderer
    participant gitIpc as gitIpc.ts
    participant DB as DatabaseService
    participant Footer as prIssueFooter
    participant GH as gh CLI

    Note over Renderer,GH: git:create-pr flow
    Renderer->>gitIpc: create-pr(taskPath, body, ...)
    gitIpc->>DB: getTaskByPath(taskPath)
    DB-->>gitIpc: task (with metadata)
    gitIpc->>Footer: injectIssueFooter(body, task.metadata)
    Footer-->>gitIpc: enriched prBody
    gitIpc->>GH: gh pr create --body-file <prBody>
    GH-->>gitIpc: PR URL

    Note over Renderer,GH: git:merge-to-main flow
    Renderer->>gitIpc: merge-to-main(taskPath)
    gitIpc->>DB: getTaskByPath(taskPath)
    DB-->>gitIpc: task (with metadata)
    gitIpc->>Footer: injectIssueFooter(undefined, task.metadata)
    Footer-->>gitIpc: footerBody (footer only)
    gitIpc->>GH: gh pr create --fill --body-file <footerBody>
    Note right of GH: ⚠️ --body-file overrides --fill body
    GH-->>gitIpc: PR URL
    gitIpc->>GH: gh pr merge --merge
    GH-->>gitIpc: merged
Loading

Last reviewed commit: 0bcc89f

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines 1251 to 1254
const prCreateArgs = ['pr', 'create', '--fill', '--base', defaultBranch];
if (bodyFile) {
prCreateArgs.push('--body-file', bodyFile);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--fill body overridden by --body-file

When --fill is combined with --body-file, the gh CLI uses the commit subject for the title but takes the body exclusively from --body-file, discarding the commit-message body that --fill would have generated. Since footerBody here is only the issue-closing footer (e.g. just Fixes #42), the PR body will lose the commit-message content that --fill previously provided.

Consider reading the --fill-generated body first (e.g. via git log --format=%b) and prepending it to the footer, or appending the footer to the fill-generated content:

Suggested change
const prCreateArgs = ['pr', 'create', '--fill', '--base', defaultBranch];
if (bodyFile) {
prCreateArgs.push('--body-file', bodyFile);
}
const prCreateArgs = ['pr', 'create', '--fill', '--base', defaultBranch];
if (bodyFile) {
prCreateArgs.push('--body-file', bodyFile);
// Note: --body-file overrides --fill's body; title still auto-fills from commits
}

}
editArgs.push('--body-file', editBodyFile);
await execFileAsync('gh', editArgs, { cwd: taskPath });
outputs.push('gh pr edit --body-file: success');
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead outputs.push after out already computed

Low Severity

outputs.push('gh pr edit --body-file: success') executes after out has already been computed from the outputs array at the earlier line. The returned output field in the success response is built from out, so this edit-success message is never visible to the caller — it's effectively dead code.

Additional Locations (1)

Fix in Cursor Fix in Web

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant