@@ -78,12 +78,15 @@ type GitHubDeployment struct {
78
78
}
79
79
80
80
type GitHubPullRequestComment struct {
81
- Content string `json:"content,omitempty"`
81
+ Content string `json:"content,omitempty"`
82
+ CommentTag string `json:"commentTag,omitempty"`
82
83
}
83
84
84
85
const (
85
86
repoURLtemplate = "{{.app.spec.source.repoURL}}"
86
87
revisionTemplate = "{{.app.status.operationState.syncResult.revision}}"
88
+ commentTagFormat = "<!-- argocd-notifications %s -->"
89
+ contentFormat = "%s\n %s"
87
90
)
88
91
89
92
func (g * GitHubNotification ) GetTemplater (name string , f texttemplate.FuncMap ) (Templater , error ) {
@@ -306,6 +309,13 @@ func (g *GitHubNotification) GetTemplater(name string, f texttemplate.FuncMap) (
306
309
return err
307
310
}
308
311
notification .GitHub .PullRequestComment .Content = contentData .String ()
312
+ notification .GitHub .PullRequestComment .CommentTag = g .PullRequestComment .CommentTag
313
+
314
+ if g .PullRequestComment .CommentTag != "" {
315
+ notification .GitHub .PullRequestComment .Content = fmt .Sprintf (contentFormat ,
316
+ notification .GitHub .PullRequestComment .Content ,
317
+ fmt .Sprintf (commentTagFormat , g .PullRequestComment .CommentTag ))
318
+ }
309
319
}
310
320
311
321
if g .CheckRun != nil {
@@ -369,7 +379,7 @@ func (g *GitHubNotification) GetTemplater(name string, f texttemplate.FuncMap) (
369
379
}, nil
370
380
}
371
381
372
- func NewGitHubService (opts GitHubOptions ) (NotificationService , error ) {
382
+ func NewGitHubService (opts GitHubOptions ) (* gitHubService , error ) {
373
383
url := "https://api.github.com"
374
384
if opts .EnterpriseBaseURL != "" {
375
385
url = opts .EnterpriseBaseURL
@@ -405,16 +415,65 @@ func NewGitHubService(opts GitHubOptions) (NotificationService, error) {
405
415
406
416
return & gitHubService {
407
417
opts : opts ,
408
- client : client ,
418
+ client : & githubClientAdapter { client : client } ,
409
419
}, nil
410
420
}
411
421
412
422
type gitHubService struct {
413
- opts GitHubOptions
423
+ opts GitHubOptions
424
+ client githubClient
425
+ }
426
+
427
+ // Define interfaces for the GitHub client
428
+ type githubClient interface {
429
+ GetIssues () issuesService
430
+ GetPullRequests () pullRequestsService
431
+ GetRepositories () repositoriesService
432
+ GetChecks () checksService
433
+ }
434
+
435
+ type issuesService interface {
436
+ ListComments (ctx context.Context , owner , repo string , number int , opts * github.IssueListCommentsOptions ) ([]* github.IssueComment , * github.Response , error )
437
+ CreateComment (ctx context.Context , owner , repo string , number int , comment * github.IssueComment ) (* github.IssueComment , * github.Response , error )
438
+ EditComment (ctx context.Context , owner , repo string , commentID int64 , comment * github.IssueComment ) (* github.IssueComment , * github.Response , error )
439
+ }
414
440
441
+ type pullRequestsService interface {
442
+ ListPullRequestsWithCommit (ctx context.Context , owner string , repo string , sha string , opts * github.PullRequestListOptions ) ([]* github.PullRequest , * github.Response , error )
443
+ }
444
+
445
+ type repositoriesService interface {
446
+ CreateStatus (ctx context.Context , owner , repo , ref string , status * github.RepoStatus ) (* github.RepoStatus , * github.Response , error )
447
+ ListDeployments (ctx context.Context , owner , repo string , opts * github.DeploymentsListOptions ) ([]* github.Deployment , * github.Response , error )
448
+ CreateDeployment (ctx context.Context , owner , repo string , request * github.DeploymentRequest ) (* github.Deployment , * github.Response , error )
449
+ CreateDeploymentStatus (ctx context.Context , owner , repo string , deploymentID int64 , request * github.DeploymentStatusRequest ) (* github.DeploymentStatus , * github.Response , error )
450
+ }
451
+
452
+ type checksService interface {
453
+ CreateCheckRun (ctx context.Context , owner , repo string , opts github.CreateCheckRunOptions ) (* github.CheckRun , * github.Response , error )
454
+ }
455
+
456
+ // Adapter implementation
457
+ type githubClientAdapter struct {
415
458
client * github.Client
416
459
}
417
460
461
+ func (g * githubClientAdapter ) GetIssues () issuesService {
462
+ return g .client .Issues
463
+ }
464
+
465
+ func (g * githubClientAdapter ) GetPullRequests () pullRequestsService {
466
+ return & pullRequestsServiceAdapter {service : g .client .PullRequests }
467
+ }
468
+
469
+ func (g * githubClientAdapter ) GetRepositories () repositoriesService {
470
+ return g .client .Repositories
471
+ }
472
+
473
+ func (g * githubClientAdapter ) GetChecks () checksService {
474
+ return g .client .Checks
475
+ }
476
+
418
477
func trunc (message string , n int ) string {
419
478
if utf8 .RuneCountInString (message ) > n {
420
479
return string ([]rune (message )[0 :n - 3 ]) + "..."
@@ -448,7 +507,7 @@ func (g gitHubService) Send(notification Notification, _ Destination) error {
448
507
if notification .GitHub .Status != nil {
449
508
// maximum is 140 characters
450
509
description := trunc (notification .Message , 140 )
451
- _ , _ , err := g .client .Repositories .CreateStatus (
510
+ _ , _ , err := g .client .GetRepositories () .CreateStatus (
452
511
context .Background (),
453
512
u [0 ],
454
513
u [1 ],
@@ -468,7 +527,7 @@ func (g gitHubService) Send(notification Notification, _ Destination) error {
468
527
if notification .GitHub .Deployment != nil {
469
528
// maximum is 140 characters
470
529
description := trunc (notification .Message , 140 )
471
- deployments , _ , err := g .client .Repositories .ListDeployments (
530
+ deployments , _ , err := g .client .GetRepositories () .ListDeployments (
472
531
context .Background (),
473
532
u [0 ],
474
533
u [1 ],
@@ -491,7 +550,7 @@ func (g gitHubService) Send(notification Notification, _ Destination) error {
491
550
if len (deployments ) != 0 {
492
551
deployment = deployments [0 ]
493
552
} else {
494
- deployment , _ , err = g .client .Repositories .CreateDeployment (
553
+ deployment , _ , err = g .client .GetRepositories () .CreateDeployment (
495
554
context .Background (),
496
555
u [0 ],
497
556
u [1 ],
@@ -507,7 +566,7 @@ func (g gitHubService) Send(notification Notification, _ Destination) error {
507
566
return err
508
567
}
509
568
}
510
- _ , _ , err = g .client .Repositories .CreateDeploymentStatus (
569
+ _ , _ , err = g .client .GetRepositories () .CreateDeploymentStatus (
511
570
context .Background (),
512
571
u [0 ],
513
572
u [1 ],
@@ -528,11 +587,9 @@ func (g gitHubService) Send(notification Notification, _ Destination) error {
528
587
if notification .GitHub .PullRequestComment != nil {
529
588
// maximum is 65536 characters
530
589
body := trunc (notification .GitHub .PullRequestComment .Content , 65536 )
531
- comment := & github.IssueComment {
532
- Body : & body ,
533
- }
590
+ commentTag := notification .GitHub .PullRequestComment .CommentTag
534
591
535
- prs , _ , err := g .client .PullRequests .ListPullRequestsWithCommit (
592
+ prs , _ , err := g .client .GetPullRequests () .ListPullRequestsWithCommit (
536
593
context .Background (),
537
594
u [0 ],
538
595
u [1 ],
@@ -544,7 +601,54 @@ func (g gitHubService) Send(notification Notification, _ Destination) error {
544
601
}
545
602
546
603
for _ , pr := range prs {
547
- _ , _ , err = g .client .Issues .CreateComment (
604
+ if commentTag != "" {
605
+ // If comment tag is provided, try to find and update existing comment
606
+ tagPattern := fmt .Sprintf (commentTagFormat , commentTag )
607
+ comments , _ , err := g .client .GetIssues ().ListComments (
608
+ context .Background (),
609
+ u [0 ],
610
+ u [1 ],
611
+ pr .GetNumber (),
612
+ nil ,
613
+ )
614
+ if err != nil {
615
+ return err
616
+ }
617
+
618
+ var existingComment * github.IssueComment
619
+ for _ , comment := range comments {
620
+ if strings .Contains (comment .GetBody (), tagPattern ) {
621
+ existingComment = comment
622
+ break
623
+ }
624
+ }
625
+
626
+ if existingComment != nil {
627
+ // Update existing comment
628
+ updatedBody := fmt .Sprintf (contentFormat , body , tagPattern )
629
+ existingComment .Body = & updatedBody
630
+ _ , _ , err = g .client .GetIssues ().EditComment (
631
+ context .Background (),
632
+ u [0 ],
633
+ u [1 ],
634
+ existingComment .GetID (),
635
+ existingComment ,
636
+ )
637
+ if err != nil {
638
+ return err
639
+ }
640
+ continue
641
+ }
642
+
643
+ // If no existing comment found, create new one with tag
644
+ body = fmt .Sprintf (contentFormat , body , tagPattern )
645
+ }
646
+
647
+ // Create new comment
648
+ comment := & github.IssueComment {
649
+ Body : & body ,
650
+ }
651
+ _ , _ , err = g .client .GetIssues ().CreateComment (
548
652
context .Background (),
549
653
u [0 ],
550
654
u [1 ],
@@ -576,7 +680,7 @@ func (g gitHubService) Send(notification Notification, _ Destination) error {
576
680
}
577
681
}
578
682
579
- _ , _ , err = g .client .Checks .CreateCheckRun (
683
+ _ , _ , err = g .client .GetChecks () .CreateCheckRun (
580
684
context .Background (),
581
685
u [0 ],
582
686
u [1 ],
@@ -598,3 +702,17 @@ func (g gitHubService) Send(notification Notification, _ Destination) error {
598
702
599
703
return nil
600
704
}
705
+
706
+ // PullRequestsServiceAdapter adapts GitHub's PullRequestsService to our interface
707
+ type pullRequestsServiceAdapter struct {
708
+ service * github.PullRequestsService
709
+ }
710
+
711
+ func (a * pullRequestsServiceAdapter ) ListPullRequestsWithCommit (ctx context.Context , owner string , repo string , sha string , opts * github.PullRequestListOptions ) ([]* github.PullRequest , * github.Response , error ) {
712
+ // Convert PullRequestListOptions to ListOptions
713
+ listOpts := & github.ListOptions {
714
+ Page : opts .Page ,
715
+ PerPage : opts .PerPage ,
716
+ }
717
+ return a .service .ListPullRequestsWithCommit (ctx , owner , repo , sha , listOpts )
718
+ }
0 commit comments