diff --git a/command/issue.go b/command/issue.go index 4fc937a1e..53db25ad3 100644 --- a/command/issue.go +++ b/command/issue.go @@ -2,6 +2,7 @@ package command import ( "fmt" + "io" "os" "strconv" "strings" @@ -94,12 +95,15 @@ func issueList(cmd *cobra.Command, args []string) error { return err } + out := cmd.OutOrStdout() + colorOut := colorableOut(cmd) + if len(issues) == 0 { - printMessage("There are no open issues") + printMessage(colorOut, "There are no open issues") return nil } - table := utils.NewTablePrinter(cmd.OutOrStdout()) + table := utils.NewTablePrinter(out) for _, issue := range issues { issueNum := strconv.Itoa(issue.Number) if table.IsTTY() { @@ -141,30 +145,32 @@ func issueStatus(cmd *cobra.Command, args []string) error { return err } - printHeader("Issues assigned to you") + out := colorableOut(cmd) + + printHeader(out, "Issues assigned to you") if issuePayload.Assigned != nil { - printIssues(" ", issuePayload.Assigned...) + printIssues(out, " ", issuePayload.Assigned...) } else { message := fmt.Sprintf(" There are no issues assgined to you") - printMessage(message) + printMessage(out, message) } - fmt.Println() + fmt.Fprintln(out) - printHeader("Issues mentioning you") + printHeader(out, "Issues mentioning you") if len(issuePayload.Mentioned) > 0 { - printIssues(" ", issuePayload.Mentioned...) + printIssues(out, " ", issuePayload.Mentioned...) } else { - printMessage(" There are no issues mentioning you") + printMessage(out, " There are no issues mentioning you") } - fmt.Println() + fmt.Fprintln(out) - printHeader("Issues opened by you") + printHeader(out, "Issues opened by you") if len(issuePayload.Authored) > 0 { - printIssues(" ", issuePayload.Authored...) + printIssues(out, " ", issuePayload.Authored...) } else { - printMessage(" There are no issues opened by you") + printMessage(out, " There are no issues opened by you") } - fmt.Println() + fmt.Fprintln(out) return nil } @@ -255,14 +261,14 @@ func issueCreate(cmd *cobra.Command, args []string) error { return nil } -func printIssues(prefix string, issues ...api.Issue) { +func printIssues(w io.Writer, prefix string, issues ...api.Issue) { for _, issue := range issues { number := utils.Green("#" + strconv.Itoa(issue.Number)) coloredLabels := labelList(issue) if coloredLabels != "" { coloredLabels = utils.Gray(fmt.Sprintf(" (%s)", coloredLabels)) } - fmt.Printf("%s%s %s%s\n", prefix, number, truncate(70, issue.Title), coloredLabels) + fmt.Fprintf(w, "%s%s %s%s\n", prefix, number, truncate(70, issue.Title), coloredLabels) } } diff --git a/command/pr.go b/command/pr.go index 5b3a4a16a..3fdf42964 100644 --- a/command/pr.go +++ b/command/pr.go @@ -2,6 +2,7 @@ package command import ( "fmt" + "io" "os" "os/exec" "strconv" @@ -78,30 +79,32 @@ func prStatus(cmd *cobra.Command, args []string) error { return err } - printHeader("Current branch") + out := colorableOut(cmd) + + printHeader(out, "Current branch") if prPayload.CurrentPR != nil { - printPrs(*prPayload.CurrentPR) + printPrs(out, *prPayload.CurrentPR) } else { message := fmt.Sprintf(" There is no pull request associated with %s", utils.Cyan("["+currentBranch+"]")) - printMessage(message) + printMessage(out, message) } - fmt.Println() + fmt.Fprintln(out) - printHeader("Created by you") + printHeader(out, "Created by you") if len(prPayload.ViewerCreated) > 0 { - printPrs(prPayload.ViewerCreated...) + printPrs(out, prPayload.ViewerCreated...) } else { - printMessage(" You have no open pull requests") + printMessage(out, " You have no open pull requests") } - fmt.Println() + fmt.Fprintln(out) - printHeader("Requesting a code review from you") + printHeader(out, "Requesting a code review from you") if len(prPayload.ReviewRequested) > 0 { - printPrs(prPayload.ReviewRequested...) + printPrs(out, prPayload.ReviewRequested...) } else { - printMessage(" You have no pull requests to review") + printMessage(out, " You have no pull requests to review") } - fmt.Println() + fmt.Fprintln(out) return nil } @@ -330,15 +333,15 @@ func prCheckout(cmd *cobra.Command, args []string) error { return nil } -func printPrs(prs ...api.PullRequest) { +func printPrs(w io.Writer, prs ...api.PullRequest) { for _, pr := range prs { prNumber := fmt.Sprintf("#%d", pr.Number) - fmt.Printf(" %s %s %s", utils.Yellow(prNumber), truncate(50, pr.Title), utils.Cyan("["+pr.HeadLabel()+"]")) + fmt.Fprintf(w, " %s %s %s", utils.Yellow(prNumber), truncate(50, pr.Title), utils.Cyan("["+pr.HeadLabel()+"]")) checks := pr.ChecksStatus() reviews := pr.ReviewStatus() if checks.Total > 0 || reviews.ChangesRequested || reviews.Approved { - fmt.Printf("\n ") + fmt.Fprintf(w, "\n ") } if checks.Total > 0 { @@ -354,27 +357,27 @@ func printPrs(prs ...api.PullRequest) { } else if checks.Passing == checks.Total { summary = utils.Green("Checks passing") } - fmt.Printf(" - %s", summary) + fmt.Fprintf(w, " - %s", summary) } if reviews.ChangesRequested { - fmt.Printf(" - %s", utils.Red("changes requested")) + fmt.Fprintf(w, " - %s", utils.Red("changes requested")) } else if reviews.ReviewRequired { - fmt.Printf(" - %s", utils.Yellow("review required")) + fmt.Fprintf(w, " - %s", utils.Yellow("review required")) } else if reviews.Approved { - fmt.Printf(" - %s", utils.Green("approved")) + fmt.Fprintf(w, " - %s", utils.Green("approved")) } - fmt.Printf("\n") + fmt.Fprint(w, "\n") } } -func printHeader(s string) { - fmt.Println(utils.Bold(s)) +func printHeader(w io.Writer, s string) { + fmt.Fprintln(w, utils.Bold(s)) } -func printMessage(s string) { - fmt.Println(utils.Gray(s)) +func printMessage(w io.Writer, s string) { + fmt.Fprintln(w, utils.Gray(s)) } func truncate(maxLength int, title string) string { diff --git a/command/root.go b/command/root.go index e8764c44b..da730dd2b 100644 --- a/command/root.go +++ b/command/root.go @@ -2,11 +2,13 @@ package command import ( "fmt" + "io" "os" "strings" "github.com/github/gh-cli/api" "github.com/github/gh-cli/context" + "github.com/github/gh-cli/utils" "github.com/spf13/cobra" ) @@ -93,3 +95,11 @@ var apiClientForContext = func(ctx context.Context) (*api.Client, error) { } return api.NewClient(opts...), nil } + +func colorableOut(cmd *cobra.Command) io.Writer { + out := cmd.OutOrStdout() + if outFile, isFile := out.(*os.File); isFile { + return utils.NewColorable(outFile) + } + return out +} diff --git a/utils/color.go b/utils/color.go index fb8479734..b955c4755 100644 --- a/utils/color.go +++ b/utils/color.go @@ -1,11 +1,19 @@ package utils import ( + "io" + "os" + + "github.com/mattn/go-colorable" "github.com/mattn/go-isatty" "github.com/mgutz/ansi" - "os" ) +// NewColorable returns an output stream that handles ANSI color sequences on Windows +func NewColorable(f *os.File) io.Writer { + return colorable.NewColorable(f) +} + func makeColorFunc(color string) func(string) string { return func(arg string) string { output := arg diff --git a/utils/table_printer.go b/utils/table_printer.go index 89b1aebce..649e246e1 100644 --- a/utils/table_printer.go +++ b/utils/table_printer.go @@ -8,7 +8,6 @@ import ( "strconv" "strings" - "github.com/mattn/go-colorable" "github.com/mattn/go-isatty" "golang.org/x/crypto/ssh/terminal" ) @@ -37,7 +36,7 @@ func NewTablePrinter(w io.Writer) TablePrinter { } } return &ttyTablePrinter{ - out: colorable.NewColorable(outFile), + out: NewColorable(outFile), maxWidth: ttyWidth, } }