github.com/diggerhq/digger/libs@v0.0.0-20240604170430-9d61cdf01cc5/comment_utils/reporting/reporting.go (about) 1 package reporting 2 3 import ( 4 "fmt" 5 "github.com/diggerhq/digger/libs/comment_utils/utils" 6 "github.com/diggerhq/digger/libs/orchestrator" 7 "log" 8 "strings" 9 "time" 10 ) 11 12 type CiReporter struct { 13 CiService orchestrator.PullRequestService 14 PrNumber int 15 IsSupportMarkdown bool 16 ReportStrategy ReportStrategy 17 } 18 19 func (ciReporter *CiReporter) Report(report string, reportFormatting func(report string) string) (string, string, error) { 20 commentId, commentUrl, err := ciReporter.ReportStrategy.Report(ciReporter.CiService, ciReporter.PrNumber, report, reportFormatting, ciReporter.SupportsMarkdown()) 21 return commentId, commentUrl, err 22 } 23 24 func (ciReporter *CiReporter) Flush() (string, string, error) { 25 return "", "", nil 26 } 27 28 func (ciReporter *CiReporter) Suppress() error { 29 return nil 30 } 31 32 func (ciReporter *CiReporter) SupportsMarkdown() bool { 33 return ciReporter.IsSupportMarkdown 34 } 35 36 type CiReporterLazy struct { 37 CiReporter CiReporter 38 isSuppressed bool 39 reports []string 40 formatters []func(report string) string 41 } 42 43 func NewCiReporterLazy(ciReporter CiReporter) *CiReporterLazy { 44 return &CiReporterLazy{ 45 CiReporter: ciReporter, 46 isSuppressed: false, 47 reports: []string{}, 48 formatters: []func(report string) string{}, 49 } 50 } 51 52 func (lazyReporter *CiReporterLazy) Report(report string, reportFormatting func(report string) string) (string, string, error) { 53 lazyReporter.reports = append(lazyReporter.reports, report) 54 lazyReporter.formatters = append(lazyReporter.formatters, reportFormatting) 55 return "", "", nil 56 } 57 58 func (lazyReporter *CiReporterLazy) Flush() (string, string, error) { 59 if lazyReporter.isSuppressed { 60 log.Printf("Reporter is suprresed, ignoring messages ...") 61 return "", "", nil 62 } 63 var commentId, commentUrl string 64 for i, _ := range lazyReporter.formatters { 65 var err error 66 commentId, commentUrl, err = lazyReporter.CiReporter.ReportStrategy.Report(lazyReporter.CiReporter.CiService, lazyReporter.CiReporter.PrNumber, lazyReporter.reports[i], lazyReporter.formatters[i], lazyReporter.SupportsMarkdown()) 67 if err != nil { 68 log.Printf("failed to report strategy: ") 69 return "", "", err 70 } 71 } 72 // clear the buffers 73 lazyReporter.formatters = []func(comment string) string{} 74 lazyReporter.reports = []string{} 75 return commentId, commentUrl, nil 76 } 77 78 func (lazyReporter *CiReporterLazy) Suppress() error { 79 lazyReporter.isSuppressed = true 80 return nil 81 } 82 83 func (lazyReporter *CiReporterLazy) SupportsMarkdown() bool { 84 return lazyReporter.CiReporter.IsSupportMarkdown 85 } 86 87 type StdOutReporter struct{} 88 89 func (reporter *StdOutReporter) Report(report string, reportFormatting func(report string) string) (string, string, error) { 90 log.Printf("Info: %v", report) 91 return "", "", nil 92 } 93 94 func (reporter *StdOutReporter) Flush() (string, string, error) { 95 return "", "", nil 96 } 97 98 func (reporter *StdOutReporter) SupportsMarkdown() bool { 99 return false 100 } 101 102 func (reporter *StdOutReporter) Suppress() error { 103 return nil 104 } 105 106 type ReportStrategy interface { 107 Report(ciService orchestrator.PullRequestService, PrNumber int, report string, reportFormatter func(report string) string, supportsCollapsibleComment bool) (commentId string, commentUrl string, error error) 108 } 109 110 type CommentPerRunStrategy struct { 111 Title string 112 TimeOfRun time.Time 113 } 114 115 func (strategy CommentPerRunStrategy) Report(ciService orchestrator.PullRequestService, PrNumber int, report string, reportFormatter func(report string) string, supportsCollapsibleComment bool) (string, string, error) { 116 comments, err := ciService.GetComments(PrNumber) 117 if err != nil { 118 return "", "", fmt.Errorf("error getting comments: %v", err) 119 } 120 121 var reportTitle string 122 if strategy.Title != "" { 123 reportTitle = strategy.Title + " " + strategy.TimeOfRun.Format("2006-01-02 15:04:05 (MST)") 124 } else { 125 reportTitle = "Digger run report at " + strategy.TimeOfRun.Format("2006-01-02 15:04:05 (MST)") 126 } 127 commentId, commentUrl, err := upsertComment(ciService, PrNumber, report, reportFormatter, comments, reportTitle, supportsCollapsibleComment) 128 return commentId, commentUrl, err 129 } 130 131 func upsertComment(ciService orchestrator.PullRequestService, PrNumber int, report string, reportFormatter func(report string) string, comments []orchestrator.Comment, reportTitle string, supportsCollapsible bool) (string, string, error) { 132 report = reportFormatter(report) 133 var commentIdForThisRun interface{} 134 var commentBody string 135 var commentUrl string 136 for _, comment := range comments { 137 if strings.Contains(*comment.Body, reportTitle) { 138 commentIdForThisRun = comment.Id 139 commentBody = *comment.Body 140 commentUrl = comment.Url 141 break 142 } 143 } 144 145 if commentIdForThisRun == nil { 146 var commentMessage string 147 if !supportsCollapsible { 148 commentMessage = utils.AsComment(reportTitle)(report) 149 } else { 150 commentMessage = utils.AsCollapsibleComment(reportTitle, false)(report) 151 } 152 comment, err := ciService.PublishComment(PrNumber, commentMessage) 153 if err != nil { 154 return "", "", fmt.Errorf("error publishing comment: %v", err) 155 } 156 return fmt.Sprintf("%v", comment.Id), comment.Url, nil 157 } 158 159 // strip first and last lines 160 lines := strings.Split(commentBody, "\n") 161 lines = lines[1 : len(lines)-1] 162 commentBody = strings.Join(lines, "\n") 163 164 commentBody = commentBody + "\n\n" + report + "\n" 165 166 var completeComment string 167 if !supportsCollapsible { 168 completeComment = utils.AsComment(reportTitle)(commentBody) 169 } else { 170 completeComment = utils.AsCollapsibleComment(reportTitle, false)(commentBody) 171 } 172 173 err := ciService.EditComment(PrNumber, commentIdForThisRun, completeComment) 174 175 if err != nil { 176 return "", "", fmt.Errorf("error editing comment: %v", err) 177 } 178 return fmt.Sprintf("%v", commentIdForThisRun), commentUrl, nil 179 } 180 181 type LatestRunCommentStrategy struct { 182 TimeOfRun time.Time 183 } 184 185 func (strategy *LatestRunCommentStrategy) Report(ciService orchestrator.PullRequestService, PrNumber int, report string, reportFormatter func(report string) string, supportsCollapsibleComment bool) (string, string, error) { 186 comments, err := ciService.GetComments(PrNumber) 187 if err != nil { 188 return "", "", fmt.Errorf("error getting comments: %v", err) 189 } 190 191 reportTitle := "Digger latest run report" 192 commentId, commentUrl, err := upsertComment(ciService, PrNumber, report, reportFormatter, comments, reportTitle, supportsCollapsibleComment) 193 return commentId, commentUrl, err 194 } 195 196 type MultipleCommentsStrategy struct{} 197 198 func (strategy *MultipleCommentsStrategy) Report(ciService orchestrator.PullRequestService, PrNumber int, report string, reportFormatter func(report string) string, supportsCollapsibleComment bool) (string, string, error) { 199 _, err := ciService.PublishComment(PrNumber, reportFormatter(report)) 200 return "", "", err 201 }