mirror of
https://github.com/containrrr/watchtower.git
synced 2025-09-21 21:30:48 +02:00
feat: add porcelain output (#1337)
* feat: add porcaline output * feat(du-cli): add create-stale action add create-stale action Signed-off-by: nils måsén * test(flags): add alias tests * fix stray format string ref * fix shell liniting problems * feat(du-cli): remove created images * add test for common template * fix interval/schedule logic * use porcelain arg as template version * fix editor save artifacts * use simpler v1 template Signed-off-by: nils måsén
This commit is contained in:
parent
a429c373ff
commit
7900471f88
13 changed files with 344 additions and 63 deletions
|
@ -3,6 +3,7 @@ package flags
|
|||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
@ -153,22 +154,32 @@ func RegisterSystemFlags(rootCmd *cobra.Command) {
|
|||
"",
|
||||
viper.GetString("WATCHTOWER_HTTP_API_TOKEN"),
|
||||
"Sets an authentication token to HTTP API requests.")
|
||||
|
||||
flags.BoolP(
|
||||
"http-api-periodic-polls",
|
||||
"",
|
||||
viper.GetBool("WATCHTOWER_HTTP_API_PERIODIC_POLLS"),
|
||||
"Also run periodic updates (specified with --interval and --schedule) if HTTP API is enabled")
|
||||
|
||||
// https://no-color.org/
|
||||
flags.BoolP(
|
||||
"no-color",
|
||||
"",
|
||||
viper.IsSet("NO_COLOR"),
|
||||
"Disable ANSI color escape codes in log output")
|
||||
|
||||
flags.StringP(
|
||||
"scope",
|
||||
"",
|
||||
viper.GetString("WATCHTOWER_SCOPE"),
|
||||
"Defines a monitoring scope for the Watchtower instance.")
|
||||
|
||||
flags.StringP(
|
||||
"porcelain",
|
||||
"P",
|
||||
viper.GetString("WATCHTOWER_PORCELAIN"),
|
||||
`Write session results to stdout using a stable versioned format. Supported values: "v1"`)
|
||||
|
||||
}
|
||||
|
||||
// RegisterNotificationFlags that are used by watchtower to send notifications
|
||||
|
@ -343,6 +354,10 @@ Should only be used for testing.`)
|
|||
viper.GetString("WATCHTOWER_WARN_ON_HEAD_FAILURE"),
|
||||
"When to warn about HEAD pull requests failing. Possible values: always, auto or never")
|
||||
|
||||
flags.Bool(
|
||||
"notification-log-stdout",
|
||||
viper.GetBool("WATCHTOWER_NOTIFICATION_LOG_STDOUT"),
|
||||
"Write notification logs to stdout instead of logging (to stderr)")
|
||||
}
|
||||
|
||||
// SetDefaults provides default values for environment variables
|
||||
|
@ -504,3 +519,60 @@ func isFile(s string) bool {
|
|||
_, err := os.Stat(s)
|
||||
return !errors.Is(err, os.ErrNotExist)
|
||||
}
|
||||
|
||||
// ProcessFlagAliases updates the value of flags that are being set by helper flags
|
||||
func ProcessFlagAliases(flags *pflag.FlagSet) {
|
||||
|
||||
porcelain, err := flags.GetString(`porcelain`)
|
||||
if err != nil {
|
||||
log.Fatalf(`Failed to get flag: %v`, err)
|
||||
}
|
||||
if porcelain != "" {
|
||||
if porcelain != "v1" {
|
||||
log.Fatalf(`Unknown porcelain version %q. Supported values: "v1"`, porcelain)
|
||||
}
|
||||
if err = appendFlagValue(flags, `notification-url`, `logger://`); err != nil {
|
||||
log.Errorf(`Failed to set flag: %v`, err)
|
||||
}
|
||||
setFlagIfDefault(flags, `notification-log-stdout`, `true`)
|
||||
setFlagIfDefault(flags, `notification-report`, `true`)
|
||||
tpl := fmt.Sprintf(`porcelain.%s.summary-no-log`, porcelain)
|
||||
setFlagIfDefault(flags, `notification-template`, tpl)
|
||||
}
|
||||
|
||||
if flags.Changed(`interval`) && flags.Changed(`schedule`) {
|
||||
log.Fatal(`Only schedule or interval can be defined, not both.`)
|
||||
}
|
||||
|
||||
// update schedule flag to match interval if it's set, or to the default if none of them are
|
||||
if flags.Changed(`interval`) || !flags.Changed(`schedule`) {
|
||||
interval, _ := flags.GetInt(`interval`)
|
||||
flags.Set(`schedule`, fmt.Sprintf(`@every %ds`, interval))
|
||||
}
|
||||
}
|
||||
|
||||
func appendFlagValue(flags *pflag.FlagSet, name string, values ...string) error {
|
||||
flag := flags.Lookup(name)
|
||||
if flag == nil {
|
||||
return fmt.Errorf(`invalid flag name %q`, name)
|
||||
}
|
||||
|
||||
if flagValues, ok := flag.Value.(pflag.SliceValue); ok {
|
||||
for _, value := range values {
|
||||
flagValues.Append(value)
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf(`the value for flag %q is not a slice value`, name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func setFlagIfDefault(flags *pflag.FlagSet, name string, value string) {
|
||||
if flags.Changed(name) {
|
||||
return
|
||||
}
|
||||
if err := flags.Set(name, value); err != nil {
|
||||
log.Errorf(`Failed to set flag: %v`, err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -127,3 +128,71 @@ func TestIsFile(t *testing.T) {
|
|||
assert.False(t, isFile("https://google.com"), "an URL should never be considered a file")
|
||||
assert.True(t, isFile(os.Args[0]), "the currently running binary path should always be considered a file")
|
||||
}
|
||||
|
||||
func TestReadFlags(t *testing.T) {
|
||||
logrus.StandardLogger().ExitFunc = func(_ int) { t.FailNow() }
|
||||
|
||||
}
|
||||
|
||||
func TestProcessFlagAliases(t *testing.T) {
|
||||
logrus.StandardLogger().ExitFunc = func(_ int) { t.FailNow() }
|
||||
cmd := new(cobra.Command)
|
||||
SetDefaults()
|
||||
RegisterDockerFlags(cmd)
|
||||
RegisterSystemFlags(cmd)
|
||||
RegisterNotificationFlags(cmd)
|
||||
|
||||
require.NoError(t, cmd.ParseFlags([]string{
|
||||
`--porcelain`, `v1`,
|
||||
`--interval`, `10`,
|
||||
}))
|
||||
flags := cmd.Flags()
|
||||
ProcessFlagAliases(flags)
|
||||
|
||||
urls, _ := flags.GetStringArray(`notification-url`)
|
||||
assert.Contains(t, urls, `logger://`)
|
||||
|
||||
logStdout, _ := flags.GetBool(`notification-log-stdout`)
|
||||
assert.True(t, logStdout)
|
||||
|
||||
report, _ := flags.GetBool(`notification-report`)
|
||||
assert.True(t, report)
|
||||
|
||||
template, _ := flags.GetString(`notification-template`)
|
||||
assert.Equal(t, `porcelain.v1.summary-no-log`, template)
|
||||
|
||||
sched, _ := flags.GetString(`schedule`)
|
||||
assert.Equal(t, `@every 10s`, sched)
|
||||
}
|
||||
|
||||
func TestProcessFlagAliasesSchedAndInterval(t *testing.T) {
|
||||
logrus.StandardLogger().ExitFunc = func(_ int) { panic(`FATAL`) }
|
||||
cmd := new(cobra.Command)
|
||||
SetDefaults()
|
||||
RegisterDockerFlags(cmd)
|
||||
RegisterSystemFlags(cmd)
|
||||
RegisterNotificationFlags(cmd)
|
||||
|
||||
require.NoError(t, cmd.ParseFlags([]string{`--schedule`, `@now`, `--interval`, `10`}))
|
||||
flags := cmd.Flags()
|
||||
|
||||
assert.PanicsWithValue(t, `FATAL`, func() {
|
||||
ProcessFlagAliases(flags)
|
||||
})
|
||||
}
|
||||
|
||||
func TestProcessFlagAliasesInvalidPorcelaineVersion(t *testing.T) {
|
||||
logrus.StandardLogger().ExitFunc = func(_ int) { panic(`FATAL`) }
|
||||
cmd := new(cobra.Command)
|
||||
SetDefaults()
|
||||
RegisterDockerFlags(cmd)
|
||||
RegisterSystemFlags(cmd)
|
||||
RegisterNotificationFlags(cmd)
|
||||
|
||||
require.NoError(t, cmd.ParseFlags([]string{`--porcelain`, `cowboy`}))
|
||||
flags := cmd.Flags()
|
||||
|
||||
assert.PanicsWithValue(t, `FATAL`, func() {
|
||||
ProcessFlagAliases(flags)
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue