From be837d4f8eb01a4d8b3de7874c65e72e2ff8d7eb Mon Sep 17 00:00:00 2001 From: Donkey_kevin <2930705585@qq.com> Date: Mon, 15 Jun 2026 19:21:42 +0800 Subject: [PATCH] Improve onboard template: per-issue content-aware welcome comments - fetchIssueDetail now gets both subject and description - renderComment substitutes {subject}, {description}, {number}, {login} - defaultTemplate includes issue summary for targeted guidance - dry-run preview shows the full rendered comment Co-Authored-By: Claude Opus 4.6 --- shortcuts/onboard/onboarding.go | 76 +++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 22 deletions(-) diff --git a/shortcuts/onboard/onboarding.go b/shortcuts/onboard/onboarding.go index 30f5ef9..2b362eb 100644 --- a/shortcuts/onboard/onboarding.go +++ b/shortcuts/onboard/onboarding.go @@ -25,7 +25,7 @@ func Shortcuts() []*common.Shortcut { Flags: []common.Flag{ {Name: "issues", Short: "i", Usage: "Comma-separated issue numbers (e.g. 1,3,7)"}, {Name: "tag", Short: "t", Usage: "Tag name to match (comma-separated)", Default: "good first issue,help wanted"}, - {Name: "template", Usage: "Custom welcome message template (use {login} for @mention)"}, + {Name: "template", Usage: "Custom welcome message template ({login}, {number}, {subject}, {description})"}, }, DryRun: true, DryRunHint: dryRunHint, @@ -96,11 +96,11 @@ func runWelcomeByIssueNumbers(ctx *common.RuntimeContext, issueArg string) error var issues []issueInfo for _, num := range issueNums { - subject, err := fetchIssueSubject(ctx, num) + info, err := fetchIssueDetail(ctx, num) if err != nil { return fmt.Errorf("获取 issue #%d 失败: %w", num, err) } - issues = append(issues, issueInfo{number: num, subject: subject}) + issues = append(issues, info) } return processIssues(ctx, issues) @@ -127,18 +127,20 @@ func parseIssueNumbers(s string) ([]int, error) { return nums, nil } -// fetchIssueSubject fetches a single issue's subject by number. -func fetchIssueSubject(ctx *common.RuntimeContext, issueNumber int) (string, error) { +// fetchIssueDetail fetches a single issue's subject and description by number. +func fetchIssueDetail(ctx *common.RuntimeContext, issueNumber int) (issueInfo, error) { path := fmt.Sprintf("/v1/%s/%s/issues/%d", ctx.Owner, ctx.Repo, issueNumber) env, err := ctx.CallAPIWithQuery("GET", path, nil) if err != nil { - return "", err + return issueInfo{}, err } data, _ := env.Data.(map[string]interface{}) - if subj := getString(data, "subject"); subj != "" { - return subj, nil + subj := getString(data, "subject") + if subj == "" { + subj = fmt.Sprintf("issue #%d", issueNumber) } - return fmt.Sprintf("issue #%d", issueNumber), nil + desc := getString(data, "description") + return issueInfo{number: issueNumber, subject: subj, description: desc}, nil } // processIssues handles the common issue processing loop used by both @@ -146,7 +148,7 @@ func fetchIssueSubject(ctx *common.RuntimeContext, issueNumber int) (string, err func processIssues(ctx *common.RuntimeContext, issues []issueInfo) error { tmpl := ctx.Arg("template") if tmpl == "" { - tmpl = defaultTemplate(ctx.Owner, ctx.Repo) + tmpl = "" } type result struct { @@ -162,7 +164,11 @@ func processIssues(ctx *common.RuntimeContext, issues []issueInfo) error { continue } + // Render per-issue message with issue-specific variables. + body := renderComment(ctx, issue, tmpl) + if ctx.IsDryRun() { + fmt.Printf("\n--- 预览 #%d \"%s\" ---\n%s\n---\n", issue.number, issue.subject, body) proceed, err := common.ConfirmAction(ctx) if err != nil { return err @@ -173,7 +179,7 @@ func processIssues(ctx *common.RuntimeContext, issues []issueInfo) error { } } - if err := addComment(ctx, issue.number, tmpl); err != nil { + if err := addComment(ctx, issue.number, body); err != nil { results = append(results, result{issue.number, "error", err.Error()}) } else { results = append(results, result{issue.number, "added", fmt.Sprintf("#%d \"%s\" — 已添加引导评论", issue.number, issue.subject)}) @@ -247,8 +253,9 @@ func tagNamesList(tags map[string]int) []string { } type issueInfo struct { - number int - subject string + number int + subject string + description string } func fetchTaggedIssues(ctx *common.RuntimeContext, tagIDs []string) ([]issueInfo, error) { @@ -313,30 +320,55 @@ func hasWelcomeComment(ctx *common.RuntimeContext, issueNumber int) bool { } func addComment(ctx *common.RuntimeContext, issueNumber int, body string) error { - body = strings.ReplaceAll(body, "{login}", ctx.Owner) path := fmt.Sprintf("/v1/%s/%s/issues/%d/journals", ctx.Owner, ctx.Repo, issueNumber) payload := map[string]interface{}{"notes": marker + "\n\n" + body} _, err := ctx.CallAPI("POST", path, payload) return err } -// defaultTemplate returns the default onboarding message. -func defaultTemplate(owner, repo string) string { +// renderComment renders the comment body for a specific issue. +// It uses the --template if provided, otherwise generates an issue-aware default. +func renderComment(ctx *common.RuntimeContext, issue issueInfo, customTmpl string) string { + tmpl := customTmpl + if tmpl == "" { + tmpl = defaultTemplate(ctx.Owner, ctx.Repo, issue) + } + body := strings.NewReplacer( + "{login}", ctx.Owner, + "{number}", strconv.Itoa(issue.number), + "{subject}", issue.subject, + "{description}", issue.description, + ).Replace(tmpl) + return body +} + +// defaultTemplate returns an issue-aware onboarding message. +func defaultTemplate(owner, repo string, issue issueInfo) string { + summary := issue.subject + if len(issue.description) > 200 { + summary = issue.description[:200] + "..." + } else if issue.description != "" { + summary = issue.description + } return fmt.Sprintf(`## 欢迎贡献!:wave: -感谢你对 [%s/%s](https://www.gitlink.org.cn/%s/%s) 的关注。这个 issue 适合新手参与,以下是快速上手指南: +感谢你对 [%s/%s](https://www.gitlink.org.cn/%s/%s) 的关注。 -### 参与步骤 +### :bulb: 关于本 Issue:{subject} + +%s + +### :rocket: 参与步骤 1. **Fork 仓库** 并克隆到本地 2. 创建新分支:` + "`git checkout -b fix/issue-{number}`" + ` -3. 修改代码并提交 +3. 参照上方 issue 描述修改代码 4. 推送到你的 Fork 后创建 Pull Request -### 注意事项 +### :memo: 注意事项 - 请先阅读 [CONTRIBUTING.md](https://www.gitlink.org.cn/%s/%s/src/master/CONTRIBUTING.md)(如有) -- 如遇到问题,欢迎在 issue 评论区留言 +- 如有疑问,欢迎在评论区留言讨论 -期待你的 PR!`, owner, repo, owner, repo, owner, repo) +期待你的 PR!`, owner, repo, owner, repo, summary, owner, repo) } func getString(m map[string]interface{}, key string) string {