diff --git a/client/clienter.go b/client/clienter.go index c2bb74d..924586f 100644 --- a/client/clienter.go +++ b/client/clienter.go @@ -8,12 +8,13 @@ import ( type Clienter interface { Add(ctx context.Context, dirs []string, name, baseURL string) error + Branches(ctx context.Context, repoDirs []string, args ...string) error CheckoutRepos(ctx context.Context, repoDirs []string, args ...string) error CloneRepos(ctx context.Context, dir string) ([]*Repository, error) + DiffRepos(ctx context.Context, repoDirs []string, args ...string) error GetDirs(ctx context.Context, dir string) ([]string, error) GetLogins(ctx context.Context) ([]string, error) GetRepos(ctx context.Context, name string) ([]*github.Repository, error) - Branches(ctx context.Context, repoDirs []string, args ...string) error ListTags(ctx context.Context, repoDirs []string, args ...string) error PullRepos(ctx context.Context, repoDirs []string, args ...string) error PushRepos(ctx context.Context, repoDirs []string, args ...string) error diff --git a/client/repos_diff.go b/client/repos_diff.go new file mode 100644 index 0000000..c46189d --- /dev/null +++ b/client/repos_diff.go @@ -0,0 +1,45 @@ +package client + +import ( + "bytes" + "context" + "fmt" + "os/exec" + "strings" +) + +func (c *Client) DiffRepos(ctx context.Context, dirs []string, args ...string) error { + args = append([]string{"diff"}, 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() + + 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 9fcf52d..78f1e75 100644 --- a/client/testclient/client.go +++ b/client/testclient/client.go @@ -98,3 +98,9 @@ func (c *TestClient) TagRepos(ctx context.Context, repoDirs []string, args ...st return nil } + +func (c *TestClient) DiffRepos(ctx context.Context, repoDirs []string, args ...string) error { + c.CommandsCalled = append(c.CommandsCalled, "DiffRepos") + + return nil +} diff --git a/cmd/diff.go b/cmd/diff.go new file mode 100644 index 0000000..5223fc8 --- /dev/null +++ b/cmd/diff.go @@ -0,0 +1,58 @@ +package cmd + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" +) + +var ( + short bool + nameOnly bool +) + +func init() { + RootCmd.AddCommand(diffCmd) + + diffCmd.Flags().StringVar(&dir, "dir", ".", "directory to diff repos from") + diffCmd.Flags().BoolVar(&short, "shortstat", false, "show only the number of changed files, insertions, and deletions") + diffCmd.Flags().BoolVar(&nameOnly, "name-only", false, "show only names of changed files") + + diffCmd.MarkFlagsMutuallyExclusive("shortstat", "name-only") +} + +var diffCmd = &cobra.Command{ + Use: "diff [flags] ", + Short: "Diff all repos in a directory", + Long: `Diff 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.`, + Args: cobra.ExactArgs(2), + PersistentPreRun: setupClient, + RunE: diffFunc, +} + +func diffFunc(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) + } + + switch { + case short: + args = append(args, "--shortstat") + case nameOnly: + args = append(args, "--name-only") + } + + err = clt.DiffRepos(ctx, repoDirs, args...) + if err != nil { + cmd.SilenceUsage = true + return fmt.Errorf("diff repos: %w", err) + } + + return nil +}