Skip to content

Commit

Permalink
Switch to wavesoftware/commandline package (#205)
Browse files Browse the repository at this point in the history
  • Loading branch information
cardil authored Sep 8, 2022
1 parent 2652e4f commit ec11a00
Show file tree
Hide file tree
Showing 77 changed files with 2,595 additions and 745 deletions.
26 changes: 3 additions & 23 deletions cmd/kn-event-sender/main.go
Original file line number Diff line number Diff line change
@@ -1,35 +1,15 @@
package main

import (
"context"
"os"

"go.uber.org/zap"
"knative.dev/kn-plugin-event/pkg/cli/retcode"
"knative.dev/kn-plugin-event/pkg/configuration"
"knative.dev/pkg/logging"
"github.com/wavesoftware/go-commandline"
"knative.dev/kn-plugin-event/internal/ics"
)

// ExitFunc will be used to exit Go process in case of error.
var ExitFunc = os.Exit // nolint:gochecknoglobals

func main() {
logger := createLogger()
app := configuration.CreateIcs()
if err := app.SendFromEnv(); err != nil {
logger.Error(err)
ExitFunc(retcode.Calc(err))
}
commandline.New(ics.App{}).ExecuteOrDie(ics.Options...)
}

// TestMain is used by tests.
//goland:noinspection GoUnusedExportedFunction
func TestMain() { //nolint:deadcode
main()
}

func createLogger() *zap.SugaredLogger {
return logging.
FromContext(context.TODO()).
With("env", os.Environ())
}
18 changes: 17 additions & 1 deletion cmd/kn-event-sender/main_test.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,33 @@
package main_test

import (
"bytes"
"net/url"
"strings"
"testing"
"time"

cloudevents "github.com/cloudevents/sdk-go/v2"
"github.com/google/uuid"
"github.com/wavesoftware/go-commandline"
"gotest.tools/v3/assert"
kes "knative.dev/kn-plugin-event/cmd/kn-event-sender"
internalics "knative.dev/kn-plugin-event/internal/ics"
"knative.dev/kn-plugin-event/pkg/cli/ics"
"knative.dev/kn-plugin-event/pkg/tests"
)

func TestMainSender(t *testing.T) {
defer func() {
internalics.Options = nil
}()
var outBuf bytes.Buffer
internalics.Options = []commandline.Option{
commandline.WithOutput(&outBuf),
}
id := uuid.New().String()
want := cloudevents.NewEvent()
want.SetID("azxswq")
want.SetID(id)
want.SetTime(time.Now().UTC())
want.SetType("example")
want.SetSource("tests://example")
Expand All @@ -31,7 +44,10 @@ func TestMainSender(t *testing.T) {
return nil
})
})
out := outBuf.String()
assert.NilError(t, err)

assert.DeepEqual(t, want, *got)
assert.Check(t, strings.Contains(out, "Event sent"))
assert.Check(t, strings.Contains(out, id))
}
10 changes: 5 additions & 5 deletions cmd/kn-event/main.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package main

import "knative.dev/kn-plugin-event/internal/cli/cmd"

// Suppress global check for testing purposes.
var mainCmd = &cmd.Cmd{} //nolint:gochecknoglobals
import (
"github.com/wavesoftware/go-commandline"
"knative.dev/kn-plugin-event/internal/cli/cmd"
)

func main() {
mainCmd.Execute()
commandline.New(new(cmd.App)).ExecuteOrDie(cmd.Options...)
}
22 changes: 14 additions & 8 deletions cmd/kn-event/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,32 @@ package main // nolint:testpackage

import (
"bytes"
"math"
"strings"
"testing"

"github.com/wavesoftware/go-commandline"
"gotest.tools/v3/assert"
"knative.dev/kn-plugin-event/internal/cli/cmd"
)

func TestMainFunc(t *testing.T) {
tc := cmd.TestingCmd{
Cmd: mainCmd,
retcode := math.MinInt64
defer func() {
cmd.Options = nil
}()
var buf bytes.Buffer
cmd.Options = []commandline.Option{
commandline.WithExit(func(code int) {
retcode = code
}),
commandline.WithOutput(&buf),
commandline.WithArgs(""),
}
buf := bytes.NewBuffer([]byte{})
tc.Out(buf)
tc.Args("")
tc.Exit(func(code int) {
assert.Equal(t, 0, code)
})

main()

out := buf.String()
assert.Check(t, strings.Contains(out, "Manage CloudEvents from command line"))
assert.Check(t, retcode == math.MinInt64)
}
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ require (
github.com/magefile/mage v1.11.0
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2
github.com/pkg/errors v0.9.1
github.com/spf13/cobra v1.3.0
github.com/spf13/cobra v1.5.0
github.com/thediveo/enumflag v0.10.0
github.com/wavesoftware/go-commandline v1.0.0
github.com/wavesoftware/go-ensure v1.0.0
github.com/wavesoftware/go-magetasks v0.6.0
go.uber.org/zap v1.21.0
gopkg.in/yaml.v2 v2.4.0
gotest.tools/v3 v3.1.0
gotest.tools/v3 v3.3.0
k8s.io/api v0.23.9
k8s.io/apimachinery v0.23.9
k8s.io/client-go v0.23.9
Expand Down Expand Up @@ -138,6 +139,7 @@ require (
github.com/stretchr/testify v1.7.0 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
github.com/vbatts/tar-split v0.11.2 // indirect
github.com/wavesoftware/go-retcode v1.0.0 // indirect
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect
go.opencensus.io v0.23.0 // indirect
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
Expand Down
58 changes: 9 additions & 49 deletions go.sum

Large diffs are not rendered by default.

8 changes: 3 additions & 5 deletions internal/cli/cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
var ErrCantBePresented = errors.New("can't be presented")

type buildCommand struct {
*Cmd
*App
event *cli.EventArgs
}

Expand All @@ -28,14 +28,12 @@ func (b *buildCommand) command() *cobra.Command {
}

func (b *buildCommand) run(cmd *cobra.Command, _ []string) error {
b.options.OutWriter = cmd.OutOrStdout()
b.options.ErrWriter = cmd.ErrOrStderr()
c := configuration.CreateCli()
c := configuration.CreateCli(cmd)
ce, err := c.CreateWithArgs(b.event)
if err != nil {
return cantBuildEventError(err)
}
out, err := c.PresentWith(ce, b.options.Output)
out, err := c.PresentWith(ce, b.Output)
if err != nil {
return fmt.Errorf("event %w: %v", ErrCantBePresented, err)
}
Expand Down
10 changes: 5 additions & 5 deletions internal/cli/cmd/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (
"testing"

cloudevents "github.com/cloudevents/sdk-go/v2"
"github.com/wavesoftware/go-commandline"
"gotest.tools/v3/assert"
"knative.dev/kn-plugin-event/internal/cli/cmd"
"knative.dev/kn-plugin-event/pkg/event"
"knative.dev/kn-plugin-event/pkg/tests"
)
Expand Down Expand Up @@ -61,10 +61,10 @@ func newCmdArgs(args ...string) cmdArgs {
func performTestsOnBuildSubCommand(t *testing.T, args cmdArgs, preparers ...eventPreparer) {
t.Helper()
buf := bytes.NewBuffer([]byte{})
c := cmd.TestingCmd{}
c.Out(buf)
c.Args(args.args...)
assert.NilError(t, c.Execute())
assert.NilError(t, testapp().Execute(
commandline.WithOutput(buf),
commandline.WithArgs(args.args...),
))
output := buf.Bytes()
ec := newEventChecks(t)
for _, preparer := range preparers {
Expand Down
97 changes: 24 additions & 73 deletions internal/cli/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,117 +2,68 @@ package cmd

import (
"fmt"
"io"
"os"

"github.com/spf13/cobra"
"github.com/thediveo/enumflag"
"github.com/wavesoftware/go-commandline"
_ "k8s.io/client-go/plugin/pkg/client/auth" // for kubeconfig auth plugins to work correctly see issue #24 .
"knative.dev/kn-plugin-event/pkg/cli"
"knative.dev/kn-plugin-event/pkg/cli/retcode"
"knative.dev/kn-plugin-event/pkg/metadata"
)

// Cmd represents a command line application entrypoint.
type Cmd struct {
options *cli.Options
root *cobra.Command
exit func(code int)
}
// Options to override the commandline for testing purposes.
var Options []commandline.Option //nolint:gochecknoglobals

// Execute will execute the application.
func (c *Cmd) Execute() {
if err := c.execute(); err != nil {
c.exit(retcode.Calc(err))
}
type App struct {
cli.Options
}

// ExecuteWithOptions will execute the application with the provided options.
func (c *Cmd) ExecuteWithOptions(options ...CommandOption) error {
return c.execute(options...)
}

// WithArgs creates an option which sets args.
func WithArgs(args ...string) CommandOption {
return func(command *cobra.Command) {
command.SetArgs(args)
}
}

// WithOutput creates an option witch sets os.Stdout and os.Stderr.
func WithOutput(out io.Writer) CommandOption {
return func(command *cobra.Command) {
command.SetOut(out)
command.SetErr(out)
}
}

// CommandOption is used to configure a command in Cmd.ExecuteWithOptions.
type CommandOption func(*cobra.Command)

func (c *Cmd) execute(configs ...CommandOption) error {
c.init()
for _, config := range configs {
config(c.root)
}
// cobra.Command should pass our own errors, no need to wrap them.
return c.root.Execute() //nolint:wrapcheck
}

func (c *Cmd) init() {
if c.root != nil {
return
}
c.exit = os.Exit
c.options = &cli.Options{}
c.root = &cobra.Command{
func (a *App) Command() *cobra.Command {
c := &cobra.Command{
Use: metadata.PluginUse,
Aliases: []string{fmt.Sprintf("kn %s", metadata.PluginUse)},
Short: metadata.PluginDescription,
Long: metadata.PluginLongDescription,
}
c.root.SetOut(os.Stdout)
c.root.SetErr(os.Stderr)
c.root.PersistentFlags().BoolVarP(
&c.options.Verbose, "verbose", "v",
c.PersistentFlags().BoolVarP(
&a.Verbose, "verbose", "v",
false, "verbose output",
)
c.root.PersistentFlags().VarP(
enumflag.New(&c.options.Output, "output", outputModeIds(), enumflag.EnumCaseInsensitive),
c.PersistentFlags().VarP(
enumflag.New(&a.Output, "output", outputModeIds(), enumflag.EnumCaseInsensitive),
"output", "o",
"Output format. One of: human|json|yaml.",
)

eventArgs := &cli.EventArgs{}
targetArgs := &cli.TargetArgs{}
commands := []subcommand{
&buildCommand{Cmd: c, event: eventArgs},
&sendCommand{Cmd: c, event: eventArgs, target: targetArgs},
&versionCommand{Cmd: c},
&buildCommand{App: a, event: eventArgs},
&sendCommand{App: a, event: eventArgs, target: targetArgs},
&versionCommand{App: a},
}
for _, each := range commands {
c.root.AddCommand(each.command())
c.AddCommand(each.command())
}

c.root.PersistentFlags().StringVar(
&c.options.KubeconfigOptions.Path, "kubeconfig", "",
c.PersistentFlags().StringVar(
&a.KubeconfigOptions.Path, "kubeconfig", "",
"kubectl configuration file (default: ~/.kube/config)",
)
c.root.PersistentFlags().StringVar(
&c.options.KubeconfigOptions.Context, "context", "",
c.PersistentFlags().StringVar(
&a.KubeconfigOptions.Context, "context", "",
"name of the kubeconfig context to use",
)
c.root.PersistentFlags().StringVar(
&c.options.KubeconfigOptions.Cluster, "cluster", "",
c.PersistentFlags().StringVar(
&a.KubeconfigOptions.Cluster, "cluster", "",
"name of the kubeconfig cluster to use",
)

c.root.PersistentPreRun = func(cmd *cobra.Command, args []string) {
c.options.OutWriter = cmd.OutOrStdout()
c.options.ErrWriter = cmd.ErrOrStderr()
}
return c
}

var _ commandline.CobraProvider = new(App)

func outputModeIds() map[cli.OutputMode][]string {
return map[cli.OutputMode][]string{
cli.HumanReadable: {"human"},
Expand Down
26 changes: 16 additions & 10 deletions internal/cli/cmd/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,29 @@ package cmd_test

import (
"bytes"
"math"
"testing"

"github.com/wavesoftware/go-commandline"
"gotest.tools/v3/assert"
"knative.dev/kn-plugin-event/internal/cli/cmd"
)

func TestRootInvalidCommand(t *testing.T) {
called := false
c := cmd.TestingCmd{}
c.Exit(func(code int) {
t.Logf("exit code received: %d", code)
called = true
})
c.Args("invalid-command")
retcode := math.MinInt64
buf := bytes.NewBuffer([]byte{})
c.Out(buf)
c.ExecuteOrFail()
testapp().ExecuteOrDie(
commandline.WithOutput(buf),
commandline.WithExit(func(code int) {
retcode = code
}),
commandline.WithArgs("invalid-command"),
)

assert.Check(t, called)
assert.Check(t, retcode != math.MinInt64)
assert.Check(t, retcode != 0)
}

func testapp() *commandline.App {
return commandline.New(new(cmd.App))
}
Loading

0 comments on commit ec11a00

Please sign in to comment.