diff --git a/pkg/cmd/pr/diff/diff.go b/pkg/cmd/pr/diff/diff.go index 3d9d32083..108041008 100644 --- a/pkg/cmd/pr/diff/diff.go +++ b/pkg/cmd/pr/diff/diff.go @@ -5,6 +5,8 @@ import ( "fmt" "io" "net/http" + "os" + "os/exec" "strings" "github.com/cli/cli/api" @@ -13,6 +15,7 @@ import ( "github.com/cli/cli/pkg/cmd/pr/shared" "github.com/cli/cli/pkg/cmdutil" "github.com/cli/cli/pkg/iostreams" + "github.com/google/shlex" "github.com/spf13/cobra" ) @@ -90,6 +93,12 @@ func diffRun(opts *DiffOptions) error { return err } + if opts.IO.IsStdoutTTY() { + if pager := os.Getenv("PAGER"); pager != "" { + return runPager(pager, diff, opts.IO.Out) + } + } + diffLines := bufio.NewScanner(diff) for diffLines.Scan() { diffLine := diffLines.Text() @@ -134,3 +143,14 @@ func isRemovalLine(dl string) bool { func validColorFlag(c string) bool { return c == "auto" || c == "always" || c == "never" } + +var runPager = func(pager string, diff io.Reader, out io.Writer) error { + args, err := shlex.Split(pager) + if err != nil { + return err + } + pagerCmd := exec.Command(args[0], args[1:]...) + pagerCmd.Stdin = diff + pagerCmd.Stdout = out + return pagerCmd.Run() +} diff --git a/pkg/cmd/pr/diff/diff_test.go b/pkg/cmd/pr/diff/diff_test.go index 85c74cb7f..3f52435a9 100644 --- a/pkg/cmd/pr/diff/diff_test.go +++ b/pkg/cmd/pr/diff/diff_test.go @@ -2,8 +2,10 @@ package diff import ( "bytes" + "io" "io/ioutil" "net/http" + "os" "testing" "github.com/cli/cli/context" @@ -131,8 +133,13 @@ func TestPRDiff_notty(t *testing.T) { } func TestPRDiff_tty(t *testing.T) { + pager := os.Getenv("PAGER") http := &httpmock.Registry{} - defer http.Verify(t) + defer func() { + os.Setenv("PAGER", pager) + http.Verify(t) + }() + os.Setenv("PAGER", "") http.StubResponse(200, bytes.NewBufferString(` { "data": { "repository": { "pullRequests": { "nodes": [ { "url": "https://github.com/OWNER/REPO/pull/123", @@ -149,6 +156,38 @@ func TestPRDiff_tty(t *testing.T) { assert.Contains(t, output.String(), "\x1b[32m+site: bin/gh\x1b[m") } +func TestPRDiff_pager(t *testing.T) { + realRunPager := runPager + pager := os.Getenv("PAGER") + http := &httpmock.Registry{} + defer func() { + runPager = realRunPager + os.Setenv("PAGER", pager) + http.Verify(t) + }() + runPager = func(pager string, diff io.Reader, out io.Writer) error { + _, err := io.Copy(out, diff) + return err + } + os.Setenv("PAGER", "fakepager") + http.StubResponse(200, bytes.NewBufferString(` + { "data": { "repository": { "pullRequests": { "nodes": [ + { "url": "https://github.com/OWNER/REPO/pull/123", + "number": 123, + "id": "foobar123", + "headRefName": "feature", + "baseRefName": "master" } + ] } } } }`)) + http.StubResponse(200, bytes.NewBufferString(testDiff)) + output, err := runCommand(http, nil, true, "") + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + if diff := cmp.Diff(testDiff, output.String()); diff != "" { + t.Errorf("command output did not match:\n%s", diff) + } +} + const testDiff = `diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index 73974448..b7fc0154 100644 --- a/.github/workflows/releases.yml