From 8d5a3181f637fac32103916983f54d4b858be311 Mon Sep 17 00:00:00 2001 From: Codex Date: Fri, 20 Feb 2026 16:45:08 -0800 Subject: [PATCH] Deduplicate leading plain ticket IDs in report rendering --- internal/report/report_builder.go | 38 ++++++++++++++++++++++---- internal/report/report_builder_test.go | 12 ++++++++ 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/internal/report/report_builder.go b/internal/report/report_builder.go index 41baaee..aa1a04e 100644 --- a/internal/report/report_builder.go +++ b/internal/report/report_builder.go @@ -51,6 +51,7 @@ var ( bulletLineRe = regexp.MustCompile(`^\s*-\s+(.+?)\s*$`) statusSuffixRe = regexp.MustCompile(`\(([^)]+)\)\s*$`) ticketPrefixRe = regexp.MustCompile(`^\[([^\]]+)\]\s+`) + bareTicketLeadRe = regexp.MustCompile(`^\s*(?:#\s*)?(?:[A-Za-z][A-Za-z0-9_]*-)?([0-9A-Za-z]+)(?:\s*[:,-]\s*|\s+)`) authorPrefixRe = regexp.MustCompile(`^\*\*(.+?)\*\*\s*-\s*`) nameAliasParenRe = regexp.MustCompile(`\([^)]*\)|([^)]*)`) ) @@ -680,16 +681,41 @@ func stripLeadingTicketPrefixIfSame(description, tickets string) string { if description == "" || tickets == "" { return description } + ticketSet := make(map[string]bool) + for _, t := range strings.Split(tickets, ",") { + t = strings.TrimSpace(t) + if t == "" { + continue + } + ticketSet[strings.ToLower(t)] = true + } + for { + trimmed := false matches := ticketPrefixRe.FindStringSubmatch(description) - if len(matches) != 2 { - break + if len(matches) == 2 { + leading := canonicalTicketIDs(matches[1]) + if leading == tickets { + description = strings.TrimSpace(description[len(matches[0]):]) + trimmed = true + } } - leading := canonicalTicketIDs(matches[1]) - if leading != tickets { - break + if trimmed { + continue + } + + // Handle plain leading ticket mentions like: + // "1234567 Implement ...", "#1234567 Implement ...", "JIRA-1234567 Implement ..." + bare := bareTicketLeadRe.FindStringSubmatchIndex(description) + if len(bare) == 4 { + candidate := strings.ToLower(strings.TrimSpace(description[bare[2]:bare[3]])) + if ticketSet[candidate] { + description = strings.TrimSpace(description[bare[1]:]) + continue + } } - description = strings.TrimSpace(description[len(matches[0]):]) + + break } return description } diff --git a/internal/report/report_builder_test.go b/internal/report/report_builder_test.go index 352495c..eebedca 100644 --- a/internal/report/report_builder_test.go +++ b/internal/report/report_builder_test.go @@ -332,6 +332,18 @@ func TestFormatItemDedupesLeadingTicketPrefix(t *testing.T) { if gotBoss != wantBoss { t.Fatalf("unexpected deduped boss item:\nwant: %s\ngot: %s", wantBoss, gotBoss) } + + plainPrefix := TemplateItem{ + Author: "Marik Hsiao", + Description: "1259566 added consul gossip encryption support", + TicketIDs: "1259566", + Status: "done", + } + gotPlain := formatTeamItem(plainPrefix) + wantPlain := "**Marik Hsiao** - [1259566] Added consul gossip encryption support (done)" + if gotPlain != wantPlain { + t.Fatalf("unexpected deduped plain-prefix item:\nwant: %s\ngot: %s", wantPlain, gotPlain) + } } func TestMergeCategoryHeadingAuthors(t *testing.T) {