Skip to content

Commit caf1fd0

Browse files
feat(git): add more flags to the git command (#141)
1 parent cc4f07e commit caf1fd0

4 files changed

Lines changed: 137 additions & 23 deletions

File tree

cmd/apps.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,18 @@ func AppCreate(id string, buildpack string, remote string, noRemote bool) error
5151
if !noRemote {
5252
if err = git.CreateRemote(s.Client.ControllerURL.Host, remote, app.ID); err != nil {
5353
if err.Error() == "exit status 128" {
54-
fmt.Println("To replace the existing git remote entry, run:")
55-
fmt.Printf(" git remote rename deis deis.old && deis git:remote -a %s\n", app.ID)
54+
msg := "A git remote with the name %s already exists. To overwrite this remote run:\n"
55+
msg += "deis git:remote --force --remote %s --app %s"
56+
return fmt.Errorf(msg, remote, remote, app.ID)
5657
}
5758
return err
5859
}
60+
61+
fmt.Printf(remoteCreationMsg, remote, app.ID)
5962
}
6063

6164
if noRemote {
6265
fmt.Printf("If you want to add a git remote for this app later, use `deis git:remote -a %s`\n", app.ID)
63-
} else {
64-
fmt.Println("remote available at", git.RemoteURL(s.Client.ControllerURL.Host, app.ID))
6566
}
6667

6768
return nil
@@ -264,7 +265,7 @@ func AppDestroy(appID, confirm string) error {
264265
fmt.Printf("done in %ds\n", int(time.Since(startTime).Seconds()))
265266

266267
if gitSession {
267-
return git.DeleteRemote(appID)
268+
return GitRemove(appID)
268269
}
269270

270271
return nil

cmd/git.go

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,67 @@
11
package cmd
22

33
import (
4+
"fmt"
5+
46
"github.com/deis/workflow-cli/pkg/git"
57
)
68

9+
const remoteCreationMsg = "Git remote %s successfully created for app %s.\n"
10+
const remoteDeletionMsg = "Git remotes for app %s removed.\n"
11+
712
// GitRemote creates a git remote for a deis app.
8-
func GitRemote(appID, remote string) error {
13+
func GitRemote(appID string, remote string, force bool) error {
914
s, appID, err := load(appID)
1015

16+
remoteURL, err := git.RemoteValue(remote)
17+
18+
if err != nil {
19+
//If git remote doesn't exist, create it without issue
20+
if err == git.ErrRemoteNotFound {
21+
git.CreateRemote(s.Client.ControllerURL.Host, remote, appID)
22+
fmt.Printf(remoteCreationMsg, remote, appID)
23+
return nil
24+
}
25+
26+
return err
27+
}
28+
29+
expectedURL := git.RemoteURL(s.Client.ControllerURL.Host, appID)
30+
31+
if remoteURL == expectedURL {
32+
fmt.Printf("Remote %s already exists and is correctly configured for app %s.\n", remote, appID)
33+
return nil
34+
}
35+
36+
if force {
37+
fmt.Printf("Deleting git remote %s.\n", remote)
38+
git.DeleteRemote(remote)
39+
git.CreateRemote(s.Client.ControllerURL.Host, remote, appID)
40+
fmt.Printf(remoteCreationMsg, remote, appID)
41+
return nil
42+
}
43+
44+
msg := "Remote %s already exists, please run 'deis git:remote -f' to overwrite\n"
45+
msg += "Existing remote URL: %s\n"
46+
msg += "When forced, will overwrite with: %s"
47+
48+
return fmt.Errorf(msg, remote, remoteURL, expectedURL)
49+
}
50+
51+
// GitRemove removes a application git remote from a repository
52+
func GitRemove(appID string) error {
53+
s, appID, err := load(appID)
54+
55+
if err != nil {
56+
return err
57+
}
58+
59+
err = git.DeleteAppRemotes(s.Client.ControllerURL.Host, appID)
60+
1161
if err != nil {
1262
return err
1363
}
1464

15-
return git.CreateRemote(s.Client.ControllerURL.Host, remote, appID)
65+
fmt.Printf(remoteDeletionMsg, appID)
66+
return nil
1667
}

parser/git.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,16 @@ func Git(argv []string) error {
1313
Valid commands for git:
1414
1515
git:remote Adds git remote of application to repository
16+
git:remove Removes git remote of application from repository
1617
1718
Use 'deis help [command]' to learn more.
1819
`
1920

2021
switch argv[0] {
2122
case "git:remote":
2223
return gitRemote(argv)
24+
case "git:remove":
25+
return gitRemove(argv)
2326
case "git":
2427
fmt.Print(usage)
2528
return nil
@@ -40,6 +43,8 @@ Options:
4043
the uniquely identifiable name for the application.
4144
-r --remote=REMOTE
4245
name of remote to create. [default: deis]
46+
-f --force
47+
overwrite remote of the given name if it already exists.
4348
`
4449

4550
args, err := docopt.Parse(usage, argv, true, "", false, true)
@@ -48,5 +53,25 @@ Options:
4853
return err
4954
}
5055

51-
return cmd.GitRemote(safeGetValue(args, "--app"), args["--remote"].(string))
56+
return cmd.GitRemote(safeGetValue(args, "--app"), args["--remote"].(string), args["--force"].(bool))
57+
}
58+
59+
func gitRemove(argv []string) error {
60+
usage := `
61+
Removes git remotes of application from repository.
62+
63+
Usage: deis git:remove [options]
64+
65+
Options:
66+
-a --app=<app>
67+
the uniquely identifiable name for the application.
68+
`
69+
70+
args, err := docopt.Parse(usage, argv, true, "", false, true)
71+
72+
if err != nil {
73+
return err
74+
}
75+
76+
return cmd.GitRemove(safeGetValue(args, "--app"))
5277
}

pkg/git/git.go

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,12 @@ import (
88
"os/exec"
99
"path/filepath"
1010
"strings"
11+
"syscall"
1112
)
1213

14+
// ErrRemoteNotFound is returned when the remote cannot be found in git
15+
var ErrRemoteNotFound = errors.New("Could not find remote matching app in 'git remote -v'")
16+
1317
// CreateRemote adds a git remote in the current directory.
1418
func CreateRemote(host, remote, appID string) error {
1519
cmd := exec.Command("git", "remote", "add", remote, RemoteURL(host, appID))
@@ -30,44 +34,62 @@ func CreateRemote(host, remote, appID string) error {
3034
return err
3135
}
3236

33-
fmt.Printf("Git remote %s added\n", remote)
34-
3537
return nil
3638
}
3739

38-
// DeleteRemote removes a git remote in the current directory.
39-
func DeleteRemote(appID string) error {
40-
name, err := remoteNameFromAppID(appID)
40+
// DeleteAppRemotes removes all git remotes corresponding to an app in the repository.
41+
func DeleteAppRemotes(host, appID string) error {
42+
names, err := remoteNamesFromAppID(host, appID)
4143

4244
if err != nil {
4345
return err
4446
}
4547

46-
if _, err = exec.Command("git", "remote", "remove", name).Output(); err != nil {
47-
return err
48+
for _, name := range names {
49+
if err := DeleteRemote(name); err != nil {
50+
return err
51+
}
4852
}
4953

50-
fmt.Printf("Git remote %s removed\n", name)
51-
5254
return nil
5355
}
5456

55-
func remoteNameFromAppID(appID string) (string, error) {
57+
// DeleteRemote removes a remote from the repository
58+
func DeleteRemote(name string) error {
59+
_, err := exec.Command("git", "remote", "remove", name).Output()
60+
return err
61+
}
62+
63+
// remoteNamesFromAppID returns the git remote names for an app
64+
func remoteNamesFromAppID(host, appID string) ([]string, error) {
5665
out, err := exec.Command("git", "remote", "-v").Output()
5766

5867
if err != nil {
59-
return "", err
68+
return []string{}, err
6069
}
6170

6271
cmd := string(out)
72+
remotes := []string{}
6373

74+
lines:
6475
for _, line := range strings.Split(cmd, "\n") {
65-
if strings.Contains(line, appID) {
66-
return strings.Split(line, "\t")[0], nil
76+
if strings.Contains(line, RemoteURL(host, appID)) {
77+
name := strings.Split(line, "\t")[0]
78+
// git remote -v can show duplicate remotes, so don't add a remote if it already has been added
79+
for _, remote := range remotes {
80+
if remote == name {
81+
continue lines
82+
}
83+
}
84+
remotes = append(remotes, name)
6785
}
6886
}
6987

70-
return "", errors.New("Could not find remote matching app in 'git remote -v'")
88+
if len(remotes) == 0 {
89+
return remotes, ErrRemoteNotFound
90+
}
91+
92+
return remotes, nil
7193
}
7294

7395
// DetectAppName detects if there is deis remote in git.
@@ -105,7 +127,7 @@ func findRemote(host string) (string, error) {
105127
}
106128
}
107129

108-
return "", errors.New("Could not find deis remote in 'git remote -v'")
130+
return "", ErrRemoteNotFound
109131
}
110132

111133
// RemoteURL returns the git URL of app.
@@ -121,3 +143,18 @@ func getBuilderHostname(host string) string {
121143
hostTokens[0] = fmt.Sprintf("%s-builder", hostTokens[0])
122144
return strings.Join(hostTokens, ".")
123145
}
146+
147+
// RemoteValue gets the url that a git remote is set to.
148+
func RemoteValue(name string) (string, error) {
149+
out, err := exec.Command("git", "remote", "get-url", name).Output()
150+
151+
if err != nil {
152+
// get the return code of the program and see if it equals not found
153+
if err.(*exec.ExitError).Sys().(syscall.WaitStatus).ExitStatus() == 128 {
154+
return "", ErrRemoteNotFound
155+
}
156+
return "", err
157+
}
158+
159+
return strings.Trim(string(out), "\n"), nil
160+
}

0 commit comments

Comments
 (0)