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  }