From cffdae0667df4d4981d1685b3f21040d6bc3d6d1 Mon Sep 17 00:00:00 2001 From: qiniu-ci Date: Sun, 10 Aug 2025 10:50:57 +0800 Subject: [PATCH 1/4] =?UTF-8?q?Initial=20plan=20for=20Issue=20#297:=20/con?= =?UTF-8?q?tinue=E5=91=BD=E4=BB=A4=E9=94=99=E8=AF=AF=E6=9B=BF=E6=8D=A2PR?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From dfa7989d3e519f3ec4775cc8058fe375a2df0ef1 Mon Sep 17 00:00:00 2001 From: qiniu-ci Date: Sun, 10 Aug 2025 10:54:42 +0800 Subject: [PATCH 2/4] fix: preserve original PR description in /continue command Modify UpdatePullRequest to support append mode by default through MCP server, preventing /continue commands from replacing existing PR content. Add optional 'replace' parameter for explicit content replacement when needed. - Add UpdatePullRequestWithMode function with append/replace modes - Update MCP server to default to append mode for PR descriptions - Maintain backward compatibility for existing UpdatePullRequest calls - Add 'replace' parameter to update_pr_description MCP tool schema Closes #297 --- internal/github/client.go | 31 +++++++++++++++++++++++-- internal/mcp/servers/github_comments.go | 17 ++++++++++++-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/internal/github/client.go b/internal/github/client.go index fe7b9f8..e3e6864 100644 --- a/internal/github/client.go +++ b/internal/github/client.go @@ -460,8 +460,13 @@ func (c *Client) ReplyToReviewComment(pr *github.PullRequest, commentID int64, c // UpdatePullRequest 更新 PR 的 Body func (c *Client) UpdatePullRequest(pr *github.PullRequest, newBody string) error { + return c.UpdatePullRequestWithMode(pr, newBody, false) +} + +// UpdatePullRequestWithMode 更新 PR 的 Body,支持追加模式 +func (c *Client) UpdatePullRequestWithMode(pr *github.PullRequest, newBody string, appendMode bool) error { prURL := pr.GetHTMLURL() - log.Infof("Updating PR body for URL: %s", prURL) + log.Infof("Updating PR body for URL: %s (append mode: %v)", prURL, appendMode) repoOwner, repoName := c.parseRepoURL(prURL) if repoOwner == "" || repoName == "" { @@ -470,7 +475,28 @@ func (c *Client) UpdatePullRequest(pr *github.PullRequest, newBody string) error log.Infof("Parsed repository: %s/%s, PR number: %d", repoOwner, repoName, pr.GetNumber()) - prRequest := &github.PullRequest{Body: &newBody} + var finalBody string + if appendMode { + // 获取当前PR的最新信息以获取现有的描述 + currentPR, _, err := c.client.PullRequests.Get(context.Background(), repoOwner, repoName, pr.GetNumber()) + if err != nil { + return fmt.Errorf("failed to get current PR: %w", err) + } + + // 构建新的Body:原有内容 + 分隔符 + 新内容 + originalBody := currentPR.GetBody() + if originalBody != "" { + finalBody = originalBody + "\n\n---\n\n" + newBody + } else { + finalBody = newBody + } + log.Infof("Appending to existing PR description") + } else { + finalBody = newBody + log.Infof("Replacing PR description") + } + + prRequest := &github.PullRequest{Body: &finalBody} _, _, err := c.client.PullRequests.Edit(context.Background(), repoOwner, repoName, pr.GetNumber(), prRequest) if err != nil { return fmt.Errorf("failed to update PR body: %w", err) @@ -480,6 +506,7 @@ func (c *Client) UpdatePullRequest(pr *github.PullRequest, newBody string) error return nil } + // GetReviewComments 获取指定 review 的所有 comments func (c *Client) GetReviewComments(pr *github.PullRequest, reviewID int64) ([]*github.PullRequestComment, error) { prURL := pr.GetHTMLURL() diff --git a/internal/mcp/servers/github_comments.go b/internal/mcp/servers/github_comments.go index 1f34344..1b71932 100644 --- a/internal/mcp/servers/github_comments.go +++ b/internal/mcp/servers/github_comments.go @@ -111,6 +111,10 @@ func NewGitHubCommentsServer(client *github.Client) *GitHubCommentsServer { Type: "string", Description: "New PR description/body (Markdown supported)", }, + "replace": { + Type: "boolean", + Description: "Whether to completely replace the existing description (default: false, which means append)", + }, }, Required: []string{"pr_number", "body"}, }, @@ -643,8 +647,17 @@ func (s *GitHubCommentsServer) updatePRDescription(ctx context.Context, call *mo return nil, fmt.Errorf("failed to get PR: %w", err) } - // 更新PR描述 - err = s.client.UpdatePullRequest(pr, body) + // 检查是否需要追加内容(保留原有描述) + // 检查参数中是否指定了replace模式,默认为追加模式以保护原有内容 + appendMode := true + if replaceModeVal, exists := call.Function.Arguments["replace"]; exists { + if replaceModeBool, ok := replaceModeVal.(bool); ok { + appendMode = !replaceModeBool // replace=true 意味着 append=false + } + } + + // 根据模式选择更新或追加 + err = s.client.UpdatePullRequestWithMode(pr, body, appendMode) if err != nil { xl.Errorf("Failed to update PR description: %v", err) return nil, fmt.Errorf("failed to update PR description: %w", err) From 1905b61993ce610dd65248cab28ef0b26e1390d1 Mon Sep 17 00:00:00 2001 From: qiniu-ci Date: Sun, 10 Aug 2025 13:22:43 +0800 Subject: [PATCH 3/4] fix: preserve original PR description for /continue command Modify processPRCommand to only update PR description for /code commands, preventing /continue and /fix commands from replacing existing PR content. These commands now only create comments while preserving original descriptions. - Skip PR description updates for /continue and /fix commands - Maintain PR description updates only for /code commands - Preserve comment creation functionality for all command types - Revert unnecessary changes to low-level GitHub client functions Closes #297 --- internal/github/client.go | 30 +------------- internal/mcp/servers/github_comments.go | 17 +------- internal/modes/tag_handler.go | 55 ++++++++++++++----------- 3 files changed, 35 insertions(+), 67 deletions(-) diff --git a/internal/github/client.go b/internal/github/client.go index e3e6864..3c5e881 100644 --- a/internal/github/client.go +++ b/internal/github/client.go @@ -460,13 +460,8 @@ func (c *Client) ReplyToReviewComment(pr *github.PullRequest, commentID int64, c // UpdatePullRequest 更新 PR 的 Body func (c *Client) UpdatePullRequest(pr *github.PullRequest, newBody string) error { - return c.UpdatePullRequestWithMode(pr, newBody, false) -} - -// UpdatePullRequestWithMode 更新 PR 的 Body,支持追加模式 -func (c *Client) UpdatePullRequestWithMode(pr *github.PullRequest, newBody string, appendMode bool) error { prURL := pr.GetHTMLURL() - log.Infof("Updating PR body for URL: %s (append mode: %v)", prURL, appendMode) + log.Infof("Updating PR body for URL: %s", prURL) repoOwner, repoName := c.parseRepoURL(prURL) if repoOwner == "" || repoName == "" { @@ -475,28 +470,7 @@ func (c *Client) UpdatePullRequestWithMode(pr *github.PullRequest, newBody strin log.Infof("Parsed repository: %s/%s, PR number: %d", repoOwner, repoName, pr.GetNumber()) - var finalBody string - if appendMode { - // 获取当前PR的最新信息以获取现有的描述 - currentPR, _, err := c.client.PullRequests.Get(context.Background(), repoOwner, repoName, pr.GetNumber()) - if err != nil { - return fmt.Errorf("failed to get current PR: %w", err) - } - - // 构建新的Body:原有内容 + 分隔符 + 新内容 - originalBody := currentPR.GetBody() - if originalBody != "" { - finalBody = originalBody + "\n\n---\n\n" + newBody - } else { - finalBody = newBody - } - log.Infof("Appending to existing PR description") - } else { - finalBody = newBody - log.Infof("Replacing PR description") - } - - prRequest := &github.PullRequest{Body: &finalBody} + prRequest := &github.PullRequest{Body: &newBody} _, _, err := c.client.PullRequests.Edit(context.Background(), repoOwner, repoName, pr.GetNumber(), prRequest) if err != nil { return fmt.Errorf("failed to update PR body: %w", err) diff --git a/internal/mcp/servers/github_comments.go b/internal/mcp/servers/github_comments.go index 1b71932..1f34344 100644 --- a/internal/mcp/servers/github_comments.go +++ b/internal/mcp/servers/github_comments.go @@ -111,10 +111,6 @@ func NewGitHubCommentsServer(client *github.Client) *GitHubCommentsServer { Type: "string", Description: "New PR description/body (Markdown supported)", }, - "replace": { - Type: "boolean", - Description: "Whether to completely replace the existing description (default: false, which means append)", - }, }, Required: []string{"pr_number", "body"}, }, @@ -647,17 +643,8 @@ func (s *GitHubCommentsServer) updatePRDescription(ctx context.Context, call *mo return nil, fmt.Errorf("failed to get PR: %w", err) } - // 检查是否需要追加内容(保留原有描述) - // 检查参数中是否指定了replace模式,默认为追加模式以保护原有内容 - appendMode := true - if replaceModeVal, exists := call.Function.Arguments["replace"]; exists { - if replaceModeBool, ok := replaceModeVal.(bool); ok { - appendMode = !replaceModeBool // replace=true 意味着 append=false - } - } - - // 根据模式选择更新或追加 - err = s.client.UpdatePullRequestWithMode(pr, body, appendMode) + // 更新PR描述 + err = s.client.UpdatePullRequest(pr, body) if err != nil { xl.Errorf("Failed to update PR description: %v", err) return nil, fmt.Errorf("failed to update PR description: %w", err) diff --git a/internal/modes/tag_handler.go b/internal/modes/tag_handler.go index 261a048..10a668d 100644 --- a/internal/modes/tag_handler.go +++ b/internal/modes/tag_handler.go @@ -903,31 +903,38 @@ func (th *TagHandler) processPRCommand( xl.Infof("Changes committed and pushed successfully, commit hash: %s", commitHash) } - // 12. 更新PR描述并添加完成评论 - xl.Infof("Updating PR description and adding completion comment") - - // 解析结构化输出用于PR描述 - summary, changes, testPlan := th.parseStructuredOutput(string(output)) - - // 使用新的PR格式化器创建优雅描述 - prFormatter := ctxsys.NewPRFormatter() - prBody := prFormatter.FormatPRDescription( - pr.GetTitle(), - pr.GetBody(), - summary, - changes, - testPlan, - string(output), - pr.GetNumber(), - ) - - // 更新PR描述 - err = th.updatePRWithMCP(ctx, ws, pr, prBody, string(output)) - if err != nil { - xl.Errorf("Failed to update PR description via MCP: %v", err) - // 不返回错误,因为这不是致命的 + // 12. 更新PR描述(仅对/code命令)并添加完成评论 + xl.Infof("Adding completion comment") + + // 只有 /code 命令才更新PR描述,/continue 和 /fix 命令不更新PR描述 + if cmdInfo.Command == models.CommandCode { + xl.Infof("Updating PR description for /code command") + + // 解析结构化输出用于PR描述 + summary, changes, testPlan := th.parseStructuredOutput(string(output)) + + // 使用新的PR格式化器创建优雅描述 + prFormatter := ctxsys.NewPRFormatter() + prBody := prFormatter.FormatPRDescription( + pr.GetTitle(), + pr.GetBody(), + summary, + changes, + testPlan, + string(output), + pr.GetNumber(), + ) + + // 更新PR描述 + err = th.updatePRWithMCP(ctx, ws, pr, prBody, string(output)) + if err != nil { + xl.Errorf("Failed to update PR description via MCP: %v", err) + // 不返回错误,因为这不是致命的 + } else { + xl.Infof("Successfully updated PR description via MCP") + } } else { - xl.Infof("Successfully updated PR description via MCP") + xl.Infof("Skipping PR description update for %s command", cmdInfo.Command) } // 添加简洁的完成评论 From f21b9025869bc77a86a95b3c23d0855d7dcacbfb Mon Sep 17 00:00:00 2001 From: qiniu-ci Date: Sun, 10 Aug 2025 13:28:04 +0800 Subject: [PATCH 4/4] style: format code with go fmt and ensure tests pass Run go fmt on modified files to maintain code quality standards. Remove extra whitespace and ensure proper Go formatting conventions. - Format internal/github/client.go and internal/modes/tag_handler.go - Verify all tests continue to pass after formatting - Maintain consistent code style across the project Closes #297 --- internal/github/client.go | 1 - internal/modes/tag_handler.go | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/github/client.go b/internal/github/client.go index 3c5e881..fe7b9f8 100644 --- a/internal/github/client.go +++ b/internal/github/client.go @@ -480,7 +480,6 @@ func (c *Client) UpdatePullRequest(pr *github.PullRequest, newBody string) error return nil } - // GetReviewComments 获取指定 review 的所有 comments func (c *Client) GetReviewComments(pr *github.PullRequest, reviewID int64) ([]*github.PullRequestComment, error) { prURL := pr.GetHTMLURL() diff --git a/internal/modes/tag_handler.go b/internal/modes/tag_handler.go index 10a668d..cf2168e 100644 --- a/internal/modes/tag_handler.go +++ b/internal/modes/tag_handler.go @@ -909,7 +909,7 @@ func (th *TagHandler) processPRCommand( // 只有 /code 命令才更新PR描述,/continue 和 /fix 命令不更新PR描述 if cmdInfo.Command == models.CommandCode { xl.Infof("Updating PR description for /code command") - + // 解析结构化输出用于PR描述 summary, changes, testPlan := th.parseStructuredOutput(string(output))