Repository: crazy-max/diun
Pull request #66 (2020-05-08 15:02:28)

Switch to kong command-line parser


Patch:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index f640329c..589f0096 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -44,19 +44,13 @@ jobs:
       -
         # https://github.com/actions/setup-go
         name: Set up Go
-        uses: actions/setup-go@master
+        uses: actions/setup-go@v2
         with:
           go-version: 1.13
-      -
-        name: Set GOPATH
-        # temporary fix (see https://github.com/actions/setup-go/issues/14)
-        run: |
-          echo "##[set-env name=GOPATH;]$(dirname $GITHUB_WORKSPACE)"
-          echo "##[add-path]$(dirname $GITHUB_WORKSPACE)/bin"
       -
         # https://github.com/actions/checkout
         name: Checkout
-        uses: actions/checkout@v1
+        uses: actions/checkout@v2
       -
         # https://github.com/goreleaser/goreleaser-action
         name: GoReleaser
@@ -122,12 +116,10 @@ jobs:
         # https://github.com/crazy-max/ghaction-docker-buildx
         name: Set up Docker Buildx
         uses: crazy-max/ghaction-docker-buildx@v1
-        with:
-          version: latest
       -
         # https://github.com/actions/checkout
         name: Checkout
-        uses: actions/checkout@v1
+        uses: actions/checkout@v2
       -
         name: Docker Buildx (build)
         run: |
diff --git a/.github/workflows/gosum.yml b/.github/workflows/gosum.yml
index b8ccf440..6af82a62 100644
--- a/.github/workflows/gosum.yml
+++ b/.github/workflows/gosum.yml
@@ -16,11 +16,13 @@ jobs:
     steps:
       -
         name: Checkout
-        uses: actions/checkout@v1
+        uses: actions/checkout@v2
       -
-        # https://github.com/actions/checkout/issues/6
-        name: Fix detached HEAD
-        run: git checkout ${GITHUB_REF#refs/heads/}
+        # https://github.com/actions/setup-go
+        name: Set up Go
+        uses: actions/setup-go@v2
+        with:
+          go-version: 1.13
       -
         name: Tidy
         run: |
diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml
index dd984b61..9aa092e3 100644
--- a/.github/workflows/labels.yml
+++ b/.github/workflows/labels.yml
@@ -15,11 +15,11 @@ jobs:
       -
         # https://github.com/actions/checkout
         name: Checkout
-        uses: actions/checkout@v1
+        uses: actions/checkout@v2
       -
         # https://github.com/crazy-max/ghaction-github-labeler
         name: Run Labeler
         if: success()
-        uses: crazy-max/ghaction-github-labeler@v1
+        uses: crazy-max/ghaction-github-labeler@v2
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bee20dff..2d0e816f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -49,7 +49,7 @@
 * Add Docker provider (#3)
 * Docker client v19.03.5
 * Move `image` field to providers layer and rename it `static`
-* Update libs
+* Update deps
 * Go 1.13.5
 * Seconds field optional for schedule
 
@@ -59,7 +59,7 @@
 
 ## 1.4.1 (2019/10/20)
 
-* Update libs
+* Update deps
 * Fix Docker labels
 
 ## 1.4.0 (2019/10/01)
@@ -90,13 +90,13 @@
 
 ## 1.2.0 (2019/08/18)
 
-* Update libs
+* Update deps
 * Display containers/image logs
 * Fix registry options not setted (Issue #5)
 
 ## 1.1.0 (2019/07/24)
 
-* Update libs
+* Update deps
 
 ## 1.0.2 (2019/07/01)
 
diff --git a/README.md b/README.md
index cc1d1cb6..09b7f698 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@
 
 ## Features
 
-* Allow to watch a full Docker repository and report new tags
+* Allow to watch a Docker repository and report new tags
 * Include and exclude filters with regular expression for tags
 * Internal cron implementation through go routines
 * Worker pool to parallelize analyses
@@ -46,7 +46,7 @@
 * [Notifications](doc/notifications.md)
 * [FAQ](doc/faq.md)
 
-## How can I help ?
+## How can I help?
 
 All kinds of contributions are welcome :raised_hands:! The most basic way to show your support is to star :star2: the project, or to raise issues :speech_balloon: You can also support this project by [**becoming a sponsor on GitHub**](https://github.com/sponsors/crazy-max) :clap: or by making a [Paypal donation](https://www.paypal.me/crazyws) to ensure this journey continues indefinitely! :rocket:
 
diff --git a/cmd/main.go b/cmd/main.go
index 5058b22a..973dc9a6 100644
--- a/cmd/main.go
+++ b/cmd/main.go
@@ -1,13 +1,14 @@
 package main
 
 import (
+	"fmt"
 	"os"
 	"os/signal"
 	"runtime"
 	"syscall"
 	"time"
 
-	"github.com/alecthomas/kingpin"
+	"github.com/alecthomas/kong"
 	"github.com/crazy-max/diun/internal/app"
 	"github.com/crazy-max/diun/internal/config"
 	"github.com/crazy-max/diun/internal/logging"
@@ -17,7 +18,7 @@ import (
 
 var (
 	diun    *app.Diun
-	flags   model.Flags
+	cli     model.Cli
 	version = "dev"
 )
 
@@ -25,24 +26,26 @@ func main() {
 	runtime.GOMAXPROCS(runtime.NumCPU())
 
 	// Parse command line
-	kingpin.Flag("config", "Diun configuration file.").Envar("CONFIG").Required().StringVar(&flags.Cfgfile)
-	kingpin.Flag("timezone", "Timezone assigned to Diun.").Envar("TZ").Default("UTC").StringVar(&flags.Timezone)
-	kingpin.Flag("log-level", "Set log level.").Envar("LOG_LEVEL").Default("info").StringVar(&flags.LogLevel)
-	kingpin.Flag("log-json", "Enable JSON logging output.").Envar("LOG_JSON").Default("false").BoolVar(&flags.LogJSON)
-	kingpin.Flag("log-caller", "Enable to add file:line of the caller.").Envar("LOG_CALLER").Default("false").BoolVar(&flags.LogCaller)
-	kingpin.UsageTemplate(kingpin.CompactUsageTemplate).Version(version).Author("CrazyMax")
-	kingpin.CommandLine.Name = "diun"
-	kingpin.CommandLine.Help = `Docker image update notifier.\nMore info: https://github.com/crazy-max/diun`
-	kingpin.Parse()
+	_ = kong.Parse(&cli,
+		kong.Name("diun"),
+		kong.Description(`Docker image update notifier. More info: https://github.com/crazy-max/diun`),
+		kong.UsageOnError(),
+		kong.Vars{
+			"version": fmt.Sprintf("%s", version),
+		},
+		kong.ConfigureHelp(kong.HelpOptions{
+			Compact: true,
+			Summary: true,
+		}))
 
 	// Load timezone location
-	location, err := time.LoadLocation(flags.Timezone)
+	location, err := time.LoadLocation(cli.Timezone)
 	if err != nil {
-		log.Panic().Err(err).Msgf("Cannot load timezone %s", flags.Timezone)
+		log.Panic().Err(err).Msgf("Cannot load timezone %s", cli.Timezone)
 	}
 
 	// Init
-	logging.Configure(&flags, location)
+	logging.Configure(&cli, location)
 	log.Info().Msgf("Starting Diun %s", version)
 
 	// Handle os signals
@@ -56,7 +59,7 @@ func main() {
 	}()
 
 	// Load and check configuration
-	cfg, err := config.Load(flags, version)
+	cfg, err := config.Load(cli, version)
 	if err != nil {
 		log.Fatal().Err(err).Msg("Cannot load configuration")
 	}
diff --git a/doc/install/binary.md b/doc/install/binary.md
index 4509284b..066135b5 100644
--- a/doc/install/binary.md
+++ b/doc/install/binary.md
@@ -16,20 +16,19 @@ After getting the binary, it can be tested with `./diun --help` or moved to a pe
 
 ```
 $ ./diun --help
-usage: diun --config=CONFIG [<flags>]
+Usage: diun --config=STRING
 
-Docker image update notifier. More info on https://github.com/crazy-max/diun
+Docker image update notifier. More info: https://github.com/crazy-max/diun
 
 Flags:
-  --help              Show context-sensitive help (also try --help-long and
-                      --help-man).
-  --config=CONFIG     Diun configuration file.
-  --timezone="UTC"    Timezone assigned to Diun.
-  --log-level="info"  Set log level.
-  --log-json          Enable JSON logging output.
-  --log-caller        Enable to add file:line of the caller.
-  --docker            Enable Docker mode.
-  --version           Show application version.
+  --help                 Show context-sensitive help.
+  --version
+  --config=STRING        Diun configuration file ($CONFIG).
+  --timezone="UTC"       Timezone assigned to Diun ($TZ).
+  --log-level="debug"    Set log level ($LOG_LEVEL).
+  --log-json             Enable JSON logging output ($LOG_JSON).
+  --log-caller           Add file:line of the caller to log output
+                         ($LOG_CALLER).
 ```
 
 ## Server configuration
diff --git a/doc/usage.md b/doc/usage.md
index 5faeca35..04e9f829 100644
--- a/doc/usage.md
+++ b/doc/usage.md
@@ -2,12 +2,12 @@
 
 ## Command line
 
-`diun --config=CONFIG [<flags>]`
+`diun --config=STRING`
 
-* `--help` : Show help text and exit.
-* `--version` : Show version and exit.
-* `--config <path>` : Diun YAML configuration file. **Required**. (example: `diun.yml`).
-* `--timezone <timezone>` : Timezone assigned to Diun. (default: `UTC`).
-* `--log-level <level>` : Log level output. (default: `info`).
-* `--log-json` : Enable JSON logging output. (default: `false`).
-* `--log-caller` : Enable to add file:line of the caller. (default: `false`).
+* `--help`: Show help text and exit.
+* `--version`: Show version and exit.
+* `--config <path>`: Diun YAML configuration file. **Required**. (e.g. `diun.yml`).
+* `--timezone <timezone>`: Timezone assigned to Diun. (default `UTC`).
+* `--log-level <level>`: Log level output. (default `info`).
+* `--log-json`: Enable JSON logging output. (default `false`).
+* `--log-caller`: Add file:line of the caller to log output. (default `false`).
diff --git a/go.mod b/go.mod
index efc423da..36553130 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,7 @@ module github.com/crazy-max/diun
 go 1.13
 
 require (
-	github.com/alecthomas/kingpin v0.0.0-20190816080609-dce89ec0b9f1
+	github.com/alecthomas/kong v0.2.9
 	github.com/containers/image/v5 v5.4.0
 	github.com/docker/docker v1.13.1
 	github.com/docker/go-connections v0.4.0
diff --git a/go.sum b/go.sum
index c57a71a9..f9d330ff 100644
--- a/go.sum
+++ b/go.sum
@@ -28,11 +28,9 @@ github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt
 github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
 github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
-github.com/alecthomas/kingpin v0.0.0-20190816080609-dce89ec0b9f1 h1:mMQ7zXsR8Z+qu7xwkCkjv80btn4DMOnek8rX+STVDdo=
-github.com/alecthomas/kingpin v0.0.0-20190816080609-dce89ec0b9f1/go.mod h1:idxgS9pV6OOpAhZvx+gcoGRMX9/tt0iqkw/pNxI0C14=
-github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
+github.com/alecthomas/kong v0.2.9 h1:WGuTS/N2/NQ/9LymVqpr1ifZ4EEkQPvwFHqZs6ak5IU=
+github.com/alecthomas/kong v0.2.9/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o=
 github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
diff --git a/internal/config/config.go b/internal/config/config.go
index 7efc5478..83eae6db 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -18,7 +18,7 @@ import (
 
 // Config holds configuration details
 type Config struct {
-	Flags     model.Flags
+	Cli       model.Cli
 	App       model.App
 	Db        model.Db                 `yaml:"db,omitempty"`
 	Watch     model.Watch              `yaml:"watch,omitempty"`
@@ -28,10 +28,10 @@ type Config struct {
 }
 
 // Load returns Configuration struct
-func Load(flags model.Flags, version string) (*Config, error) {
+func Load(cli model.Cli, version string) (*Config, error) {
 	var err error
 	var cfg = Config{
-		Flags: flags,
+		Cli: cli,
 		App: model.App{
 			ID:      "diun",
 			Name:    "Diun",
@@ -78,11 +78,11 @@ func Load(flags model.Flags, version string) (*Config, error) {
 		},
 	}
 
-	if _, err = os.Lstat(flags.Cfgfile); err != nil {
+	if _, err = os.Lstat(cli.Cfgfile); err != nil {
 		return nil, fmt.Errorf("unable to open config file, %s", err)
 	}
 
-	bytes, err := ioutil.ReadFile(flags.Cfgfile)
+	bytes, err := ioutil.ReadFile(cli.Cfgfile)
 	if err != nil {
 		return nil, fmt.Errorf("unable to read config file, %s", err)
 	}
diff --git a/internal/logging/logger.go b/internal/logging/logger.go
index 05e21a2c..03e3e169 100644
--- a/internal/logging/logger.go
+++ b/internal/logging/logger.go
@@ -13,7 +13,7 @@ import (
 )
 
 // Configure configures logger
-func Configure(fl *model.Flags, location *time.Location) {
+func Configure(cli *model.Cli, location *time.Location) {
 	var err error
 	var w io.Writer
 
@@ -21,7 +21,7 @@ func Configure(fl *model.Flags, location *time.Location) {
 		return time.Now().In(location)
 	}
 
-	if !fl.LogJSON {
+	if !cli.LogJSON {
 		w = zerolog.ConsoleWriter{
 			Out:        os.Stdout,
 			TimeFormat: time.RFC1123,
@@ -31,20 +31,20 @@ func Configure(fl *model.Flags, location *time.Location) {
 	}
 
 	ctx := zerolog.New(w).With().Timestamp()
-	if fl.LogCaller {
+	if cli.LogCaller {
 		ctx = ctx.Caller()
 	}
 
 	log.Logger = ctx.Logger()
 
-	logLevel, err := zerolog.ParseLevel(fl.LogLevel)
+	logLevel, err := zerolog.ParseLevel(cli.LogLevel)
 	if err != nil {
 		log.Fatal().Err(err).Msgf("Unknown log level")
 	} else {
 		zerolog.SetGlobalLevel(logLevel)
 	}
 
-	logrusLevel, err := logrus.ParseLevel(fl.LogLevel)
+	logrusLevel, err := logrus.ParseLevel(cli.LogLevel)
 	if err != nil {
 		log.Fatal().Err(err).Msgf("Unknown log level")
 	} else {
diff --git a/internal/model/cli.go b/internal/model/cli.go
new file mode 100644
index 00000000..ef440cce
--- /dev/null
+++ b/internal/model/cli.go
@@ -0,0 +1,13 @@
+package model
+
+import "github.com/alecthomas/kong"
+
+// Cli holds command line args, flags and cmds
+type Cli struct {
+	Version   kong.VersionFlag
+	Cfgfile   string `kong:"required,name='config',env='CONFIG',help='Diun configuration file.'"`
+	Timezone  string `kong:"name='timezone',env='TZ',default='UTC',help='Timezone assigned to Diun.'"`
+	LogLevel  string `kong:"name='log-level',env='LOG_LEVEL',default='debug',help='Set log level.'"`
+	LogJSON   bool   `kong:"name='log-json',env='LOG_JSON',default='false',help='Enable JSON logging output.'"`
+	LogCaller bool   `kong:"name='log-caller',env='LOG_CALLER',default='false',help='Add file:line of the caller to log output.'"`
+}
diff --git a/internal/model/flags.go b/internal/model/flags.go
deleted file mode 100644
index 3f058520..00000000
--- a/internal/model/flags.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package model
-
-// Flags holds flags from command line
-type Flags struct {
-	Cfgfile   string
-	Timezone  string
-	LogLevel  string
-	LogJSON   bool
-	LogCaller bool
-}


Test patch:
diff --git a/internal/config/config_test.go b/internal/config/config_test.go
index 4928226d..220b0cc6 100644
--- a/internal/config/config_test.go
+++ b/internal/config/config_test.go
@@ -11,29 +11,29 @@ import (
 func TestLoad(t *testing.T) {
 	cases := []struct {
 		name     string
-		flags    model.Flags
+		cli      model.Cli
 		wantData *config.Config
 		wantErr  bool
 	}{
 		{
 			name:    "Fail on non-existing file",
-			flags:   model.Flags{},
+			cli:     model.Cli{},
 			wantErr: true,
 		},
 		{
 			name: "Fail on wrong file format",
-			flags: model.Flags{
+			cli: model.Cli{
 				Cfgfile: "config.invalid.yml",
 			},
 			wantErr: true,
 		},
 		{
 			name: "Success",
-			flags: model.Flags{
+			cli: model.Cli{
 				Cfgfile: "config.test.yml",
 			},
 			wantData: &config.Config{
-				Flags: model.Flags{
+				Cli: model.Cli{
 					Cfgfile: "config.test.yml",
 				},
 				App: model.App{
@@ -188,7 +188,7 @@ func TestLoad(t *testing.T) {
 	}
 	for _, tt := range cases {
 		t.Run(tt.name, func(t *testing.T) {
-			cfg, err := config.Load(tt.flags, "test")
+			cfg, err := config.Load(tt.cli, "test")
 			assert.Equal(t, tt.wantData, cfg)
 			assert.Equal(t, tt.wantErr, err != nil)
 		})