Add status command
This commit is contained in:
parent
2b4c6d3318
commit
e26879425f
@ -33,7 +33,10 @@ By default, the config file is searched for in `[HOME_DIR]./config/grm/config.ya
|
|||||||
| command | Description |
|
| command | Description |
|
||||||
|---------|-------------|
|
|---------|-------------|
|
||||||
| sync | Fetches changes from repositories or pulls a repository if one does not exist.
|
| sync | Fetches changes from repositories or pulls a repository if one does not exist.
|
||||||
|
| status | Get repository information - what is the current branch, how many commits are above and behind it for each remote.
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
0.1 Add sync command - allow to fetch and clone repositories
|
- 0.2.0 Add status command - get information about the current status in the repository
|
||||||
|
- 0.1.1 Allow to use env vars in config
|
||||||
|
- 0.1.0 Add sync command - allow to fetch and clone repositories
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
APP_NAME = "Git repository manager"
|
APP_NAME = "Git repository manager"
|
||||||
APP_DESCRIPTION = "Manage your repository with simple app"
|
APP_DESCRIPTION = "Manage your repository with simple app"
|
||||||
VERSION = "0.1.1"
|
VERSION = "0.2.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GitRepositoryManager struct {
|
type GitRepositoryManager struct {
|
||||||
@ -49,7 +49,6 @@ func (g *GitRepositoryManager) Parse(args []string) {
|
|||||||
|
|
||||||
func (g *GitRepositoryManager) Run() {
|
func (g *GitRepositoryManager) Run() {
|
||||||
if g.cliArguments.Sync {
|
if g.cliArguments.Sync {
|
||||||
|
|
||||||
g.console.InfoFMsg("Synchronizing repositories")
|
g.console.InfoFMsg("Synchronizing repositories")
|
||||||
println()
|
println()
|
||||||
sync := commands.NewSynchronizer(g.configuration.Workspace)
|
sync := commands.NewSynchronizer(g.configuration.Workspace)
|
||||||
@ -58,6 +57,11 @@ func (g *GitRepositoryManager) Run() {
|
|||||||
g.console.InfoFMsg("All repositories are synced")
|
g.console.InfoFMsg("All repositories are synced")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if g.cliArguments.Status {
|
||||||
|
status := commands.NewStatusChecker(g.configuration.Workspace)
|
||||||
|
g.runCommand(status)
|
||||||
|
}
|
||||||
|
|
||||||
if g.cliArguments.Version {
|
if g.cliArguments.Version {
|
||||||
g.console.InfoFMsg("Current version: %v", VERSION)
|
g.console.InfoFMsg("Current version: %v", VERSION)
|
||||||
}
|
}
|
||||||
|
@ -90,5 +90,5 @@ func Example_test_sync_output() {
|
|||||||
// Output:
|
// Output:
|
||||||
// Info: Synchronizing repositories
|
// Info: Synchronizing repositories
|
||||||
// Info: All repositories are synced
|
// Info: All repositories are synced
|
||||||
// Info: Current version: 0.1.1
|
// Info: Current version: 0.2.0
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ func (co ConsoleOutput) InfoFMsg(format string, a ...interface{}) {
|
|||||||
func (co ConsoleOutput) UnchangedStatusF(format string, a ...interface{}) {
|
func (co ConsoleOutput) UnchangedStatusF(format string, a ...interface{}) {
|
||||||
msg := fmt.Sprintf(format, a...)
|
msg := fmt.Sprintf(format, a...)
|
||||||
if co.Color {
|
if co.Color {
|
||||||
msg = fmt.Sprintf("%v%v", colorGreen, msg)
|
msg = fmt.Sprintf("%v%v%v", colorGreen, msg, colorReset)
|
||||||
}
|
}
|
||||||
fmt.Println(msg)
|
fmt.Println(msg)
|
||||||
}
|
}
|
||||||
@ -47,7 +47,7 @@ func (co ConsoleOutput) UnchangedStatusF(format string, a ...interface{}) {
|
|||||||
func (co ConsoleOutput) ChangedStatusF(format string, a ...interface{}) {
|
func (co ConsoleOutput) ChangedStatusF(format string, a ...interface{}) {
|
||||||
msg := fmt.Sprintf(format, a...)
|
msg := fmt.Sprintf(format, a...)
|
||||||
if co.Color {
|
if co.Color {
|
||||||
msg = fmt.Sprintf("%v%v", colorYellow, msg)
|
msg = fmt.Sprintf("%v%v%v", colorYellow, msg, colorReset)
|
||||||
}
|
}
|
||||||
fmt.Println(msg)
|
fmt.Println(msg)
|
||||||
}
|
}
|
||||||
@ -55,7 +55,7 @@ func (co ConsoleOutput) ChangedStatusF(format string, a ...interface{}) {
|
|||||||
func (co ConsoleOutput) ErrorStatusF(format string, a ...interface{}) {
|
func (co ConsoleOutput) ErrorStatusF(format string, a ...interface{}) {
|
||||||
msg := fmt.Sprintf(format, a...)
|
msg := fmt.Sprintf(format, a...)
|
||||||
if co.Color {
|
if co.Color {
|
||||||
msg = fmt.Sprintf("%v%v", colorRed, msg)
|
msg = fmt.Sprintf("%v%v%v", colorRed, msg, colorReset)
|
||||||
}
|
}
|
||||||
fmt.Println(msg)
|
fmt.Println(msg)
|
||||||
}
|
}
|
||||||
|
164
commands/status_cmd.go
Normal file
164
commands/status_cmd.go
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/go-git/go-git/v5"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing/object"
|
||||||
|
"gitlab.com/revalus/grm/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StatusChecker struct {
|
||||||
|
workspace string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStatusChecker(workspace string) StatusChecker {
|
||||||
|
return StatusChecker{
|
||||||
|
workspace: workspace,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func findNumberOfCommitDiffs(srcCommit *object.Commit, dstCommit *object.Commit) int {
|
||||||
|
|
||||||
|
getFiveElementsFromHashes := func(commit *object.Commit, hashedSlice *[]string) *object.Commit {
|
||||||
|
|
||||||
|
var err error
|
||||||
|
for iter := 0; iter <= 5; iter++ {
|
||||||
|
|
||||||
|
*hashedSlice = append(*hashedSlice, commit.Hash.String())
|
||||||
|
commit, err = commit.Parents().Next()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return commit
|
||||||
|
}
|
||||||
|
|
||||||
|
getRangeDiff := func(listFist, listSecond []string) (int, bool) {
|
||||||
|
diffRange := 0
|
||||||
|
|
||||||
|
for _, itemFirst := range listFist {
|
||||||
|
for _, itemSecond := range listSecond {
|
||||||
|
if itemFirst == itemSecond {
|
||||||
|
return diffRange, true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
diffRange++
|
||||||
|
}
|
||||||
|
|
||||||
|
return diffRange, false
|
||||||
|
}
|
||||||
|
|
||||||
|
baseCommitHashes := []string{}
|
||||||
|
destCommitHashes := []string{}
|
||||||
|
for {
|
||||||
|
|
||||||
|
if srcCommit != nil {
|
||||||
|
srcCommit = getFiveElementsFromHashes(srcCommit, &baseCommitHashes)
|
||||||
|
}
|
||||||
|
if dstCommit != nil {
|
||||||
|
dstCommit = getFiveElementsFromHashes(dstCommit, &destCommitHashes)
|
||||||
|
}
|
||||||
|
|
||||||
|
diff, finished := getRangeDiff(baseCommitHashes, destCommitHashes)
|
||||||
|
|
||||||
|
if finished {
|
||||||
|
return diff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc StatusChecker) Command(repoCfg config.RepositoryConfig, status chan CommandStatus) {
|
||||||
|
|
||||||
|
cmdStatus := CommandStatus{
|
||||||
|
Name: repoCfg.Name,
|
||||||
|
Changed: false,
|
||||||
|
Message: "",
|
||||||
|
Error: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
destPath := fmt.Sprintf("%v/%v", sc.workspace, repoCfg.Dest)
|
||||||
|
repo, err := git.PlainOpen(destPath)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
cmdStatus.Error = true
|
||||||
|
cmdStatus.Message = err.Error()
|
||||||
|
status <- cmdStatus
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
headReference, err := repo.Head()
|
||||||
|
if err != nil {
|
||||||
|
cmdStatus.Error = true
|
||||||
|
cmdStatus.Message = err.Error()
|
||||||
|
status <- cmdStatus
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
remotes, err := repo.Remotes()
|
||||||
|
if err != nil || len(remotes) == 0 {
|
||||||
|
cmdStatus.Error = true
|
||||||
|
cmdStatus.Message = "cannot find remote branches"
|
||||||
|
status <- cmdStatus
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
currentBranchCommit, err := repo.CommitObject(headReference.Hash())
|
||||||
|
if err != nil {
|
||||||
|
cmdStatus.Error = true
|
||||||
|
cmdStatus.Message = err.Error()
|
||||||
|
status <- cmdStatus
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type remoteStatus struct {
|
||||||
|
ahead int
|
||||||
|
behind int
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
remotesStatus := make(map[string]remoteStatus)
|
||||||
|
|
||||||
|
for _, remote := range remotes {
|
||||||
|
remoteName := remote.Config().Name
|
||||||
|
|
||||||
|
remoteRevision, err := repo.ResolveRevision(plumbing.Revision(fmt.Sprintf("%v/%v", remoteName, headReference.Name().Short())))
|
||||||
|
if err != nil {
|
||||||
|
remotesStatus[remoteName] = remoteStatus{
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteBranchCommit, err := repo.CommitObject(*remoteRevision)
|
||||||
|
if err != nil {
|
||||||
|
remotesStatus[remoteName] = remoteStatus{
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
status := remoteStatus{
|
||||||
|
ahead: findNumberOfCommitDiffs(currentBranchCommit, remoteBranchCommit),
|
||||||
|
behind: findNumberOfCommitDiffs(remoteBranchCommit, currentBranchCommit),
|
||||||
|
}
|
||||||
|
if status.ahead > 0 || status.behind > 0 {
|
||||||
|
cmdStatus.Changed = true
|
||||||
|
}
|
||||||
|
remotesStatus[remoteName] = status
|
||||||
|
|
||||||
|
}
|
||||||
|
cmdStatus.Message = fmt.Sprintf("branch %v", headReference.Name().Short())
|
||||||
|
for remoteName, status := range remotesStatus {
|
||||||
|
if status.err != nil {
|
||||||
|
cmdStatus.Message = fmt.Sprintf("%v - ( | %v | problem: %v )", cmdStatus.Message, remoteName, status.err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cmdStatus.Message = fmt.Sprintf("%v - ( | %v | \u2191%v \u2193%v )", cmdStatus.Message, remoteName, status.ahead, status.behind)
|
||||||
|
}
|
||||||
|
|
||||||
|
status <- cmdStatus
|
||||||
|
}
|
403
commands/status_cmd_test.go
Normal file
403
commands/status_cmd_test.go
Normal file
@ -0,0 +1,403 @@
|
|||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/go-git/go-billy/v5"
|
||||||
|
"github.com/go-git/go-billy/v5/memfs"
|
||||||
|
"github.com/go-git/go-billy/v5/osfs"
|
||||||
|
"github.com/go-git/go-git/v5"
|
||||||
|
gitcfg "github.com/go-git/go-git/v5/config"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing/cache"
|
||||||
|
"github.com/go-git/go-git/v5/storage/filesystem"
|
||||||
|
"github.com/go-git/go-git/v5/storage/memory"
|
||||||
|
"gitlab.com/revalus/grm/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TestDir struct {
|
||||||
|
rootFS billy.Filesystem
|
||||||
|
baseRepository struct {
|
||||||
|
fileSystem billy.Filesystem
|
||||||
|
repo *git.Repository
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTestDirForTests() TestDir {
|
||||||
|
|
||||||
|
checkError := func(err error) {
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("During preparing repositories, an error occurred: %v\n", err)
|
||||||
|
os.Exit(4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
baseTMPPath := fmt.Sprintf("%v/grmTest", os.TempDir())
|
||||||
|
if _, ok := os.Stat(baseTMPPath); ok != nil {
|
||||||
|
err := os.Mkdir(baseTMPPath, 0777)
|
||||||
|
checkError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpDir, err := os.MkdirTemp(baseTMPPath, "*")
|
||||||
|
checkError(err)
|
||||||
|
|
||||||
|
baseFileSystem := osfs.New(tmpDir)
|
||||||
|
|
||||||
|
initRepositoryFileSystem, err := baseFileSystem.Chroot("worktree")
|
||||||
|
checkError(err)
|
||||||
|
|
||||||
|
directoryForGitMetadata, err := initRepositoryFileSystem.Chroot(".git")
|
||||||
|
checkError(err)
|
||||||
|
|
||||||
|
repository, err := git.Init(filesystem.NewStorage(directoryForGitMetadata, cache.NewObjectLRUDefault()), initRepositoryFileSystem)
|
||||||
|
checkError(err)
|
||||||
|
|
||||||
|
fileForFirstCommit, err := initRepositoryFileSystem.Create("TestFile.txt")
|
||||||
|
checkError(err)
|
||||||
|
|
||||||
|
_, err = fileForFirstCommit.Write([]byte("foo-conent"))
|
||||||
|
checkError(err)
|
||||||
|
|
||||||
|
repositoryWorkTree, err := repository.Worktree()
|
||||||
|
checkError(err)
|
||||||
|
|
||||||
|
repositoryWorkTree.Add(fileForFirstCommit.Name())
|
||||||
|
_, err = repositoryWorkTree.Commit("First commit", &git.CommitOptions{})
|
||||||
|
|
||||||
|
checkError(err)
|
||||||
|
|
||||||
|
return TestDir{
|
||||||
|
baseRepository: struct {
|
||||||
|
fileSystem billy.Filesystem
|
||||||
|
repo *git.Repository
|
||||||
|
}{
|
||||||
|
fileSystem: initRepositoryFileSystem,
|
||||||
|
repo: repository,
|
||||||
|
},
|
||||||
|
rootFS: baseFileSystem,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func unexpectedError(err error, t *testing.T) {
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeCommit(wk *git.Worktree, commitMessage string, fileName string) error {
|
||||||
|
|
||||||
|
wk.Commit(commitMessage, &git.CommitOptions{})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIfBranchesAreEqual(t *testing.T) {
|
||||||
|
tmpDirWithInitialRepository := getTestDirForTests()
|
||||||
|
|
||||||
|
fakeLocalRepo, err := git.Clone(memory.NewStorage(), memfs.New(), &git.CloneOptions{
|
||||||
|
URL: tmpDirWithInitialRepository.baseRepository.fileSystem.Root(),
|
||||||
|
})
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
currentReference, err := fakeLocalRepo.Head()
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
remote, err := fakeLocalRepo.Remote("origin")
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
remoteRevision, err := fakeLocalRepo.ResolveRevision(plumbing.Revision(fmt.Sprintf("%v/%v", remote.Config().Name, currentReference.Name().Short())))
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
currentBranchCommit, err := fakeLocalRepo.CommitObject(currentReference.Hash())
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
remoteBranchCommit, err := fakeLocalRepo.CommitObject(*remoteRevision)
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
result := findNumberOfCommitDiffs(currentBranchCommit, remoteBranchCommit)
|
||||||
|
if result != 0 {
|
||||||
|
t.Errorf("Expected to get 0 changes, instead of this got %v", result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIfCurrentBranchIsAbove(t *testing.T) {
|
||||||
|
|
||||||
|
tmpDirWithInitialRepository := getTestDirForTests()
|
||||||
|
tmpFileSystemForLocalRepository := memfs.New()
|
||||||
|
fakeLocalRepo, err := git.Clone(memory.NewStorage(), tmpFileSystemForLocalRepository, &git.CloneOptions{
|
||||||
|
URL: tmpDirWithInitialRepository.baseRepository.fileSystem.Root(),
|
||||||
|
})
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
localWorktree, err := fakeLocalRepo.Worktree()
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
err = makeCommit(localWorktree, "commit 1", "Commit1")
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
localReference, err := fakeLocalRepo.Head()
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
remoteConnection, err := fakeLocalRepo.Remote("origin")
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
remoteRevision, err := fakeLocalRepo.ResolveRevision(plumbing.Revision(fmt.Sprintf("%v/%v", remoteConnection.Config().Name, localReference.Name().Short())))
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
currentBranchCommit, err := fakeLocalRepo.CommitObject(localReference.Hash())
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
remoteBranchCommit, err := fakeLocalRepo.CommitObject(*remoteRevision)
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
result := findNumberOfCommitDiffs(currentBranchCommit, remoteBranchCommit)
|
||||||
|
if result != 1 {
|
||||||
|
t.Errorf("Expected to get 1 changes, instead of this got %v", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 1; i < 15; i++ {
|
||||||
|
err = makeCommit(localWorktree, fmt.Sprintf("Commit +%v", i), fmt.Sprintf("Commit%v", i))
|
||||||
|
unexpectedError(err, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
localReference, err = fakeLocalRepo.Head()
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
currentBranchCommit, err = fakeLocalRepo.CommitObject(localReference.Hash())
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
result = findNumberOfCommitDiffs(currentBranchCommit, remoteBranchCommit)
|
||||||
|
if result != 15 {
|
||||||
|
t.Errorf("Expected to get 5 changes, instead of this got %v", result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommandRepositoryDoesNotExists(t *testing.T) {
|
||||||
|
|
||||||
|
tmpDirWithInitialRepository := getTestDirForTests()
|
||||||
|
|
||||||
|
fileSystemForLocalRepo, err := tmpDirWithInitialRepository.rootFS.Chroot("NotMatterValue")
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
directoryForLocalRepoMetadata, err := fileSystemForLocalRepo.Chroot(".git")
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
storageForTestRepo := filesystem.NewStorage(directoryForLocalRepoMetadata, cache.NewObjectLRUDefault())
|
||||||
|
_, err = git.Clone(storageForTestRepo, fileSystemForLocalRepo, &git.CloneOptions{
|
||||||
|
URL: tmpDirWithInitialRepository.baseRepository.fileSystem.Root(),
|
||||||
|
})
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
sc := StatusChecker{
|
||||||
|
workspace: tmpDirWithInitialRepository.rootFS.Root(),
|
||||||
|
}
|
||||||
|
|
||||||
|
repoCfg := config.RepositoryConfig{
|
||||||
|
Name: "test",
|
||||||
|
Src: tmpDirWithInitialRepository.baseRepository.fileSystem.Root(),
|
||||||
|
Dest: tmpDirWithInitialRepository.rootFS.Root(),
|
||||||
|
}
|
||||||
|
|
||||||
|
ch := make(chan CommandStatus)
|
||||||
|
go sc.Command(repoCfg, ch)
|
||||||
|
repoStatus := <-ch
|
||||||
|
expectedMessage := "repository does not exist"
|
||||||
|
|
||||||
|
if !repoStatus.Error {
|
||||||
|
t.Errorf("Expected error")
|
||||||
|
}
|
||||||
|
if repoStatus.Changed {
|
||||||
|
t.Errorf("Unexpected change value")
|
||||||
|
}
|
||||||
|
if repoStatus.Message != expectedMessage {
|
||||||
|
t.Errorf("Expected to get \"%v\", instead of this got \"%v\"", expectedMessage, repoStatus.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommandRepositoryNoRemoteBranch(t *testing.T) {
|
||||||
|
|
||||||
|
tmpDirWithInitialRepository := getTestDirForTests()
|
||||||
|
dirNameForLocalRepository := "testRepo"
|
||||||
|
fileSystemForLocalRepo, err := tmpDirWithInitialRepository.rootFS.Chroot(dirNameForLocalRepository)
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
directoryForLocalRepoMetadata, err := fileSystemForLocalRepo.Chroot(".git")
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
storageForTestRepo := filesystem.NewStorage(directoryForLocalRepoMetadata, cache.NewObjectLRUDefault())
|
||||||
|
fakeLocalRepository, err := git.Clone(storageForTestRepo, fileSystemForLocalRepo, &git.CloneOptions{
|
||||||
|
URL: tmpDirWithInitialRepository.baseRepository.fileSystem.Root(),
|
||||||
|
})
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
err = fakeLocalRepository.DeleteRemote("origin")
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
sc := StatusChecker{
|
||||||
|
workspace: tmpDirWithInitialRepository.rootFS.Root(),
|
||||||
|
}
|
||||||
|
|
||||||
|
repoCfg := config.RepositoryConfig{
|
||||||
|
Name: "test",
|
||||||
|
Src: tmpDirWithInitialRepository.baseRepository.fileSystem.Root(),
|
||||||
|
Dest: dirNameForLocalRepository,
|
||||||
|
}
|
||||||
|
|
||||||
|
ch := make(chan CommandStatus)
|
||||||
|
go sc.Command(repoCfg, ch)
|
||||||
|
repoStatus := <-ch
|
||||||
|
expectedMessage := "cannot find remote branches"
|
||||||
|
|
||||||
|
if !repoStatus.Error {
|
||||||
|
t.Errorf("Expected error")
|
||||||
|
}
|
||||||
|
if repoStatus.Changed {
|
||||||
|
t.Errorf("Unexpected change value")
|
||||||
|
}
|
||||||
|
|
||||||
|
if repoStatus.Message != expectedMessage {
|
||||||
|
t.Errorf("Expected to get \"%v\", instead of this got \"%v\"", expectedMessage, repoStatus.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommandAllCorrect(t *testing.T) {
|
||||||
|
|
||||||
|
tmpDirWithInitialRepository := getTestDirForTests()
|
||||||
|
dirNameForLocalRepository := "testRepo"
|
||||||
|
fileSystemForLocalRepo, err := tmpDirWithInitialRepository.rootFS.Chroot(dirNameForLocalRepository)
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
directoryForLocalRepoMetadata, err := fileSystemForLocalRepo.Chroot(".git")
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
storageForTestRepo := filesystem.NewStorage(directoryForLocalRepoMetadata, cache.NewObjectLRUDefault())
|
||||||
|
fakeLocalRepository, err := git.Clone(storageForTestRepo, fileSystemForLocalRepo, &git.CloneOptions{
|
||||||
|
URL: tmpDirWithInitialRepository.baseRepository.fileSystem.Root(),
|
||||||
|
})
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
sc := StatusChecker{
|
||||||
|
workspace: tmpDirWithInitialRepository.rootFS.Root(),
|
||||||
|
}
|
||||||
|
repoCfg := config.RepositoryConfig{
|
||||||
|
Name: "test",
|
||||||
|
Src: tmpDirWithInitialRepository.baseRepository.fileSystem.Root(),
|
||||||
|
Dest: dirNameForLocalRepository,
|
||||||
|
}
|
||||||
|
|
||||||
|
ch := make(chan CommandStatus)
|
||||||
|
|
||||||
|
go sc.Command(repoCfg, ch)
|
||||||
|
repoStatus := <-ch
|
||||||
|
expectedMessage := "branch master - ( | origin | \u21910 \u21930 )"
|
||||||
|
|
||||||
|
if repoStatus.Error {
|
||||||
|
t.Errorf("Unexpected error")
|
||||||
|
t.Errorf("Message %v", repoStatus.Message)
|
||||||
|
}
|
||||||
|
if repoStatus.Changed {
|
||||||
|
t.Errorf("Expeected that changed will be true")
|
||||||
|
}
|
||||||
|
if repoStatus.Message != expectedMessage {
|
||||||
|
t.Errorf("Expected to get \"%v\", instead of this got \"%v\"", expectedMessage, repoStatus.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
fakeLocalWorkTree, err := fakeLocalRepository.Worktree()
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
err = makeCommit(fakeLocalWorkTree, "commit 1", "Commit1")
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
go sc.Command(repoCfg, ch)
|
||||||
|
repoStatus = <-ch
|
||||||
|
expectedMessage = "branch master - ( | origin | \u21911 \u21930 )"
|
||||||
|
|
||||||
|
if repoStatus.Message != expectedMessage {
|
||||||
|
t.Errorf("Expected to get \"%v\", instead of this got \"%v\"", expectedMessage, repoStatus.Message)
|
||||||
|
}
|
||||||
|
if repoStatus.Error {
|
||||||
|
t.Errorf("Unexpected error")
|
||||||
|
t.Errorf("Message %v", repoStatus.Message)
|
||||||
|
}
|
||||||
|
if !repoStatus.Changed {
|
||||||
|
t.Errorf("Expeected that changed will be true")
|
||||||
|
}
|
||||||
|
if repoStatus.Message != expectedMessage {
|
||||||
|
t.Errorf("Expected to get \"%v\", instead of this got \"%v\"", expectedMessage, repoStatus.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCommandMultiRemote(t *testing.T) {
|
||||||
|
|
||||||
|
tmpDirWithInitialRepository := getTestDirForTests()
|
||||||
|
dirNameForLocalRepository := "testRepo"
|
||||||
|
fileSystemForLocalRepo, err := tmpDirWithInitialRepository.rootFS.Chroot(dirNameForLocalRepository)
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
directoryForLocalRepoMetadata, err := fileSystemForLocalRepo.Chroot(".git")
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
storageForTestRepo := filesystem.NewStorage(directoryForLocalRepoMetadata, cache.NewObjectLRUDefault())
|
||||||
|
fakeLocalRepository, err := git.Clone(storageForTestRepo, fileSystemForLocalRepo, &git.CloneOptions{
|
||||||
|
URL: tmpDirWithInitialRepository.baseRepository.fileSystem.Root(),
|
||||||
|
})
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
fakeLocalRepository.CreateRemote(&gitcfg.RemoteConfig{
|
||||||
|
Name: "subremote",
|
||||||
|
URLs: []string{tmpDirWithInitialRepository.baseRepository.fileSystem.Root()},
|
||||||
|
})
|
||||||
|
|
||||||
|
fakeLocalRepository.Fetch(&git.FetchOptions{
|
||||||
|
RemoteName: "subremote",
|
||||||
|
})
|
||||||
|
|
||||||
|
sc := StatusChecker{
|
||||||
|
workspace: tmpDirWithInitialRepository.rootFS.Root(),
|
||||||
|
}
|
||||||
|
repoCfg := config.RepositoryConfig{
|
||||||
|
Name: "test",
|
||||||
|
Src: tmpDirWithInitialRepository.baseRepository.fileSystem.Root(),
|
||||||
|
Dest: dirNameForLocalRepository,
|
||||||
|
}
|
||||||
|
|
||||||
|
ch := make(chan CommandStatus)
|
||||||
|
|
||||||
|
go sc.Command(repoCfg, ch)
|
||||||
|
repoStatus := <-ch
|
||||||
|
expectedMessage := "branch master - ( | origin | \u21910 \u21930 ) - ( | subremote | \u21910 \u21930 )"
|
||||||
|
|
||||||
|
if repoStatus.Error {
|
||||||
|
t.Errorf("Unexpected error")
|
||||||
|
t.Errorf("Message %v", repoStatus.Message)
|
||||||
|
}
|
||||||
|
if repoStatus.Changed {
|
||||||
|
t.Errorf("Expeected that changed will be true")
|
||||||
|
}
|
||||||
|
if repoStatus.Message != expectedMessage {
|
||||||
|
t.Errorf("Expected to get \"%v\", instead of this got \"%v\"", expectedMessage, repoStatus.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
fakeLocalWorkTree, err := fakeLocalRepository.Worktree()
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
err = makeCommit(fakeLocalWorkTree, "commit 1", "Commit1")
|
||||||
|
unexpectedError(err, t)
|
||||||
|
|
||||||
|
go sc.Command(repoCfg, ch)
|
||||||
|
repoStatus = <-ch
|
||||||
|
expectedMessage = "branch master - ( | origin | \u21911 \u21930 ) - ( | subremote | \u21911 \u21930 )"
|
||||||
|
|
||||||
|
if repoStatus.Error {
|
||||||
|
t.Errorf("Unexpected error")
|
||||||
|
t.Errorf("Message %v", repoStatus.Message)
|
||||||
|
}
|
||||||
|
if !repoStatus.Changed {
|
||||||
|
t.Errorf("Expeected that changed will be true")
|
||||||
|
}
|
||||||
|
if repoStatus.Message != expectedMessage {
|
||||||
|
t.Errorf("Expected to get \"%v\", instead of this got \"%v\"", expectedMessage, repoStatus.Message)
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,7 @@ func ParseCliArguments(name, description string, arguments []string) (CliArgumen
|
|||||||
parser := argparse.NewParser(name, description)
|
parser := argparse.NewParser(name, description)
|
||||||
|
|
||||||
syncCMD := parser.NewCommand("sync", "Synchronize repositories with remote branches, if the repository does not exist, clone it. (If pulling is not possible, the repository will be fetched)")
|
syncCMD := parser.NewCommand("sync", "Synchronize repositories with remote branches, if the repository does not exist, clone it. (If pulling is not possible, the repository will be fetched)")
|
||||||
|
statusCMD := parser.NewCommand("status", "Get information about repositories")
|
||||||
|
|
||||||
configFile := parser.String("c", "config-file", &argparse.Options{
|
configFile := parser.String("c", "config-file", &argparse.Options{
|
||||||
Default: getDefaultConfigDir(),
|
Default: getDefaultConfigDir(),
|
||||||
@ -38,16 +39,19 @@ func ParseCliArguments(name, description string, arguments []string) (CliArgumen
|
|||||||
Default: false,
|
Default: false,
|
||||||
Help: "Turn off color printing",
|
Help: "Turn off color printing",
|
||||||
})
|
})
|
||||||
|
|
||||||
if err := parser.Parse(arguments); err != nil {
|
if err := parser.Parse(arguments); err != nil {
|
||||||
return CliArguments{}, err
|
return CliArguments{}, errors.New(parser.Usage("Please follow this help"))
|
||||||
}
|
}
|
||||||
if !syncCMD.Happened() && !(*version) {
|
|
||||||
|
if !syncCMD.Happened() && !(*version) && !statusCMD.Happened() {
|
||||||
return CliArguments{}, errors.New(errNoCommand)
|
return CliArguments{}, errors.New(errNoCommand)
|
||||||
}
|
}
|
||||||
|
|
||||||
return CliArguments{
|
return CliArguments{
|
||||||
ConfigurationFile: *configFile,
|
ConfigurationFile: *configFile,
|
||||||
Sync: syncCMD.Happened(),
|
Sync: syncCMD.Happened(),
|
||||||
|
Status: statusCMD.Happened(),
|
||||||
Version: *version,
|
Version: *version,
|
||||||
Color: !(*color),
|
Color: !(*color),
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -14,6 +14,7 @@ type RepositoryConfig struct {
|
|||||||
type CliArguments struct {
|
type CliArguments struct {
|
||||||
ConfigurationFile string
|
ConfigurationFile string
|
||||||
Sync bool
|
Sync bool
|
||||||
|
Status bool
|
||||||
Version bool
|
Version bool
|
||||||
Color bool
|
Color bool
|
||||||
}
|
}
|
||||||
|
2
go.mod
2
go.mod
@ -4,6 +4,7 @@ go 1.17
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/akamensky/argparse v1.3.1
|
github.com/akamensky/argparse v1.3.1
|
||||||
|
github.com/go-git/go-billy/v5 v5.3.1
|
||||||
github.com/go-git/go-git/v5 v5.4.2
|
github.com/go-git/go-git/v5 v5.4.2
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||||
)
|
)
|
||||||
@ -14,7 +15,6 @@ require (
|
|||||||
github.com/acomagu/bufpipe v1.0.3 // indirect
|
github.com/acomagu/bufpipe v1.0.3 // indirect
|
||||||
github.com/emirpasic/gods v1.12.0 // indirect
|
github.com/emirpasic/gods v1.12.0 // indirect
|
||||||
github.com/go-git/gcfg v1.5.0 // indirect
|
github.com/go-git/gcfg v1.5.0 // indirect
|
||||||
github.com/go-git/go-billy/v5 v5.3.1 // indirect
|
|
||||||
github.com/google/go-cmp v0.5.6 // indirect
|
github.com/google/go-cmp v0.5.6 // indirect
|
||||||
github.com/imdario/mergo v0.3.12 // indirect
|
github.com/imdario/mergo v0.3.12 // indirect
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
|
Loading…
Reference in New Issue
Block a user