cloudflare/pint
Publicmirrored from https://github.com/cloudflare/pintAvailable
internal/reporter/comments.go
157lines · modecode
| 1 | package reporter |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "slices" |
| 6 | "strings" |
| 7 | |
| 8 | "github.com/cloudflare/pint/internal/checks" |
| 9 | ) |
| 10 | |
| 11 | type PendingCommentV2 struct { |
| 12 | path string |
| 13 | text string |
| 14 | line int |
| 15 | anchor checks.Anchor |
| 16 | } |
| 17 | |
| 18 | type ExistingCommentV2 struct { |
| 19 | meta any |
| 20 | path string |
| 21 | text string |
| 22 | line int |
| 23 | } |
| 24 | |
| 25 | type Commenter interface { |
| 26 | Describe() string |
| 27 | Destinations(context.Context) ([]any, error) |
| 28 | Summary(context.Context, any, Summary, []error) error |
| 29 | List(context.Context, any) ([]ExistingCommentV2, error) |
| 30 | Create(context.Context, any, PendingCommentV2) error |
| 31 | Delete(context.Context, any, ExistingCommentV2) error |
| 32 | CanCreate(int) (bool, error) |
| 33 | IsEqual(ExistingCommentV2, PendingCommentV2) bool |
| 34 | } |
| 35 | |
| 36 | func makeComments(summary Summary) (comments []PendingCommentV2) { |
| 37 | var buf strings.Builder |
| 38 | for _, reports := range dedupReports(summary.reports) { |
| 39 | mergeDetails := identicalDetails(reports) |
| 40 | |
| 41 | buf.Reset() |
| 42 | |
| 43 | buf.WriteString(problemIcon(reports[0].Problem.Severity)) |
| 44 | buf.WriteString(" **") |
| 45 | buf.WriteString(reports[0].Problem.Severity.String()) |
| 46 | buf.WriteString("** reported by [pint](https://cloudflare.github.io/pint/) **") |
| 47 | buf.WriteString(reports[0].Problem.Reporter) |
| 48 | buf.WriteString("** check.\n\n") |
| 49 | for _, report := range reports { |
| 50 | buf.WriteString("------\n\n") |
| 51 | buf.WriteString(report.Problem.Text) |
| 52 | buf.WriteString("\n\n") |
| 53 | if !mergeDetails && report.Problem.Details != "" { |
| 54 | buf.WriteString(report.Problem.Details) |
| 55 | buf.WriteString("\n\n") |
| 56 | } |
| 57 | if report.Path.SymlinkTarget != report.Path.Name { |
| 58 | buf.WriteString(":leftwards_arrow_with_hook: This problem was detected on a symlinked file ") |
| 59 | buf.WriteRune('`') |
| 60 | buf.WriteString(report.Path.Name) |
| 61 | buf.WriteString("`.\n\n") |
| 62 | } |
| 63 | } |
| 64 | if mergeDetails && reports[0].Problem.Details != "" { |
| 65 | buf.WriteString("------\n\n") |
| 66 | buf.WriteString(reports[0].Problem.Details) |
| 67 | buf.WriteString("\n\n") |
| 68 | } |
| 69 | buf.WriteString("------\n\n") |
| 70 | buf.WriteString(":information_source: To see documentation covering this check and instructions on how to resolve it [click here](https://cloudflare.github.io/pint/checks/") |
| 71 | buf.WriteString(reports[0].Problem.Reporter) |
| 72 | buf.WriteString(".html).\n") |
| 73 | |
| 74 | line := reports[0].Problem.Lines.Last |
| 75 | for i := reports[0].Problem.Lines.Last; i >= reports[0].Problem.Lines.First; i-- { |
| 76 | if slices.Contains(reports[0].ModifiedLines, i) { |
| 77 | line = i |
| 78 | break |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | comments = append(comments, PendingCommentV2{ |
| 83 | anchor: reports[0].Problem.Anchor, |
| 84 | path: reports[0].Path.SymlinkTarget, |
| 85 | line: line, |
| 86 | text: buf.String(), |
| 87 | }) |
| 88 | } |
| 89 | return comments |
| 90 | } |
| 91 | |
| 92 | func dedupReports(src []Report) (dst [][]Report) { |
| 93 | for _, report := range src { |
| 94 | index := -1 |
| 95 | for i, d := range dst { |
| 96 | if d[0].Problem.Severity != report.Problem.Severity { |
| 97 | continue |
| 98 | } |
| 99 | if d[0].Problem.Reporter != report.Problem.Reporter { |
| 100 | continue |
| 101 | } |
| 102 | if d[0].Path.SymlinkTarget != report.Path.SymlinkTarget { |
| 103 | continue |
| 104 | } |
| 105 | if d[0].Problem.Lines.First != report.Problem.Lines.First { |
| 106 | continue |
| 107 | } |
| 108 | if d[0].Problem.Lines.Last != report.Problem.Lines.Last { |
| 109 | continue |
| 110 | } |
| 111 | if d[0].Problem.Anchor != report.Problem.Anchor { |
| 112 | continue |
| 113 | } |
| 114 | index = i |
| 115 | break |
| 116 | } |
| 117 | if index < 0 { |
| 118 | dst = append(dst, []Report{report}) |
| 119 | continue |
| 120 | } |
| 121 | // Skip this report if we have exact same message already |
| 122 | if dst[index][0].Problem.Text == report.Problem.Text && dst[index][0].Problem.Details == report.Problem.Details { |
| 123 | continue |
| 124 | } |
| 125 | dst[index] = append(dst[index], report) |
| 126 | } |
| 127 | return dst |
| 128 | } |
| 129 | |
| 130 | func identicalDetails(src []Report) bool { |
| 131 | if len(src) <= 1 { |
| 132 | return false |
| 133 | } |
| 134 | var details string |
| 135 | for _, report := range src { |
| 136 | if details == "" { |
| 137 | details = report.Problem.Details |
| 138 | continue |
| 139 | } |
| 140 | if details != report.Problem.Details { |
| 141 | return false |
| 142 | } |
| 143 | } |
| 144 | return true |
| 145 | } |
| 146 | |
| 147 | func problemIcon(s checks.Severity) string { |
| 148 | // nolint:exhaustive |
| 149 | switch s { |
| 150 | case checks.Warning: |
| 151 | return ":warning:" |
| 152 | case checks.Information: |
| 153 | return ":information_source:" |
| 154 | default: |
| 155 | return ":stop_sign:" |
| 156 | } |
| 157 | } |
| 158 | |