Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions github/githubclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ func (c *client) CreatePullRequest(ctx context.Context, gitcmd git.GitInterface,

templatizer := config_fetcher.PRTemplatizer(c.config, gitcmd)

body := templatizer.Body(info, commit)
body := templatizer.Body(info, commit, nil)
resp, err := c.api.CreatePullRequest(ctx, genclient.CreatePullRequestInput{
RepositoryId: info.RepositoryID,
BaseRefName: baseRefName,
Expand All @@ -403,6 +403,7 @@ func (c *client) CreatePullRequest(ctx context.Context, gitcmd git.GitInterface,
ToBranch: baseRefName,
Commit: commit,
Title: commit.Subject,
Body: resp.CreatePullRequest.PullRequest.Body,
MergeStatus: github.PullRequestMergeStatus{
ChecksPass: github.CheckStatusUnknown,
ReviewApproved: false,
Expand Down Expand Up @@ -437,7 +438,7 @@ func (c *client) UpdatePullRequest(ctx context.Context, gitcmd git.GitInterface,

templatizer := config_fetcher.PRTemplatizer(c.config, gitcmd)
title := templatizer.Title(info, commit)
body := templatizer.Body(info, commit)
body := templatizer.Body(info, commit, pr)
input := genclient.UpdatePullRequestInput{
PullRequestId: pr.ID,
Title: &title,
Expand Down
18 changes: 9 additions & 9 deletions github/githubclient/gen/genclient/client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 11 additions & 9 deletions github/githubclient/gen/genclient/operations.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions github/githubclient/queries.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ mutation CreatePullRequest(
pullRequest {
id
number
body
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion github/template/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ import (

type PRTemplatizer interface {
Title(info *github.GitHubInfo, commit git.Commit) string
Body(info *github.GitHubInfo, commit git.Commit) string
Body(info *github.GitHubInfo, commit git.Commit, pr *github.PullRequest) string
}
2 changes: 1 addition & 1 deletion github/template/template_basic/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func (t *BasicTemplatizer) Title(info *github.GitHubInfo, commit git.Commit) str
return commit.Subject
}

func (t *BasicTemplatizer) Body(info *github.GitHubInfo, commit git.Commit) string {
func (t *BasicTemplatizer) Body(info *github.GitHubInfo, commit git.Commit, pr *github.PullRequest) string {
body := commit.Body
body += "\n\n"
body += template.ManualMergeNotice()
Expand Down
8 changes: 4 additions & 4 deletions github/template/template_basic/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ func TestBody(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := templatizer.Body(info, tt.commit)
got := templatizer.Body(info, tt.commit, nil)

// Verify all expected strings are present
for _, wantStr := range tt.wantContains {
Expand Down Expand Up @@ -229,7 +229,7 @@ func TestBodyManualMergeNoticeFormat(t *testing.T) {
Body: "Test body",
}

result := templatizer.Body(info, commit)
result := templatizer.Body(info, commit, nil)

// Verify the exact format of the manual merge notice
expectedNotice := "⚠️ *Part of a stack created by [spr](https://github.com/ejoffe/spr). Do not merge manually using the UI - doing so may have unexpected results.*"
Expand Down Expand Up @@ -280,7 +280,7 @@ func TestBodyPreservesOriginalContent(t *testing.T) {
Body: tc.body,
}

result := templatizer.Body(info, commit)
result := templatizer.Body(info, commit, nil)

// The result should contain the original body (if not empty)
if tc.body != "" {
Expand Down Expand Up @@ -349,7 +349,7 @@ Performance improvements:

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := templatizer.Body(info, tt.commit)
result := templatizer.Body(info, tt.commit, nil)

// Should contain the original body content
assert.Contains(t, result, tt.commit.Body)
Expand Down
91 changes: 88 additions & 3 deletions github/template/template_custom/template.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package template_custom

import (
"bufio"
"errors"
"fmt"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
Expand Down Expand Up @@ -34,21 +36,104 @@ func (t *CustomTemplatizer) Title(info *github.GitHubInfo, commit git.Commit) st
return commit.Subject
}

func (t *CustomTemplatizer) Body(info *github.GitHubInfo, commit git.Commit) string {
func (t *CustomTemplatizer) Body(info *github.GitHubInfo, commit git.Commit, pr *github.PullRequest) string {
body := t.formatBody(commit, info.PullRequests)
pullRequestTemplate, err := t.readPRTemplate()
if err != nil {
log.Fatal().Err(err).Msg("failed to read PR template")
}
body, err = t.insertBodyIntoPRTemplate(body, pullRequestTemplate, nil)
body, err = t.insertBodyIntoPRTemplate(body, pullRequestTemplate, pr)
if err != nil {
log.Fatal().Err(err).Msg("failed to insert body into PR template")
}

// Open editor for user to edit the PR content only when creating a new PR (pr == nil)
if pr != nil {
return body
}

if !promptUserToEdit(commit) {
return body
}

body, err = EditWithEditor(body)
if err != nil {
log.Fatal().Err(err).Msg("failed to edit PR content with editor")
}

return body
}

func (t *CustomTemplatizer) formatBody(commit git.Commit, stack []*github.PullRequest) string {
// promptUserToEdit prompts the user if they want to edit the PR content in their editor
func promptUserToEdit(commit git.Commit) bool {
scanner := bufio.NewScanner(os.Stdin)
for {
fmt.Println()
fmt.Println("New PR for:")
fmt.Printf(" %s: %s\n", commit.CommitHash[:7], commit.Subject)
fmt.Println()
fmt.Print("Edit PR content? [Y/n]: ")
if !scanner.Scan() {
// On error or EOF, default to editing
return true
}
input := strings.ToLower(strings.TrimSpace(scanner.Text()))
switch input {
case "y", "yes":
return true
case "n", "no":
return false
case "":
// Empty input defaults to yes
return true
default:
// Invalid input, ask again
continue
}
}
}

// EditWithEditor opens the default editor to allow the user to edit the provided content.
func EditWithEditor(initialContent string) (string, error) {
editor := os.Getenv("EDITOR")
if editor == "" {
editor = "vi"
}

// Create temporary file to hold the content
tmpFile, err := os.CreateTemp("", "spr-pr-*.md")
if err != nil {
return "", fmt.Errorf("failed to create temporary file: %w", err)
}
defer os.Remove(tmpFile.Name())

// Write initial content to temporary file
if _, err := tmpFile.WriteString(initialContent); err != nil {
tmpFile.Close()
return "", fmt.Errorf("failed to write to temporary file: %w", err)
}
tmpFile.Close()

// Open editor
cmd := exec.Command(editor, tmpFile.Name())
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

if err := cmd.Run(); err != nil {
return "", fmt.Errorf("editor command failed: %w", err)
}

// Read edited content from temporary file
editedBytes, err := os.ReadFile(tmpFile.Name())
if err != nil {
return "", fmt.Errorf("failed to read edited content: %w", err)
}

return string(editedBytes), nil
}

func (t *CustomTemplatizer) formatBody(commit git.Commit, stack []*github.PullRequest) string {
if len(stack) <= 1 {
return strings.TrimSpace(commit.Body)
}
Expand Down
2 changes: 1 addition & 1 deletion github/template/template_stack/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func (t *StackTemplatizer) Title(info *github.GitHubInfo, commit git.Commit) str
return commit.Subject
}

func (t *StackTemplatizer) Body(info *github.GitHubInfo, commit git.Commit) string {
func (t *StackTemplatizer) Body(info *github.GitHubInfo, commit git.Commit, pr *github.PullRequest) string {
body := commit.Body

// Always show stack section and notice
Expand Down
Loading
Loading