diff --git a/errors/errors.go b/errors/errors.go index fbe6ea6c..59ff8716 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -4,4 +4,5 @@ import "errors" var ( UnauthorizedError = errors.New("`repo-token` lacks required permissions") + NoGitError = errors.New("`git` not installed") ) diff --git a/main.go b/main.go index 077eddf7..332351de 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" "os" + "os/exec" "sort" "strings" @@ -165,18 +166,55 @@ func postGithubComment(ctx context.Context, flagsRef references.ReferenceSummary func getDiffs(ctx context.Context, config *lcr.Config, prNumber int) ([]*diff.FileDiff, error) { gha.Debug("Getting pull request diff...") - rawOpts := github.RawOptions{Type: github.Diff} - raw, resp, err := config.GHClient.PullRequests.GetRaw(ctx, config.Owner, config.Repo, prNumber, rawOpts) + + var ( + client = config.GHClient + owner = config.Owner + repo = config.Repo + rawOpts = github.RawOptions{Type: github.Diff} + rawDiff []byte + ) + + raw, resp, err := client.PullRequests.GetRaw(ctx, owner, repo, prNumber, rawOpts) + rawDiff = []byte(raw) if err != nil { // TODO use this elsewhere if resp.StatusCode == http.StatusUnauthorized { return nil, e.UnauthorizedError } - return nil, err + // check that git is installed + if _, gitCmdErr := exec.Command("git", "-v").CombinedOutput(); gitCmdErr != nil { + return nil, e.NoGitError + } + + // For very large diffs, the github api will return a 406, when this + // happens, fallback to calling `git diff` directly + if resp != nil && resp.StatusCode == http.StatusNotAcceptable { + gha.Debug("Diff too large, fallback to traditional git command") + pr, _, err := client.PullRequests.Get(ctx, owner, repo, prNumber) + if err != nil { + return nil, err + } + + headSha := pr.GetHead().GetSHA() + + commitsComparison, _, err := client.Repositories.CompareCommits(ctx, owner, repo, headSha, pr.GetBase().GetSHA(), nil) + if err != nil { + return nil, err + } + + mergeBaseSha := commitsComparison.GetMergeBaseCommit().GetSHA() + rawDiff, err = exec.Command("git", "diff", "--find-renames", mergeBaseSha, headSha).CombinedOutput() + // git diff return exit status 1 if there is a diff, so that does + // not indicate an error + if err != nil && err.Error() != "exit status 1" { + return nil, fmt.Errorf("failed to run git diff: %w", err) + } + } } - multi, err := diff.ParseMultiFileDiff([]byte(raw)) + multi, err := diff.ParseMultiFileDiff(rawDiff) if err != nil { return nil, err }