github.com/reviewdog/reviewdog@v0.17.5-0.20240516205324-0cd103a83d58/service/gitlab/gitlab_mr_diff.go (about) 1 package gitlab 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "os/exec" 8 "strings" 9 10 "github.com/xanzy/go-gitlab" 11 12 "github.com/reviewdog/reviewdog" 13 "github.com/reviewdog/reviewdog/service/serviceutil" 14 ) 15 16 var _ reviewdog.DiffService = &MergeRequestDiff{} 17 18 // MergeRequestDiff is a diff service for GitLab MergeRequest. 19 type MergeRequestDiff struct { 20 cli *gitlab.Client 21 pr int 22 sha string 23 projects string 24 25 // wd is working directory relative to root of repository. 26 wd string 27 } 28 29 // NewGitLabMergeRequestDiff returns a new MergeRequestDiff service. 30 // itLabMergeRequestDiff service needs git command in $PATH. 31 func NewGitLabMergeRequestDiff(cli *gitlab.Client, owner, repo string, pr int, sha string) (*MergeRequestDiff, error) { 32 workDir, err := serviceutil.GitRelWorkdir() 33 if err != nil { 34 return nil, fmt.Errorf("MergeRequestCommitCommenter needs 'git' command: %w", err) 35 } 36 return &MergeRequestDiff{ 37 cli: cli, 38 pr: pr, 39 sha: sha, 40 projects: owner + "/" + repo, 41 wd: workDir, 42 }, nil 43 } 44 45 // Diff returns a diff of MergeRequest. It runs `git diff` locally instead of 46 // diff_url of GitLab Merge Request because diff of diff_url is not suited for 47 // comment API in a sense that diff of diff_url is equivalent to 48 // `git diff --no-renames`, we want diff which is equivalent to 49 // `git diff --find-renames`. 50 func (g *MergeRequestDiff) Diff(ctx context.Context) ([]byte, error) { 51 mr, _, err := g.cli.MergeRequests.GetMergeRequest(g.projects, g.pr, nil) 52 if err != nil { 53 return nil, err 54 } 55 targetBranch, _, err := g.cli.Branches.GetBranch(mr.TargetProjectID, mr.TargetBranch, nil) 56 if err != nil { 57 return nil, err 58 } 59 return g.gitDiff(ctx, g.sha, targetBranch.Commit.ID) 60 } 61 62 func (g *MergeRequestDiff) gitDiff(_ context.Context, baseSha, targetSha string) ([]byte, error) { 63 mergeBase := os.Getenv("CI_MERGE_REQUEST_DIFF_BASE_SHA") 64 if mergeBase == "" { 65 b, err := exec.Command("git", "merge-base", targetSha, baseSha).Output() 66 if err != nil { 67 return nil, fmt.Errorf("failed to get merge-base commit: %w", err) 68 } 69 mergeBase = strings.Trim(string(b), "\n") 70 } 71 bytes, err := exec.Command("git", "diff", "--find-renames", mergeBase, baseSha).Output() 72 if err != nil { 73 return nil, fmt.Errorf("failed to run git diff: %w", err) 74 } 75 return bytes, nil 76 } 77 78 // Strip returns 1 as a strip of git diff. 79 func (g *MergeRequestDiff) Strip() int { 80 return 1 81 }