diff --git a/cmd/logging.go b/cmd/logging.go index 1c5c3373..e53a638f 100644 --- a/cmd/logging.go +++ b/cmd/logging.go @@ -9,6 +9,7 @@ import ( "github.com/spf13/cobra" internallog "github.com/lindell/multi-gitter/internal/log" + "github.com/lindell/multi-gitter/internal/multigitter/terminal" ) func configureLogging(cmd *cobra.Command, logFile string) { @@ -25,6 +26,8 @@ func configureLogging(cmd *cobra.Command, logFile string) { }) flags.StringP("log-file", "", logFile, `The file where all logs should be printed to. "-" means stdout.`) + + flags.BoolP("plain-output", "", false, `Don't use any terminal formatting when printing the output.`) } func logFlagInit(cmd *cobra.Command, _ []string) error { @@ -36,16 +39,25 @@ func logFlagInit(cmd *cobra.Command, _ []string) error { } log.SetLevel(logLevel) + // Set how custom terminal formatting is handled + plainOutput, _ := cmd.Flags().GetBool("plain-output") + terminal.DefaultPrinter.Plain = plainOutput + // Parse and set the log format strFormat, _ := cmd.Flags().GetString("log-format") var formatter log.Formatter switch strFormat { case "text": - formatter = &log.TextFormatter{} + formatter = &log.TextFormatter{ + DisableColors: plainOutput, + } case "json": formatter = &log.JSONFormatter{} case "json-pretty": + if plainOutput { + return errors.New("can't use json-pretty logs with with plain-output") + } formatter = &log.JSONFormatter{ PrettyPrint: true, } diff --git a/internal/multigitter/repocounter/counter.go b/internal/multigitter/repocounter/counter.go index 72b2cc5f..d9a46685 100644 --- a/internal/multigitter/repocounter/counter.go +++ b/internal/multigitter/repocounter/counter.go @@ -74,7 +74,7 @@ func (r *Counter) Info() string { if errInfo.pullRequest == nil { exitInfo += fmt.Sprintf(" %s\n", errInfo.repository.FullName()) } else { - if urler, ok := errInfo.pullRequest.(urler); ok { + if urler, hasURL := errInfo.pullRequest.(urler); hasURL && urler.URL() != "" { exitInfo += fmt.Sprintf(" %s\n", terminal.Link(errInfo.pullRequest.String(), urler.URL())) } else { exitInfo += fmt.Sprintf(" %s\n", errInfo.pullRequest.String()) @@ -87,7 +87,7 @@ func (r *Counter) Info() string { exitInfo += "Repositories with a successful run:\n" for _, repo := range r.successRepositories { if repo.pullRequest != nil { - if urler, ok := repo.pullRequest.(urler); ok { + if urler, hasURL := repo.pullRequest.(urler); hasURL && urler.URL() != "" { exitInfo += fmt.Sprintf(" %s\n", terminal.Link(repo.pullRequest.String(), urler.URL())) } else { exitInfo += fmt.Sprintf(" %s\n", repo.pullRequest.String()) diff --git a/internal/multigitter/status.go b/internal/multigitter/status.go index 953b3a85..0a6b82df 100644 --- a/internal/multigitter/status.go +++ b/internal/multigitter/status.go @@ -25,7 +25,7 @@ func (s Statuser) Statuses(ctx context.Context) error { } for _, pr := range prs { - if urler, ok := pr.(urler); ok { + if urler, hasURL := pr.(urler); hasURL && urler.URL() != "" { fmt.Fprintf(s.Output, "%s: %s\n", terminal.Link(pr.String(), urler.URL()), pr.Status()) } else { fmt.Fprintf(s.Output, "%s: %s\n", pr.String(), pr.Status()) diff --git a/internal/multigitter/terminal/terminal.go b/internal/multigitter/terminal/terminal.go index d12e336b..a06866fd 100644 --- a/internal/multigitter/terminal/terminal.go +++ b/internal/multigitter/terminal/terminal.go @@ -2,13 +2,38 @@ package terminal import "fmt" +// Printer formats things to the terminal +type Printer struct { + Plain bool // Don't use terminal formatting +} + +var DefaultPrinter = &Printer{} + // Link generates a link in that can be displayed in the terminal // https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda -func Link(text, url string) string { +func (t *Printer) Link(text, url string) string { + if t.Plain { + return text + } + return fmt.Sprintf("\x1B]8;;%s\a%s\x1B]8;;\a", url, text) } // Bold generates a bold text for the terminal -func Bold(text string) string { +func (t *Printer) Bold(text string) string { + if t.Plain { + return text + } + return fmt.Sprintf("\033[1m%s\033[0m", text) } + +// Link generates a link in that can be displayed in the terminal using the default terminal printer +func Link(text, url string) string { + return DefaultPrinter.Link(text, url) +} + +// Bold generates a bold text for the terminal using the default terminal printer +func Bold(text string) string { + return DefaultPrinter.Bold(text) +} diff --git a/tests/table_test.go b/tests/table_test.go index 2323b301..a6199e36 100644 --- a/tests/table_test.go +++ b/tests/table_test.go @@ -976,6 +976,53 @@ Repositories with a successful run: }, }, + { + name: "formats urls", + vcCreate: func(t *testing.T) *vcmock.VersionController { + return &vcmock.VersionController{ + Repositories: []vcmock.Repository{ + createRepo(t, "owner", "has-url", "i like apples"), + }, + } + }, + args: []string{ + "run", + "--author-name", "Test Author", + "--author-email", "test@example.com", + "-B", "custom-branch-name", + "-m", "custom message", + changerBinaryPath, + }, + verify: func(t *testing.T, vcMock *vcmock.VersionController, runData runData) { + assert.Equal(t, "Repositories with a successful run:\n \x1b]8;;https://github.com/owner/has-url/pull/1\aowner/has-url #1\x1b]8;;\a\n", runData.out) + }, + }, + + { + name: "does not format urls when --plain-output is used", + vcCreate: func(t *testing.T) *vcmock.VersionController { + return &vcmock.VersionController{ + Repositories: []vcmock.Repository{ + createRepo(t, "owner", "has-url", "i like apples"), + }, + } + }, + args: []string{ + "run", + "--author-name", "Test Author", + "--author-email", "test@example.com", + "-B", "custom-branch-name", + "-m", "custom message", + "--plain-output", + changerBinaryPath, + }, + verify: func(t *testing.T, vcMock *vcmock.VersionController, runData runData) { + assert.Equal(t, `Repositories with a successful run: + owner/has-url #1 +`, runData.out) + }, + }, + { name: "same feature and base branch name", vcCreate: func(t *testing.T) *vcmock.VersionController { diff --git a/tests/vcmock/vcmock.go b/tests/vcmock/vcmock.go index 93f2682c..dd37d5f0 100644 --- a/tests/vcmock/vcmock.go +++ b/tests/vcmock/vcmock.go @@ -197,6 +197,14 @@ func (pr PullRequest) String() string { return fmt.Sprintf("%s #%d", pr.Repository.FullName(), pr.PRNumber) } +func (pr PullRequest) URL() string { + if pr.Repository.RepoName == "has-url" { + return "https://github.com/owner/has-url/pull/1" + } + + return "" +} + // Repository is a mock repository type Repository struct { OwnerName string