Skip to content
This repository has been archived by the owner on Mar 4, 2024. It is now read-only.

Commit

Permalink
Merge pull request #10 from vshn/flags
Browse files Browse the repository at this point in the history
Improve handling around required flags
  • Loading branch information
ccremer authored Jan 18, 2022
2 parents b1895b6 + ff17c98 commit 58ffc5c
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 36 deletions.
8 changes: 5 additions & 3 deletions example_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,18 @@ func newExampleCommand() *cli.Command {
Before: command.validate,
Action: command.execute,
Flags: []cli.Flag{
&cli.StringFlag{Destination: &command.ExampleFlag, Name: "flag", EnvVars: envVars("EXAMPLE_FLAG"), Value: "foo", Usage: "a demonstration how to configure the command"},
&cli.StringFlag{Destination: &command.ExampleFlag, Name: "flag", EnvVars: envVars("EXAMPLE_FLAG"), Value: "foo", Usage: "a demonstration how to configure the command", Required: true},
},
}
}

func (c *exampleCommand) validate(context *cli.Context) error {
_ = LogMetadata(context)
log := AppLogger(context).WithName(exampleCommandName)
log.V(1).Info("validating config")
if c.ExampleFlag == "" {
return fmt.Errorf("option cannot be empty: %s", "flag")
// The `Required` property in the StringFlag above already checks if it's non-empty.
if len(c.ExampleFlag) <= 2 {
return fmt.Errorf("option needs at least 3 characters: %s", "flag")
}
return nil
}
Expand Down
2 changes: 1 addition & 1 deletion example_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func TestExampleCommand_Validate(t *testing.T) {
}{
// TODO: test cases
"GivenEmptyFlag_ThenExpectError": {
expectedError: "option cannot be empty: flag",
expectedError: "option needs at least 3 characters: flag",
},
"GivenValidConfig_ThenExpectNoError": {
givenExampleFlag: "test",
Expand Down
24 changes: 23 additions & 1 deletion logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package main

import (
"log"
"os"
"runtime"
"strings"
"sync/atomic"

Expand All @@ -19,9 +21,29 @@ func AppLogger(c *cli.Context) logr.Logger {
return c.Context.Value(loggerContextKey{}).(*atomic.Value).Load().(logr.Logger)
}

func setupLogging(c *cli.Context) {
// LogMetadata prints various metadata to the root logger.
// It prints version, architecture and current user ID and returns nil.
func LogMetadata(c *cli.Context) error {
logger := AppLogger(c)
if !usesProductionLoggingConfig(c) {
logger = logger.WithValues("version", version)
}
logger.WithValues(
"date", date,
"commit", commit,
"go_os", runtime.GOOS,
"go_arch", runtime.GOARCH,
"go_version", runtime.Version(),
"uid", os.Getuid(),
"gid", os.Getgid(),
).Info("Starting up " + appName)
return nil
}

func setupLogging(c *cli.Context) error {
logger := newZapLogger(appName, c.Bool("debug"), usesProductionLoggingConfig(c))
c.Context.Value(loggerContextKey{}).(*atomic.Value).Store(logger)
return nil
}

func usesProductionLoggingConfig(c *cli.Context) bool {
Expand Down
38 changes: 8 additions & 30 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"
"os"
"os/signal"
"runtime"
"sync/atomic"
"syscall"
"time"
Expand All @@ -32,7 +31,12 @@ var (
func main() {
ctx, stop, app := newApp()
defer stop()
_ = app.RunContext(ctx, os.Args)
err := app.RunContext(ctx, os.Args)
// If required flags aren't set, it will return with error before we could set up logging
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
}
}

func newApp() (context.Context, context.CancelFunc, *cli.App) {
Expand All @@ -46,7 +50,7 @@ func newApp() (context.Context, context.CancelFunc, *cli.App) {

EnableBashCompletion: true,

Before: beforeAction,
Before: setupLogging,
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "debug",
Expand Down Expand Up @@ -86,34 +90,8 @@ func rootAction(hasSubcommands bool) func(context *cli.Context) error {
if hasSubcommands {
return cli.ShowAppHelp(context)
}
logMetadata(context)
return nil
}
}

func beforeAction(c *cli.Context) error {
setupLogging(c)
if c.Args().Present() {
// only print metadata if not displaying usage
logMetadata(c)
}
return nil
}

func logMetadata(c *cli.Context) {
log := AppLogger(c)
if !usesProductionLoggingConfig(c) {
log = log.WithValues("version", version)
return LogMetadata(context)
}
log.WithValues(
"date", date,
"commit", commit,
"go_os", runtime.GOOS,
"go_arch", runtime.GOARCH,
"go_version", runtime.Version(),
"uid", os.Getuid(),
"gid", os.Getgid(),
).Info("Starting up " + appName)
}

// env combines envPrefix with given suffix delimited by underscore.
Expand Down
3 changes: 2 additions & 1 deletion main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"context"
"flag"
"sync/atomic"
"testing"

Expand All @@ -14,7 +15,7 @@ func newAppContext(t *testing.T) *cli.Context {
logger := zapr.NewLogger(zaptest.NewLogger(t))
instance := &atomic.Value{}
instance.Store(logger)
return cli.NewContext(&cli.App{}, nil, &cli.Context{
return cli.NewContext(&cli.App{}, flag.NewFlagSet("", flag.ContinueOnError), &cli.Context{
Context: context.WithValue(context.Background(), loggerContextKey{}, instance),
})
}

0 comments on commit 58ffc5c

Please sign in to comment.