diff --git a/client/clienter.go b/client/clienter.go index ddbc491..394564e 100644 --- a/client/clienter.go +++ b/client/clienter.go @@ -16,6 +16,7 @@ type Clienter interface { GetLogins(ctx context.Context) ([]string, error) GetRepos(ctx context.Context, name string) ([]*github.Repository, error) ListTags(ctx context.Context, repoDirs []string, args ...string) error + LogRepos(ctx context.Context, repoDirs []string, ignoreEmtpy bool, args ...string) error PullRepos(ctx context.Context, repoDirs []string, args ...string) error PushRepos(ctx context.Context, repoDirs []string, args ...string) error Remotes(ctx context.Context, repoDirs []string, args ...string) error diff --git a/client/repos_log.go b/client/repos_log.go new file mode 100644 index 0000000..cc0564b --- /dev/null +++ b/client/repos_log.go @@ -0,0 +1,49 @@ +package client + +import ( + "bytes" + "context" + "fmt" + "os/exec" + "strings" +) + +func (c *Client) LogRepos(ctx context.Context, dirs []string, ignoreEmpty bool, args ...string) error { + args = append([]string{"log"}, args...) + + c.scrb.BeginDescribe("Command") + defer c.scrb.EndDescribe() + + c.scrb.Print(fmt.Sprintf("git %s", strings.Join(args, " "))) + + c.scrb.BeginDescribe("directories") + defer c.scrb.EndDescribe() + + for _, dir := range dirs { + out := &bytes.Buffer{} + errout := &bytes.Buffer{} + + cmd := exec.CommandContext(ctx, "git", args...) + cmd.Stdout = out + cmd.Stderr = errout + cmd.Dir = dir + + err := cmd.Run() + + if ignoreEmpty && out.Len() == 0 && err == nil { + continue + } + + c.scrb.BeginDescribe(dir) + if err != nil { + c.scrb.Error(err) + c.scrb.PrintLines(errout) + } else { + c.scrb.PrintLines(out) + } + + c.scrb.EndDescribe() + } + + return nil +} diff --git a/client/testclient/client.go b/client/testclient/client.go index 6757a47..536b717 100644 --- a/client/testclient/client.go +++ b/client/testclient/client.go @@ -104,3 +104,9 @@ func (c *TestClient) DiffRepos(ctx context.Context, repoDirs []string, cfg *clie return nil } + +func (c *TestClient) LogRepos(ctx context.Context, repoDirs []string, ignoreEmtpy bool, args ...string) error { + c.CommandsCalled = append(c.CommandsCalled, "LogRepos") + + return nil +} diff --git a/cmd/log.go b/cmd/log.go new file mode 100644 index 0000000..fa0a753 --- /dev/null +++ b/cmd/log.go @@ -0,0 +1,56 @@ +package cmd + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" +) + +var ( + oneline bool + noColor bool +) + +func init() { + RootCmd.AddCommand(logCmd) + + logCmd.Flags().BoolVar(&oneline, "oneline", false, "Show each commit on a single line") + logCmd.Flags().BoolVar(&noColor, "no-color", false, "Disable color output") + logCmd.Flags().BoolVar(&ignoreEmtpy, "ignore-empty", false, "Ignore empty repositories") +} + +var logCmd = &cobra.Command{ + Use: "log", + Short: "Show commit logs for all repos in a directory", + Long: `Show commit logs all repos in a directory. Since commit hashes would not be the same between +multiple repos this command really only makes sense when used with two branch names or two tags.`, + PersistentPreRun: setupClient, + RunE: logFunc, +} + +func logFunc(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + repoDirs, err := clt.GetDirs(ctx, dir) + if err != nil { + cmd.SilenceUsage = true + return fmt.Errorf("get dirs: %w", err) + } + + if oneline { + args = append(args, "--oneline") + } + + if !noColor { + args = append(args, "--color") + } + + err = clt.LogRepos(ctx, repoDirs, ignoreEmtpy, args...) + if err != nil { + cmd.SilenceUsage = true + return fmt.Errorf("log repos: %w", err) + } + + return nil +}