Skip to content
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

Merged
merged 3 commits into from
May 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/av/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ func init() {
stackDiffCmd,
stackNextCmd,
stackPrevCmd,
stackReorderCmd,
stackReparentCmd,
stackSyncCmd,
stackSubmitCmd,
Expand Down
36 changes: 36 additions & 0 deletions cmd/av/stack_reorder.go
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")
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/cpuguy83/go-md2man/v2 v2.0.2
github.com/fatih/color v1.15.0
github.com/golangci/golangci-lint v1.52.2
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/kr/text v0.2.0
github.com/segmentio/golines v0.11.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,8 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
Expand Down
15 changes: 15 additions & 0 deletions internal/actions/reorder.go
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")
}
20 changes: 20 additions & 0 deletions internal/reorder/cmds.go
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
}
12 changes: 12 additions & 0 deletions internal/reorder/errors.go
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)
}
28 changes: 28 additions & 0 deletions internal/reorder/parse.go
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 parseStackBranchCmd(args)
case "pick", "p":
return parsePickCmd(args)
default:
return nil, errors.Errorf("unknown reorder command %q", cmdName)
}
}
41 changes: 41 additions & 0 deletions internal/reorder/parse_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package reorder

import (
"reflect"
"testing"
)

func TestParseCmd(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)
}
})
}
}
30 changes: 30 additions & 0 deletions internal/reorder/pick.go
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
}
10 changes: 10 additions & 0 deletions internal/reorder/pick_test.go
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())
}
7 changes: 7 additions & 0 deletions internal/reorder/reorder.go
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")
}
61 changes: 61 additions & 0 deletions internal/reorder/stackbranch.go
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.
//
// stack-branch <branch-name> [--parent <parent-branch-name>] [--trunk <trunk-branch-name>]
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 parseStackBranchCmd(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{"stack-branch", "exactly one argument is required (the name of the branch to create)"}
}
if cmd.Trunk != "" && cmd.Parent != "" {
return nil, ErrInvalidCmd{"stack-branch", "cannot specify both --parent and --trunk"}
}
cmd.Name = fs.Arg(0)
return cmd, nil
}
21 changes: 21 additions & 0 deletions internal/reorder/stackbranch_test.go
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())
})
}
}