-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ Add gut sync command | Structure code changes
For better readibility, `getProfileIDFromPath`has been moved to profile package To avoid export, I've lower cased variables from save.go (controller)
- Loading branch information
Showing
12 changed files
with
333 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ main | |
go.work | ||
|
||
test/ | ||
.vscode | ||
|
||
# MacOS | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package controller | ||
|
||
import ( | ||
"errors" | ||
|
||
"github.com/AlecAivazis/survey/v2" | ||
"github.com/julien040/gut/src/executor" | ||
) | ||
|
||
func validatorURL(val interface{}) error { | ||
url, ok := val.(string) | ||
if !ok { | ||
return errors.New("url is not a string") | ||
} | ||
if url == "" { | ||
return errors.New("url is empty") | ||
} | ||
isValid := checkURL(url) | ||
if !isValid { | ||
return errors.New("url is not valid") | ||
} | ||
return nil | ||
|
||
} | ||
|
||
func addRemote(path string, origin bool) (executor.Remote, error) { | ||
var qs []*survey.Question | ||
var answers struct { | ||
Name string | ||
Url string | ||
} | ||
|
||
if !origin { | ||
qs = append(qs, &survey.Question{ | ||
Name: "name", | ||
Prompt: &survey.Input{ | ||
Message: "Name of the remote:", | ||
}, | ||
Validate: survey.Required, | ||
}) | ||
} | ||
qs = append(qs, &survey.Question{ | ||
Name: "url", | ||
Prompt: &survey.Input{ | ||
Message: "URL of the remote:", | ||
}, | ||
Validate: validatorURL, | ||
}) | ||
err := survey.Ask(qs, &answers) | ||
if err != nil { | ||
exitOnError("We can't get your answers 😢", err) | ||
} | ||
if origin { | ||
answers.Name = "origin" | ||
} | ||
err = executor.AddRemote(path, answers.Name, answers.Url) | ||
if err != nil { | ||
exitOnError("We can't add the remote 😢", err) | ||
} | ||
return executor.Remote{ | ||
Name: answers.Name, | ||
Url: answers.Url, | ||
}, nil | ||
|
||
} | ||
|
||
func chooseRemote(path string) (executor.Remote, error) { | ||
remote, err := executor.ListRemote(path) | ||
if err != nil { | ||
exitOnError("We can't get the remote of the repository 😢", err) | ||
} | ||
remoteName := make([]string, len(remote)) | ||
for i, r := range remote { | ||
remoteName[i] = r.Name + " <" + r.Url + ">" | ||
} | ||
var remoteChoice int | ||
prompt := &survey.Select{ | ||
Message: "Choose a remote:", | ||
Options: remoteName, | ||
Help: "Choose a remote to use", | ||
} | ||
err = survey.AskOne(prompt, &remoteChoice) | ||
if err != nil { | ||
exitOnError("We can't get your choice 😢", err) | ||
} | ||
return remote[remoteChoice], nil | ||
|
||
} | ||
|
||
func getRemote(path string) (executor.Remote, error) { | ||
remote, err := executor.ListRemote(path) | ||
if err != nil { | ||
exitOnError("We can't get the remote of the repository 😢", err) | ||
} | ||
lenRemote := len(remote) | ||
// Case no remote : We ask the user to add one | ||
if lenRemote == 0 { | ||
return addRemote(path, true) | ||
} else if lenRemote == 1 { // Case one remote : We return it | ||
return remote[0], nil | ||
} else { // Case multiple remote : We ask the user to choose one | ||
return chooseRemote(path) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package controller | ||
|
||
import ( | ||
"os" | ||
|
||
"github.com/julien040/gut/src/executor" | ||
"github.com/julien040/gut/src/print" | ||
"github.com/julien040/gut/src/profile" | ||
|
||
"github.com/go-git/go-git/v5" | ||
"github.com/go-git/go-git/v5/plumbing/transport" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
func Sync(cmd *cobra.Command, args []string) { | ||
wd, err := os.Getwd() | ||
if err != nil { | ||
exitOnError("We can't get the current working directory 😢", err) | ||
} | ||
remote, err := getRemote(wd) | ||
if err != nil { | ||
exitOnError("We can't get the remote of the repository 😢", err) | ||
} | ||
syncRepo(wd, remote, false) | ||
} | ||
|
||
func syncRepo(path string, remote executor.Remote, requestProfile bool) error { | ||
/* | ||
This must get refactored for better readability | ||
*/ | ||
var profileLocal profile.Profile | ||
|
||
// If it's not the first time syncRepo is called, we ask the user to select a profile | ||
if requestProfile { | ||
profileLocal = selectProfile("", true) | ||
} else { // Else, we get the profile from the path | ||
profilePath, err := profile.GetProfileFromPath(path) | ||
if err != nil { // If there is no profile associated with the path, we ask the user to select one | ||
profileLocal = selectProfile("", true) | ||
} else { // Else, we use the profile associated with the path | ||
profileLocal = profilePath | ||
} | ||
} | ||
// Once we have the profile, we pull the repository | ||
err := executor.Pull(path, remote.Name, profileLocal.Username, profileLocal.Password) | ||
// If the credentials are wrong, we ask the user to select another profile | ||
if err == transport.ErrAuthorizationFailed || err == transport.ErrAuthenticationRequired { | ||
print.Message("Uh oh, your credentials are wrong 😢. Please select another profile.", print.Error) | ||
return syncRepo(path, remote, true) | ||
} else if err == git.ErrNonFastForwardUpdate { | ||
/* | ||
Transform this into a function prompting the user to create a pull request | ||
*/ | ||
print.Message("Uh oh, there is a conflict 😢. Currently, Gut doesn't support conflict resolution. Please resolve the conflict manually.", print.Error) | ||
print.Message("You can use the git cli to resolve the conflict. \n git pull "+remote.Name+" \n git push "+remote.Name, print.None) | ||
print.Message("\n\nAlternatively, you can switch to another branch and then sync the repository. To switch to another branch, use the command: \n gut switch <branch_name>", print.None) | ||
print.Message("Switching to another branch will let you open a new pull request if your provider supports it.", print.None) | ||
os.Exit(1) | ||
|
||
} else if err == git.NoErrAlreadyUpToDate || err == nil { // If there is nothing to pull or if there is no error, we push the repository | ||
err := executor.Push(path, remote.Name, profileLocal.Username, profileLocal.Password) | ||
if err == git.NoErrAlreadyUpToDate || err == nil { // If there is nothing to push, we exit | ||
print.Message("The repository has been synced with "+remote.Name+" 🎉", print.Success) | ||
return nil | ||
} else { | ||
// If there is another unknown error, we exit | ||
exitOnError("We can't push the repository 😢", err) | ||
} | ||
} else { // If there is another unknown error, we exit | ||
exitOnError("We can't pull the repository 😢", err) | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package executor | ||
|
||
import ( | ||
"github.com/go-git/go-git/v5/plumbing/transport/http" | ||
|
||
"github.com/go-git/go-git/v5" | ||
) | ||
|
||
func Pull(path string, remote string, username string, password string) error { | ||
repo, err := OpenRepo(path) | ||
if err != nil { | ||
return err | ||
} | ||
worktree, err := repo.Worktree() | ||
if err != nil { | ||
return err | ||
} | ||
err = worktree.Pull(&git.PullOptions{ | ||
RemoteName: remote, | ||
Auth: &http.BasicAuth{ | ||
Username: username, | ||
Password: password, | ||
}, | ||
}) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package executor | ||
|
||
import ( | ||
"github.com/go-git/go-git/v5/plumbing/transport/http" | ||
|
||
"github.com/go-git/go-git/v5" | ||
) | ||
|
||
func Push(path string, remote string, username string, password string) error { | ||
repo, err := OpenRepo(path) | ||
if err != nil { | ||
return err | ||
} | ||
err = repo.Push(&git.PushOptions{ | ||
RemoteName: remote, | ||
Auth: &http.BasicAuth{ | ||
Username: username, | ||
Password: password, | ||
}, | ||
}) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} |
Oops, something went wrong.