github.com/mongodb/grip@v0.0.0-20240213223901-f906268d82b9/send/github_comment.go (about)

     1  package send
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"log"
     7  	"os"
     8  	"time"
     9  
    10  	"github.com/google/go-github/v53/github"
    11  	"github.com/mongodb/grip/message"
    12  	"github.com/pkg/errors"
    13  	"go.opentelemetry.io/otel/attribute"
    14  	"go.opentelemetry.io/otel/codes"
    15  	"go.opentelemetry.io/otel/trace"
    16  )
    17  
    18  type githubCommentLogger struct {
    19  	issue int
    20  	opts  *GithubOptions
    21  	gh    githubClient
    22  
    23  	*Base
    24  }
    25  
    26  // NewGithubCommentLogger creates a new Sender implementation that
    27  // adds a comment to a github issue (or pull request) for every log
    28  // message sent.
    29  //
    30  // Specify the credentials to use the GitHub via the GithubOptions
    31  // structure, and the issue number as an argument to the constructor.
    32  func NewGithubCommentLogger(name string, issueID int, opts *GithubOptions) (Sender, error) {
    33  	opts.populate()
    34  	s := &githubCommentLogger{
    35  		Base:  NewBase(name),
    36  		opts:  opts,
    37  		issue: issueID,
    38  		gh:    &githubClientImpl{},
    39  	}
    40  
    41  	s.gh.Init(opts.Token, opts.MaxAttempts, opts.MinDelay)
    42  
    43  	fallback := log.New(os.Stdout, "", log.LstdFlags)
    44  	if err := s.SetErrorHandler(ErrorHandlerFromLogger(fallback)); err != nil {
    45  		return nil, err
    46  	}
    47  
    48  	if err := s.SetFormatter(MakeDefaultFormatter()); err != nil {
    49  		return nil, err
    50  	}
    51  
    52  	s.reset = func() {
    53  		fallback.SetPrefix(fmt.Sprintf("[%s] [%s/%s#%d] ",
    54  			s.Name(), opts.Account, opts.Repo, issueID))
    55  	}
    56  
    57  	return s, nil
    58  }
    59  
    60  func (s *githubCommentLogger) Send(m message.Composer) {
    61  	if s.Level().ShouldLog(m) {
    62  		text, err := s.formatter(m)
    63  		if err != nil {
    64  			s.ErrorHandler()(err, m)
    65  			return
    66  		}
    67  
    68  		comment := &github.IssueComment{Body: &text}
    69  
    70  		ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
    71  		defer cancel()
    72  
    73  		ctx, span := tracer.Start(ctx, "CreateComment", trace.WithAttributes(
    74  			attribute.String(githubEndpointAttribute, "CreateComment"),
    75  			attribute.String(githubOwnerAttribute, s.opts.Account),
    76  			attribute.String(githubRepoAttribute, s.opts.Repo),
    77  		))
    78  		defer span.End()
    79  
    80  		if _, resp, err := s.gh.CreateComment(ctx, s.opts.Account, s.opts.Repo, s.issue, comment); err != nil {
    81  			s.ErrorHandler()(errors.Wrap(err, "sending GitHub create comment request"), m)
    82  
    83  			span.RecordError(err)
    84  			span.SetStatus(codes.Error, "sending comment")
    85  		} else if err = handleHTTPResponseError(resp.Response); err != nil {
    86  			s.ErrorHandler()(errors.Wrap(err, "creating GitHub comment"), m)
    87  
    88  			span.RecordError(err)
    89  			span.SetStatus(codes.Error, "sending comment")
    90  		}
    91  	}
    92  }
    93  
    94  func (s *githubCommentLogger) Flush(_ context.Context) error { return nil }