Limit number of concurrent goroutines
This commit is contained in:
parent
5fd9bc851b
commit
62dadc53bf
15
README.md
15
README.md
@ -25,13 +25,14 @@ By default, the config file is searched for in `[HOME_DIR]./config/grm/config.ya
|
|||||||
|
|
||||||
### Global args
|
### Global args
|
||||||
|
|
||||||
| argument | type | default | Description |
|
| argument | type | default | Description |
|
||||||
|---------------------------|----------|--------------------------------------|------------------------------------------------------------------------|
|
|------------------------------|----------|--------------------------------------|------------------------------------------------------------------------|
|
||||||
| **-c**, **--config-file** | *string* | `[HOME_DIR]./config/grm/config.yaml` | Path to configuration file, where the repositories must be specified |
|
| **-c**, **--config-file** | *string* | `[HOME_DIR]./config/grm/config.yaml` | Path to configuration file, where the repositories must be specified |
|
||||||
| **-v**, **--version** | *bool* | `false` | Display current version |
|
| **-v**, **--version** | *bool* | `false` | Display current version |
|
||||||
| **--no-color** | *bool* | `false` | Turning off the display of output in color |
|
| **--no-color** | *bool* | `false` | Turning off the display of output in color |
|
||||||
| **-n** **--name** | *string* | `empty` | Limit action to the specified repository name |
|
| **-n** **--name** | *string* | `empty` | Limit action to the specified repository name |
|
||||||
| **-t** **--tag** | *string* | `empty` | Limit action to the specified repository tag (may be more than one tag)|
|
| **-t** **--tag** | *string* | `empty` | Limit action to the specified repository tag (may be more than one tag)|
|
||||||
|
| **max-concurrent-process** | *string* | `empty` | Determine how many tasks can run simultaneously |
|
||||||
|
|
||||||
### Commands
|
### Commands
|
||||||
|
|
||||||
|
58
app/app.go
58
app/app.go
@ -4,7 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"sync"
|
||||||
|
|
||||||
"gitlab.com/revalus/grm/commands"
|
"gitlab.com/revalus/grm/commands"
|
||||||
"gitlab.com/revalus/grm/config"
|
"gitlab.com/revalus/grm/config"
|
||||||
@ -24,28 +24,34 @@ type GitRepositoryManager struct {
|
|||||||
configuration config.Configuration
|
configuration config.Configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GitRepositoryManager) Parse(args []string) {
|
func (g *GitRepositoryManager) Parse(args []string) error {
|
||||||
checkCriticalError := func(err error) {
|
arguments, err := config.ParseCliArguments(APP_NAME, APP_DESCRIPTION, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error: %v", err.Error())
|
fmt.Printf("Error: %v", err.Error())
|
||||||
os.Exit(2)
|
return err
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
arguments, err := config.ParseCliArguments(APP_NAME, APP_DESCRIPTION, args)
|
|
||||||
checkCriticalError(err)
|
|
||||||
|
|
||||||
configFileContent, err := getFileContent(arguments.ConfigurationFile)
|
configFileContent, err := getFileContent(arguments.ConfigurationFile)
|
||||||
checkCriticalError(err)
|
if err != nil {
|
||||||
|
fmt.Printf("Error: %v", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
fileExcension, err := getFileExcension(arguments.ConfigurationFile)
|
fileExcension, err := getFileExcension(arguments.ConfigurationFile)
|
||||||
checkCriticalError(err)
|
if err != nil {
|
||||||
|
fmt.Printf("Error: %v", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
configuration, err := config.GetRepositoryConfig(configFileContent, fileExcension)
|
configuration, err := config.GetRepositoryConfig(configFileContent, fileExcension)
|
||||||
checkCriticalError(err)
|
if err != nil {
|
||||||
|
fmt.Printf("Error: %v", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
g.cliArguments = arguments
|
g.cliArguments = arguments
|
||||||
g.configuration = configuration
|
g.configuration = configuration
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GitRepositoryManager) Run(w io.Writer) int {
|
func (g *GitRepositoryManager) Run(w io.Writer) int {
|
||||||
@ -55,7 +61,7 @@ func (g *GitRepositoryManager) Run(w io.Writer) int {
|
|||||||
|
|
||||||
exitCode := 0
|
exitCode := 0
|
||||||
|
|
||||||
if len(g.cliArguments.LimitTags) != 0 {
|
if len(g.cliArguments.LimitToTags) != 0 {
|
||||||
err := g.limitTags()
|
err := g.limitTags()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
echo.ErrorfMsg(err.Error())
|
echo.ErrorfMsg(err.Error())
|
||||||
@ -63,7 +69,7 @@ func (g *GitRepositoryManager) Run(w io.Writer) int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if g.cliArguments.LimitName != "" {
|
if g.cliArguments.LimitToName != "" {
|
||||||
err := g.limitName()
|
err := g.limitName()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
echo.ErrorfMsg(err.Error())
|
echo.ErrorfMsg(err.Error())
|
||||||
@ -90,7 +96,7 @@ func (g *GitRepositoryManager) Run(w io.Writer) int {
|
|||||||
return exitCode
|
return exitCode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g GitRepositoryManager) describeStatus(status commands.CommandStatus) {
|
func describeStatus(status commands.CommandStatus) {
|
||||||
if status.Error {
|
if status.Error {
|
||||||
echo.RedMessageF("Repository \"%v\": an error occurred: %v", status.Name, status.Message)
|
echo.RedMessageF("Repository \"%v\": an error occurred: %v", status.Name, status.Message)
|
||||||
return
|
return
|
||||||
@ -107,7 +113,7 @@ func (g *GitRepositoryManager) limitTags() error {
|
|||||||
limitedTagsTmp := []config.RepositoryConfig{}
|
limitedTagsTmp := []config.RepositoryConfig{}
|
||||||
|
|
||||||
for _, item := range g.configuration.Repositories {
|
for _, item := range g.configuration.Repositories {
|
||||||
if checkAnyOfItemInSlice(item.Tags, g.cliArguments.LimitTags) {
|
if checkAnyOfItemInSlice(item.Tags, g.cliArguments.LimitToTags) {
|
||||||
limitedTagsTmp = append(limitedTagsTmp, item)
|
limitedTagsTmp = append(limitedTagsTmp, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,7 +126,7 @@ func (g *GitRepositoryManager) limitTags() error {
|
|||||||
|
|
||||||
func (g *GitRepositoryManager) limitName() error {
|
func (g *GitRepositoryManager) limitName() error {
|
||||||
for _, item := range g.configuration.Repositories {
|
for _, item := range g.configuration.Repositories {
|
||||||
if g.cliArguments.LimitName == item.Name {
|
if g.cliArguments.LimitToName == item.Name {
|
||||||
g.configuration.Repositories = []config.RepositoryConfig{item}
|
g.configuration.Repositories = []config.RepositoryConfig{item}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -129,13 +135,19 @@ func (g *GitRepositoryManager) limitName() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GitRepositoryManager) runCommand(cmd commands.Command) {
|
func (g *GitRepositoryManager) runCommand(cmd commands.Command) {
|
||||||
statusChan := make(chan commands.CommandStatus)
|
routines := make(chan struct{}, g.cliArguments.Routines)
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
for _, repo := range g.configuration.Repositories {
|
for _, repo := range g.configuration.Repositories {
|
||||||
go cmd.Command(repo, statusChan)
|
wg.Add(1)
|
||||||
}
|
|
||||||
|
|
||||||
for range g.configuration.Repositories {
|
go func(r config.RepositoryConfig) {
|
||||||
g.describeStatus(<-statusChan)
|
defer wg.Done()
|
||||||
|
routines <- struct{}{}
|
||||||
|
describeStatus(cmd.Command(r))
|
||||||
|
|
||||||
|
<-routines
|
||||||
|
}(repo)
|
||||||
}
|
}
|
||||||
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
130
app/app_test.go
130
app/app_test.go
@ -31,7 +31,7 @@ func (emt ExpectedMessageTester) Write(p []byte) (n int, err error) {
|
|||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fk FakeCommandToTest) Command(repoCfg config.RepositoryConfig, cmdStatus chan commands.CommandStatus) {
|
func (fk FakeCommandToTest) Command(repoCfg config.RepositoryConfig) commands.CommandStatus {
|
||||||
status := commands.CommandStatus{
|
status := commands.CommandStatus{
|
||||||
Name: repoCfg.Name,
|
Name: repoCfg.Name,
|
||||||
Changed: false,
|
Changed: false,
|
||||||
@ -46,7 +46,7 @@ func (fk FakeCommandToTest) Command(repoCfg config.RepositoryConfig, cmdStatus c
|
|||||||
status.Changed = true
|
status.Changed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdStatus <- status
|
return status
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareConfigContent() (string, string) {
|
func prepareConfigContent() (string, string) {
|
||||||
@ -122,9 +122,10 @@ func TestOutputFromSync(t *testing.T) {
|
|||||||
Workspace: "/tmp",
|
Workspace: "/tmp",
|
||||||
},
|
},
|
||||||
cliArguments: config.CliArguments{
|
cliArguments: config.CliArguments{
|
||||||
Sync: true,
|
Sync: true,
|
||||||
Version: true,
|
Version: true,
|
||||||
Color: false,
|
Color: false,
|
||||||
|
Routines: 10,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
emt := ExpectedMessageTester{
|
emt := ExpectedMessageTester{
|
||||||
@ -140,7 +141,8 @@ func TestOutputFromSync(t *testing.T) {
|
|||||||
func TestLimitTags(t *testing.T) {
|
func TestLimitTags(t *testing.T) {
|
||||||
grm := GitRepositoryManager{
|
grm := GitRepositoryManager{
|
||||||
cliArguments: config.CliArguments{
|
cliArguments: config.CliArguments{
|
||||||
LimitTags: []string{"example"},
|
LimitToTags: []string{"example"},
|
||||||
|
Routines: 10,
|
||||||
},
|
},
|
||||||
configuration: config.Configuration{
|
configuration: config.Configuration{
|
||||||
Repositories: []config.RepositoryConfig{
|
Repositories: []config.RepositoryConfig{
|
||||||
@ -169,7 +171,8 @@ func TestLimitTags(t *testing.T) {
|
|||||||
func TestLimitName(t *testing.T) {
|
func TestLimitName(t *testing.T) {
|
||||||
grm := GitRepositoryManager{
|
grm := GitRepositoryManager{
|
||||||
cliArguments: config.CliArguments{
|
cliArguments: config.CliArguments{
|
||||||
LimitName: "notExample",
|
LimitToName: "notExample",
|
||||||
|
Routines: 10,
|
||||||
},
|
},
|
||||||
configuration: config.Configuration{
|
configuration: config.Configuration{
|
||||||
Repositories: []config.RepositoryConfig{
|
Repositories: []config.RepositoryConfig{
|
||||||
@ -196,7 +199,8 @@ func TestLimitName(t *testing.T) {
|
|||||||
func TestRunWithNotExistingNameInLimit(t *testing.T) {
|
func TestRunWithNotExistingNameInLimit(t *testing.T) {
|
||||||
grm := GitRepositoryManager{
|
grm := GitRepositoryManager{
|
||||||
cliArguments: config.CliArguments{
|
cliArguments: config.CliArguments{
|
||||||
LimitName: "not-existing-name",
|
LimitToName: "not-existing-name",
|
||||||
|
Routines: 10,
|
||||||
},
|
},
|
||||||
configuration: config.Configuration{
|
configuration: config.Configuration{
|
||||||
Repositories: []config.RepositoryConfig{
|
Repositories: []config.RepositoryConfig{
|
||||||
@ -221,7 +225,8 @@ func TestRunWithNotExistingNameInLimit(t *testing.T) {
|
|||||||
func TestRunWithNotExistingTagsInLimit(t *testing.T) {
|
func TestRunWithNotExistingTagsInLimit(t *testing.T) {
|
||||||
grm := GitRepositoryManager{
|
grm := GitRepositoryManager{
|
||||||
cliArguments: config.CliArguments{
|
cliArguments: config.CliArguments{
|
||||||
LimitTags: []string{"not-existing-tag"},
|
LimitToTags: []string{"not-existing-tag"},
|
||||||
|
Routines: 10,
|
||||||
},
|
},
|
||||||
configuration: config.Configuration{
|
configuration: config.Configuration{
|
||||||
Repositories: []config.RepositoryConfig{
|
Repositories: []config.RepositoryConfig{
|
||||||
@ -249,7 +254,8 @@ func TestGetStatusOutput(t *testing.T) {
|
|||||||
Workspace: "/tmp",
|
Workspace: "/tmp",
|
||||||
},
|
},
|
||||||
cliArguments: config.CliArguments{
|
cliArguments: config.CliArguments{
|
||||||
Status: true,
|
Status: true,
|
||||||
|
Routines: 10,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
emt := ExpectedMessageTester{
|
emt := ExpectedMessageTester{
|
||||||
@ -262,6 +268,106 @@ func TestGetStatusOutput(t *testing.T) {
|
|||||||
if status != 0 {
|
if status != 0 {
|
||||||
t.Errorf("Expected to get status %v, instead o this got %v", 1, status)
|
t.Errorf("Expected to get status %v, instead o this got %v", 1, status)
|
||||||
}
|
}
|
||||||
// Output:
|
}
|
||||||
// Info: Current status of repositories
|
|
||||||
|
func TestDescribeStatusErrorNoColor(t *testing.T) {
|
||||||
|
emt := ExpectedMessageTester{
|
||||||
|
expectedMessages: []string{
|
||||||
|
"Repository \"Test\": an error occurred: test\n",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
echo.Color(false)
|
||||||
|
echo.Output(emt)
|
||||||
|
status := commands.CommandStatus{
|
||||||
|
Name: "Test",
|
||||||
|
Message: "test",
|
||||||
|
Error: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
describeStatus(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDescribeStatusErrorColor(t *testing.T) {
|
||||||
|
emt := ExpectedMessageTester{
|
||||||
|
expectedMessages: []string{
|
||||||
|
fmt.Sprintf("%vRepository \"Test\": an error occurred: test%v\n", echo.ColorRed, echo.ColorReset),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
echo.Color(true)
|
||||||
|
echo.Output(emt)
|
||||||
|
status := commands.CommandStatus{
|
||||||
|
Name: "Test",
|
||||||
|
Message: "test",
|
||||||
|
Error: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
describeStatus(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDescribeStatusChangedNoColor(t *testing.T) {
|
||||||
|
emt := ExpectedMessageTester{
|
||||||
|
expectedMessages: []string{
|
||||||
|
"Repository \"Test\": test\n",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
echo.Color(false)
|
||||||
|
echo.Output(emt)
|
||||||
|
status := commands.CommandStatus{
|
||||||
|
Name: "Test",
|
||||||
|
Message: "test",
|
||||||
|
Changed: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
describeStatus(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDescribeStatusChangedColor(t *testing.T) {
|
||||||
|
emt := ExpectedMessageTester{
|
||||||
|
expectedMessages: []string{
|
||||||
|
fmt.Sprintf("%vRepository \"Test\": test%v\n", echo.ColorYellow, echo.ColorReset),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
echo.Color(true)
|
||||||
|
echo.Output(emt)
|
||||||
|
status := commands.CommandStatus{
|
||||||
|
Name: "Test",
|
||||||
|
Message: "test",
|
||||||
|
Changed: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
describeStatus(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDescribeStatusNoChangeNoColor(t *testing.T) {
|
||||||
|
emt := ExpectedMessageTester{
|
||||||
|
expectedMessages: []string{
|
||||||
|
"Repository \"Test\": test\n",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
echo.Color(false)
|
||||||
|
echo.Output(emt)
|
||||||
|
status := commands.CommandStatus{
|
||||||
|
Name: "Test",
|
||||||
|
Message: "test",
|
||||||
|
Changed: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
describeStatus(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDescribeStatusNoChangeColor(t *testing.T) {
|
||||||
|
emt := ExpectedMessageTester{
|
||||||
|
expectedMessages: []string{
|
||||||
|
fmt.Sprintf("%vRepository \"Test\": test%v\n", echo.ColorGreen, echo.ColorReset),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
echo.Color(true)
|
||||||
|
echo.Output(emt)
|
||||||
|
status := commands.CommandStatus{
|
||||||
|
Name: "Test",
|
||||||
|
Message: "test",
|
||||||
|
Changed: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
describeStatus(status)
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ package commands
|
|||||||
import "gitlab.com/revalus/grm/config"
|
import "gitlab.com/revalus/grm/config"
|
||||||
|
|
||||||
type Command interface {
|
type Command interface {
|
||||||
Command(repoCfg config.RepositoryConfig, cmdStatus chan CommandStatus)
|
Command(repoCfg config.RepositoryConfig) CommandStatus
|
||||||
}
|
}
|
||||||
type CommandStatus struct {
|
type CommandStatus struct {
|
||||||
Name string
|
Name string
|
||||||
|
@ -71,7 +71,7 @@ func findNumberOfCommitDiffs(srcCommit *object.Commit, dstCommit *object.Commit)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc StatusChecker) Command(repoCfg config.RepositoryConfig, status chan CommandStatus) {
|
func (sc StatusChecker) Command(repoCfg config.RepositoryConfig) CommandStatus {
|
||||||
|
|
||||||
cmdStatus := CommandStatus{
|
cmdStatus := CommandStatus{
|
||||||
Name: repoCfg.Name,
|
Name: repoCfg.Name,
|
||||||
@ -86,32 +86,28 @@ func (sc StatusChecker) Command(repoCfg config.RepositoryConfig, status chan Com
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
cmdStatus.Error = true
|
cmdStatus.Error = true
|
||||||
cmdStatus.Message = err.Error()
|
cmdStatus.Message = err.Error()
|
||||||
status <- cmdStatus
|
return cmdStatus
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
headReference, err := repo.Head()
|
headReference, err := repo.Head()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cmdStatus.Error = true
|
cmdStatus.Error = true
|
||||||
cmdStatus.Message = err.Error()
|
cmdStatus.Message = err.Error()
|
||||||
status <- cmdStatus
|
return cmdStatus
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
remotes, err := repo.Remotes()
|
remotes, err := repo.Remotes()
|
||||||
if err != nil || len(remotes) == 0 {
|
if err != nil || len(remotes) == 0 {
|
||||||
cmdStatus.Error = true
|
cmdStatus.Error = true
|
||||||
cmdStatus.Message = "cannot find remote branches"
|
cmdStatus.Message = "cannot find remote branches"
|
||||||
status <- cmdStatus
|
return cmdStatus
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
currentBranchCommit, err := repo.CommitObject(headReference.Hash())
|
currentBranchCommit, err := repo.CommitObject(headReference.Hash())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cmdStatus.Error = true
|
cmdStatus.Error = true
|
||||||
cmdStatus.Message = err.Error()
|
cmdStatus.Message = err.Error()
|
||||||
status <- cmdStatus
|
return cmdStatus
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type remoteStatus struct {
|
type remoteStatus struct {
|
||||||
@ -160,5 +156,5 @@ func (sc StatusChecker) Command(repoCfg config.RepositoryConfig, status chan Com
|
|||||||
cmdStatus.Message = fmt.Sprintf("%v - ( | %v | \u2191%v \u2193%v )", cmdStatus.Message, remoteName, status.ahead, status.behind)
|
cmdStatus.Message = fmt.Sprintf("%v - ( | %v | \u2191%v \u2193%v )", cmdStatus.Message, remoteName, status.ahead, status.behind)
|
||||||
}
|
}
|
||||||
|
|
||||||
status <- cmdStatus
|
return cmdStatus
|
||||||
}
|
}
|
||||||
|
@ -109,9 +109,7 @@ func TestCommandRepositoryDoesNotExists(t *testing.T) {
|
|||||||
Dest: tmpDirWithInitialRepository.rootFS.Root(),
|
Dest: tmpDirWithInitialRepository.rootFS.Root(),
|
||||||
}
|
}
|
||||||
|
|
||||||
ch := make(chan CommandStatus)
|
repoStatus := sc.Command(repoCfg)
|
||||||
go sc.Command(repoCfg, ch)
|
|
||||||
repoStatus := <-ch
|
|
||||||
expectedMessage := "repository does not exist"
|
expectedMessage := "repository does not exist"
|
||||||
|
|
||||||
if !repoStatus.Error {
|
if !repoStatus.Error {
|
||||||
@ -149,10 +147,7 @@ func TestCommandRepositoryNoRemoteBranch(t *testing.T) {
|
|||||||
Dest: dirNameForLocalRepository,
|
Dest: dirNameForLocalRepository,
|
||||||
}
|
}
|
||||||
|
|
||||||
ch := make(chan CommandStatus)
|
repoStatus := sc.Command(repoCfg)
|
||||||
|
|
||||||
go sc.Command(repoCfg, ch)
|
|
||||||
repoStatus := <-ch
|
|
||||||
expectedMessage := "cannot find remote branches"
|
expectedMessage := "cannot find remote branches"
|
||||||
|
|
||||||
if !repoStatus.Error {
|
if !repoStatus.Error {
|
||||||
@ -171,9 +166,7 @@ func TestCommandAllCorrectWithoutChanges(t *testing.T) {
|
|||||||
|
|
||||||
sc, _, repoCfg, _ := getBaseForTestingSyncCommand()
|
sc, _, repoCfg, _ := getBaseForTestingSyncCommand()
|
||||||
|
|
||||||
ch := make(chan CommandStatus)
|
repoStatus := sc.Command(repoCfg)
|
||||||
go sc.Command(repoCfg, ch)
|
|
||||||
repoStatus := <-ch
|
|
||||||
expectedMessage := "branch master - ( | origin | \u21910 \u21930 )"
|
expectedMessage := "branch master - ( | origin | \u21910 \u21930 )"
|
||||||
|
|
||||||
if repoStatus.Error {
|
if repoStatus.Error {
|
||||||
@ -191,15 +184,12 @@ func TestCommandAllCorrectWithOneChange(t *testing.T) {
|
|||||||
|
|
||||||
sc, fakeLocalRepository, repoCfg, _ := getBaseForTestingSyncCommand()
|
sc, fakeLocalRepository, repoCfg, _ := getBaseForTestingSyncCommand()
|
||||||
|
|
||||||
ch := make(chan CommandStatus)
|
|
||||||
|
|
||||||
fakeLocalWorkTree, err := fakeLocalRepository.Worktree()
|
fakeLocalWorkTree, err := fakeLocalRepository.Worktree()
|
||||||
checkErrorDuringPreparation(err)
|
checkErrorDuringPreparation(err)
|
||||||
|
|
||||||
makeCommit(fakeLocalWorkTree, "commit 1")
|
makeCommit(fakeLocalWorkTree, "commit 1")
|
||||||
|
|
||||||
go sc.Command(repoCfg, ch)
|
repoStatus := sc.Command(repoCfg)
|
||||||
repoStatus := <-ch
|
|
||||||
expectedMessage := "branch master - ( | origin | \u21911 \u21930 )"
|
expectedMessage := "branch master - ( | origin | \u21911 \u21930 )"
|
||||||
|
|
||||||
if repoStatus.Message != expectedMessage {
|
if repoStatus.Message != expectedMessage {
|
||||||
@ -220,9 +210,7 @@ func TestCommandAllCorrectWithOneChange(t *testing.T) {
|
|||||||
func TestCommandMultiRemoteNoChanges(t *testing.T) {
|
func TestCommandMultiRemoteNoChanges(t *testing.T) {
|
||||||
|
|
||||||
sc, _, repoCfg := getBaseForTestingSyncMultipleRemote()
|
sc, _, repoCfg := getBaseForTestingSyncMultipleRemote()
|
||||||
ch := make(chan CommandStatus)
|
repoStatus := sc.Command(repoCfg)
|
||||||
go sc.Command(repoCfg, ch)
|
|
||||||
repoStatus := <-ch
|
|
||||||
expectedMessage := "branch master - ( | origin | \u21910 \u21930 ) - ( | subremote | \u21910 \u21930 )"
|
expectedMessage := "branch master - ( | origin | \u21910 \u21930 ) - ( | subremote | \u21910 \u21930 )"
|
||||||
|
|
||||||
if repoStatus.Error {
|
if repoStatus.Error {
|
||||||
@ -246,9 +234,7 @@ func TestCommandMultiRemoteWithOneChange(t *testing.T) {
|
|||||||
makeCommit(fakeLocalWorkTree, "commit 1")
|
makeCommit(fakeLocalWorkTree, "commit 1")
|
||||||
checkErrorDuringPreparation(err)
|
checkErrorDuringPreparation(err)
|
||||||
|
|
||||||
ch := make(chan CommandStatus)
|
repoStatus := sc.Command(repoCfg)
|
||||||
go sc.Command(repoCfg, ch)
|
|
||||||
repoStatus := <-ch
|
|
||||||
expectedMessage := "branch master - ( | origin | \u21911 \u21930 ) - ( | subremote | \u21911 \u21930 )"
|
expectedMessage := "branch master - ( | origin | \u21911 \u21930 ) - ( | subremote | \u21911 \u21930 )"
|
||||||
|
|
||||||
if repoStatus.Error {
|
if repoStatus.Error {
|
||||||
|
@ -49,7 +49,7 @@ func cloneRepository(destPath string, repoCfg *config.RepositoryConfig) (bool, e
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Synchronizer) Command(repoCfg config.RepositoryConfig, status chan CommandStatus) {
|
func (s Synchronizer) Command(repoCfg config.RepositoryConfig) CommandStatus {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
cmdStatus := CommandStatus{
|
cmdStatus := CommandStatus{
|
||||||
@ -75,7 +75,7 @@ func (s Synchronizer) Command(repoCfg config.RepositoryConfig, status chan Comma
|
|||||||
} else {
|
} else {
|
||||||
cmdStatus.Error = true
|
cmdStatus.Error = true
|
||||||
cmdStatus.Message = err.Error()
|
cmdStatus.Message = err.Error()
|
||||||
status <- cmdStatus
|
return cmdStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -83,6 +83,6 @@ func (s Synchronizer) Command(repoCfg config.RepositoryConfig, status chan Comma
|
|||||||
cmdStatus.Message = err.Error()
|
cmdStatus.Message = err.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
status <- cmdStatus
|
return cmdStatus
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,12 +28,7 @@ func TestSyncCommand(t *testing.T) {
|
|||||||
Dest: "awesome-go",
|
Dest: "awesome-go",
|
||||||
}
|
}
|
||||||
|
|
||||||
ch := make(chan CommandStatus)
|
cloneStatus := sync.Command(cfg)
|
||||||
|
|
||||||
// Pull part
|
|
||||||
go sync.Command(cfg, ch)
|
|
||||||
|
|
||||||
cloneStatus := <-ch
|
|
||||||
if cloneStatus.Error {
|
if cloneStatus.Error {
|
||||||
t.Errorf("Unexpected error: %v", cloneStatus.Message)
|
t.Errorf("Unexpected error: %v", cloneStatus.Message)
|
||||||
}
|
}
|
||||||
@ -54,11 +49,7 @@ func TestSyncCommand(t *testing.T) {
|
|||||||
t.Errorf("Expected to get %v, instead of this got %v", syncCloned, cloneStatus.Message)
|
t.Errorf("Expected to get %v, instead of this got %v", syncCloned, cloneStatus.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch part
|
fetchStatus := sync.Command(cfg)
|
||||||
go sync.Command(cfg, ch)
|
|
||||||
|
|
||||||
fetchStatus := <-ch
|
|
||||||
|
|
||||||
if fetchStatus.Error {
|
if fetchStatus.Error {
|
||||||
t.Errorf("Unexpected error: %v", err.Error())
|
t.Errorf("Unexpected error: %v", err.Error())
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,11 @@ func ParseCliArguments(name, description string, arguments []string) (CliArgumen
|
|||||||
Help: "Limit actions to repositories that contain specific tags",
|
Help: "Limit actions to repositories that contain specific tags",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
limitRoutines := parser.Int("", "max-concurrent-process", &argparse.Options{
|
||||||
|
Default: 10,
|
||||||
|
Help: "Determine how many tasks can run simultaneously",
|
||||||
|
})
|
||||||
|
|
||||||
if err := parser.Parse(arguments); err != nil {
|
if err := parser.Parse(arguments); err != nil {
|
||||||
return CliArguments{}, errors.New(parser.Usage("Please follow this help"))
|
return CliArguments{}, errors.New(parser.Usage("Please follow this help"))
|
||||||
}
|
}
|
||||||
@ -66,7 +71,8 @@ func ParseCliArguments(name, description string, arguments []string) (CliArgumen
|
|||||||
Status: statusCMD.Happened(),
|
Status: statusCMD.Happened(),
|
||||||
Version: *version,
|
Version: *version,
|
||||||
Color: !(*color),
|
Color: !(*color),
|
||||||
LimitName: *limitName,
|
LimitToName: *limitName,
|
||||||
LimitTags: *limitTags,
|
LimitToTags: *limitTags,
|
||||||
|
Routines: *limitRoutines,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ type CliArguments struct {
|
|||||||
Status bool
|
Status bool
|
||||||
Version bool
|
Version bool
|
||||||
Color bool
|
Color bool
|
||||||
LimitName string
|
LimitToName string
|
||||||
LimitTags []string
|
LimitToTags []string
|
||||||
|
Routines int
|
||||||
}
|
}
|
||||||
|
22
echo/echo.go
22
echo/echo.go
@ -7,11 +7,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
colorReset = "\033[0m"
|
ColorReset = "\033[0m"
|
||||||
colorRed = "\033[31m"
|
ColorRed = "\033[31m"
|
||||||
colorGreen = "\033[32m"
|
ColorGreen = "\033[32m"
|
||||||
colorYellow = "\033[33m"
|
ColorYellow = "\033[33m"
|
||||||
colorBlue = "\033[34m"
|
ColorBlue = "\033[34m"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -30,7 +30,7 @@ func Output(writer io.Writer) {
|
|||||||
func ErrorfMsg(format string, a ...interface{}) error {
|
func ErrorfMsg(format string, a ...interface{}) error {
|
||||||
msg := fmt.Sprintf(format, a...)
|
msg := fmt.Sprintf(format, a...)
|
||||||
if useColor {
|
if useColor {
|
||||||
msg = fmt.Sprintf("%vError:%v %v", colorRed, colorReset, msg)
|
msg = fmt.Sprintf("%vError:%v %v", ColorRed, ColorReset, msg)
|
||||||
} else {
|
} else {
|
||||||
msg = fmt.Sprintf("Error: %v", msg)
|
msg = fmt.Sprintf("Error: %v", msg)
|
||||||
}
|
}
|
||||||
@ -40,7 +40,7 @@ func ErrorfMsg(format string, a ...interface{}) error {
|
|||||||
func InfoFMsg(format string, a ...interface{}) error {
|
func InfoFMsg(format string, a ...interface{}) error {
|
||||||
msg := fmt.Sprintf(format, a...)
|
msg := fmt.Sprintf(format, a...)
|
||||||
if useColor {
|
if useColor {
|
||||||
msg = fmt.Sprintf("%vInfo:%v %v", colorBlue, colorReset, msg)
|
msg = fmt.Sprintf("%vInfo:%v %v", ColorBlue, ColorReset, msg)
|
||||||
} else {
|
} else {
|
||||||
msg = fmt.Sprintf("Info: %v", msg)
|
msg = fmt.Sprintf("Info: %v", msg)
|
||||||
}
|
}
|
||||||
@ -48,19 +48,19 @@ func InfoFMsg(format string, a ...interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GreenMessageF(format string, a ...interface{}) error {
|
func GreenMessageF(format string, a ...interface{}) error {
|
||||||
return writeWithColor(fmt.Sprintf(format, a...), colorGreen)
|
return writeWithColor(fmt.Sprintf(format, a...), ColorGreen)
|
||||||
}
|
}
|
||||||
|
|
||||||
func YellowMessageF(format string, a ...interface{}) error {
|
func YellowMessageF(format string, a ...interface{}) error {
|
||||||
return writeWithColor(fmt.Sprintf(format, a...), colorYellow)
|
return writeWithColor(fmt.Sprintf(format, a...), ColorYellow)
|
||||||
}
|
}
|
||||||
func RedMessageF(format string, a ...interface{}) error {
|
func RedMessageF(format string, a ...interface{}) error {
|
||||||
return writeWithColor(fmt.Sprintf(format, a...), colorRed)
|
return writeWithColor(fmt.Sprintf(format, a...), ColorRed)
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeWithColor(msg string, color string) error {
|
func writeWithColor(msg string, color string) error {
|
||||||
if useColor {
|
if useColor {
|
||||||
return write(fmt.Sprintf("%v%v%v", color, msg, colorReset))
|
return write(fmt.Sprintf("%v%v%v", color, msg, ColorReset))
|
||||||
}
|
}
|
||||||
return write(msg)
|
return write(msg)
|
||||||
|
|
||||||
|
6
main.go
6
main.go
@ -11,7 +11,11 @@ const ()
|
|||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
app := app.GitRepositoryManager{}
|
app := app.GitRepositoryManager{}
|
||||||
app.Parse(os.Args)
|
err := app.Parse(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
exitCode := app.Run(os.Stdout)
|
exitCode := app.Run(os.Stdout)
|
||||||
os.Exit(exitCode)
|
os.Exit(exitCode)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user