diff --git a/client/client.go b/client/client.go index 27c9078..f561338 100644 --- a/client/client.go +++ b/client/client.go @@ -1,3 +1,4 @@ +// Package client wires together the repos and remotes layers and exposes a unified Client. package client import ( @@ -23,6 +24,7 @@ import ( "golang.org/x/time/rate" ) +// Client provides the full set of cross-repo git operations backed by the GitHub API. type Client struct { *repos.Repos remoteMgr *remotes.Remotes @@ -32,6 +34,7 @@ type Client struct { ghHTTPSAuth *sshgit.Password } +// New constructs a Client from cfg, initialising SSH auth, HTTPS auth, the GitHub API client, and rate limiter. func New(cfg *config.Config) (*Client, error) { pool := trust.New() @@ -145,6 +148,7 @@ func knownHostsCallback() (ssh.HostKeyCallback, error) { return cb, nil } +// GetLogins returns the authenticated user's login and all org logins, lowercased. func (c *Client) GetLogins(ctx context.Context) ([]string, error) { logins := []string{} @@ -181,22 +185,27 @@ func (c *Client) GetLogins(ctx context.Context) ([]string, error) { return logins, nil } +// Remotes runs git remote across all dirs. func (c *Client) Remotes(ctx context.Context, dirs []string, args ...string) error { return c.remoteMgr.Remotes(ctx, dirs, args...) } +// Add runs git remote add across all dirs, building the remote URL from baseURL and each dir basename. func (c *Client) Add(ctx context.Context, dirs []string, name, baseURL string) error { return c.remoteMgr.Add(ctx, dirs, name, baseURL) } +// Remove runs git remote remove across all dirs. func (c *Client) Remove(ctx context.Context, dirs []string, name string) error { return c.remoteMgr.Remove(ctx, dirs, name) } +// Rename runs git remote rename across all dirs. func (c *Client) Rename(ctx context.Context, dirs []string, oldName, newName string) error { return c.remoteMgr.Rename(ctx, dirs, oldName, newName) } +// SetURLs runs git remote set-url across all dirs, building the URL from baseURL and each dir basename. 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 fadacb8..1f01ad2 100644 --- a/client/clienter.go +++ b/client/clienter.go @@ -8,6 +8,7 @@ import ( "github.com/google/go-github/github" ) +// Clienter is the interface implemented by Client, used to inject fakes in cmd tests. type Clienter interface { Add(ctx context.Context, dirs []string, name, baseURL string) error Branches(ctx context.Context, repoDirs []string, args ...string) error diff --git a/client/context/context.go b/client/context/context.go index 6a24e52..1d1a8e3 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -1,3 +1,4 @@ +// Package context provides request-scoped state helpers used throughout the align client. package context import ( @@ -17,13 +18,16 @@ var ( excludesContextKey reposContext = 1 verboseKey = verboseContextKey{} + // ErrReposNotFoundInContext is returned by RepoMap when no repository map has been stored in the context. ErrReposNotFoundInContext = errors.New("repos map not found in context") ) +// WithVerbose returns a copy of ctx with the verbose flag set. func WithVerbose(ctx context.Context, verbose bool) context.Context { return context.WithValue(ctx, verboseKey, verbose) } +// Verbose retrieves the verbose flag from ctx, returning false if unset. func Verbose(ctx context.Context) bool { v := ctx.Value(verboseKey) verbose, ok := v.(bool) @@ -33,16 +37,19 @@ func Verbose(ctx context.Context) bool { return verbose } +// Repository holds the name and SSH URL of a repository to clone. type Repository struct { Name string URL string } +// WithRepos stores the given GitHub repositories as a dir→[]Repository map in ctx. func WithRepos(ctx context.Context, repos []*github.Repository) context.Context { repoMap := parseDirRepoMap(repos) return context.WithValue(ctx, reposContextKey, repoMap) } +// RepoMap retrieves the directory→repository map from ctx. func RepoMap(ctx context.Context) (map[string][]*Repository, error) { v := ctx.Value(reposContextKey) repoMap, ok := v.(map[string][]*Repository) @@ -52,10 +59,12 @@ func RepoMap(ctx context.Context) (map[string][]*Repository, error) { return repoMap, nil } +// WithExcludes stores the repository exclusion list in ctx. func WithExcludes(ctx context.Context, repos []*Repository) context.Context { return context.WithValue(ctx, excludesContextKey, repos) } +// Excludes retrieves the exclusion list from ctx, returning nil if unset. func Excludes(ctx context.Context) ([]*Repository, error) { v := ctx.Value(excludesContextKey) excludes, ok := v.([]*Repository) @@ -83,6 +92,7 @@ func parseDirRepoMap(repos []*github.Repository) map[string][]*Repository { return dirRepo } +// RemoveExcludes returns a copy of repoMap with excluded repositories removed. func RemoveExcludes(ctx context.Context, repoMap map[string][]*Repository) (map[string][]*Repository, error) { newMap := map[string][]*Repository{} diff --git a/client/dirs.go b/client/dirs.go index 361eeee..845a86f 100644 --- a/client/dirs.go +++ b/client/dirs.go @@ -7,6 +7,7 @@ import ( "path" ) +// GetDirs returns subdirectories of baseDir that contain a .git directory. func (c *Client) GetDirs(ctx context.Context, baseDir string) ([]string, error) { files, err := os.ReadDir(baseDir) if err != nil { diff --git a/client/repos/diff.go b/client/repos/diff.go index b1c16b9..3261bc4 100644 --- a/client/repos/diff.go +++ b/client/repos/diff.go @@ -10,6 +10,7 @@ import ( "strings" ) +// DiffConfig controls filtering and output options for DiffRepos. type DiffConfig struct { IgnoreEmpty bool IgnoreFilePrefix []string @@ -17,6 +18,7 @@ type DiffConfig struct { Args []string } +// DiffRepos runs git diff across all dirs using cfg to filter output. func (r *Repos) DiffRepos(ctx context.Context, dirs []string, cfg *DiffConfig) error { args := append([]string{"diff"}, cfg.Args...) diff --git a/client/repos/repos.go b/client/repos/repos.go index 781137b..55c4cc9 100644 --- a/client/repos/repos.go +++ b/client/repos/repos.go @@ -1,3 +1,8 @@ +// Package repos implements git operations fanned out across multiple repository directories. +// +// The simple fan-out methods (CheckoutRepos, CommitRepos, FetchRepos, MergeRepos, PullRepos, +// PushRepos, ResetRepos, StageFiles, StashRepos) each prepend their git sub-command and +// delegate to fanOut. They carry no individual doc comments. package repos import ( @@ -6,12 +11,14 @@ import ( "golang.org/x/time/rate" ) +// Repos holds the scribe, GitHub client, and rate limiter shared by all operations. type Repos struct { scrb scribe.Scriber ghClient *github.Client rate *rate.Limiter } +// New returns a Repos using the provided scribe, GitHub client, and rate limiter. func New(scrb scribe.Scriber, ghClient *github.Client, rate *rate.Limiter) *Repos { return &Repos{ scrb: scrb, diff --git a/config/file.go b/config/file.go index 959e4e7..eaab0cb 100644 --- a/config/file.go +++ b/config/file.go @@ -1,3 +1,4 @@ +// Package config handles reading and writing the align configuration at ~/.align/config. package config import ( @@ -23,19 +24,17 @@ var defaultConfig = Config{ }, } -// Config represents the config file for align +// Config holds the top-level align configuration read from ~/.align/config. type Config struct { Github *GithubHost `yaml:"github.com"` } -// New takes a token string and creates the most basic config capable of being -// written. +// New returns a minimal Config with the given GitHub token set. func New(tkn string) *Config { return &Config{Github: &GithubHost{Token: tkn}} } -// WriteFile writes the file to the defined location for the current user, and -// returns any errors encountered doing so. +// WriteFile marshals and writes the config to ~/.align/config. func (c *Config) WriteFile() error { b, err := yaml.Marshal(c) if err != nil { diff --git a/config/github.go b/config/github.go index 8f17f4f..e3634ec 100644 --- a/config/github.go +++ b/config/github.go @@ -1,6 +1,6 @@ package config -// GithubHost represents a single host for which align has a configuration +// GithubHost holds authentication and rate-limit settings for a GitHub host. type GithubHost struct { Token string `yaml:"token"` Username string `yaml:"username"` @@ -9,7 +9,7 @@ type GithubHost struct { Limits *Limits `yaml:"limits"` } -// Limits represents a limits override for the client +// Limits configures GitHub API client request rates. type Limits struct { RequestsPerSecond int `yaml:"request_per_second"` Burst int `yaml:"burst"` diff --git a/config/parse.go b/config/parse.go index c7f3888..c768f40 100644 --- a/config/parse.go +++ b/config/parse.go @@ -9,8 +9,7 @@ import ( "gopkg.in/yaml.v2" ) -// ParseFromFile reads the align config file from the home directory. It returns -// any errors it encounters with parsing the file. +// ParseFromFile reads ~/.align/config, creating the config directory if absent. func ParseFromFile() (*Config, error) { usr, err := user.Current() if err != nil { @@ -54,9 +53,7 @@ func ParseFromFile() (*Config, error) { return &conf, nil } -// DirExists returns a bool and error representing whether or not a config -// directory exists for the current user, and any errors it encounters with -// statting the existence of the directory. +// DirExists reports whether the ~/.align config directory exists. func DirExists() (bool, error) { usr, err := user.Current() if err != nil { @@ -74,9 +71,7 @@ func DirExists() (bool, error) { return true, nil } -// FileExists returns a bool and error representing whether or not a -// config file exists for the current user, and any errors it encounters with -// statting the existence of the file. +// FileExists reports whether the ~/.align/config file exists. func FileExists() (bool, error) { usr, err := user.Current() if err != nil { @@ -94,8 +89,7 @@ func FileExists() (bool, error) { return true, nil } -// CreateDir creates the config directory and all necessary parent directories -// missing. It returns any error it encounters with creating the directory. +// CreateDir creates the ~/.align config directory, including any missing parents. func CreateDir() error { usr, err := user.Current() if err != nil {