-
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.
Merge pull request #78 from garethjevans/rebase
feat: added a command to rebase based on the default branch
- Loading branch information
Showing
11 changed files
with
525 additions
and
0 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
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,22 @@ | ||
## dx rebase | ||
|
||
Rebase the local clone | ||
|
||
### Synopsis | ||
|
||
Performs a 'git fetch upstream master && git rebase upstream/master && git push origin master'. Uses the default_branch name determined from the GitHub API. | ||
|
||
``` | ||
dx rebase [flags] | ||
``` | ||
|
||
### Options inherited from parent commands | ||
|
||
``` | ||
--help Show help for command | ||
``` | ||
|
||
### SEE ALSO | ||
|
||
* [dx](dx.md) - Plumming dx | ||
|
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,49 @@ | ||
package rebasecmd | ||
|
||
import ( | ||
"github.com/jenkins-x/jx-logging/pkg/log" | ||
"github.com/pkg/errors" | ||
"github.com/plumming/dx/pkg/domain" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
type RebaseCmd struct { | ||
Cmd *cobra.Command | ||
Args []string | ||
} | ||
|
||
func NewRebaseCmd() *cobra.Command { | ||
c := &RebaseCmd{} | ||
cmd := &cobra.Command{ | ||
Use: "rebase", | ||
Short: "Rebase the local clone", | ||
Long: "Performs a 'git fetch upstream master && git rebase upstream/master && git push origin master'. " + | ||
"Uses the default_branch name determined from the GitHub API.", | ||
Example: "", | ||
Aliases: []string{"rb"}, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
c.Cmd = cmd | ||
c.Args = args | ||
err := c.Run() | ||
if err != nil { | ||
log.Logger().Fatalf("unable to run command: %s", err) | ||
} | ||
}, | ||
Args: cobra.NoArgs, | ||
} | ||
return cmd | ||
} | ||
|
||
func (c *RebaseCmd) Run() error { | ||
d := domain.NewRebase() | ||
|
||
err := d.Validate() | ||
if err != nil { | ||
return errors.Wrap(err, "validate failed") | ||
} | ||
err = d.Run() | ||
if err != nil { | ||
return errors.Wrap(err, "validate failed") | ||
} | ||
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,21 @@ | ||
package domain | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/plumming/dx/pkg/api" | ||
) | ||
|
||
func GetDefaultBranch(client *api.Client, org string, repo string) (string, error) { | ||
repository := repository{} | ||
err := client.REST("GET", fmt.Sprintf("repos/%s/%s", org, repo), nil, &repository) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
return repository.DefaultBranch, nil | ||
} | ||
|
||
type repository struct { | ||
DefaultBranch string `json:"default_branch"` | ||
} |
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,47 @@ | ||
package domain_test | ||
|
||
import ( | ||
"bytes" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/plumming/dx/pkg/api" | ||
"github.com/plumming/dx/pkg/domain" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestGetDefaultBranch_Main(t *testing.T) { | ||
http := &api.FakeHTTP{} | ||
client := api.NewClient(api.ReplaceTripper(http)) | ||
|
||
http.StubResponse(200, bytes.NewBufferString("{ \"default_branch\":\"main\" }")) | ||
|
||
defaultBranch, err := domain.GetDefaultBranch(client, "orgname", "reponame") | ||
assert.NoError(t, err) | ||
|
||
assert.Equal(t, defaultBranch, "main") | ||
} | ||
|
||
func TestGetDefaultBranch_Master(t *testing.T) { | ||
http := &api.FakeHTTP{} | ||
client := api.NewClient(api.ReplaceTripper(http)) | ||
|
||
http.StubResponse(200, bytes.NewBufferString("{ \"default_branch\":\"master\"}")) | ||
|
||
defaultBranch, err := domain.GetDefaultBranch(client, "orgname", "reponame") | ||
assert.NoError(t, err) | ||
|
||
assert.Equal(t, defaultBranch, "master") | ||
} | ||
|
||
func TestGetOrgAndRepo(t *testing.T) { | ||
output := `origin https://github.com/clone/chilly (fetch) | ||
origin https://github.com/clone/chilly (push) | ||
upstream https://github.com/plumming/dx (fetch) | ||
upstream https://github.com/plumming/dx (push)` | ||
|
||
org, repo, err := domain.ExtractOrgAndRepoFromGitRemotes(strings.NewReader(output)) | ||
assert.NoError(t, err) | ||
assert.Equal(t, org, "clone") | ||
assert.Equal(t, repo, "chilly") | ||
} |
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,174 @@ | ||
package domain | ||
|
||
import ( | ||
"errors" | ||
"io" | ||
url2 "net/url" | ||
"strings" | ||
|
||
"github.com/plumming/dx/pkg/util" | ||
) | ||
|
||
func GetOrgAndRepoFromCurrentDir() (string, string, error) { | ||
c := util.Command{ | ||
Name: "git", | ||
Args: []string{"remote", "-v"}, | ||
} | ||
output, err := c.RunWithoutRetry() | ||
if err != nil { | ||
return "", "", err | ||
} | ||
|
||
return ExtractOrgAndRepoFromGitRemotes(strings.NewReader(output)) | ||
} | ||
|
||
func CurrentBranchName(dir string) (string, error) { | ||
c := util.Command{ | ||
Name: "git", | ||
Args: []string{"branch", "--show-current"}, | ||
Dir: dir, | ||
} | ||
output, err := c.RunWithoutRetry() | ||
if err != nil { | ||
return "", err | ||
} | ||
return output, nil | ||
} | ||
|
||
func SwitchBranch(dir string, name string) (string, error) { | ||
c := util.Command{ | ||
Name: "git", | ||
Args: []string{"checkout", name}, | ||
Dir: dir, | ||
} | ||
output, err := c.RunWithoutRetry() | ||
if err != nil { | ||
return "", err | ||
} | ||
return output, nil | ||
} | ||
|
||
func Stash(dir string) (string, error) { | ||
c := util.Command{ | ||
Name: "git", | ||
Args: []string{"stash"}, | ||
Dir: dir, | ||
} | ||
output, err := c.RunWithoutRetry() | ||
if err != nil { | ||
return "", err | ||
} | ||
return output, nil | ||
} | ||
|
||
func StashPop(dir string) (string, error) { | ||
c := util.Command{ | ||
Name: "git", | ||
Args: []string{"stash", "pop"}, | ||
Dir: dir, | ||
} | ||
output, err := c.RunWithoutRetry() | ||
if err != nil { | ||
return "", err | ||
} | ||
return output, nil | ||
} | ||
|
||
func Add(dir string, name string) (string, error) { | ||
c := util.Command{ | ||
Name: "git", | ||
Args: []string{"add", name}, | ||
Dir: dir, | ||
} | ||
output, err := c.RunWithoutRetry() | ||
if err != nil { | ||
return "", err | ||
} | ||
return output, nil | ||
} | ||
|
||
func Commit(dir string, message string) (string, error) { | ||
c := util.Command{ | ||
Name: "git", | ||
Args: []string{"commit", "-m", message}, | ||
Dir: dir, | ||
} | ||
output, err := c.RunWithoutRetry() | ||
if err != nil { | ||
return "", err | ||
} | ||
return output, nil | ||
} | ||
|
||
func Status(dir string) (string, error) { | ||
c := util.Command{ | ||
Name: "git", | ||
Args: []string{"status"}, | ||
Dir: dir, | ||
} | ||
output, err := c.RunWithoutRetry() | ||
if err != nil { | ||
return "", err | ||
} | ||
return output, nil | ||
} | ||
|
||
func LocalChanges(dir string) (bool, error) { | ||
c := util.Command{ | ||
Name: "git", | ||
Args: []string{"status", "--porcelain"}, | ||
Dir: dir, | ||
} | ||
output, err := c.RunWithoutRetry() | ||
if err != nil { | ||
return false, err | ||
} | ||
return output != "", nil | ||
} | ||
|
||
func ConfigCommitterInformation(dir string, email string, name string) error { | ||
c := util.Command{ | ||
Name: "git", | ||
Args: []string{"config", "user.email", email}, | ||
Dir: dir, | ||
} | ||
_, err := c.RunWithoutRetry() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
c = util.Command{ | ||
Name: "git", | ||
Args: []string{"config", "user.name", name}, | ||
Dir: dir, | ||
} | ||
_, err = c.RunWithoutRetry() | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func ExtractOrgAndRepoFromGitRemotes(reader io.Reader) (string, string, error) { | ||
buf := new(strings.Builder) | ||
_, err := io.Copy(buf, reader) | ||
if err != nil { | ||
return "", "", err | ||
} | ||
lines := strings.Split(buf.String(), "\n") | ||
for _, line := range lines { | ||
if strings.HasPrefix(line, "origin") && strings.HasSuffix(line, "(push)") { | ||
urlString := strings.TrimSpace(strings.ReplaceAll(strings.ReplaceAll(line, "origin\t", ""), "(push)", "")) | ||
url, err := url2.Parse(urlString) | ||
if err != nil { | ||
return "", "", err | ||
} | ||
fragments := strings.Split(url.Path, "/") | ||
if len(fragments) != 3 { | ||
return "", "", errors.New("invalid url path '" + url.Path + "'") | ||
} | ||
return fragments[1], fragments[2], nil | ||
} | ||
} | ||
return "", "", errors.New("unable to find remote named 'origin'") | ||
} |
Oops, something went wrong.