02920b685b
- Replace interface{} with any in github/reviews.go (Go 1.18+ idiom)
- Add default panic case to VCS client init switch
- Refactor supersedeOldReviews to return error instead of os.Exit(1)
- Remove spurious blank lines in formatter.go and formatter_test.go
- Add doc comment to DeleteReview explaining when to use vs DismissReview
- Sanitize extractSentinelName output to prevent log injection
59 lines
1.9 KiB
Go
59 lines
1.9 KiB
Go
package review
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// FormatMarkdown formats a ReviewResult into the markdown body for a Gitea review.
|
|
func FormatMarkdown(result *ReviewResult, reviewerName string) string {
|
|
return FormatMarkdownWithDisplay(result, reviewerName, reviewerName)
|
|
}
|
|
|
|
// FormatMarkdownWithDisplay formats a ReviewResult with separate display name and sentinel name.
|
|
// Note: displayName is not HTML-escaped as Gitea sanitizes rendered Markdown.
|
|
// Persona display names are controlled by repo owners (trusted input).
|
|
// displayName is used for the header title, sentinelName is used for the cleanup sentinel.
|
|
// If displayName is empty, sentinelName is used for both.
|
|
func FormatMarkdownWithDisplay(result *ReviewResult, displayName, sentinelName string) string {
|
|
var sb strings.Builder
|
|
|
|
// Use display name for header, or fall back to sentinel name
|
|
headerName := displayName
|
|
if headerName == "" {
|
|
headerName = sentinelName
|
|
}
|
|
|
|
if headerName != "" {
|
|
title := CapitalizeFirst(headerName)
|
|
sb.WriteString(fmt.Sprintf("# %s Review\n\n", title))
|
|
}
|
|
|
|
sb.WriteString("## Summary\n\n")
|
|
sb.WriteString(result.Summary)
|
|
sb.WriteString("\n\n")
|
|
|
|
if len(result.Findings) > 0 {
|
|
sb.WriteString("## Findings\n\n")
|
|
sb.WriteString("| # | Severity | File | Line | Finding |\n")
|
|
sb.WriteString("|---|----------|------|------|--------|\n")
|
|
|
|
for i, f := range result.Findings {
|
|
sb.WriteString(fmt.Sprintf("| %d | [%s] | `%s` | %d | %s |\n",
|
|
i+1, f.Severity, f.File, f.Line, f.Finding))
|
|
}
|
|
sb.WriteString("\n")
|
|
}
|
|
|
|
sb.WriteString("## Recommendation\n\n")
|
|
sb.WriteString(fmt.Sprintf("**%s** — %s\n", result.Verdict, result.Recommendation))
|
|
|
|
if sentinelName != "" {
|
|
sb.WriteString(fmt.Sprintf("\n---\n*Review by %s*\n", headerName))
|
|
// Hidden sentinel for identifying this bot's reviews during cleanup
|
|
sb.WriteString(fmt.Sprintf("\n<!-- review-bot:%s -->\n", sentinelName))
|
|
}
|
|
|
|
return sb.String()
|
|
}
|