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 1 commit
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")
}
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ require (
emperror.dev/errors v0.8.1
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
github.com/shurcooL/githubv4 v0.0.0-20220115235240-a14260e6f8a2
github.com/sirupsen/logrus v1.9.0
github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.15.0
github.com/stretchr/testify v1.8.2
github.com/whilp/git-urls v1.0.0
Expand Down Expand Up @@ -156,7 +158,6 @@ require (
github.com/spf13/afero v1.9.5 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect
github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect
github.com/stretchr/objx v0.5.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,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 parseBranchCmd(args)
Copy link
Contributor

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?

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 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)
}
})
}
}
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.
//
// branch <branch-name> [--parent <parent-branch-name>] [--trunk <trunk-branch-name>]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stack-branch

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, thanks. Originally it was named just branch (before the decision to make it stack-branch to avoid conflicts with rebase's break) and I just missed these. Thanks for catching!

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
}
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())
})
}
}