Skip to content

Commit

Permalink
refactor(config): Move flag and completion logic into config package
Browse files Browse the repository at this point in the history
  • Loading branch information
gabe565 committed Jun 26, 2024
1 parent 82096da commit 367167f
Show file tree
Hide file tree
Showing 20 changed files with 261 additions and 299 deletions.
111 changes: 17 additions & 94 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (

"github.com/clevyr/yampl/internal/colorize"
"github.com/clevyr/yampl/internal/config"
"github.com/clevyr/yampl/internal/config/flags"
"github.com/clevyr/yampl/internal/util"
"github.com/clevyr/yampl/internal/visitor"
"github.com/rs/zerolog"
Expand All @@ -36,57 +35,13 @@ func NewCommand() *cobra.Command {
DisableAutoGenTag: true,
ValidArgsFunction: validArgs,
Version: buildVersion(version),
PreRunE: preRun,
RunE: run,
}
conf := config.New()

registerCompletionFlag(cmd)
registerLogFlags(cmd)
registerValuesFlag(cmd, conf)

cmd.Flags().BoolVarP(&conf.Inplace, "inplace", "i", conf.Inplace, "Edit files in place")
if err := cmd.RegisterFlagCompletionFunc("inplace", util.BoolCompletion); err != nil {
panic(err)
}

cmd.Flags().BoolVarP(&conf.Recursive, "recursive", "r", conf.Recursive, "Recursively update yaml files in the given directory")
if err := cmd.RegisterFlagCompletionFunc("recursive", util.BoolCompletion); err != nil {
panic(err)
}

cmd.Flags().StringVarP(&conf.Prefix, "prefix", "p", conf.Prefix, "Template comments must begin with this prefix. The beginning '#' is implied.")
if err := cmd.RegisterFlagCompletionFunc("prefix", cobra.NoFileCompletions); err != nil {
panic(err)
}

cmd.Flags().StringVar(&conf.LeftDelim, "left-delim", conf.LeftDelim, "Override template left delimiter")
if err := cmd.RegisterFlagCompletionFunc("left-delim", cobra.NoFileCompletions); err != nil {
panic(err)
}

cmd.Flags().StringVar(&conf.RightDelim, "right-delim", conf.RightDelim, "Override template right delimiter")
if err := cmd.RegisterFlagCompletionFunc("right-delim", cobra.NoFileCompletions); err != nil {
panic(err)
}

cmd.Flags().IntVarP(&conf.Indent, "indent", "I", conf.Indent, "Override output indentation")
if err := cmd.RegisterFlagCompletionFunc("indent", cobra.NoFileCompletions); err != nil {
panic(err)
}

cmd.Flags().BoolVarP(&conf.Fail, "fail", "f", conf.Fail, `Exit with an error if a template variable is not set`)
if err := cmd.RegisterFlagCompletionFunc("fail", util.BoolCompletion); err != nil {
panic(err)
}

cmd.Flags().BoolVarP(&conf.Strip, "strip", "s", conf.Strip, "Strip template comments from output")
if err := cmd.RegisterFlagCompletionFunc("strip", util.BoolCompletion); err != nil {
panic(err)
}

conf.RegisterFlags(cmd)
cmd.InitDefaultVersionFlag()

conf.RegisterCompletions(cmd)
visitor.RegisterCompletion(cmd, conf)
cmd.SetContext(config.WithContext(context.Background(), conf))
return cmd
}
Expand All @@ -95,62 +50,28 @@ func validArgs(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCom
return []string{"yaml", "yml"}, cobra.ShellCompDirectiveFilterFileExt
}

var (
ErrNoFiles = errors.New("no input files")
ErrMissingConfig = errors.New("missing config")
)

func preRun(cmd *cobra.Command, args []string) error {
completionFlag, err := cmd.Flags().GetString(CompletionFlag)
if err != nil {
panic(err)
}
if completionFlag != "" {
return nil
}

initLog(cmd)

cmd.SilenceUsage = true
var ErrNoFiles = errors.New("no input files")

func run(cmd *cobra.Command, args []string) error {
conf, ok := config.FromContext(cmd.Context())
if !ok {
return ErrMissingConfig
}

if !strings.HasPrefix(conf.Prefix, "#") {
conf.Prefix = "#" + conf.Prefix
}

if len(args) == 0 && (conf.Inplace || conf.Recursive) {
return ErrNoFiles
}

rawValues, err := cmd.Flags().GetStringToString(flags.ValueFlag)
if err != nil {
panic(err)
panic("config missing from command context")
}

conf.Values.Fill(rawValues)

return nil
}

func run(cmd *cobra.Command, args []string) error {
completionFlag, err := cmd.Flags().GetString(CompletionFlag)
if err != nil {
panic(err)
}
if completionFlag != "" {
return completion(cmd, args)
if err := conf.Load(cmd); err != nil {
return err
}

conf, ok := config.FromContext(cmd.Context())
if !ok {
return ErrMissingConfig
if conf.Completion != "" {
return completion(cmd, conf.Completion)
}

if len(args) == 0 {
if conf.Inplace || conf.Recursive {
return ErrNoFiles
}
cmd.SilenceUsage = true

s, err := templateReader(conf, os.Stdin, log.Logger)
if err != nil {
return err
Expand All @@ -161,6 +82,8 @@ func run(cmd *cobra.Command, args []string) error {
}
}

cmd.SilenceUsage = true

for i, p := range args {
if err := openAndTemplate(conf, cmd.OutOrStdout(), p); err != nil {
return fmt.Errorf("%s: %w", p, err)
Expand Down
26 changes: 8 additions & 18 deletions cmd/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,23 @@ import (
"github.com/stretchr/testify/require"
)

func Test_preRun(t *testing.T) {
func Test_run(t *testing.T) {
t.Run("silent usage", func(t *testing.T) {
cmd := NewCommand()
_ = preRun(cmd, []string{})
_ = run(cmd, []string{})
assert.True(t, cmd.SilenceUsage)
})

t.Run("no error", func(t *testing.T) {
err := preRun(NewCommand(), []string{})
require.NoError(t, err)
require.NoError(t, run(NewCommand(), []string{}))
})

t.Run("invalid prefix", func(t *testing.T) {
cmd := NewCommand()
conf, ok := config.FromContext(cmd.Context())
require.True(t, ok)
conf.Prefix = "tmpl"

if err := preRun(cmd, []string{}); !assert.NoError(t, err) {
return
}

require.NoError(t, run(cmd, []string{}))
want := "#tmpl"
assert.Equal(t, want, conf.Prefix)
})
Expand All @@ -44,28 +39,23 @@ func Test_preRun(t *testing.T) {
conf, ok := config.FromContext(cmd.Context())
require.True(t, ok)
conf.Inplace = true

err := preRun(cmd, []string{})
require.Error(t, err)
require.Error(t, run(cmd, []string{}))
})

t.Run("recursive no files", func(t *testing.T) {
cmd := NewCommand()
conf, ok := config.FromContext(cmd.Context())
require.True(t, ok)
conf.Recursive = true

err := preRun(cmd, []string{})
require.Error(t, err)
require.Error(t, run(cmd, []string{}))
})

t.Run("completion flag enabled", func(t *testing.T) {
cmd := NewCommand()
if err := cmd.Flags().Set(CompletionFlag, "zsh"); !assert.NoError(t, err) {
if err := cmd.Flags().Set(config.CompletionFlag, "zsh"); !assert.NoError(t, err) {
return
}
err := preRun(cmd, []string{})
require.NoError(t, err)
require.NoError(t, run(cmd, []string{}))
})
}

Expand Down
25 changes: 25 additions & 0 deletions cmd/completion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package cmd

import (
"errors"
"fmt"

"github.com/spf13/cobra"
)

var ErrInvalidShell = errors.New("invalid shell")

func completion(cmd *cobra.Command, shell string) error {
switch shell {
case "bash":
return cmd.Root().GenBashCompletion(cmd.OutOrStdout())
case "zsh":
return cmd.Root().GenZshCompletion(cmd.OutOrStdout())
case "fish":
return cmd.Root().GenFishCompletion(cmd.OutOrStdout(), true)
case "powershell":
return cmd.Root().GenPowerShellCompletionWithDesc(cmd.OutOrStdout())
default:
return fmt.Errorf("%w: %s", ErrInvalidShell, shell)
}
}
48 changes: 48 additions & 0 deletions cmd/completion_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package cmd

import (
"io"
"testing"

"github.com/clevyr/yampl/internal/config"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func Test_completion(t *testing.T) {
r, w := io.Pipe()
_ = r.Close()

type args struct {
cmd *cobra.Command
shell string
}
tests := []struct {
name string
w io.Writer
args args
wantErr require.ErrorAssertionFunc
}{
{"bash", io.Discard, args{NewCommand(), "bash"}, require.NoError},
{"bash error", w, args{NewCommand(), "bash"}, require.Error},
{"zsh", io.Discard, args{NewCommand(), "zsh"}, require.NoError},
{"zsh error", w, args{NewCommand(), "zsh"}, require.Error},
{"fish", io.Discard, args{NewCommand(), "fish"}, require.NoError},
{"fish error", w, args{NewCommand(), "fish"}, require.Error},
{"powershell", io.Discard, args{NewCommand(), "powershell"}, require.NoError},
{"powershell error", w, args{NewCommand(), "powershell"}, require.Error},
{"other", io.Discard, args{NewCommand(), "other"}, require.Error},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.args.cmd.SetOut(tt.w)

if err := tt.args.cmd.Flags().Set(config.CompletionFlag, tt.args.shell); !assert.NoError(t, err) {
return
}
err := completion(tt.args.cmd, tt.args.shell)
tt.wantErr(t, err)
})
}
}
53 changes: 0 additions & 53 deletions cmd/flag_completion.go

This file was deleted.

Loading

0 comments on commit 367167f

Please sign in to comment.