github.com/haya14busa/reviewdog@v0.0.0-20180723114510-ffb00ef78fd3/gitlab_mr_diff.go (about)

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