package webhook import ( "regexp" "strconv" ) var ( closesRe = regexp.MustCompile(`(?i)\b(?:closes|fixes|resolves|close|fix|resolve)\s+#(\d+)`) branchRe = regexp.MustCompile(`(?:^|[-/])(\d+)(?:[-/]|$)`) nonceRe = regexp.MustCompile(`(?i)`) reviewRe = regexp.MustCompile(`(?i)`) ) // ResolveIssueNumber resolves the issue number in priority order: // 1. PR body keyword (Closes/Fixes/Resolves #N) // 2. Branch name containing a number // 3. Legacy path number func ResolveIssueNumber(prBody, branch string, legacyNumber int) (int, bool) { if m := closesRe.FindStringSubmatch(prBody); m != nil { n, _ := strconv.Atoi(m[1]) return n, true } if branch != "" { if m := branchRe.FindStringSubmatch(branch); m != nil { n, _ := strconv.Atoi(m[1]) return n, true } } if legacyNumber > 0 { return legacyNumber, true } return 0, false } // ShouldAutoReview returns the effective auto-review flag. // The per-issue stateJSON "autoReview" bool takes precedence over globalAutoReview. func ShouldAutoReview(stateJSON map[string]any, globalAutoReview bool) bool { if v, ok := stateJSON["autoReview"].(bool); ok { return v } return globalAutoReview } // ExtractNonce extracts the nonce value from a marker. func ExtractNonce(issueBody string) (string, bool) { m := nonceRe.FindStringSubmatch(issueBody) if m == nil || m[1] == "" { return "", false } return m[1], true } // IsReviewMarker reports whether commentBody contains . func IsReviewMarker(commentBody string) bool { return reviewRe.MatchString(commentBody) }