github.com/Mistwind/reviewdog@v0.0.0-20230317041057-48e69b6d9e86/service/gitlab/gitlab_push_commits.go (about) 1 package gitlab 2 3 import ( 4 "context" 5 "fmt" 6 "path/filepath" 7 "sync" 8 9 "github.com/xanzy/go-gitlab" 10 "golang.org/x/sync/errgroup" 11 12 "github.com/reviewdog/reviewdog" 13 "github.com/reviewdog/reviewdog/service/commentutil" 14 "github.com/reviewdog/reviewdog/service/serviceutil" 15 ) 16 17 var _ reviewdog.CommentService = &PushCommitsCommenter{} 18 19 // PushCommitsCommenter is a comment service for GitLab commit in push. 20 // 21 // API: 22 // https://docs.gitlab.com/ce/api/commits.html#post-comment-to-commit 23 // POST /projects/:id/repository/commits/:sha/comments 24 type PushCommitsCommenter struct { 25 cli *gitlab.Client 26 sha string 27 projects string 28 29 sync.Mutex 30 postComments []*reviewdog.Comment 31 32 postedcs commentutil.PostedComments 33 34 // wd is working directory relative to root of repository. 35 wd string 36 } 37 38 // NewGitLabPushCommitsCommenter returns a new PushCommitsCommenter service. 39 // PushCommitsCommenter service needs git command in $PATH. 40 func NewGitLabPushCommitsCommenter(cli *gitlab.Client, owner, repo string, sha string) (*PushCommitsCommenter, error) { 41 workDir, err := serviceutil.GitRelWorkdir() 42 if err != nil { 43 return nil, fmt.Errorf("PushCommitsCommenter needs 'git' command: %w", err) 44 } 45 return &PushCommitsCommenter{ 46 cli: cli, 47 sha: sha, 48 projects: owner + "/" + repo, 49 wd: workDir, 50 }, nil 51 } 52 53 // Post accepts a comment and holds it. Flush method actually posts comments to 54 // GitLab in parallel. 55 func (g *PushCommitsCommenter) Post(_ context.Context, c *reviewdog.Comment) error { 56 c.Result.Diagnostic.GetLocation().Path = filepath.ToSlash( 57 filepath.Join(g.wd, c.Result.Diagnostic.GetLocation().GetPath())) 58 g.Lock() 59 defer g.Unlock() 60 g.postComments = append(g.postComments, c) 61 return nil 62 } 63 64 // Flush posts comments which has not been posted yet. 65 func (g *PushCommitsCommenter) Flush(ctx context.Context) error { 66 g.Lock() 67 defer g.Unlock() 68 69 return g.postCommentsForEach(ctx) 70 } 71 72 func (g *PushCommitsCommenter) postCommentsForEach(ctx context.Context) error { 73 var eg errgroup.Group 74 for _, c := range g.postComments { 75 c := c 76 loc := c.Result.Diagnostic.GetLocation() 77 lnum := int(loc.GetRange().GetStart().GetLine()) 78 body := commentutil.MarkdownComment(c) 79 if !c.Result.InDiffFile || lnum == 0 || g.postedcs.IsPosted(c, lnum, body) { 80 continue 81 } 82 eg.Go(func() error { 83 prcomment := &gitlab.PostCommitCommentOptions{ 84 Note: gitlab.String(body), 85 Path: gitlab.String(loc.GetPath()), 86 Line: gitlab.Int(lnum), 87 LineType: gitlab.String("new"), 88 } 89 _, _, err := g.cli.Commits.PostCommitComment(g.projects, g.sha, prcomment, gitlab.WithContext(ctx)) 90 return err 91 }) 92 } 93 return eg.Wait() 94 }