@@ -39,10 +39,15 @@ func (OSFileSystem) WriteFile(filename string, data []byte, perm os.FileMode) er
3939}
4040
4141type aggregateOptions struct {
42- reportID string
43- splunkURL string
44- splunkToken string
45- splunkEvent SplunkEvent
42+ reportID string
43+ splunkURL string
44+ splunkToken string
45+ splunkEvent string
46+ baseSha string
47+ headSha string
48+ repoURL string
49+ gitHubWorkflowName string
50+ gitHubWorkflowRunURL string
4651}
4752
4853// AggregateOption is a functional option for configuring the aggregation process.
@@ -56,14 +61,49 @@ func WithReportID(reportID string) AggregateOption {
5661}
5762
5863// WithSplunk also sends the aggregation to a Splunk instance as events.
59- func WithSplunk (url , token string , event SplunkEvent ) AggregateOption {
64+ func WithSplunk (url , token string , event string ) AggregateOption {
6065 return func (opts * aggregateOptions ) {
6166 opts .splunkURL = url
6267 opts .splunkToken = token
6368 opts .splunkEvent = event
6469 }
6570}
6671
72+ // WithHeadSha sets the head SHA for the aggregated report.
73+ func WithHeadSha (headSha string ) AggregateOption {
74+ return func (opts * aggregateOptions ) {
75+ opts .headSha = headSha
76+ }
77+ }
78+
79+ // WithBaseSha sets the base SHA for the aggregated report.
80+ func WithBaseSha (baseSha string ) AggregateOption {
81+ return func (opts * aggregateOptions ) {
82+ opts .baseSha = baseSha
83+ }
84+ }
85+
86+ // WithRepoURL sets the repository URL for the aggregated report.
87+ func WithRepoURL (repoURL string ) AggregateOption {
88+ return func (opts * aggregateOptions ) {
89+ opts .repoURL = repoURL
90+ }
91+ }
92+
93+ // WithGitHubWorkflowName sets the GitHub workflow name for the aggregated report.
94+ func WithGitHubWorkflowName (githubWorkflowName string ) AggregateOption {
95+ return func (opts * aggregateOptions ) {
96+ opts .gitHubWorkflowName = githubWorkflowName
97+ }
98+ }
99+
100+ // WithGitHubWorkflowRunURL sets the GitHub workflow run URL for the aggregated report.
101+ func WithGitHubWorkflowRunURL (githubWorkflowRunURL string ) AggregateOption {
102+ return func (opts * aggregateOptions ) {
103+ opts .gitHubWorkflowRunURL = githubWorkflowRunURL
104+ }
105+ }
106+
67107// LoadAndAggregate reads all JSON files in a directory and aggregates the results into a single TestReport.
68108func LoadAndAggregate (resultsPath string , options ... AggregateOption ) (* TestReport , error ) {
69109 if _ , err := os .Stat (resultsPath ); os .IsNotExist (err ) {
@@ -115,6 +155,7 @@ func LoadAndAggregate(resultsPath string, options ...AggregateOption) (*TestRepo
115155 if err != nil {
116156 return nil , fmt .Errorf ("error aggregating reports: %w" , err )
117157 }
158+
118159 return aggregatedReport , nil
119160}
120161
@@ -318,14 +359,20 @@ func SaveReport(fs FileSystem, filePath string, report TestReport) error {
318359// aggregate aggregates multiple TestReport objects into a single TestReport as they are received
319360func aggregate (reportChan <- chan * TestReport , errChan <- chan error , opts * aggregateOptions ) (* TestReport , error ) {
320361 var (
362+ fullReport = & TestReport {
363+ ID : opts .reportID ,
364+ BaseSHA : opts .baseSha ,
365+ HeadSHA : opts .headSha ,
366+ RepoURL : opts .repoURL ,
367+ GitHubWorkflowName : opts .gitHubWorkflowName ,
368+ GitHubWorkflowRunURL : opts .gitHubWorkflowRunURL ,
369+ }
321370 testMap = make (map [string ]TestResult )
322- fullReport = & TestReport {}
323371 excludedTests = map [string ]struct {}{}
324372 selectedTests = map [string ]struct {}{}
325373 sendToSplunk = opts .splunkURL != ""
326374 )
327375
328- fullReport .ID = opts .reportID
329376 for report := range reportChan {
330377 if fullReport .GoProject == "" {
331378 fullReport .GoProject = report .GoProject
@@ -388,23 +435,25 @@ func aggregate(reportChan <-chan *TestReport, errChan <-chan error, opts *aggreg
388435// sendDataToSplunk sends a truncated TestReport and each individual TestResults to Splunk as events
389436func sendDataToSplunk (opts * aggregateOptions , report TestReport , results ... TestResult ) error {
390437 start := time .Now ()
438+ // Dry-run mode for example runs
439+ isExampleRun := strings .Contains (opts .splunkURL , "splunk.example.com" )
440+
391441 client := resty .New ().
392442 SetBaseURL (opts .splunkURL ).
393443 SetAuthScheme ("Splunk" ).
394444 SetAuthToken (opts .splunkToken ).
395445 SetHeader ("Content-Type" , "application/json" ).
396446 SetLogger (ZerologRestyLogger {})
397- client .AddRetryAfterErrorCondition ().SetRetryCount (5 ).SetTimeout (time .Second * 10 )
398447
399448 log .Debug ().Str ("report id" , report .ID ).Int ("results" , len (results )).Msg ("Sending aggregated data to Splunk" )
400449
401- // Send results
402450 var (
403451 splunkErrs = []error {}
404452 resultsBatchSize = 10
405453 resultsBatch = []SplunkTestResult {}
406454 successfulResultsSent = 0
407455 )
456+
408457 for resultCount , result := range results {
409458 resultsBatch = append (resultsBatch , SplunkTestResult {
410459 Event : SplunkTestResultEvent {
@@ -415,53 +464,70 @@ func sendDataToSplunk(opts *aggregateOptions, report TestReport, results ...Test
415464 SourceType : SplunkSourceType ,
416465 Index : SplunkIndex ,
417466 })
418- // Send results in batches so Splunk doesn't get mad
467+
419468 if len (resultsBatch ) >= resultsBatchSize || resultCount == len (results )- 1 {
420469 batchData , testNames , err := batchSplunkResults (resultsBatch )
421470 if err != nil {
422471 return fmt .Errorf ("error batching results: %w" , err )
423472 }
424473
425- resp , err := client .R ().
426- SetBody (batchData .String ()).
427- Post ("" )
428- if err != nil {
429- splunkErrs = append (splunkErrs ,
430- fmt .Errorf ("error sending flakeguard results for [%s] to Splunk: %w" , strings .Join (testNames , ", " ), err ),
431- )
432- }
433- if resp .IsError () {
434- splunkErrs = append (splunkErrs ,
435- fmt .Errorf ("error sending flakeguard result for [%s] to Splunk: %s" , strings .Join (testNames , ", " ), resp .String ()),
436- )
437- }
438- if err == nil && ! resp .IsError () {
439- successfulResultsSent += len (resultsBatch )
474+ if isExampleRun {
475+ log .Debug ().Strs ("tests" , testNames ).Msg ("Example Run. Would send the below results to Splunk" )
476+ for _ , result := range resultsBatch {
477+ jsonResult , err := json .Marshal (result )
478+ if err != nil {
479+ return fmt .Errorf ("error marshaling result for '%s': %w" , result .Event .Data .TestName , err )
480+ }
481+ fmt .Println (string (jsonResult ))
482+ }
483+ } else {
484+ resp , err := client .R ().SetBody (batchData .String ()).Post ("" )
485+ if err != nil {
486+ splunkErrs = append (splunkErrs ,
487+ fmt .Errorf ("error sending results for [%s] to Splunk: %w" , strings .Join (testNames , ", " ), err ),
488+ )
489+ }
490+ if resp .IsError () {
491+ splunkErrs = append (splunkErrs ,
492+ fmt .Errorf ("error sending result for [%s] to Splunk: %s" , strings .Join (testNames , ", " ), resp .String ()),
493+ )
494+ }
495+ if err == nil && ! resp .IsError () {
496+ successfulResultsSent += len (resultsBatch )
497+ }
440498 }
441499 resultsBatch = []SplunkTestResult {}
442500 }
443501 }
444502
445- // Check if errors occurred while uploading results and send report with incomplete flag
446- resp , err := client .R ().
447- SetBody (SplunkTestReport {
448- Event : SplunkTestReportEvent {
449- Event : opts .splunkEvent ,
450- Type : Report ,
451- Data : report ,
452- Incomplete : len (splunkErrs ) > 0 ,
453- },
454- SourceType : SplunkSourceType ,
455- Index : SplunkIndex ,
456- }).
457- Post ("" )
458-
459- if err != nil {
460- splunkErrs = append (splunkErrs , fmt .Errorf ("error sending flakeguard report '%s' to Splunk: %w" , report .ID , err ))
503+ reportData := SplunkTestReport {
504+ Event : SplunkTestReportEvent {
505+ Event : opts .splunkEvent ,
506+ Type : Report ,
507+ Data : report ,
508+ Incomplete : len (splunkErrs ) > 0 ,
509+ },
510+ SourceType : SplunkSourceType ,
511+ Index : SplunkIndex ,
461512 }
462- if resp .IsError () {
463- splunkErrs = append (splunkErrs , fmt .Errorf ("error sending flakeguard report '%s' to Splunk: %s" , report .ID , resp .String ()))
513+
514+ if isExampleRun {
515+ log .Info ().Msg ("Example Run. Would send the below report to Splunk" )
516+ jsonReport , err := json .Marshal (reportData )
517+ if err != nil {
518+ return fmt .Errorf ("error marshaling report: %w" , err )
519+ }
520+ fmt .Println (string (jsonReport ))
521+ } else {
522+ resp , err := client .R ().SetBody (reportData ).Post ("" )
523+ if err != nil {
524+ splunkErrs = append (splunkErrs , fmt .Errorf ("error sending report '%s' to Splunk: %w" , report .ID , err ))
525+ }
526+ if resp .IsError () {
527+ splunkErrs = append (splunkErrs , fmt .Errorf ("error sending report '%s' to Splunk: %s" , report .ID , resp .String ()))
528+ }
464529 }
530+
465531 if len (splunkErrs ) > 0 {
466532 log .Error ().
467533 Int ("successfully sent" , successfulResultsSent ).
@@ -476,6 +542,7 @@ func sendDataToSplunk(opts *aggregateOptions, report TestReport, results ...Test
476542 Str ("duration" , time .Since (start ).String ()).
477543 Msg ("All results sent successfully" )
478544 }
545+
479546 return errors .Join (splunkErrs ... )
480547}
481548
0 commit comments