diff --git a/cmd/single/main.go b/cmd/single/main.go index f56ecbb4a..97da52d51 100644 --- a/cmd/single/main.go +++ b/cmd/single/main.go @@ -67,6 +67,7 @@ func buildCommands() *cobra.Command { treeGen := tree.NewGenerator(dirManager, fileManager) repoAdder := repo.NewAdder(ritchieHomeDir, http.DefaultClient, treeGen, dirManager, fileManager) repoLister := repo.NewLister(ritchieHomeDir, fileManager) + repoPrioritySetter := repo.NewPrioritySetter(ritchieHomeDir, fileManager, dirManager) sessionManager := session.NewManager(ritchieHomeDir) workspaceManager := workspace.NewChecker(ritchieHomeDir) @@ -137,6 +138,7 @@ func buildCommands() *cobra.Command { setCtxCmd := cmd.NewSetContextCmd(ctxFindSetter, inputText, inputList) showCtxCmd := cmd.NewShowContextCmd(ctxFinder) addRepoCmd := cmd.NewAddRepoCmd(http.DefaultClient, repoAdder, inputText, inputPassword, inputURL, inputList, inputBool, inputInt) + setPriorityCmd := cmd.NewSetPriorityCmd(inputList, inputInt, repoLister, repoPrioritySetter) autocompleteZsh := cmd.NewAutocompleteZsh(autocompleteGen) autocompleteBash := cmd.NewAutocompleteBash(autocompleteGen) autocompleteFish := cmd.NewAutocompleteFish(autocompleteGen) @@ -149,7 +151,7 @@ func buildCommands() *cobra.Command { addCmd.AddCommand(addRepoCmd) createCmd.AddCommand(createFormulaCmd) deleteCmd.AddCommand(deleteCtxCmd) - setCmd.AddCommand(setCredentialCmd, setCtxCmd) + setCmd.AddCommand(setCredentialCmd, setCtxCmd, setPriorityCmd) showCmd.AddCommand(showCtxCmd) buildCmd.AddCommand(buildFormulaCmd) diff --git a/cmd/team/main.go b/cmd/team/main.go index ac795b950..fcbb3d73b 100644 --- a/cmd/team/main.go +++ b/cmd/team/main.go @@ -78,6 +78,7 @@ func buildCommands() *cobra.Command { treeGen := tree.NewGenerator(dirManager, fileManager) repoAdder := repo.NewAdder(ritchieHomeDir, http.DefaultClient, treeGen, dirManager, fileManager) repoLister := repo.NewLister(ritchieHomeDir, fileManager) + repoPrioritySetter := repo.NewPrioritySetter(ritchieHomeDir, fileManager, dirManager) sessionManager := session.NewManager(ritchieHomeDir) workspaceManager := workspace.NewChecker(ritchieHomeDir) @@ -155,6 +156,7 @@ func buildCommands() *cobra.Command { loginCmd := cmd.NewLoginCmd(inputText, inputPassword, loginManager, serverFinder, otpResolver) logoutCmd := cmd.NewLogoutCmd(logoutManager) setCmd := cmd.NewSetCmd() + setPriorityCmd := cmd.NewSetPriorityCmd(inputList, inputInt, repoLister, repoPrioritySetter) showCmd := cmd.NewShowCmd() updateCmd := cmd.NewUpdateCmd() buildCmd := cmd.NewBuildCmd() @@ -185,7 +187,7 @@ func buildCommands() *cobra.Command { addCmd.AddCommand(addRepoCmd) createCmd.AddCommand(createFormulaCmd) deleteCmd.AddCommand(deleteCtxCmd) - setCmd.AddCommand(setCredentialCmd, setCtxCmd) + setCmd.AddCommand(setCredentialCmd, setCtxCmd, setPriorityCmd) showCmd.AddCommand(showCtxCmd) buildCmd.AddCommand(buildFormulaCmd) diff --git a/pkg/cmd/mocks_test.go b/pkg/cmd/mocks_test.go index ff2e46bdd..321cb4660 100644 --- a/pkg/cmd/mocks_test.go +++ b/pkg/cmd/mocks_test.go @@ -1,6 +1,8 @@ package cmd import ( + "errors" + "github.com/ZupIT/ritchie-cli/pkg/api" "github.com/ZupIT/ritchie-cli/pkg/autocomplete" "github.com/ZupIT/ritchie-cli/pkg/credential" @@ -18,6 +20,10 @@ func (inputTextMock) Text(name string, required bool, helper ...string) (string, return "mocked text", nil } +func (inputTextMock) TextWithValidate(name string, validate func(interface{}) error, helper ...string) (string, error) { + return "mocked text", nil +} + type inputTextValidatorMock struct{} func (inputTextValidatorMock) Text(name string, validate func(interface{}) error, helper ...string) (string, error) { @@ -30,6 +36,10 @@ func (inputSecretMock) Text(name string, required bool, helper ...string) (strin return "username=ritchie", nil } +func (inputSecretMock) TextWithValidate(name string, validate func(interface{}) error, helper ...string) (string, error) { + return "mocked text", nil +} + type inputURLMock struct{} func (inputURLMock) URL(name, defaultValue string) (string, error) { @@ -42,6 +52,12 @@ func (inputIntMock) Int(name string) (int64, error) { return 0, nil } +type inputIntErrorMock struct{} + +func (inputIntErrorMock) Int(name string) (int64, error) { + return 0, errors.New("some error") +} + type inputPasswordMock struct{} func (inputPasswordMock) Password(label string) (string, error) { @@ -72,12 +88,27 @@ func (inputListMock) List(name string, items []string) (string, error) { return "item-mocked", nil } +type inputListCustomMock struct{ + name string +} + +func (m inputListCustomMock) List(name string, items []string) (string, error) { + return m.name, nil +} + + type inputListCredMock struct{} func (inputListCredMock) List(name string, items []string) (string, error) { return "me", nil } +type inputListErrorMock struct{} + +func (inputListErrorMock) List(name string, items []string) (string, error) { + return "item-mocked", errors.New("some error") +} + type repoAdder struct{} func (a repoAdder) List() ([]formula.Repository, error) { @@ -159,8 +190,39 @@ func (repoDeleterMock) Delete(name string) error { type repoListerMock struct{} -func (repoListerMock) List() ([]formula.Repository, error) { - return []formula.Repository{}, nil +func (repoListerMock) List() ([]formula.Repo, error) { + return []formula.Repo{}, nil +} + +type repoListerNonEmptyMock struct{} + +func (repoListerNonEmptyMock) List() ([]formula.Repo, error) { + return []formula.Repo{ + { + Name: "repoName", + Priority: 0, + }, + }, nil +} + +type repoListerErrorMock struct{} + +func (repoListerErrorMock) List() ([]formula.Repo, error) { + return []formula.Repo{}, errors.New("some error") +} + +type repoPrioritySetterMock struct {} + +func (repoPrioritySetterMock) SetPriority(repo formula.Repo, priority int) error { + return nil +} + +type repoPrioritySetterCustomMock struct { + setPriority func(repo formula.Repo, priority int) error +} + +func (m repoPrioritySetterCustomMock) SetPriority(repo formula.Repo, priority int) error { + return m.setPriority(repo, priority) } type repoLoaderMock struct{} @@ -332,8 +394,7 @@ type InputMultilineMock struct{} func (InputMultilineMock) MultiLineText(name string, required bool) (string, error) { return "username=ritchie", nil } - -type otpResolverMock struct{} +type otpResolverMock struct {} func (m otpResolverMock) RequestOtp(url, organization string) (otp.Response, error) { return otp.Response{Otp: true}, nil @@ -345,4 +406,4 @@ type otpResolverCustomMock struct { func (m otpResolverCustomMock) RequestOtp(url, organization string) (otp.Response, error) { return m.requestOtp(url, organization) -} +} \ No newline at end of file diff --git a/pkg/cmd/set_priority.go b/pkg/cmd/set_priority.go new file mode 100644 index 000000000..6dfd891b8 --- /dev/null +++ b/pkg/cmd/set_priority.go @@ -0,0 +1,78 @@ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/ZupIT/ritchie-cli/pkg/formula" + "github.com/ZupIT/ritchie-cli/pkg/prompt" +) + +const ( + newRepositoryPriority = "Now %q repository has priority %v" +) + +type SetPriorityCmd struct { + prompt.InputList + prompt.InputInt + formula.RepositoryLister + formula.RepositoryPrioritySetter +} + +func NewSetPriorityCmd(il prompt.InputList, ii prompt.InputInt, rl formula.RepositoryLister, rs formula.RepositoryPrioritySetter) *cobra.Command { + s := SetPriorityCmd{il, ii, rl, rs} + cmd := &cobra.Command{ + Use: "repo-priority", + Short: "Set a repository priority", + Example: "rit set repo-priority", + RunE: s.runFunc(), + } + return cmd +} + +func (s SetPriorityCmd) runFunc() CommandRunnerFunc { + return func(cmd *cobra.Command, args []string) error { + repositories, err := s.RepositoryLister.List() + if err != nil { + return err + } + + if len(repositories) == 0 { + prompt.Warning("You should add a repository first") + return nil + } + + var reposNames []string + for _, r := range repositories { + reposNames = append(reposNames, r.Name) + } + + repoName, err := s.InputList.List("Repository:", reposNames) + if err != nil { + return err + } + + priority, err := s.InputInt.Int("New priority:") + if err != nil { + return err + } + + var repo formula.Repo + for _, r := range repositories { + if r.Name == repoName { + repo = r + break + } + } + + err = s.SetPriority(repo.Name, int(priority)) + if err != nil { + return err + } + + successMsg := fmt.Sprintf(newRepositoryPriority, repoName, priority) + prompt.Success(successMsg) + return nil + } +} diff --git a/pkg/cmd/set_priority_test.go b/pkg/cmd/set_priority_test.go new file mode 100644 index 000000000..84a65ea51 --- /dev/null +++ b/pkg/cmd/set_priority_test.go @@ -0,0 +1,96 @@ +package cmd + +import ( + "errors" + "testing" + + "github.com/ZupIT/ritchie-cli/pkg/formula" + "github.com/ZupIT/ritchie-cli/pkg/prompt" +) + +func TestSetRepoCmd_runFunc(t *testing.T) { + type fields struct { + InputList prompt.InputList + InputInt prompt.InputInt + RepoLister formula.RepositoryLister + RepoPrioritySetter formula.RepositoryPrioritySetter + } + tests := []struct { + name string + fields fields + wantErr bool + }{ + { + name: "run with success", + fields: fields{ + InputList: inputListMock{}, + InputInt: inputIntMock{}, + RepoLister: repoListerNonEmptyMock{}, + RepoPrioritySetter: repoPrioritySetterMock{}, + }, + wantErr: false, + }, + { + name: "error on repoLister", + fields: fields{ + InputList: inputListMock{}, + InputInt: inputIntMock{}, + RepoLister: repoListerErrorMock{}, + RepoPrioritySetter: repoPrioritySetterMock{}, + }, + wantErr: true, + }, + { + name: "error on inputList", + fields: fields{ + InputList: inputListErrorMock{}, + InputInt: inputIntMock{}, + RepoLister: repoListerMock{}, + RepoPrioritySetter: repoPrioritySetterMock{}, + }, + wantErr: true, + }, + { + name: "error on inputInt", + fields: fields{ + InputList: inputListMock{}, + InputInt: inputIntErrorMock{}, + RepoLister: repoListerMock{}, + RepoPrioritySetter: repoPrioritySetterMock{}, + }, + wantErr: true, + }, + { + name: "success pass on if r.Name == repoName", + fields: fields{ + InputList: inputListCustomMock{name: "repoName"}, + InputInt: inputIntMock{}, + RepoLister: repoListerNonEmptyMock{}, + RepoPrioritySetter: repoPrioritySetterMock{}, + }, + wantErr: false, + }, + { + name: "error on setPriority", + fields: fields{ + InputList: inputListMock{}, + InputInt: inputIntMock{}, + RepoLister: repoListerMock{}, + RepoPrioritySetter: repoPrioritySetterCustomMock{ + setPriority: func(repo formula.Repo, priority int) error { + return errors.New("some error") + }, + }, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewSetPriorityCmd(tt.fields.InputList, tt.fields.InputInt, tt.fields.RepoLister, tt.fields.RepoPrioritySetter) + if err := s.Execute(); (err != nil) != tt.wantErr { + t.Errorf("runFunc() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/pkg/formula/repo.go b/pkg/formula/repo.go index e27e78601..600501209 100644 --- a/pkg/formula/repo.go +++ b/pkg/formula/repo.go @@ -45,6 +45,10 @@ type RepositoryDeleter interface { Delete(name string) error } +type RepositoryPrioritySetter interface { + SetPriority(repoName string, priority int) error +} + type RepositoryAddLister interface { RepositoryAdder RepositoryLister diff --git a/pkg/formula/repo/adder.go b/pkg/formula/repo/adder.go index 2dc9545b9..47f153992 100644 --- a/pkg/formula/repo/adder.go +++ b/pkg/formula/repo/adder.go @@ -145,7 +145,7 @@ func (ad AddManager) downloadRepo(repo formula.Repo) error { } func (ad AddManager) saveRepo(repoPath string, repos formula.Repos) error { - bytes, err := json.Marshal(repos) + bytes, err := json.MarshalIndent(repos, "", "\t") if err != nil { return err } diff --git a/pkg/formula/repo/priority_setter.go b/pkg/formula/repo/priority_setter.go new file mode 100644 index 000000000..563e6a720 --- /dev/null +++ b/pkg/formula/repo/priority_setter.go @@ -0,0 +1,71 @@ +package repo + +import ( + "encoding/json" + "errors" + "path" + "sort" + + "github.com/ZupIT/ritchie-cli/pkg/formula" + "github.com/ZupIT/ritchie-cli/pkg/stream" +) + +const ( + repositoryDoNotExistError = "there is no repositories yet" +) + +type SetPriorityManager struct { + ritHome string + file stream.FileWriteReadExister + dir stream.DirCreater +} + +func NewPrioritySetter(ritHome string, file stream.FileWriteReadExister, dir stream.DirCreater) SetPriorityManager { + return SetPriorityManager{ + ritHome: ritHome, + file: file, + dir: dir, + } +} + +func (sm SetPriorityManager) SetPriority(repoName string, priority int) error { + var repos formula.Repos + repoPath := path.Join(sm.ritHome, reposDirName, reposFileName) + if !sm.file.Exists(repoPath) { + return errors.New(repositoryDoNotExistError) + } + read, err := sm.file.Read(repoPath) + if err != nil { + return err + } + + if err := json.Unmarshal(read, &repos); err != nil { + return err + } + + for i, _ := range repos { + if repoName == repos[i].Name { + repos[i].Priority = priority + } else if repos[i].Priority >= priority { + repos[i].Priority++ + } + } + + sort.Sort(repos) + + bytes, err := json.MarshalIndent(repos, "", "\t") + if err != nil { + return err + } + + dirPath := path.Dir(repoPath) + if err := sm.dir.Create(dirPath); err != nil { + return err + } + + if err := sm.file.Write(repoPath, bytes); err != nil { + return err + } + + return nil +} \ No newline at end of file