github.com/vipcoin-gold/reviewdog@v1.0.2/service/gitlab/gitlab_mr_diff.go (about)

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