diff --git a/client/client.go b/client/client.go index 3375604..175c9f1 100644 --- a/client/client.go +++ b/client/client.go @@ -9,6 +9,8 @@ import ( "strings" sshgit "github.com/go-git/go-git/v5/plumbing/transport/ssh" + "github.com/gomicro/align/client/remotes" + "github.com/gomicro/align/client/repos" "github.com/gomicro/align/config" "github.com/gomicro/scribe" "github.com/gomicro/scribe/color" @@ -20,12 +22,12 @@ import ( ) type Client struct { + *repos.Repos + remoteMgr *remotes.Remotes cfg *config.Config ghClient *github.Client - rate *rate.Limiter ghSSHAuth *sshgit.PublicKeys ghHTTPSAuth *sshgit.Password - scrb scribe.Scriber } func New(cfg *config.Config) (*Client, error) { @@ -104,13 +106,15 @@ func New(cfg *config.Config) (*Client, error) { return nil, fmt.Errorf("scribe: %w", err) } + ghClient := github.NewClient(oauth2.NewClient(ctx, ts)) + return &Client{ + Repos: repos.New(scrb, ghClient, rl), + remoteMgr: remotes.New(scrb), cfg: cfg, - ghClient: github.NewClient(oauth2.NewClient(ctx, ts)), - rate: rl, + ghClient: ghClient, ghSSHAuth: publicKeys, ghHTTPSAuth: pass, - scrb: scrb, }, nil } @@ -149,3 +153,19 @@ func (c *Client) GetLogins(ctx context.Context) ([]string, error) { return logins, nil } + +func (c *Client) Remotes(ctx context.Context, dirs []string, args ...string) error { + return c.remoteMgr.Remotes(ctx, dirs, args...) +} + +func (c *Client) Add(ctx context.Context, dirs []string, name, baseURL string) error { + return c.remoteMgr.Add(ctx, dirs, name, baseURL) +} + +func (c *Client) Remove(ctx context.Context, dirs []string, name string) error { + return c.remoteMgr.Remove(ctx, dirs, name) +} + +func (c *Client) SetURLs(ctx context.Context, dirs []string, name, baseURL string) error { + return c.remoteMgr.SetURLs(ctx, dirs, name, baseURL) +} diff --git a/client/clienter.go b/client/clienter.go index ccaa144..fb37773 100644 --- a/client/clienter.go +++ b/client/clienter.go @@ -3,6 +3,8 @@ package client import ( "context" + clientctx "github.com/gomicro/align/client/context" + "github.com/gomicro/align/client/repos" "github.com/google/go-github/github" ) @@ -10,9 +12,9 @@ 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) + CloneRepos(ctx context.Context, dir string) ([]*clientctx.Repository, error) CommitRepos(ctx context.Context, dirs []string, args ...string) error - DiffRepos(ctx context.Context, repoDirs []string, cfg *DiffConfig) error + DiffRepos(ctx context.Context, repoDirs []string, cfg *repos.DiffConfig) error GetBranchAndTagNames(ctx context.Context, dirs []string) ([]string, error) GetBranchNames(ctx context.Context, dirs []string) ([]string, error) GetDirs(ctx context.Context, dir string) ([]string, error) diff --git a/client/context.go b/client/context/context.go similarity index 83% rename from client/context.go rename to client/context/context.go index 7a65648..6a24e52 100644 --- a/client/context.go +++ b/client/context/context.go @@ -1,4 +1,4 @@ -package client +package context import ( "context" @@ -10,18 +10,36 @@ import ( ) type reposContext int +type verboseContextKey struct{} var ( reposContextKey reposContext = 0 excludesContextKey reposContext = 1 - verboseContextKey reposContext = 2 + verboseKey = verboseContextKey{} ErrReposNotFoundInContext = errors.New("repos map not found in context") ) +func WithVerbose(ctx context.Context, verbose bool) context.Context { + return context.WithValue(ctx, verboseKey, verbose) +} + +func Verbose(ctx context.Context) bool { + v := ctx.Value(verboseKey) + verbose, ok := v.(bool) + if !ok { + return false + } + return verbose +} + +type Repository struct { + Name string + URL string +} + func WithRepos(ctx context.Context, repos []*github.Repository) context.Context { repoMap := parseDirRepoMap(repos) - return context.WithValue(ctx, reposContextKey, repoMap) } @@ -31,7 +49,6 @@ func RepoMap(ctx context.Context) (map[string][]*Repository, error) { if !ok { return nil, ErrReposNotFoundInContext } - return repoMap, nil } @@ -45,17 +62,11 @@ func Excludes(ctx context.Context) ([]*Repository, error) { if !ok { return nil, nil } - return excludes, nil } -type Repository struct { - name string - url string -} - func parseDirRepoMap(repos []*github.Repository) map[string][]*Repository { - var dirRepo = map[string][]*Repository{} + dirRepo := map[string][]*Repository{} for _, repo := range repos { parts := strings.Split(*repo.SSHURL, "/") @@ -63,17 +74,16 @@ func parseDirRepoMap(repos []*github.Repository) map[string][]*Repository { name := strings.TrimSuffix(parts[1], ".git") r := &Repository{ - name: name, - url: *repo.SSHURL, + Name: name, + URL: *repo.SSHURL, } dirRepo[dir] = append(dirRepo[dir], r) } - return dirRepo } -func removeExcludes(ctx context.Context, repoMap map[string][]*Repository) (map[string][]*Repository, error) { +func RemoveExcludes(ctx context.Context, repoMap map[string][]*Repository) (map[string][]*Repository, error) { newMap := map[string][]*Repository{} excludes, err := Excludes(ctx) @@ -85,12 +95,11 @@ func removeExcludes(ctx context.Context, repoMap map[string][]*Repository) (map[ for i := range rs { keep := true for j := range excludes { - if rs[i].url == excludes[j].url { + if rs[i].URL == excludes[j].URL { keep = false break } } - if keep { newMap[dir] = append(newMap[dir], rs[i]) } @@ -99,17 +108,3 @@ func removeExcludes(ctx context.Context, repoMap map[string][]*Repository) (map[ return newMap, nil } - -func WithVerbose(ctx context.Context, verbose bool) context.Context { - return context.WithValue(ctx, verboseContextKey, verbose) -} - -func Verbose(ctx context.Context) bool { - v := ctx.Value(verboseContextKey) - verbose, ok := v.(bool) - if !ok { - return false - } - - return verbose -} diff --git a/client/repos_dirs.go b/client/dirs.go similarity index 100% rename from client/repos_dirs.go rename to client/dirs.go diff --git a/client/remotes.go b/client/remotes.go deleted file mode 100644 index a9dadfe..0000000 --- a/client/remotes.go +++ /dev/null @@ -1,35 +0,0 @@ -package client - -import ( - "bytes" - "context" - "os/exec" -) - -func (c *Client) Remotes(ctx context.Context, dirs []string, args ...string) error { - args = append([]string{"remote"}, args...) - - 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 - - c.scrb.BeginDescribe(dir) - - err := cmd.Run() - 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/remotes_add.go b/client/remotes/add.go similarity index 70% rename from client/remotes_add.go rename to client/remotes/add.go index cef9f24..5a1a8b1 100644 --- a/client/remotes_add.go +++ b/client/remotes/add.go @@ -1,4 +1,4 @@ -package client +package remotes import ( "bytes" @@ -7,22 +7,23 @@ import ( "os/exec" "strings" + ctxhelper "github.com/gomicro/align/client/context" "github.com/gosuri/uiprogress" ) -func (c *Client) Add(ctx context.Context, dirs []string, name, baseURL string) error { +func (r *Remotes) Add(ctx context.Context, dirs []string, name, baseURL string) error { count := len(dirs) args := append([]string{"remote", "add"}, name) - verbose := Verbose(ctx) + verbose := ctxhelper.Verbose(ctx) var bar *uiprogress.Bar currRepo := "" if verbose { - c.scrb.BeginDescribe("Command") - defer c.scrb.EndDescribe() + r.scrb.BeginDescribe("Command") + defer r.scrb.EndDescribe() var vargs []string vargs = append(vargs, args...) @@ -30,10 +31,10 @@ func (c *Client) Add(ctx context.Context, dirs []string, name, baseURL string) e url := buildURL(baseURL, "") vargs = append(vargs, url) - c.scrb.Print(fmt.Sprintf("git %s", strings.Join(vargs, " "))) + r.scrb.Print(fmt.Sprintf("git %s", strings.Join(vargs, " "))) - c.scrb.BeginDescribe("directories") - defer c.scrb.EndDescribe() + r.scrb.BeginDescribe("directories") + defer r.scrb.EndDescribe() } else { bar = uiprogress.AddBar(count). AppendCompleted(). @@ -69,15 +70,15 @@ func (c *Client) Add(ctx context.Context, dirs []string, name, baseURL string) e } if verbose { - c.scrb.BeginDescribe(dir) + r.scrb.BeginDescribe(dir) if err != nil { - c.scrb.Error(err) - c.scrb.PrintLines(errout) + r.scrb.Error(err) + r.scrb.PrintLines(errout) } else { - c.scrb.PrintLines(out) + r.scrb.PrintLines(out) } - c.scrb.EndDescribe() + r.scrb.EndDescribe() } else { bar.Incr() } diff --git a/client/remotes/remotes.go b/client/remotes/remotes.go new file mode 100644 index 0000000..f10d2a6 --- /dev/null +++ b/client/remotes/remotes.go @@ -0,0 +1,45 @@ +package remotes + +import ( + "bytes" + "context" + "os/exec" + + "github.com/gomicro/scribe" +) + +type Remotes struct { + scrb scribe.Scriber +} + +func New(scrb scribe.Scriber) *Remotes { + return &Remotes{scrb: scrb} +} + +func (r *Remotes) Remotes(ctx context.Context, dirs []string, args ...string) error { + args = append([]string{"remote"}, args...) + + 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 + + r.scrb.BeginDescribe(dir) + + err := cmd.Run() + if err != nil { + r.scrb.Error(err) + r.scrb.PrintLines(errout) + } else { + r.scrb.PrintLines(out) + } + + r.scrb.EndDescribe() + } + + return nil +} diff --git a/client/remotes_remove.go b/client/remotes/remove.go similarity index 66% rename from client/remotes_remove.go rename to client/remotes/remove.go index f48896a..c5c8a19 100644 --- a/client/remotes_remove.go +++ b/client/remotes/remove.go @@ -1,4 +1,4 @@ -package client +package remotes import ( "bytes" @@ -7,27 +7,28 @@ import ( "os/exec" "strings" + ctxhelper "github.com/gomicro/align/client/context" "github.com/gosuri/uiprogress" ) -func (c *Client) Remove(ctx context.Context, dirs []string, name string) error { +func (r *Remotes) Remove(ctx context.Context, dirs []string, name string) error { count := len(dirs) args := append([]string{"remote", "remove"}, name) - verbose := Verbose(ctx) + verbose := ctxhelper.Verbose(ctx) var bar *uiprogress.Bar currRepo := "" if verbose { - c.scrb.BeginDescribe("Command") - defer c.scrb.EndDescribe() + r.scrb.BeginDescribe("Command") + defer r.scrb.EndDescribe() - c.scrb.Print(fmt.Sprintf("git %s", strings.Join(args, " "))) + r.scrb.Print(fmt.Sprintf("git %s", strings.Join(args, " "))) - c.scrb.BeginDescribe("directories") - defer c.scrb.EndDescribe() + r.scrb.BeginDescribe("directories") + defer r.scrb.EndDescribe() } else { bar = uiprogress.AddBar(count). AppendCompleted(). @@ -57,15 +58,15 @@ func (c *Client) Remove(ctx context.Context, dirs []string, name string) error { } if verbose { - c.scrb.BeginDescribe(dir) + r.scrb.BeginDescribe(dir) if err != nil { - c.scrb.Error(err) - c.scrb.PrintLines(errout) + r.scrb.Error(err) + r.scrb.PrintLines(errout) } else { - c.scrb.PrintLines(out) + r.scrb.PrintLines(out) } - c.scrb.EndDescribe() + r.scrb.EndDescribe() } else { bar.Incr() } diff --git a/client/remotes_seturls.go b/client/remotes/seturls.go similarity index 72% rename from client/remotes_seturls.go rename to client/remotes/seturls.go index 3ef2870..617a016 100644 --- a/client/remotes_seturls.go +++ b/client/remotes/seturls.go @@ -1,4 +1,4 @@ -package client +package remotes import ( "bytes" @@ -7,22 +7,23 @@ import ( "os/exec" "strings" + ctxhelper "github.com/gomicro/align/client/context" "github.com/gosuri/uiprogress" ) -func (c *Client) SetURLs(ctx context.Context, dirs []string, name, baseURL string) error { +func (r *Remotes) SetURLs(ctx context.Context, dirs []string, name, baseURL string) error { count := len(dirs) args := append([]string{"remote", "set-url"}, name) - verbose := Verbose(ctx) + verbose := ctxhelper.Verbose(ctx) var bar *uiprogress.Bar currRepo := "" if verbose { - c.scrb.BeginDescribe("Command") - defer c.scrb.EndDescribe() + r.scrb.BeginDescribe("Command") + defer r.scrb.EndDescribe() var vargs []string vargs = append(vargs, args...) @@ -30,10 +31,10 @@ func (c *Client) SetURLs(ctx context.Context, dirs []string, name, baseURL strin url := buildURL(baseURL, "") vargs = append(vargs, url) - c.scrb.Print(fmt.Sprintf("git %s", strings.Join(vargs, " "))) + r.scrb.Print(fmt.Sprintf("git %s", strings.Join(vargs, " "))) - c.scrb.BeginDescribe("directories") - defer c.scrb.EndDescribe() + r.scrb.BeginDescribe("directories") + defer r.scrb.EndDescribe() } else { bar = uiprogress.AddBar(count). AppendCompleted(). @@ -69,15 +70,15 @@ func (c *Client) SetURLs(ctx context.Context, dirs []string, name, baseURL strin } if verbose { - c.scrb.BeginDescribe(dir) + r.scrb.BeginDescribe(dir) if err != nil { - c.scrb.Error(err) - c.scrb.PrintLines(errout) + r.scrb.Error(err) + r.scrb.PrintLines(errout) } else { - c.scrb.PrintLines(out) + r.scrb.PrintLines(out) } - c.scrb.EndDescribe() + r.scrb.EndDescribe() } else { bar.Incr() } diff --git a/client/repos/branch.go b/client/repos/branch.go new file mode 100644 index 0000000..388abb3 --- /dev/null +++ b/client/repos/branch.go @@ -0,0 +1,169 @@ +package repos + +import ( + "bytes" + "context" + "errors" + "fmt" + "os/exec" + "sort" + "strings" + + ctxhelper "github.com/gomicro/align/client/context" + "github.com/gosuri/uiprogress" +) + +func (r *Repos) ListBranches(ctx context.Context, dirs []string, args ...string) error { + args = append([]string{"branch"}, args...) + + verbose := ctxhelper.Verbose(ctx) + if verbose { + r.scrb.BeginDescribe("Running with command:") + r.scrb.Print(strings.Join(append([]string{"git"}, args...), " ")) + r.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 + + r.scrb.BeginDescribe(dir) + + err := cmd.Run() + if err != nil { + r.scrb.Error(err) + r.scrb.PrintLines(errout) + } else { + r.scrb.PrintLines(out) + } + + r.scrb.EndDescribe() + } + + return nil +} + +func (r *Repos) Branches(ctx context.Context, dirs []string, args ...string) error { + count := len(dirs) + args = append([]string{"branch"}, args...) + + verbose := ctxhelper.Verbose(ctx) + + var bar *uiprogress.Bar + currRepo := "" + + if verbose { + r.scrb.BeginDescribe("Command") + defer r.scrb.EndDescribe() + + r.scrb.Print(fmt.Sprintf("git %s", strings.Join(args, " "))) + + r.scrb.BeginDescribe("directories") + defer r.scrb.EndDescribe() + } else { + bar = uiprogress.AddBar(count). + AppendCompleted(). + PrependElapsed(). + PrependFunc(func(b *uiprogress.Bar) string { + return fmt.Sprintf("Branches (%d/%d)", b.Current(), count) + }). + AppendFunc(func(b *uiprogress.Bar) string { + return currRepo + }) + } + + var errs []error + + for _, dir := range dirs { + currRepo = fmt.Sprintf("\nCurrent Repo: %v", dir) + + 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 verbose { + r.scrb.BeginDescribe(dir) + if err != nil { + r.scrb.Error(err) + r.scrb.PrintLines(errout) + } else { + r.scrb.PrintLines(out) + } + + r.scrb.EndDescribe() + } else { + if err != nil { + errs = append(errs, fmt.Errorf("%s: %w: %s", dir, err, strings.TrimSpace(errout.String()))) + } + + bar.Incr() + } + } + + currRepo = "" + + return errors.Join(errs...) +} + +func (r *Repos) GetBranchNames(ctx context.Context, dirs []string) ([]string, error) { + seen := map[string]struct{}{} + names := []string{} + + for _, dir := range dirs { + out := &bytes.Buffer{} + cmd := exec.CommandContext(ctx, "git", "branch", "--list", "--format=%(refname:short)") + cmd.Stdout = out + cmd.Dir = dir + + err := cmd.Run() + if err != nil { + return nil, fmt.Errorf("get branch names: %w", err) + } + + for _, name := range strings.Split(strings.TrimSpace(out.String()), "\n") { + if name == "" { + continue + } + if _, ok := seen[name]; !ok { + seen[name] = struct{}{} + names = append(names, name) + } + } + } + + sort.Strings(names) + return names, nil +} + +func (r *Repos) GetBranchAndTagNames(ctx context.Context, dirs []string) ([]string, error) { + branches, err := r.GetBranchNames(ctx, dirs) + if err != nil { + return nil, fmt.Errorf("get branches: %w", err) + } + + tags, err := r.GetTagNames(ctx, dirs) + if err != nil { + return nil, fmt.Errorf("get tags: %w", err) + } + + seen := map[string]struct{}{} + names := []string{} + for _, n := range append(branches, tags...) { + if _, ok := seen[n]; !ok { + seen[n] = struct{}{} + names = append(names, n) + } + } + + return names, nil +} diff --git a/client/repos_checkout.go b/client/repos/checkout.go similarity index 67% rename from client/repos_checkout.go rename to client/repos/checkout.go index 9bd0c44..43293bc 100644 --- a/client/repos_checkout.go +++ b/client/repos/checkout.go @@ -1,4 +1,4 @@ -package client +package repos import ( "bytes" @@ -8,26 +8,27 @@ import ( "os/exec" "strings" + ctxhelper "github.com/gomicro/align/client/context" "github.com/gosuri/uiprogress" ) -func (c *Client) CheckoutRepos(ctx context.Context, dirs []string, args ...string) error { +func (r *Repos) CheckoutRepos(ctx context.Context, dirs []string, args ...string) error { count := len(dirs) args = append([]string{"checkout"}, args...) - verbose := Verbose(ctx) + verbose := ctxhelper.Verbose(ctx) var bar *uiprogress.Bar currRepo := "" if verbose { - c.scrb.BeginDescribe("Command") - defer c.scrb.EndDescribe() + r.scrb.BeginDescribe("Command") + defer r.scrb.EndDescribe() - c.scrb.Print(fmt.Sprintf("git %s", strings.Join(args, " "))) + r.scrb.Print(fmt.Sprintf("git %s", strings.Join(args, " "))) - c.scrb.BeginDescribe("directories") - defer c.scrb.EndDescribe() + r.scrb.BeginDescribe("directories") + defer r.scrb.EndDescribe() } else { bar = uiprogress.AddBar(count). AppendCompleted(). @@ -55,15 +56,15 @@ func (c *Client) CheckoutRepos(ctx context.Context, dirs []string, args ...strin err := cmd.Run() if verbose { - c.scrb.BeginDescribe(dir) + r.scrb.BeginDescribe(dir) if err != nil { - c.scrb.Error(err) - c.scrb.PrintLines(errout) + r.scrb.Error(err) + r.scrb.PrintLines(errout) } else { - c.scrb.PrintLines(out) + r.scrb.PrintLines(out) } - c.scrb.EndDescribe() + r.scrb.EndDescribe() } else { if err != nil { errs = append(errs, fmt.Errorf("%s: %w: %s", dir, err, strings.TrimSpace(errout.String()))) diff --git a/client/repos_clone.go b/client/repos/clone.go similarity index 76% rename from client/repos_clone.go rename to client/repos/clone.go index 33893b6..e0056fe 100644 --- a/client/repos_clone.go +++ b/client/repos/clone.go @@ -1,4 +1,4 @@ -package client +package repos import ( "bytes" @@ -8,16 +8,17 @@ import ( "os/exec" "path" + ctxhelper "github.com/gomicro/align/client/context" "github.com/gosuri/uiprogress" ) -func (c *Client) CloneRepos(ctx context.Context, baseDir string) ([]*Repository, error) { - dirRepos, err := RepoMap(ctx) +func (r *Repos) CloneRepos(ctx context.Context, baseDir string) ([]*ctxhelper.Repository, error) { + dirRepos, err := ctxhelper.RepoMap(ctx) if err != nil { return nil, fmt.Errorf("repomap context: %w", err) } - dirRepos, err = removeExcludes(ctx, dirRepos) + dirRepos, err = ctxhelper.RemoveExcludes(ctx, dirRepos) if err != nil { return nil, fmt.Errorf("remove excludes: %w", err) } @@ -38,7 +39,7 @@ func (c *Client) CloneRepos(ctx context.Context, baseDir string) ([]*Repository, return currRepo }) - cloned := []*Repository{} + cloned := []*ctxhelper.Repository{} var errs error for dir, rs := range dirRepos { if baseDir != "" { @@ -46,8 +47,8 @@ func (c *Client) CloneRepos(ctx context.Context, baseDir string) ([]*Repository, } for i := range rs { - currRepo = fmt.Sprintf("\nCurrent Repo: %v/%v", dir, rs[i].name) - dest := path.Join(".", dir, rs[i].name) + currRepo = fmt.Sprintf("\nCurrent Repo: %v/%v", dir, rs[i].Name) + dest := path.Join(".", dir, rs[i].Name) exists, err := dirExists(dest) if err != nil { @@ -64,7 +65,7 @@ func (c *Client) CloneRepos(ctx context.Context, baseDir string) ([]*Repository, } if !exists { - cmd := exec.CommandContext(ctx, "git", "clone", rs[i].url, dest) + cmd := exec.CommandContext(ctx, "git", "clone", rs[i].URL, dest) buf := bytes.Buffer{} cmd.Stdout = &buf diff --git a/client/repos_commit.go b/client/repos/commit.go similarity index 67% rename from client/repos_commit.go rename to client/repos/commit.go index 8d2dcc7..0c84d31 100644 --- a/client/repos_commit.go +++ b/client/repos/commit.go @@ -1,4 +1,4 @@ -package client +package repos import ( "bytes" @@ -8,26 +8,27 @@ import ( "os/exec" "strings" + ctxhelper "github.com/gomicro/align/client/context" "github.com/gosuri/uiprogress" ) -func (c *Client) CommitRepos(ctx context.Context, dirs []string, args ...string) error { +func (r *Repos) CommitRepos(ctx context.Context, dirs []string, args ...string) error { count := len(dirs) args = append([]string{"commit"}, args...) - verbose := Verbose(ctx) + verbose := ctxhelper.Verbose(ctx) var bar *uiprogress.Bar currRepo := "" if verbose { - c.scrb.BeginDescribe("Command") - defer c.scrb.EndDescribe() + r.scrb.BeginDescribe("Command") + defer r.scrb.EndDescribe() - c.scrb.Print(fmt.Sprintf("git %s", strings.Join(args, " "))) + r.scrb.Print(fmt.Sprintf("git %s", strings.Join(args, " "))) - c.scrb.BeginDescribe("directories") - defer c.scrb.EndDescribe() + r.scrb.BeginDescribe("directories") + defer r.scrb.EndDescribe() } else { bar = uiprogress.AddBar(count). AppendCompleted(). @@ -55,15 +56,15 @@ func (c *Client) CommitRepos(ctx context.Context, dirs []string, args ...string) err := cmd.Run() if verbose { - c.scrb.BeginDescribe(dir) + r.scrb.BeginDescribe(dir) if err != nil { - c.scrb.Error(err) - c.scrb.PrintLines(errout) + r.scrb.Error(err) + r.scrb.PrintLines(errout) } else { - c.scrb.PrintLines(out) + r.scrb.PrintLines(out) } - c.scrb.EndDescribe() + r.scrb.EndDescribe() } else { if err != nil { errs = append(errs, fmt.Errorf("%s: %w: %s", dir, err, strings.TrimSpace(errout.String()))) diff --git a/client/repos_diff.go b/client/repos/diff.go similarity index 80% rename from client/repos_diff.go rename to client/repos/diff.go index 26d5616..2fede78 100644 --- a/client/repos_diff.go +++ b/client/repos/diff.go @@ -1,4 +1,4 @@ -package client +package repos import ( "bufio" @@ -16,16 +16,16 @@ type DiffConfig struct { Args []string } -func (c *Client) DiffRepos(ctx context.Context, dirs []string, cfg *DiffConfig) error { +func (r *Repos) DiffRepos(ctx context.Context, dirs []string, cfg *DiffConfig) error { args := append([]string{"diff"}, cfg.Args...) - c.scrb.BeginDescribe("Command") - defer c.scrb.EndDescribe() + r.scrb.BeginDescribe("Command") + defer r.scrb.EndDescribe() - c.scrb.Print(fmt.Sprintf("git %s", strings.Join(args, " "))) + r.scrb.Print(fmt.Sprintf("git %s", strings.Join(args, " "))) - c.scrb.BeginDescribe("directories") - defer c.scrb.EndDescribe() + r.scrb.BeginDescribe("directories") + defer r.scrb.EndDescribe() for _, dir := range dirs { out := &bytes.Buffer{} @@ -47,15 +47,15 @@ func (c *Client) DiffRepos(ctx context.Context, dirs []string, cfg *DiffConfig) continue } - c.scrb.BeginDescribe(dir) + r.scrb.BeginDescribe(dir) if err != nil { - c.scrb.Error(err) - c.scrb.PrintLines(errout) + r.scrb.Error(err) + r.scrb.PrintLines(errout) } else { - c.scrb.PrintLines(out) + r.scrb.PrintLines(out) } - c.scrb.EndDescribe() + r.scrb.EndDescribe() } return nil diff --git a/client/repos_get.go b/client/repos/get.go similarity index 80% rename from client/repos_get.go rename to client/repos/get.go index 76267a9..ed8e3ce 100644 --- a/client/repos_get.go +++ b/client/repos/get.go @@ -1,4 +1,4 @@ -package client +package repos import ( "context" @@ -9,12 +9,12 @@ import ( "github.com/gosuri/uiprogress" ) -func (c *Client) GetRepos(ctx context.Context, name string) ([]*github.Repository, error) { +func (r *Repos) GetRepos(ctx context.Context, name string) ([]*github.Repository, error) { count := 0 orgFound := true - c.rate.Wait(ctx) //nolint: errcheck - org, resp, err := c.ghClient.Organizations.Get(ctx, name) + r.rate.Wait(ctx) //nolint: errcheck + org, resp, err := r.ghClient.Organizations.Get(ctx, name) if resp == nil && err != nil { if _, ok := err.(*github.RateLimitError); ok { return nil, fmt.Errorf("github: hit rate limit") @@ -26,8 +26,8 @@ func (c *Client) GetRepos(ctx context.Context, name string) ([]*github.Repositor if resp.StatusCode == http.StatusNotFound { orgFound = false - c.rate.Wait(ctx) //nolint: errcheck - user, _, err := c.ghClient.Users.Get(ctx, name) + r.rate.Wait(ctx) //nolint: errcheck + user, _, err := r.ghClient.Users.Get(ctx, name) if err != nil { if _, ok := err.(*github.RateLimitError); ok { return nil, fmt.Errorf("github: hit rate limit") @@ -76,11 +76,11 @@ func (c *Client) GetRepos(ctx context.Context, name string) ([]*github.Repositor var repos []*github.Repository for { var rs []*github.Repository - c.rate.Wait(ctx) //nolint: errcheck + r.rate.Wait(ctx) //nolint: errcheck if orgFound { - rs, resp, err = c.ghClient.Repositories.ListByOrg(ctx, name, orgOpts) + rs, resp, err = r.ghClient.Repositories.ListByOrg(ctx, name, orgOpts) } else { - rs, resp, err = c.ghClient.Repositories.List(ctx, name, userOpts) + rs, resp, err = r.ghClient.Repositories.List(ctx, name, userOpts) } if err != nil { diff --git a/client/repos/log.go b/client/repos/log.go new file mode 100644 index 0000000..14493db --- /dev/null +++ b/client/repos/log.go @@ -0,0 +1,54 @@ +package repos + +import ( + "bytes" + "context" + "fmt" + "os/exec" + "strings" + + ctxhelper "github.com/gomicro/align/client/context" +) + +func (r *Repos) LogRepos(ctx context.Context, dirs []string, ignoreEmpty bool, args ...string) error { + args = append([]string{"log"}, args...) + + verbose := ctxhelper.Verbose(ctx) + if verbose { + r.scrb.BeginDescribe("Command") + defer r.scrb.EndDescribe() + + r.scrb.Print(fmt.Sprintf("git %s", strings.Join(args, " "))) + + r.scrb.BeginDescribe("directories") + defer r.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 + } + + r.scrb.BeginDescribe(dir) + if err != nil { + r.scrb.Error(err) + r.scrb.PrintLines(errout) + } else { + r.scrb.PrintLines(out) + } + + r.scrb.EndDescribe() + } + + return nil +} diff --git a/client/repos_pull.go b/client/repos/pull.go similarity index 67% rename from client/repos_pull.go rename to client/repos/pull.go index 48b3c83..ed567ad 100644 --- a/client/repos_pull.go +++ b/client/repos/pull.go @@ -1,4 +1,4 @@ -package client +package repos import ( "bytes" @@ -8,26 +8,27 @@ import ( "os/exec" "strings" + ctxhelper "github.com/gomicro/align/client/context" "github.com/gosuri/uiprogress" ) -func (c *Client) PullRepos(ctx context.Context, dirs []string, args ...string) error { +func (r *Repos) PullRepos(ctx context.Context, dirs []string, args ...string) error { count := len(dirs) args = append([]string{"pull"}, args...) - verbose := Verbose(ctx) + verbose := ctxhelper.Verbose(ctx) var bar *uiprogress.Bar currRepo := "" if verbose { - c.scrb.BeginDescribe("Command") - defer c.scrb.EndDescribe() + r.scrb.BeginDescribe("Command") + defer r.scrb.EndDescribe() - c.scrb.Print(fmt.Sprintf("git %s", strings.Join(args, " "))) + r.scrb.Print(fmt.Sprintf("git %s", strings.Join(args, " "))) - c.scrb.BeginDescribe("directories") - defer c.scrb.EndDescribe() + r.scrb.BeginDescribe("directories") + defer r.scrb.EndDescribe() } else { bar = uiprogress.AddBar(count). AppendCompleted(). @@ -55,15 +56,15 @@ func (c *Client) PullRepos(ctx context.Context, dirs []string, args ...string) e err := cmd.Run() if verbose { - c.scrb.BeginDescribe(dir) + r.scrb.BeginDescribe(dir) if err != nil { - c.scrb.Error(err) - c.scrb.PrintLines(errout) + r.scrb.Error(err) + r.scrb.PrintLines(errout) } else { - c.scrb.PrintLines(out) + r.scrb.PrintLines(out) } - c.scrb.EndDescribe() + r.scrb.EndDescribe() } else { if err != nil { errs = append(errs, fmt.Errorf("%s: %w: %s", dir, err, strings.TrimSpace(errout.String()))) diff --git a/client/repos_push.go b/client/repos/push.go similarity index 67% rename from client/repos_push.go rename to client/repos/push.go index f812169..64ed06b 100644 --- a/client/repos_push.go +++ b/client/repos/push.go @@ -1,4 +1,4 @@ -package client +package repos import ( "bytes" @@ -8,26 +8,27 @@ import ( "os/exec" "strings" + ctxhelper "github.com/gomicro/align/client/context" "github.com/gosuri/uiprogress" ) -func (c *Client) PushRepos(ctx context.Context, dirs []string, args ...string) error { +func (r *Repos) PushRepos(ctx context.Context, dirs []string, args ...string) error { count := len(dirs) args = append([]string{"push"}, args...) - verbose := Verbose(ctx) + verbose := ctxhelper.Verbose(ctx) var bar *uiprogress.Bar currRepo := "" if verbose { - c.scrb.BeginDescribe("Command") - defer c.scrb.EndDescribe() + r.scrb.BeginDescribe("Command") + defer r.scrb.EndDescribe() - c.scrb.Print(fmt.Sprintf("git %s", strings.Join(args, " "))) + r.scrb.Print(fmt.Sprintf("git %s", strings.Join(args, " "))) - c.scrb.BeginDescribe("directories") - defer c.scrb.EndDescribe() + r.scrb.BeginDescribe("directories") + defer r.scrb.EndDescribe() } else { bar = uiprogress.AddBar(count). AppendCompleted(). @@ -56,15 +57,15 @@ func (c *Client) PushRepos(ctx context.Context, dirs []string, args ...string) e err = cmd.Run() if verbose { - c.scrb.BeginDescribe(dir) + r.scrb.BeginDescribe(dir) if err != nil { - c.scrb.Error(err) - c.scrb.PrintLines(errout) + r.scrb.Error(err) + r.scrb.PrintLines(errout) } else { - c.scrb.PrintLines(out) + r.scrb.PrintLines(out) } - c.scrb.EndDescribe() + r.scrb.EndDescribe() } else { if err != nil { errs = append(errs, fmt.Errorf("%s: %w: %s", dir, err, strings.TrimSpace(errout.String()))) diff --git a/client/repos_remotes_names.go b/client/repos/remotes.go similarity index 68% rename from client/repos_remotes_names.go rename to client/repos/remotes.go index c14b4f9..b174b69 100644 --- a/client/repos_remotes_names.go +++ b/client/repos/remotes.go @@ -1,32 +1,33 @@ -package client +package repos import ( "bytes" "context" + "fmt" "os/exec" + "sort" "strings" ) -func (c *Client) GetRemoteNames(ctx context.Context, dirs []string) ([]string, error) { +func (r *Repos) GetRemoteNames(ctx context.Context, dirs []string) ([]string, error) { seen := map[string]struct{}{} names := []string{} for _, dir := range dirs { out := &bytes.Buffer{} - cmd := exec.CommandContext(ctx, "git", "remote") cmd.Stdout = out cmd.Dir = dir - if err := cmd.Run(); err != nil { - continue + err := cmd.Run() + if err != nil { + return nil, fmt.Errorf("get remote names: %w", err) } for _, name := range strings.Split(strings.TrimSpace(out.String()), "\n") { if name == "" { continue } - if _, ok := seen[name]; !ok { seen[name] = struct{}{} names = append(names, name) @@ -34,5 +35,6 @@ func (c *Client) GetRemoteNames(ctx context.Context, dirs []string) ([]string, e } } + sort.Strings(names) return names, nil } diff --git a/client/repos/repos.go b/client/repos/repos.go new file mode 100644 index 0000000..781137b --- /dev/null +++ b/client/repos/repos.go @@ -0,0 +1,21 @@ +package repos + +import ( + "github.com/gomicro/scribe" + "github.com/google/go-github/github" + "golang.org/x/time/rate" +) + +type Repos struct { + scrb scribe.Scriber + ghClient *github.Client + rate *rate.Limiter +} + +func New(scrb scribe.Scriber, ghClient *github.Client, rate *rate.Limiter) *Repos { + return &Repos{ + scrb: scrb, + ghClient: ghClient, + rate: rate, + } +} diff --git a/client/repos_stage.go b/client/repos/stage.go similarity index 66% rename from client/repos_stage.go rename to client/repos/stage.go index 45f2d5f..3dcbcdb 100644 --- a/client/repos_stage.go +++ b/client/repos/stage.go @@ -1,4 +1,4 @@ -package client +package repos import ( "bytes" @@ -8,26 +8,27 @@ import ( "os/exec" "strings" + ctxhelper "github.com/gomicro/align/client/context" "github.com/gosuri/uiprogress" ) -func (c *Client) StageFiles(ctx context.Context, dirs []string, args ...string) error { +func (r *Repos) StageFiles(ctx context.Context, dirs []string, args ...string) error { count := len(dirs) args = append([]string{"add"}, args...) - verbose := Verbose(ctx) + verbose := ctxhelper.Verbose(ctx) var bar *uiprogress.Bar currRepo := "" if verbose { - c.scrb.BeginDescribe("Command") - defer c.scrb.EndDescribe() + r.scrb.BeginDescribe("Command") + defer r.scrb.EndDescribe() - c.scrb.Print(fmt.Sprintf("git %s", strings.Join(args, " "))) + r.scrb.Print(fmt.Sprintf("git %s", strings.Join(args, " "))) - c.scrb.BeginDescribe("directories") - defer c.scrb.EndDescribe() + r.scrb.BeginDescribe("directories") + defer r.scrb.EndDescribe() } else { bar = uiprogress.AddBar(count). AppendCompleted(). @@ -55,15 +56,15 @@ func (c *Client) StageFiles(ctx context.Context, dirs []string, args ...string) err := cmd.Run() if verbose { - c.scrb.BeginDescribe(dir) + r.scrb.BeginDescribe(dir) if err != nil { - c.scrb.Error(err) - c.scrb.PrintLines(errout) + r.scrb.Error(err) + r.scrb.PrintLines(errout) } else { - c.scrb.PrintLines(out) + r.scrb.PrintLines(out) } - c.scrb.EndDescribe() + r.scrb.EndDescribe() } else { if err != nil { errs = append(errs, fmt.Errorf("%s: %w: %s", dir, err, strings.TrimSpace(errout.String()))) diff --git a/client/repos/status.go b/client/repos/status.go new file mode 100644 index 0000000..b24592a --- /dev/null +++ b/client/repos/status.go @@ -0,0 +1,54 @@ +package repos + +import ( + "bytes" + "context" + "fmt" + "os/exec" + "strings" + + ctxhelper "github.com/gomicro/align/client/context" +) + +func (r *Repos) StatusRepos(ctx context.Context, dirs []string, ignoreEmpty bool, args ...string) error { + args = append([]string{"status"}, args...) + + verbose := ctxhelper.Verbose(ctx) + if verbose { + r.scrb.BeginDescribe("Command") + defer r.scrb.EndDescribe() + + r.scrb.Print(fmt.Sprintf("git %s", strings.Join(args, " "))) + + r.scrb.BeginDescribe("directories") + defer r.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 + } + + r.scrb.BeginDescribe(dir) + if err != nil { + r.scrb.Error(err) + r.scrb.PrintLines(errout) + } else { + r.scrb.PrintLines(out) + } + + r.scrb.EndDescribe() + } + + return nil +} diff --git a/client/repos/tag.go b/client/repos/tag.go new file mode 100644 index 0000000..128e016 --- /dev/null +++ b/client/repos/tag.go @@ -0,0 +1,150 @@ +package repos + +import ( + "bytes" + "context" + "errors" + "fmt" + "os/exec" + "sort" + "strings" + + ctxhelper "github.com/gomicro/align/client/context" + "github.com/gosuri/uiprogress" +) + +func (r *Repos) ListTags(ctx context.Context, dirs []string, args ...string) error { + args = append([]string{"tag"}, args...) + + verbose := ctxhelper.Verbose(ctx) + if verbose { + r.scrb.BeginDescribe("Command") + defer r.scrb.EndDescribe() + + r.scrb.Print(fmt.Sprintf("git %s", strings.Join(args, " "))) + + r.scrb.BeginDescribe("directories") + defer r.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 + + r.scrb.BeginDescribe(dir) + + err := cmd.Run() + if err != nil { + r.scrb.Error(err) + r.scrb.PrintLines(errout) + } else { + r.scrb.PrintLines(out) + } + + r.scrb.EndDescribe() + } + + return nil +} + +func (r *Repos) TagRepos(ctx context.Context, dirs []string, args ...string) error { + count := len(dirs) + args = append([]string{"tag"}, args...) + + verbose := ctxhelper.Verbose(ctx) + + var bar *uiprogress.Bar + currRepo := "" + + if verbose { + r.scrb.BeginDescribe("Command") + defer r.scrb.EndDescribe() + + r.scrb.Print(fmt.Sprintf("git %s", strings.Join(args, " "))) + + r.scrb.BeginDescribe("directories") + defer r.scrb.EndDescribe() + } else { + bar = uiprogress.AddBar(count). + AppendCompleted(). + PrependElapsed(). + PrependFunc(func(b *uiprogress.Bar) string { + return fmt.Sprintf("Tagging (%d/%d)", b.Current(), count) + }). + AppendFunc(func(b *uiprogress.Bar) string { + return currRepo + }) + } + + var errs []error + + for _, dir := range dirs { + currRepo = fmt.Sprintf("\nCurrent Repo: %v", dir) + + 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 verbose { + r.scrb.BeginDescribe(dir) + if err != nil { + r.scrb.Error(err) + r.scrb.PrintLines(errout) + } else { + r.scrb.PrintLines(out) + } + + r.scrb.EndDescribe() + } else { + if err != nil { + errs = append(errs, fmt.Errorf("%s: %w: %s", dir, err, strings.TrimSpace(errout.String()))) + } + + bar.Incr() + } + } + + currRepo = "" + + return errors.Join(errs...) +} + +func (r *Repos) GetTagNames(ctx context.Context, dirs []string) ([]string, error) { + seen := map[string]struct{}{} + names := []string{} + + for _, dir := range dirs { + out := &bytes.Buffer{} + cmd := exec.CommandContext(ctx, "git", "tag", "--list") + cmd.Stdout = out + cmd.Dir = dir + + err := cmd.Run() + if err != nil { + return nil, fmt.Errorf("get tag names: %w", err) + } + + for _, name := range strings.Split(strings.TrimSpace(out.String()), "\n") { + if name == "" { + continue + } + if _, ok := seen[name]; !ok { + seen[name] = struct{}{} + names = append(names, name) + } + } + } + + sort.Strings(names) + return names, nil +} diff --git a/client/repos_branch.go b/client/repos_branch.go deleted file mode 100644 index 5cd8a64..0000000 --- a/client/repos_branch.go +++ /dev/null @@ -1,114 +0,0 @@ -package client - -import ( - "bytes" - "context" - "errors" - "fmt" - "os/exec" - "strings" - - "github.com/gosuri/uiprogress" -) - -func (c *Client) ListBranches(ctx context.Context, dirs []string, args ...string) error { - args = append([]string{"branch"}, args...) - - verbose := Verbose(ctx) - if verbose { - c.scrb.BeginDescribe("Running with command:") - c.scrb.Print(strings.Join(append([]string{"git"}, args...), " ")) - 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 - - c.scrb.BeginDescribe(dir) - - err := cmd.Run() - if err != nil { - c.scrb.Error(err) - c.scrb.PrintLines(errout) - } else { - c.scrb.PrintLines(out) - } - - c.scrb.EndDescribe() - } - - return nil -} - -func (c *Client) Branches(ctx context.Context, dirs []string, args ...string) error { - count := len(dirs) - args = append([]string{"branch"}, args...) - - verbose := Verbose(ctx) - - var bar *uiprogress.Bar - currRepo := "" - - if verbose { - 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() - } else { - bar = uiprogress.AddBar(count). - AppendCompleted(). - PrependElapsed(). - PrependFunc(func(b *uiprogress.Bar) string { - return fmt.Sprintf("Branches (%d/%d)", b.Current(), count) - }). - AppendFunc(func(b *uiprogress.Bar) string { - return currRepo - }) - } - - var errs []error - - for _, dir := range dirs { - currRepo = fmt.Sprintf("\nCurrent Repo: %v", dir) - - 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 verbose { - c.scrb.BeginDescribe(dir) - if err != nil { - c.scrb.Error(err) - c.scrb.PrintLines(errout) - } else { - c.scrb.PrintLines(out) - } - - c.scrb.EndDescribe() - } else { - if err != nil { - errs = append(errs, fmt.Errorf("%s: %w: %s", dir, err, strings.TrimSpace(errout.String()))) - } - - bar.Incr() - } - } - - currRepo = "" - - return errors.Join(errs...) -} diff --git a/client/repos_branch_names.go b/client/repos_branch_names.go deleted file mode 100644 index 455972b..0000000 --- a/client/repos_branch_names.go +++ /dev/null @@ -1,38 +0,0 @@ -package client - -import ( - "bytes" - "context" - "os/exec" - "strings" -) - -func (c *Client) GetBranchNames(ctx context.Context, dirs []string) ([]string, error) { - seen := map[string]struct{}{} - names := []string{} - - for _, dir := range dirs { - out := &bytes.Buffer{} - - cmd := exec.CommandContext(ctx, "git", "branch", "--list", "--format=%(refname:short)") - cmd.Stdout = out - cmd.Dir = dir - - if err := cmd.Run(); err != nil { - continue - } - - for _, name := range strings.Split(strings.TrimSpace(out.String()), "\n") { - if name == "" { - continue - } - - if _, ok := seen[name]; !ok { - seen[name] = struct{}{} - names = append(names, name) - } - } - } - - return names, nil -} diff --git a/client/repos_branch_tag_names.go b/client/repos_branch_tag_names.go deleted file mode 100644 index 4258646..0000000 --- a/client/repos_branch_tag_names.go +++ /dev/null @@ -1,29 +0,0 @@ -package client - -import ( - "context" -) - -func (c *Client) GetBranchAndTagNames(ctx context.Context, dirs []string) ([]string, error) { - branches, err := c.GetBranchNames(ctx, dirs) - if err != nil { - return nil, err - } - - tags, err := c.GetTagNames(ctx, dirs) - if err != nil { - return nil, err - } - - seen := map[string]struct{}{} - names := make([]string, 0, len(branches)+len(tags)) - - for _, name := range append(branches, tags...) { - if _, ok := seen[name]; !ok { - seen[name] = struct{}{} - names = append(names, name) - } - } - - return names, nil -} diff --git a/client/repos_log.go b/client/repos_log.go deleted file mode 100644 index ff41139..0000000 --- a/client/repos_log.go +++ /dev/null @@ -1,52 +0,0 @@ -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...) - - verbose := Verbose(ctx) - if verbose { - 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/repos_status.go b/client/repos_status.go deleted file mode 100644 index eafe06d..0000000 --- a/client/repos_status.go +++ /dev/null @@ -1,52 +0,0 @@ -package client - -import ( - "bytes" - "context" - "fmt" - "os/exec" - "strings" -) - -func (c *Client) StatusRepos(ctx context.Context, dirs []string, ignoreEmpty bool, args ...string) error { - args = append([]string{"status"}, args...) - - verbose := Verbose(ctx) - if verbose { - 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/repos_tag.go b/client/repos_tag.go deleted file mode 100644 index d939f58..0000000 --- a/client/repos_tag.go +++ /dev/null @@ -1,118 +0,0 @@ -package client - -import ( - "bytes" - "context" - "errors" - "fmt" - "os/exec" - "strings" - - "github.com/gosuri/uiprogress" -) - -func (c *Client) ListTags(ctx context.Context, dirs []string, args ...string) error { - args = append([]string{"tag"}, args...) - - verbose := Verbose(ctx) - if verbose { - 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 - - c.scrb.BeginDescribe(dir) - - err := cmd.Run() - if err != nil { - c.scrb.Error(err) - c.scrb.PrintLines(errout) - } else { - c.scrb.PrintLines(out) - } - - c.scrb.EndDescribe() - } - - return nil -} - -func (c *Client) TagRepos(ctx context.Context, dirs []string, args ...string) error { - count := len(dirs) - args = append([]string{"tag"}, args...) - - verbose := Verbose(ctx) - - var bar *uiprogress.Bar - currRepo := "" - - if verbose { - 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() - } else { - bar = uiprogress.AddBar(count). - AppendCompleted(). - PrependElapsed(). - PrependFunc(func(b *uiprogress.Bar) string { - return fmt.Sprintf("Tagging (%d/%d)", b.Current(), count) - }). - AppendFunc(func(b *uiprogress.Bar) string { - return currRepo - }) - } - - var errs []error - - for _, dir := range dirs { - currRepo = fmt.Sprintf("\nCurrent Repo: %v", dir) - - 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 verbose { - c.scrb.BeginDescribe(dir) - if err != nil { - c.scrb.Error(err) - c.scrb.PrintLines(errout) - } else { - c.scrb.PrintLines(out) - } - - c.scrb.EndDescribe() - } else { - if err != nil { - errs = append(errs, fmt.Errorf("%s: %w: %s", dir, err, strings.TrimSpace(errout.String()))) - } - - bar.Incr() - } - } - - currRepo = "" - - return errors.Join(errs...) -} diff --git a/client/repos_tag_names.go b/client/repos_tag_names.go deleted file mode 100644 index 46a6ccd..0000000 --- a/client/repos_tag_names.go +++ /dev/null @@ -1,38 +0,0 @@ -package client - -import ( - "bytes" - "context" - "os/exec" - "strings" -) - -func (c *Client) GetTagNames(ctx context.Context, dirs []string) ([]string, error) { - seen := map[string]struct{}{} - names := []string{} - - for _, dir := range dirs { - out := &bytes.Buffer{} - - cmd := exec.CommandContext(ctx, "git", "tag", "--list") - cmd.Stdout = out - cmd.Dir = dir - - if err := cmd.Run(); err != nil { - continue - } - - for _, name := range strings.Split(strings.TrimSpace(out.String()), "\n") { - if name == "" { - continue - } - - if _, ok := seen[name]; !ok { - seen[name] = struct{}{} - names = append(names, name) - } - } - } - - return names, nil -} diff --git a/client/testclient/client.go b/client/testclient/client.go index 3e68cd4..4f639cb 100644 --- a/client/testclient/client.go +++ b/client/testclient/client.go @@ -3,7 +3,8 @@ package testclient import ( "context" - "github.com/gomicro/align/client" + clientctx "github.com/gomicro/align/client/context" + "github.com/gomicro/align/client/repos" "github.com/google/go-github/github" ) @@ -27,7 +28,7 @@ func (c *TestClient) CommitRepos(ctx context.Context, dirs []string, args ...str return nil } -func (c *TestClient) CloneRepos(ctx context.Context, baseDir string) ([]*client.Repository, error) { +func (c *TestClient) CloneRepos(ctx context.Context, baseDir string) ([]*clientctx.Repository, error) { c.CommandsCalled = append(c.CommandsCalled, "CloneRepos") return nil, nil @@ -141,7 +142,7 @@ func (c *TestClient) TagRepos(ctx context.Context, repoDirs []string, args ...st return nil } -func (c *TestClient) DiffRepos(ctx context.Context, repoDirs []string, cfg *client.DiffConfig) error { +func (c *TestClient) DiffRepos(ctx context.Context, repoDirs []string, cfg *repos.DiffConfig) error { c.CommandsCalled = append(c.CommandsCalled, "DiffRepos") return nil diff --git a/cmd/add.go b/cmd/add.go index d92c73b..bdbd841 100644 --- a/cmd/add.go +++ b/cmd/add.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/gomicro/align/client" + ctxhelper "github.com/gomicro/align/client/context" "github.com/gosuri/uiprogress" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -27,7 +27,7 @@ in each repo (equivalent to 'git add -A'). With arguments, stages only the speci func addFunc(cmd *cobra.Command, args []string) error { verbose := viper.GetBool("verbose") - ctx := client.WithVerbose(context.Background(), verbose) + ctx := ctxhelper.WithVerbose(context.Background(), verbose) if !verbose { uiprogress.Start() diff --git a/cmd/branch.go b/cmd/branch.go index 6bd1a5b..5e75cd9 100644 --- a/cmd/branch.go +++ b/cmd/branch.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/gomicro/align/client" + ctxhelper "github.com/gomicro/align/client/context" "github.com/gosuri/uiprogress" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -66,7 +66,7 @@ func branchCmdValidArgsFunc(cmd *cobra.Command, args []string, toComplete string func branchFunc(cmd *cobra.Command, args []string) error { verbose := viper.GetBool("verbose") - ctx := client.WithVerbose(context.Background(), verbose) + ctx := ctxhelper.WithVerbose(context.Background(), verbose) repoDirs, err := clt.GetDirs(ctx, dir) if err != nil { @@ -109,7 +109,7 @@ func branchFunc(cmd *cobra.Command, args []string) error { } // This must be verbose to show anything - ctx = client.WithVerbose(ctx, true) + ctx = ctxhelper.WithVerbose(ctx, true) err = clt.Branches(ctx, repoDirs, args...) if err != nil { diff --git a/cmd/checkout.go b/cmd/checkout.go index 4a73997..ded5fb2 100644 --- a/cmd/checkout.go +++ b/cmd/checkout.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/gomicro/align/client" + ctxhelper "github.com/gomicro/align/client/context" "github.com/gosuri/uiprogress" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -55,7 +55,7 @@ func checkoutCmdValidArgsFunc(cmd *cobra.Command, args []string, toComplete stri func checkoutFunc(cmd *cobra.Command, args []string) error { verbose := viper.GetBool("verbose") - ctx := client.WithVerbose(context.Background(), verbose) + ctx := ctxhelper.WithVerbose(context.Background(), verbose) if !verbose { uiprogress.Start() diff --git a/cmd/clone.go b/cmd/clone.go index bec863b..10d478d 100644 --- a/cmd/clone.go +++ b/cmd/clone.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/gomicro/align/client" + ctxhelper "github.com/gomicro/align/client/context" "github.com/google/go-github/github" "github.com/gosuri/uiprogress" "github.com/spf13/cobra" @@ -34,7 +34,7 @@ var cloneCmd = &cobra.Command{ func cloneFunc(cmd *cobra.Command, args []string) error { verbose := viper.GetBool("verbose") - ctx := client.WithVerbose(context.Background(), verbose) + ctx := ctxhelper.WithVerbose(context.Background(), verbose) if !verbose { uiprogress.Start() @@ -54,7 +54,7 @@ func cloneFunc(cmd *cobra.Command, args []string) error { repos = filterByTopics(repos, topics) - ctx = client.WithRepos(ctx, repos) + ctx = ctxhelper.WithRepos(ctx, repos) _, err = clt.CloneRepos(ctx, dir) if err != nil { diff --git a/cmd/commit.go b/cmd/commit.go index 2d40ca1..1860526 100644 --- a/cmd/commit.go +++ b/cmd/commit.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/gomicro/align/client" + ctxhelper "github.com/gomicro/align/client/context" "github.com/gosuri/uiprogress" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -38,7 +38,7 @@ var commitCmd = &cobra.Command{ func commitFunc(cmd *cobra.Command, args []string) error { verbose := viper.GetBool("verbose") - ctx := client.WithVerbose(context.Background(), verbose) + ctx := ctxhelper.WithVerbose(context.Background(), verbose) if !verbose { uiprogress.Start() diff --git a/cmd/diff.go b/cmd/diff.go index 5454321..3587cc9 100644 --- a/cmd/diff.go +++ b/cmd/diff.go @@ -4,7 +4,8 @@ import ( "context" "fmt" - "github.com/gomicro/align/client" + ctxhelper "github.com/gomicro/align/client/context" + "github.com/gomicro/align/client/repos" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -76,7 +77,7 @@ func diffCmdValidArgsFunc(cmd *cobra.Command, args []string, toComplete string) func diffFunc(cmd *cobra.Command, args []string) error { verbose := viper.GetBool("verbose") - ctx := client.WithVerbose(context.Background(), verbose) + ctx := ctxhelper.WithVerbose(context.Background(), verbose) repoDirs, err := clt.GetDirs(ctx, dir) if err != nil { @@ -95,7 +96,7 @@ func diffFunc(cmd *cobra.Command, args []string) error { args = append([]string{"--color"}, args...) } - cfg := &client.DiffConfig{ + cfg := &repos.DiffConfig{ IgnoreEmpty: ignoreEmtpy, IgnoreFilePrefix: ignoreFilePrefix, MatchExtension: matchExtension, diff --git a/cmd/log.go b/cmd/log.go index ea3e16b..164bd2e 100644 --- a/cmd/log.go +++ b/cmd/log.go @@ -5,7 +5,7 @@ import ( "fmt" "strings" - "github.com/gomicro/align/client" + ctxhelper "github.com/gomicro/align/client/context" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -75,7 +75,7 @@ func logCmdValidArgsFunc(cmd *cobra.Command, args []string, toComplete string) ( func logFunc(cmd *cobra.Command, args []string) error { verbose := viper.GetBool("verbose") - ctx := client.WithVerbose(context.Background(), verbose) + ctx := ctxhelper.WithVerbose(context.Background(), verbose) repoDirs, err := clt.GetDirs(ctx, dir) if err != nil { diff --git a/cmd/pull.go b/cmd/pull.go index aec539e..2cce06b 100644 --- a/cmd/pull.go +++ b/cmd/pull.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/gomicro/align/client" + ctxhelper "github.com/gomicro/align/client/context" "github.com/gosuri/uiprogress" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -32,7 +32,7 @@ var pullCmd = &cobra.Command{ func pullFunc(cmd *cobra.Command, args []string) error { verbose := viper.GetBool("verbose") - ctx := client.WithVerbose(context.Background(), verbose) + ctx := ctxhelper.WithVerbose(context.Background(), verbose) if !verbose { uiprogress.Start() diff --git a/cmd/push.go b/cmd/push.go index 4d63bc0..a2c8895 100644 --- a/cmd/push.go +++ b/cmd/push.go @@ -5,7 +5,7 @@ import ( "fmt" "slices" - "github.com/gomicro/align/client" + ctxhelper "github.com/gomicro/align/client/context" "github.com/gosuri/uiprogress" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -73,7 +73,7 @@ func pushCmdValidArgsFunc(cmd *cobra.Command, args []string, toComplete string) func pushFunc(cmd *cobra.Command, args []string) error { verbose := viper.GetBool("verbose") - ctx := client.WithVerbose(context.Background(), verbose) + ctx := ctxhelper.WithVerbose(context.Background(), verbose) if !verbose { uiprogress.Start() diff --git a/cmd/remote/add.go b/cmd/remote/add.go index 6259287..e988793 100644 --- a/cmd/remote/add.go +++ b/cmd/remote/add.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/gomicro/align/client" + ctxhelper "github.com/gomicro/align/client/context" "github.com/gosuri/uiprogress" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -24,7 +24,7 @@ var addCmd = &cobra.Command{ func addFunc(cmd *cobra.Command, args []string) error { verbose := viper.GetBool("verbose") - ctx := client.WithVerbose(context.Background(), verbose) + ctx := ctxhelper.WithVerbose(context.Background(), verbose) if !verbose { uiprogress.Start() diff --git a/cmd/remote/remote.go b/cmd/remote/remote.go index 67a60b1..22a71d4 100644 --- a/cmd/remote/remote.go +++ b/cmd/remote/remote.go @@ -6,6 +6,7 @@ import ( "os" "github.com/gomicro/align/client" + ctxhelper "github.com/gomicro/align/client/context" "github.com/gomicro/align/config" "github.com/spf13/cobra" ) @@ -30,7 +31,7 @@ var RemoteCmd = &cobra.Command{ } func remoteFunc(cmd *cobra.Command, args []string) error { - ctx := client.WithVerbose(context.Background(), verbose) + ctx := ctxhelper.WithVerbose(context.Background(), verbose) repoDirs, err := clt.GetDirs(ctx, dir) if err != nil { diff --git a/cmd/remote/remove.go b/cmd/remote/remove.go index 88e0a1f..6856bbb 100644 --- a/cmd/remote/remove.go +++ b/cmd/remote/remove.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/gomicro/align/client" + ctxhelper "github.com/gomicro/align/client/context" "github.com/gosuri/uiprogress" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -24,7 +24,7 @@ var removeCmd = &cobra.Command{ func removeFunc(cmd *cobra.Command, args []string) error { verbose := viper.GetBool("verbose") - ctx := client.WithVerbose(context.Background(), verbose) + ctx := ctxhelper.WithVerbose(context.Background(), verbose) if !verbose { uiprogress.Start() diff --git a/cmd/remote/set-url.go b/cmd/remote/set-url.go index a25ec17..d8ddb76 100644 --- a/cmd/remote/set-url.go +++ b/cmd/remote/set-url.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/gomicro/align/client" + ctxhelper "github.com/gomicro/align/client/context" "github.com/gosuri/uiprogress" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -24,7 +24,7 @@ var setURLCmd = &cobra.Command{ func setURLFunc(cmd *cobra.Command, args []string) error { verbose := viper.GetBool("verbose") - ctx := client.WithVerbose(context.Background(), verbose) + ctx := ctxhelper.WithVerbose(context.Background(), verbose) if !verbose { uiprogress.Start() diff --git a/cmd/status.go b/cmd/status.go index ed33367..15137da 100644 --- a/cmd/status.go +++ b/cmd/status.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/gomicro/align/client" + ctxhelper "github.com/gomicro/align/client/context" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -27,7 +27,7 @@ var statusCmd = &cobra.Command{ func statusFunc(cmd *cobra.Command, args []string) error { verbose := viper.GetBool("verbose") - ctx := client.WithVerbose(context.Background(), verbose) + ctx := ctxhelper.WithVerbose(context.Background(), verbose) repoDirs, err := clt.GetDirs(ctx, dir) if err != nil { diff --git a/cmd/tag.go b/cmd/tag.go index ef2ebe0..8ab0695 100644 --- a/cmd/tag.go +++ b/cmd/tag.go @@ -6,7 +6,7 @@ import ( "os/exec" "strings" - "github.com/gomicro/align/client" + ctxhelper "github.com/gomicro/align/client/context" "github.com/gosuri/uiprogress" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -69,7 +69,7 @@ func tagCmdValidArgsFunc(cmd *cobra.Command, args []string, toComplete string) ( func tagFunc(cmd *cobra.Command, args []string) error { verbose := viper.GetBool("verbose") - ctx := client.WithVerbose(context.Background(), verbose) + ctx := ctxhelper.WithVerbose(context.Background(), verbose) repoDirs, err := clt.GetDirs(ctx, dir) if err != nil {