Documentation
¶
Overview ¶
Package reposync implements repository sync planning and execution. It converts a desired repository list into an action plan (clone, update, delete) and executes it, supporting both local config and forge API sources.
Index ¶
- Variables
- func FormatCompactStatus(ps *PostSyncStatus) string
- func MaskTokenInURL(urlStr string) string
- type Action
- type ActionResult
- type ActionType
- type AuthConfig
- type AuthResult
- type DiagnosticExecutor
- type DiagnosticOptions
- type DiagnosticProgress
- type DivergenceType
- type ExecutionResult
- type Executor
- type FSPlanner
- type FileHistoryStore
- func (s *FileHistoryStore) CleanupOld(ctx context.Context, olderThan time.Duration) error
- func (s *FileHistoryStore) GetTrend(ctx context.Context, repoName string) ([]RepoHealth, error)
- func (s *FileHistoryStore) Load(ctx context.Context, limit int) ([]HistorySnapshot, error)
- func (s *FileHistoryStore) Save(ctx context.Context, report *HealthReport) error
- type FileStateStore
- type ForgePlanner
- type ForgePlannerConfig
- type ForgeProvider
- type GitExecutor
- type HealthReport
- type HealthStatus
- type HealthSummary
- type HistorySnapshot
- type HistoryStore
- type InMemoryStateStore
- type NetworkStatus
- type NoopExecutor
- type NoopProgressSink
- type Orchestrator
- type Plan
- type PlanInput
- type PlanOptions
- type PlanRequest
- type Planner
- type PostSyncStatus
- type ProgressSink
- type RepoHealth
- type RepoSpec
- type RepositoryPatternFilter
- type RunOptions
- type RunRequest
- type RunState
- type RunStateItem
- type RunStatus
- type Runner
- type StateStore
- type StaticPlanner
- type Strategy
- type WorkTreeStatus
Constants ¶
This section is empty.
Variables ¶
var ErrMissingDependency = errors.New("missing dependency")
ErrMissingDependency is returned when required collaborators are unset.
var ErrNoRepositories = errors.New("no repositories provided")
ErrNoRepositories is returned when no repositories are provided.
Functions ¶
func FormatCompactStatus ¶
func FormatCompactStatus(ps *PostSyncStatus) string
FormatCompactStatus renders PostSyncStatus as "master|↓5|↑3|dirty".
func MaskTokenInURL ¶
MaskTokenInURL masks the token in a URL for safe logging.
Types ¶
type Action ¶
type Action struct {
Repo RepoSpec
Type ActionType
Strategy Strategy
Reason string
PlannedBy string
Workspace string // workspace name for grouping display (empty = flat repositories)
}
Action describes a single operation in a plan.
type ActionResult ¶
type ActionResult struct {
Action Action
Message string
Error error
PostStatus *PostSyncStatus
}
ActionResult is a per-repo outcome.
type ActionType ¶
type ActionType string
ActionType enumerates planned operations.
const ( ActionClone ActionType = "clone" ActionUpdate ActionType = "update" ActionSkip ActionType = "skip" ActionDelete ActionType = "delete" )
ActionType values represent the planned operation for each repository.
type AuthConfig ¶
type AuthConfig struct {
// Token is used for HTTPS clone URL injection
Token string
// Provider is the forge provider type (github, gitlab, gitea)
// Used to determine the correct token format for URL injection
Provider string
// SSHKeyPath is the path to SSH private key file (priority)
SSHKeyPath string
// SSHKeyContent is the SSH private key content (used if SSHKeyPath is empty)
SSHKeyContent string
// SSHPort is the custom SSH port (0 = default)
SSHPort int
}
AuthConfig holds authentication settings for git operations.
type AuthResult ¶
type AuthResult struct {
// CloneURL is the modified clone URL (with token injected for HTTPS)
CloneURL string
// Env contains environment variables to set for git commands
Env []string
// TempKeyPath is the path to temporary SSH key file (if created from content)
// Caller should display warning to user about cleanup
TempKeyPath string
// Warnings contains non-fatal warnings (e.g., temp file cleanup reminder)
Warnings []string
}
AuthResult contains the result of authentication setup.
func PrepareAuth ¶
func PrepareAuth(cloneURL string, auth AuthConfig) (*AuthResult, error)
PrepareAuth prepares authentication for a git clone operation. It modifies the clone URL for HTTPS (token injection) and sets up environment variables for SSH (GIT_SSH_COMMAND).
Priority:
- If auth config has token/key -> use it
- Otherwise -> fallback to system defaults (no modification)
type DiagnosticExecutor ¶
DiagnosticExecutor performs health checks on repositories.
func (DiagnosticExecutor) CheckHealth ¶
func (e DiagnosticExecutor) CheckHealth(ctx context.Context, repos []RepoSpec, opts DiagnosticOptions) (*HealthReport, error)
CheckHealth performs health diagnostics on multiple repositories.
type DiagnosticOptions ¶
type DiagnosticOptions struct {
// SkipFetch skips remote fetch before checking divergence.
// This is faster but may give stale results.
SkipFetch bool
// FetchTimeout is max time to wait for remote fetch (per repo).
// Default: 30s.
FetchTimeout time.Duration
// Parallel is number of concurrent health checks.
// Default: 4.
Parallel int
// CheckWorkTree enables working tree status checks.
// Default: true.
CheckWorkTree bool
// IncludeRecommendations generates actionable guidance.
// Default: true.
IncludeRecommendations bool
// Progress is an optional progress callback.
Progress DiagnosticProgress
}
DiagnosticOptions configures health check behavior.
func DefaultDiagnosticOptions ¶
func DefaultDiagnosticOptions() DiagnosticOptions
DefaultDiagnosticOptions returns sensible defaults.
type DiagnosticProgress ¶
type DiagnosticProgress interface {
OnRepoStart(repo RepoSpec)
OnRepoComplete(health RepoHealth)
}
DiagnosticProgress receives progress notifications during health checks.
type DivergenceType ¶
type DivergenceType string
DivergenceType classifies how local and remote branches differ.
const ( // DivergenceNone means local and remote are identical. DivergenceNone DivergenceType = "none" // DivergenceFastForward means local is behind remote, can fast-forward. DivergenceFastForward DivergenceType = "fast-forward" // DivergenceDiverged means local and remote have diverged, requires merge/rebase. DivergenceDiverged DivergenceType = "diverged" // DivergenceAhead means local is ahead of remote, can push. DivergenceAhead DivergenceType = "ahead" // DivergenceConflict means there are merge conflicts or incompatible states. DivergenceConflict DivergenceType = "conflict" // DivergenceNoUpstream means no upstream branch is configured. DivergenceNoUpstream DivergenceType = "no-upstream" )
type ExecutionResult ¶
type ExecutionResult struct {
Succeeded []ActionResult
Failed []ActionResult
Skipped []ActionResult
}
ExecutionResult captures aggregated outcomes from a run.
type Executor ¶
type Executor interface {
Execute(ctx context.Context, plan Plan, opts RunOptions, sink ProgressSink, store StateStore) (ExecutionResult, error)
}
Executor runs a Plan with concurrency, retries, and strategies.
type FSPlanner ¶
type FSPlanner struct{}
FSPlanner inspects the filesystem to decide clone/update/delete actions.
type FileHistoryStore ¶
type FileHistoryStore struct {
BaseDir string
}
FileHistoryStore stores health snapshots in JSON files.
func NewFileHistoryStore ¶
func NewFileHistoryStore(baseDir string) *FileHistoryStore
NewFileHistoryStore creates a history store that saves to a directory.
func (*FileHistoryStore) CleanupOld ¶
CleanupOld removes snapshots older than the specified duration.
func (*FileHistoryStore) GetTrend ¶
func (s *FileHistoryStore) GetTrend(ctx context.Context, repoName string) ([]RepoHealth, error)
GetTrend retrieves health history for a specific repository.
func (*FileHistoryStore) Load ¶
func (s *FileHistoryStore) Load(ctx context.Context, limit int) ([]HistorySnapshot, error)
Load retrieves the most recent N snapshots.
func (*FileHistoryStore) Save ¶
func (s *FileHistoryStore) Save(ctx context.Context, report *HealthReport) error
Save stores a health report snapshot.
type FileStateStore ¶
type FileStateStore struct {
// contains filtered or unexported fields
}
FileStateStore persists run state to a JSON file for resume/audit.
func NewFileStateStore ¶
func NewFileStateStore(path string) *FileStateStore
NewFileStateStore creates a new file-backed state store.
type ForgePlanner ¶
type ForgePlanner struct {
// contains filtered or unexported fields
}
ForgePlanner produces a Plan by querying a gitforge Provider.
func NewForgePlanner ¶
func NewForgePlanner(fp ForgeProvider, config ForgePlannerConfig) *ForgePlanner
NewForgePlanner creates a new ForgePlanner with the given provider and config.
func (*ForgePlanner) Describe ¶
func (p *ForgePlanner) Describe(req PlanRequest) string
Describe returns a description of the planner configuration.
func (*ForgePlanner) Plan ¶
func (p *ForgePlanner) Plan(ctx context.Context, req PlanRequest) (Plan, error)
Plan implements the Planner interface. It queries the provider for repositories and creates a plan based on local state.
type ForgePlannerConfig ¶
type ForgePlannerConfig struct {
// TargetPath is the base directory for cloning repositories
TargetPath string
// Organization is the org/group to sync from
Organization string
// IsUser indicates if Organization is actually a user (for ListUserRepos)
IsUser bool
// IncludeArchived includes archived repositories
IncludeArchived bool
// IncludeForks includes forked repositories
IncludeForks bool
// IncludePrivate includes private repositories
IncludePrivate bool
// CloneProto is the clone protocol: ssh, https
CloneProto string
// SSHPort is the custom SSH port (0 = default 22)
SSHPort int
// IncludeSubgroups includes subgroups (GitLab only)
IncludeSubgroups bool
// SubgroupMode is flat (dash-separated) or nested (directories)
SubgroupMode string
// FlatSeparator is the separator for flat mode (default: "-")
// Examples: "-", "_", ".", "" (empty = no separator)
// Invalid characters: / \ : * ? " < > |
FlatSeparator string
// Branch is the branch to checkout after clone/update (comma-separated fallback list)
Branch string
// Auth contains authentication settings for clone operations
Auth AuthConfig
// Metadata filters
FilterLanguages []string // Filter by language (lowercase)
FilterMinStars int // Minimum star count
FilterMaxStars int // Maximum star count (0 = unlimited)
FilterLastPushAfter time.Time // Only include repos pushed after this time
// Name/path regex filters
FilterIncludePatterns []string // Include repos whose name or full name matches
FilterExcludePatterns []string // Exclude repos whose name or full name matches
}
ForgePlannerConfig configures the ForgePlanner behavior.
type ForgeProvider ¶
type ForgeProvider interface {
Name() string
ListOrganizationRepos(ctx context.Context, org string) ([]*provider.Repository, error)
ListUserRepos(ctx context.Context, user string) ([]*provider.Repository, error)
}
ForgeProvider defines the minimal interface required from gitforge providers. This allows git-sync to work with any gitforge provider without importing the entire gitforge package directly in the core reposync package.
type GitExecutor ¶
GitExecutor executes plans using gzh-cli-gitforge for actual Git operations.
func (GitExecutor) Execute ¶
func (e GitExecutor) Execute(ctx context.Context, plan Plan, opts RunOptions, sink ProgressSink, store StateStore) (ExecutionResult, error)
Execute runs the plan with concurrency, retries, and optional dry-run.
type HealthReport ¶
type HealthReport struct {
// Results contains per-repository health status.
Results []RepoHealth
// Summary provides counts by health status.
Summary HealthSummary
// TotalDuration is the total time for all checks.
TotalDuration time.Duration
// CheckedAt is when the health check was performed.
CheckedAt time.Time
}
HealthReport aggregates health check results for multiple repositories.
type HealthStatus ¶
type HealthStatus string
HealthStatus represents the overall health of a repository.
const ( // HealthHealthy indicates the repository is in good state (up-to-date, clean). HealthHealthy HealthStatus = "healthy" // HealthWarning indicates the repository needs attention (diverged, can be resolved). HealthWarning HealthStatus = "warning" // HealthError indicates the repository has serious issues (conflicts, dirty + behind). HealthError HealthStatus = "error" // HealthUnreachable indicates the repository couldn't be checked (network timeout, invalid repo). HealthUnreachable HealthStatus = "unreachable" )
type HealthSummary ¶
type HealthSummary struct {
// Healthy is count of healthy repositories.
Healthy int
// Warning is count of repositories with warnings.
Warning int
// Error is count of repositories with errors.
Error int
// Unreachable is count of unreachable repositories.
Unreachable int
// Total is total number of repositories checked.
Total int
}
HealthSummary provides aggregate statistics.
type HistorySnapshot ¶
type HistorySnapshot struct {
Timestamp time.Time `json:"timestamp"`
Report *HealthReport `json:"report"`
}
HistorySnapshot represents a point-in-time health check result.
type HistoryStore ¶
type HistoryStore interface {
Save(ctx context.Context, report *HealthReport) error
Load(ctx context.Context, limit int) ([]HistorySnapshot, error)
GetTrend(ctx context.Context, repoName string) ([]RepoHealth, error)
}
HistoryStore manages historical health check snapshots.
type InMemoryStateStore ¶
type InMemoryStateStore struct {
// contains filtered or unexported fields
}
InMemoryStateStore is a lightweight StateStore useful for dry-runs and tests.
func NewInMemoryStateStore ¶
func NewInMemoryStateStore() *InMemoryStateStore
NewInMemoryStateStore creates a new in-memory state store.
type NetworkStatus ¶
type NetworkStatus string
NetworkStatus represents the network connectivity status.
const ( // NetworkOK means remote fetch succeeded. NetworkOK NetworkStatus = "ok" // NetworkTimeout means remote fetch timed out. NetworkTimeout NetworkStatus = "timeout" // NetworkUnreachable means remote is unreachable (DNS, connection refused, etc). NetworkUnreachable NetworkStatus = "unreachable" // NetworkAuthFailed means authentication failed. NetworkAuthFailed NetworkStatus = "auth-failed" )
type NoopExecutor ¶
type NoopExecutor struct{}
NoopExecutor records actions and reports success without touching the filesystem or Git. It is intentionally side-effect free for dry-runs and early wiring.
func (NoopExecutor) Execute ¶
func (NoopExecutor) Execute(ctx context.Context, plan Plan, opts RunOptions, sink ProgressSink, store StateStore) (ExecutionResult, error)
Execute implements Executor.
type NoopProgressSink ¶
type NoopProgressSink struct{}
NoopProgressSink is a progress sink that does nothing.
func (NoopProgressSink) OnComplete ¶
func (NoopProgressSink) OnComplete(_ ActionResult)
OnComplete implements ProgressSink.
func (NoopProgressSink) OnProgress ¶
func (NoopProgressSink) OnProgress(_ Action, _ string, _ float64)
OnProgress implements ProgressSink.
func (NoopProgressSink) OnStart ¶
func (NoopProgressSink) OnStart(_ Action)
OnStart implements ProgressSink.
type Orchestrator ¶
type Orchestrator struct {
Planner Planner
Executor Executor
StateStore StateStore
}
Orchestrator wires Planner/Executor/StateStore to implement Runner.
func NewOrchestrator ¶
func NewOrchestrator(planner Planner, executor Executor, state StateStore) *Orchestrator
NewOrchestrator creates a Runner from injected collaborators.
func (*Orchestrator) Run ¶
func (o *Orchestrator) Run(ctx context.Context, req RunRequest) (ExecutionResult, error)
Run executes the plan/execution lifecycle.
type Plan ¶
type Plan struct {
Actions []Action
}
Plan is the result of planning (e.g., clone/pull/fetch/delete actions). Details will be expanded as the orchestration logic lands.
type PlanInput ¶
type PlanInput struct {
Repos []RepoSpec
}
PlanInput captures desired repositories and optional context (e.g., host aliases, path rules). It is intentionally minimal for now; richer fields will be added in follow-up steps.
type PlanOptions ¶
type PlanOptions struct {
DefaultStrategy Strategy
CleanupOrphans bool
Roots []string // optional roots to detect orphan directories
}
PlanOptions influence how a plan is produced (defaults, cleanup policies).
type PlanRequest ¶
type PlanRequest struct {
Input PlanInput
Options PlanOptions
}
PlanRequest combines the desired repositories with planning-time options.
type Planner ¶
type Planner interface {
Plan(ctx context.Context, req PlanRequest) (Plan, error)
}
Planner produces a Plan from desired repositories and options. Concrete implementation will live in future steps; this placeholder defines the interface surface for consumers and CLI wiring.
type PostSyncStatus ¶
type PostSyncStatus struct {
Branch string
AheadBy int
BehindBy int
IsDirty bool
HasConflicts bool
// StatusErr records a failure to read the working tree. IsDirty and
// HasConflicts are only meaningful when it is nil — their zero values are
// indistinguishable from a clean, conflict-free repository, so a renderer
// that ignores this field reports an unreadable repo as a healthy one.
// Same reasoning as WorkTreeUnknown in diagnostic.go.
StatusErr error
}
PostSyncStatus captures lightweight git status collected after a successful sync.
type ProgressSink ¶
type ProgressSink interface {
OnStart(action Action)
OnProgress(action Action, message string, progress float64)
OnComplete(result ActionResult)
}
ProgressSink receives progress events from the executor.
type RepoHealth ¶
type RepoHealth struct {
// Repo is the repository descriptor.
Repo RepoSpec
// HealthStatus is the overall health classification.
HealthStatus HealthStatus
// NetworkStatus indicates remote connectivity.
NetworkStatus NetworkStatus
// DivergenceType classifies local vs remote state.
DivergenceType DivergenceType
// WorkTreeStatus indicates working tree state.
WorkTreeStatus WorkTreeStatus
// CurrentBranch is the active branch name.
CurrentBranch string
// UpstreamBranch is the tracked upstream branch (e.g., "origin/main").
UpstreamBranch string
// AheadBy is commits ahead of upstream.
AheadBy int
// BehindBy is commits behind upstream.
BehindBy int
// ModifiedFiles is count of modified files.
ModifiedFiles int
// UntrackedFiles is count of untracked files.
UntrackedFiles int
// ConflictFiles is count of files with conflicts.
ConflictFiles int
// Recommendation provides actionable guidance.
Recommendation string
// Error contains error details if health check failed.
Error error
// Duration is how long the health check took.
Duration time.Duration
// FetchDuration is how long remote fetch took (if performed).
FetchDuration time.Duration
}
RepoHealth represents the diagnostic result for a single repository.
type RepoSpec ¶
type RepoSpec struct {
Name string
Description string // optional: human-readable description of the repository
Provider string
CloneURL string
AdditionalRemotes map[string]string // Additional git remotes (name: url), configured after clone
TargetPath string
Branch string // optional: branch to checkout after clone/update (empty = no checkout)
StrictBranchCheckout bool // if true, branch checkout failure causes action failure (default: false)
Strategy Strategy
Enabled *bool // if false, repo is excluded from sync (default: true, nil = true)
AssumePresent bool // if true, planner treats repo as already present (skip clone check)
// Auth contains authentication config for this repo's clone operation.
// If empty, system defaults are used (git credential helper, ssh-agent).
Auth AuthConfig
}
RepoSpec describes a repository to manage.
type RepositoryPatternFilter ¶
type RepositoryPatternFilter struct {
// contains filtered or unexported fields
}
RepositoryPatternFilter matches repositories by name or forge full name.
func NewRepositoryPatternFilter ¶
func NewRepositoryPatternFilter(includePatterns, excludePatterns []string) (*RepositoryPatternFilter, error)
NewRepositoryPatternFilter compiles include/exclude regex patterns.
func (*RepositoryPatternFilter) Match ¶
func (f *RepositoryPatternFilter) Match(repo *provider.Repository) bool
Match returns true when the repository passes include/exclude filtering.
type RunOptions ¶
RunOptions control execution behavior.
type RunRequest ¶
type RunRequest struct {
PlanRequest PlanRequest
RunOptions RunOptions
Progress ProgressSink
State StateStore
}
RunRequest contains everything required for a run.
type RunState ¶
type RunState struct {
Items []RunStateItem
}
RunState captures progress for resuming operations.
type RunStateItem ¶
RunStateItem tracks per-repo status.
type Runner ¶
type Runner interface {
Run(ctx context.Context, req RunRequest) (ExecutionResult, error)
}
Runner encapsulates a full plan + execute lifecycle.
type StateStore ¶
type StateStore interface {
Save(ctx context.Context, state RunState) error
Load(ctx context.Context) (RunState, error)
}
StateStore persists run state for resume/audit.
type StaticPlanner ¶
type StaticPlanner struct{}
StaticPlanner produces a trivial plan that maps every RepoSpec to a single action (clone or update) using the provided defaults. It is primarily useful for early wiring, tests, and dry-runs.
func (StaticPlanner) Describe ¶
func (StaticPlanner) Describe(req PlanRequest) string
Describe returns a short description of what would be planned; useful for logging in CLI integrations.
func (StaticPlanner) Plan ¶
func (StaticPlanner) Plan(_ context.Context, req PlanRequest) (Plan, error)
Plan implements Planner.
type Strategy ¶
type Strategy string
Strategy defines how updates are performed.
const ( StrategyReset Strategy = "reset" StrategyPull Strategy = "pull" StrategyFetch Strategy = "fetch" StrategyRebase Strategy = "rebase" StrategyClone Strategy = "clone" )
Strategy values control how an existing repository is brought up to date.
func ParseStrategy ¶
ParseStrategy converts a user-supplied string into a Strategy enum.
type WorkTreeStatus ¶
type WorkTreeStatus string
WorkTreeStatus represents the working tree state.
const ( // WorkTreeClean means no uncommitted changes. WorkTreeClean WorkTreeStatus = "clean" // WorkTreeDirty means there are uncommitted changes. WorkTreeDirty WorkTreeStatus = "dirty" // WorkTreeConflict means there are merge/rebase conflicts. WorkTreeConflict WorkTreeStatus = "conflict" // WorkTreeRebaseInProgress means a rebase is in progress. WorkTreeRebaseInProgress WorkTreeStatus = "rebase-in-progress" // WorkTreeMergeInProgress means a merge is in progress. WorkTreeMergeInProgress WorkTreeStatus = "merge-in-progress" // WorkTreeUnknown means the working tree could not be read (for example a // corrupt .git/index). It is deliberately distinct from WorkTreeClean: the // question was asked and went unanswered, which is not the same as an answer // of "no changes". The empty zero value still means "not checked", which is // what CheckWorkTree=false leaves behind. WorkTreeUnknown WorkTreeStatus = "unknown" )