diff --git a/server/internal/handler/github.go b/server/internal/handler/github.go index 1091778bab..e459dcdd29 100644 --- a/server/internal/handler/github.go +++ b/server/internal/handler/github.go @@ -581,8 +581,12 @@ func (h *Handler) ListPullRequestsForIssue(w http.ResponseWriter, r *http.Reques // because branch names are conventionally lowercase but issue prefixes are // uppercase. Word boundary on the left prevents matching inside email-style // strings (e.g. "abc@MUL-1") and the digit anchor on the right rules out -// version numbers like "v1.2-3". -var identifierRe = regexp.MustCompile(`(?i)\b([a-z][a-z0-9]{0,6})-(\d+)\b`) +// version numbers like "v1.2-3". The key group allows up to 9 chars (not the +// Space key's 7-char cap) because legacy issue_prefix values up to 10 chars +// still resolve via the issue_identifier_alias backfill (see migration 134); +// extraction only needs to find a candidate, the DB lookup (current key, +// then alias) decides validity. +var identifierRe = regexp.MustCompile(`(?i)\b([a-z][a-z0-9]{0,9})-(\d+)\b`) // closingIdentifierRe extracts identifiers that appear immediately after a // GitHub-style closing keyword ("close[sd]?", "fix(e[sd])?", "resolve[sd]?"), @@ -594,7 +598,7 @@ var identifierRe = regexp.MustCompile(`(?i)\b([a-z][a-z0-9]{0,6})-(\d+)\b`) // title prefixes like "MUL-1: ..." link the PR (via identifierRe) but // never auto-close. var closingIdentifierRe = regexp.MustCompile( - `(?i)\b(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)[:\s]+([a-z][a-z0-9]{0,6})-(\d+)\b`, + `(?i)\b(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)[:\s]+([a-z][a-z0-9]{0,9})-(\d+)\b`, ) // HandleGitHubWebhook (POST /api/webhooks/github) is GitHub's destination for diff --git a/server/migrations/134_issue_identifier_alias.up.sql b/server/migrations/134_issue_identifier_alias.up.sql index 107624f3d6..7d1fbc245c 100644 --- a/server/migrations/134_issue_identifier_alias.up.sql +++ b/server/migrations/134_issue_identifier_alias.up.sql @@ -14,3 +14,23 @@ CREATE TABLE issue_identifier_alias ( ); CREATE INDEX idx_issue_identifier_alias_issue ON issue_identifier_alias(issue_id); + +-- Backfill aliases for the renaming migration 131 already performed. 131 +-- normalized every workspace's legacy issue_prefix into a Space key +-- satisfying ^[A-Z][A-Z0-9]{0,6}$ (uppercase, strip non-alnum, truncate to 7). +-- Legacy prefixes longer than 7 chars, digit-first, or punctuated therefore +-- diverge from the key their issues now resolve under, and — unlike a +-- runtime move-to-space — that rename never went through the alias-writing +-- path above, since no issue actually changed space_id. Old links/CLI/GitHub +-- references using the pre-migration prefix would otherwise 404 forever. +-- workspace.issue_prefix is untouched by 131/132 (kept intentionally; see +-- 132's header comment), so the original value is still available here. +INSERT INTO issue_identifier_alias (workspace_id, space_key_lower, number, issue_id) +SELECT i.workspace_id, lower(btrim(w.issue_prefix)), i.number, i.id +FROM issue i +JOIN workspace w ON w.id = i.workspace_id +JOIN workspace_space wt ON wt.id = i.space_id +WHERE w.issue_prefix IS NOT NULL + AND btrim(w.issue_prefix) <> '' + AND lower(btrim(w.issue_prefix)) <> lower(wt.key) +ON CONFLICT DO NOTHING;