github.com/reviewdog/reviewdog@v0.17.5-0.20240516205324-0cd103a83d58/service/gerrit/change_diff.go (about) 1 package gerrit 2 3 import ( 4 "context" 5 "fmt" 6 "os/exec" 7 "strings" 8 9 "golang.org/x/build/gerrit" 10 11 "github.com/reviewdog/reviewdog" 12 "github.com/reviewdog/reviewdog/service/serviceutil" 13 ) 14 15 const ( 16 stripDiffResult = 1 17 ) 18 19 var _ reviewdog.DiffService = &ChangeDiff{} 20 21 // ChangeDiff is a diff service for Gerrit changes. 22 type ChangeDiff struct { 23 cli *gerrit.Client 24 changeID string 25 branch string 26 27 // wd is working directory relative to root of repository. 28 wd string 29 } 30 31 // NewChangeDiff returns a new ChangeDiff service, 32 // it needs git command in $PATH. 33 func NewChangeDiff(cli *gerrit.Client, branch, changeID string) (*ChangeDiff, error) { 34 workDir, err := serviceutil.GitRelWorkdir() 35 if err != nil { 36 return nil, fmt.Errorf("ChangeDiff needs 'git' command: %w", err) 37 } 38 return &ChangeDiff{ 39 cli: cli, 40 branch: branch, 41 changeID: changeID, 42 wd: workDir, 43 }, nil 44 } 45 46 // Diff returns a diff of MergeRequest. It runs `git diff` locally instead of 47 // diff_url of GitLab Merge Request because diff of diff_url is not suited for 48 // comment API in a sense that diff of diff_url is equivalent to 49 // `git diff --no-renames`, we want diff which is equivalent to 50 // `git diff --find-renames`. 51 func (g *ChangeDiff) Diff(ctx context.Context) ([]byte, error) { 52 change, err := g.cli.GetChangeDetail(ctx, g.changeID, gerrit.QueryChangesOpt{ 53 Fields: []string{"CURRENT_REVISION"}, 54 }) 55 if err != nil { 56 return nil, err 57 } 58 return g.gitDiff(ctx, change.CurrentRevision, g.branch) 59 } 60 61 func (g *ChangeDiff) gitDiff(_ context.Context, baseSha, targetSha string) ([]byte, error) { 62 b, err := exec.Command("git", "merge-base", targetSha, baseSha).Output() // #nosec 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 *ChangeDiff) Strip() int { 76 return stripDiffResult 77 }