-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(stack reorder): Add command scaffolding #123
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package main | ||
|
||
import ( | ||
"emperror.dev/errors" | ||
"github.com/spf13/cobra" | ||
"strings" | ||
) | ||
|
||
var stackReorderFlags struct { | ||
Continue bool | ||
Abort bool | ||
} | ||
|
||
const stackReorderDoc = ` | ||
Interactively reorder the stack. | ||
|
||
This is analogous to git rebase --interactive but operates on the stack (rather | ||
than branch) level. | ||
|
||
Branches can be re-arranged within the stack and commits can be edited, | ||
squashed, dropped, or moved within the stack. | ||
` | ||
|
||
var stackReorderCmd = &cobra.Command{ | ||
Use: "reorder", | ||
Short: "reorder the stack", | ||
Long: strings.TrimSpace(stackReorderDoc), | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
return errors.New("not implemented") | ||
}, | ||
} | ||
|
||
func init() { | ||
stackReorderCmd.Flags().BoolVar(&stackReorderFlags.Continue, "continue", false, "continue a previous reorder") | ||
stackReorderCmd.Flags().BoolVar(&stackReorderFlags.Abort, "abort", false, "abort a previous reorder") | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package actions | ||
|
||
import ( | ||
"github.com/aviator-co/av/internal/git" | ||
"github.com/aviator-co/av/internal/meta" | ||
) | ||
|
||
type ReorderOpts struct { | ||
Continue bool | ||
Abort bool | ||
} | ||
|
||
func Reorder(repo *git.Repo, tx meta.WriteTx, opts ReorderOpts) error { | ||
panic("not implemented") | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package reorder | ||
|
||
// Context is the context of a reorder operation. | ||
// Commands can use the context to access the current state of the reorder | ||
// operation and mutate the context to reflect their changes. | ||
type Context struct { | ||
// The current HEAD of the reorder operation. | ||
Head string | ||
// The name of the current branch in the reorder operation. | ||
Branch string | ||
} | ||
|
||
type Cmd interface { | ||
// Execute executes the command. | ||
Execute(ctx *Context) error | ||
// String returns a string representation of the command. | ||
// The string representation must be parseable such that | ||
// ParseCmd(cmd.String()) == cmd. | ||
String() string | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package reorder | ||
|
||
import "fmt" | ||
|
||
type ErrInvalidCmd struct { | ||
Cmd string | ||
Reason string | ||
} | ||
|
||
func (e ErrInvalidCmd) Error() string { | ||
return fmt.Sprintf("invalid %s command: %s", e.Cmd, e.Reason) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package reorder | ||
|
||
import ( | ||
"emperror.dev/errors" | ||
"github.com/google/shlex" | ||
) | ||
|
||
// ParseCmd parses a reorder command from a string. | ||
// Comments must be stripped from the input before calling this function. | ||
func ParseCmd(line string) (Cmd, error) { | ||
args, err := shlex.Split(line) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "invalid reorder command") | ||
} | ||
if len(args) == 0 { | ||
return nil, errors.New("empty reorder command") | ||
} | ||
cmdName := args[0] | ||
args = args[1:] | ||
switch cmdName { | ||
case "stack-branch", "sb": | ||
return parseBranchCmd(args) | ||
case "pick", "p": | ||
return parsePickCmd(args) | ||
default: | ||
return nil, errors.Errorf("unknown reorder command %q", cmdName) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package reorder | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
func TestParseBranchCmd(t *testing.T) { | ||
for _, tt := range []struct { | ||
Input string | ||
Cmd Cmd | ||
Err bool | ||
}{ | ||
{"stack-branch", StackBranchCmd{}, true}, | ||
{"stack-branch feature-one", StackBranchCmd{Name: "feature-one"}, false}, | ||
{"stack-branch feature-one --parent master", StackBranchCmd{Name: "feature-one", Parent: "master"}, false}, | ||
{"stack-branch feature-one --trunk master", StackBranchCmd{Name: "feature-one", Trunk: "master"}, false}, | ||
{"stack-branch feature-one --parent master --trunk master", StackBranchCmd{}, true}, | ||
{"pick", PickCmd{}, true}, | ||
{"pick foo", PickCmd{Commit: "foo"}, false}, | ||
{"pick foo bar", PickCmd{}, true}, | ||
} { | ||
t.Run(tt.Input, func(t *testing.T) { | ||
cmd, err := ParseCmd(tt.Input) | ||
|
||
if tt.Err { | ||
if err == nil { | ||
t.Errorf("got err %v, want %v", err, tt.Err) | ||
} | ||
return | ||
} else if err != nil { | ||
t.Errorf("got unexpected err %v", err) | ||
return | ||
} | ||
|
||
if !reflect.DeepEqual(cmd, tt.Cmd) { | ||
t.Errorf("got %#v, want %#v", cmd, &tt.Cmd) | ||
} | ||
}) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package reorder | ||
|
||
import ( | ||
"fmt" | ||
) | ||
|
||
// PickCmd is a command that picks a commit from the history and applies it on | ||
// top of the current HEAD. | ||
type PickCmd struct { | ||
Commit string | ||
} | ||
|
||
func (b PickCmd) Execute(ctx *Context) error { | ||
panic("not implemented") | ||
} | ||
|
||
func (b PickCmd) String() string { | ||
return fmt.Sprintf("pick %s", b.Commit) | ||
} | ||
|
||
var _ Cmd = &PickCmd{} | ||
|
||
func parsePickCmd(args []string) (Cmd, error) { | ||
if len(args) != 1 { | ||
return nil, ErrInvalidCmd{"pick", "exactly one argument is required (the commit to pick)"} | ||
} | ||
return PickCmd{ | ||
Commit: args[0], | ||
}, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package reorder | ||
|
||
import ( | ||
"github.com/stretchr/testify/assert" | ||
"testing" | ||
) | ||
|
||
func TestPickCmd_String(t *testing.T) { | ||
assert.Equal(t, "pick mycommit", PickCmd{Commit: "mycommit"}.String()) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package reorder | ||
|
||
type Opts struct{} | ||
|
||
func Reorder(opts Opts) error { | ||
panic("not implemented") | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package reorder | ||
|
||
import ( | ||
"github.com/spf13/pflag" | ||
"strings" | ||
) | ||
|
||
// StackBranchCmd is a command to create a new branch in a stack. | ||
// | ||
// branch <branch-name> [--parent <parent-branch-name>] [--trunk <trunk-branch-name>] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. stack-branch There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, thanks. Originally it was named just |
||
type StackBranchCmd struct { | ||
// The name of the branch to create. | ||
Name string | ||
// The name of the parent branch. If not specified, the previous branch in | ||
// the reorder stack is used (or an error is raised if there is no previous | ||
// branch). | ||
// Mutually exclusive with --trunk. | ||
Parent string | ||
// The name of the trunk branch. | ||
// Mutually exclusive with --parent. | ||
Trunk string | ||
} | ||
|
||
func (b StackBranchCmd) Execute(ctx *Context) error { | ||
panic("not implemented") | ||
} | ||
|
||
func (b StackBranchCmd) String() string { | ||
sb := strings.Builder{} | ||
sb.WriteString("stack-branch ") | ||
sb.WriteString(b.Name) | ||
if b.Parent != "" { | ||
sb.WriteString(" --parent ") | ||
sb.WriteString(b.Parent) | ||
} | ||
if b.Trunk != "" { | ||
sb.WriteString(" --trunk ") | ||
sb.WriteString(b.Trunk) | ||
} | ||
return sb.String() | ||
} | ||
|
||
var _ Cmd = &StackBranchCmd{} | ||
|
||
func parseBranchCmd(args []string) (Cmd, error) { | ||
cmd := StackBranchCmd{} | ||
fs := pflag.NewFlagSet("stack-branch", pflag.ContinueOnError) | ||
fs.StringVar(&cmd.Parent, "parent", "", "parent branch") | ||
fs.StringVar(&cmd.Trunk, "trunk", "", "trunk branch") | ||
if err := fs.Parse(args); err != nil { | ||
return nil, err | ||
} | ||
if fs.NArg() != 1 { | ||
return nil, ErrInvalidCmd{"branch", "exactly one argument is required (the name of the branch to create)"} | ||
} | ||
if cmd.Trunk != "" && cmd.Parent != "" { | ||
return nil, ErrInvalidCmd{"branch", "cannot specify both --parent and --trunk"} | ||
} | ||
cmd.Name = fs.Arg(0) | ||
return cmd, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package reorder | ||
|
||
import ( | ||
"github.com/stretchr/testify/assert" | ||
"testing" | ||
) | ||
|
||
func TestStackBranchCmd_String(t *testing.T) { | ||
for _, tt := range []struct { | ||
Cmd StackBranchCmd | ||
Output string | ||
}{ | ||
{StackBranchCmd{Name: "feature-one"}, "stack-branch feature-one"}, | ||
{StackBranchCmd{Name: "feature-one", Parent: "master"}, "stack-branch feature-one --parent master"}, | ||
{StackBranchCmd{Name: "feature-one", Trunk: "master"}, "stack-branch feature-one --trunk master"}, | ||
} { | ||
t.Run(tt.Output, func(t *testing.T) { | ||
assert.Equal(t, tt.Output, tt.Cmd.String()) | ||
}) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps rename this as parseStackBranchCmd to align with the command name?