package commands import ( "errors" "fmt" "gitlab.com/revalus/grm/internal/config" "github.com/go-git/go-git/v5" ) type Synchronizer struct { workspace string } func NewSynchronizer(workspace string) Synchronizer { return Synchronizer{ workspace: workspace, } } const ( syncUpToDate = "up to date" syncFetched = "has been fetched" // Why fetched, instead of updated? To be consistent with git commands :D syncCloned = "has been cloned" ) func fetchRepository(repo *git.Repository) (bool, error) { err := repo.Fetch(&git.FetchOptions{}) switch { case errors.Is(err, git.NoErrAlreadyUpToDate): return false, nil case errors.Is(err, git.NoErrAlreadyUpToDate): return false, nil default: return true, nil } } func cloneRepository(destPath string, repoCfg *config.RepositoryConfig) (bool, error) { _, err := git.PlainClone(destPath, false, &git.CloneOptions{ URL: repoCfg.Src, }) if err != nil { return false, err } return true, nil } func (s Synchronizer) Command(repoCfg config.RepositoryConfig) CommandStatus { var err error cmdStatus := CommandStatus{ Name: repoCfg.Name, Changed: false, Message: "", Error: false, } destPath := fmt.Sprintf("%v/%v", s.workspace, repoCfg.Dest) repo, err := git.PlainOpen(destPath) if err != nil { if errors.Is(err, git.ErrRepositoryNotExists) { cmdStatus.Changed, err = cloneRepository(destPath, &repoCfg) cmdStatus.Message = syncCloned } else { cmdStatus.Error = true cmdStatus.Message = err.Error() } return cmdStatus } cmdStatus.Changed, err = fetchRepository(repo) if cmdStatus.Changed { cmdStatus.Message = syncFetched } else { cmdStatus.Message = syncUpToDate } if err != nil { cmdStatus.Error = true cmdStatus.Message = err.Error() } return cmdStatus }