From 67cdf91f94a16fdb7122c2e450addd88c931ca6c Mon Sep 17 00:00:00 2001 From: mmetc <92726601+mmetc@users.noreply.github.com> Date: Thu, 14 Dec 2023 09:16:38 +0100 Subject: [PATCH] Short build tag in version number (#2658) * use short commit hash in version number * var -> const * cscli: extract version.go, doc.go * don't repeat commit hash in version number --- cmd/crowdsec-cli/doc.go | 49 ++++++++++++ cmd/crowdsec-cli/main.go | 154 +++++++++++++----------------------- cmd/crowdsec-cli/version.go | 27 +++++++ mk/platform.mk | 2 +- pkg/cwversion/version.go | 32 ++++++-- test/bats/01_cscli.bats | 2 +- 6 files changed, 159 insertions(+), 107 deletions(-) create mode 100644 cmd/crowdsec-cli/doc.go create mode 100644 cmd/crowdsec-cli/version.go diff --git a/cmd/crowdsec-cli/doc.go b/cmd/crowdsec-cli/doc.go new file mode 100644 index 000000000..a4896f3da --- /dev/null +++ b/cmd/crowdsec-cli/doc.go @@ -0,0 +1,49 @@ +package main + +import ( + "fmt" + "path/filepath" + "strings" + + "github.com/spf13/cobra" + "github.com/spf13/cobra/doc" +) + +type cliDoc struct{} + +func NewCLIDoc() *cliDoc { + return &cliDoc{} +} + +func (cli cliDoc) NewCommand(rootCmd *cobra.Command) *cobra.Command { + cmd := &cobra.Command{ + Use: "doc", + Short: "Generate the documentation in `./doc/`. Directory must exist.", + Args: cobra.ExactArgs(0), + Hidden: true, + DisableAutoGenTag: true, + RunE: func(_ *cobra.Command, _ []string) error { + if err := doc.GenMarkdownTreeCustom(rootCmd, "./doc/", cli.filePrepender, cli.linkHandler); err != nil { + return fmt.Errorf("failed to generate cobra doc: %s", err) + } + return nil + }, + } + + return cmd +} + +func (cli cliDoc) filePrepender(filename string) string { + const header = `--- +id: %s +title: %s +--- +` + name := filepath.Base(filename) + base := strings.TrimSuffix(name, filepath.Ext(name)) + return fmt.Sprintf(header, base, strings.ReplaceAll(base, "_", " ")) +} + +func (cli cliDoc) linkHandler(name string) string { + return fmt.Sprintf("/cscli/%s", name) +} diff --git a/cmd/crowdsec-cli/main.go b/cmd/crowdsec-cli/main.go index a187e432b..380e984e8 100644 --- a/cmd/crowdsec-cli/main.go +++ b/cmd/crowdsec-cli/main.go @@ -1,21 +1,15 @@ package main import ( - "fmt" "os" - "path/filepath" - "strings" - - "slices" "github.com/fatih/color" cc "github.com/ivanpirog/coloredcobra" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" - "github.com/spf13/cobra/doc" + "slices" "github.com/crowdsecurity/crowdsec/pkg/csconfig" - "github.com/crowdsecurity/crowdsec/pkg/cwversion" "github.com/crowdsecurity/crowdsec/pkg/database" "github.com/crowdsecurity/crowdsec/pkg/fflag" ) @@ -36,6 +30,7 @@ var flagBranch = "" func initConfig() { var err error + if trace_lvl { log.SetLevel(log.TraceLevel) } else if dbg_lvl { @@ -70,6 +65,7 @@ func initConfig() { if OutputFormat != "" { csConfig.Cscli.Output = OutputFormat + if OutputFormat != "json" && OutputFormat != "raw" && OutputFormat != "human" { log.Fatalf("output format %s unknown", OutputFormat) } @@ -86,12 +82,14 @@ func initConfig() { if OutputColor != "" { csConfig.Cscli.Color = OutputColor + if OutputColor != "yes" && OutputColor != "no" && OutputColor != "auto" { log.Fatalf("output color %s unknown", OutputColor) } } } +// list of valid subcommands for the shell completion var validArgs = []string{ "alerts", "appsec-configs", "appsec-rules", "bouncers", "capi", "collections", "completion", "config", "console", "contexts", "dashboard", "decisions", "explain", @@ -99,30 +97,14 @@ var validArgs = []string{ "postoverflows", "scenarios", "simulation", "support", "version", } -func prepender(filename string) string { - const header = `--- -id: %s -title: %s ---- -` - name := filepath.Base(filename) - base := strings.TrimSuffix(name, filepath.Ext(name)) - return fmt.Sprintf(header, base, strings.ReplaceAll(base, "_", " ")) +var NoNeedConfig = []string{ + "doc", + "help", + "completion", + "version", + "hubtest", } -func linkHandler(name string) string { - return fmt.Sprintf("/cscli/%s", name) -} - -var ( - NoNeedConfig = []string{ - "help", - "completion", - "version", - "hubtest", - } -) - func main() { // set the formatter asap and worry about level later logFormatter := &log.TextFormatter{TimestampFormat: "2006-01-02 15:04:05", FullTimestamp: true} @@ -136,7 +118,7 @@ func main() { log.Fatalf("failed to set feature flags from env: %s", err) } - var rootCmd = &cobra.Command{ + cmd := &cobra.Command{ Use: "cscli", Short: "cscli allows you to manage crowdsec", Long: `cscli is the main command to interact with your crowdsec service, scenarios & db. @@ -149,7 +131,7 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall } cc.Init(&cc.Config{ - RootCmd: rootCmd, + RootCmd: cmd, Headings: cc.Yellow, Commands: cc.Green + cc.Bold, CmdShortDescr: cc.Cyan, @@ -160,45 +142,19 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall Flags: cc.Green, FlagsDescr: cc.Cyan, }) - rootCmd.SetOut(color.Output) + cmd.SetOut(color.Output) - var cmdDocGen = &cobra.Command{ - Use: "doc", - Short: "Generate the documentation in `./doc/`. Directory must exist.", - Args: cobra.ExactArgs(0), - Hidden: true, - DisableAutoGenTag: true, - RunE: func(cmd *cobra.Command, args []string) error { - if err := doc.GenMarkdownTreeCustom(rootCmd, "./doc/", prepender, linkHandler); err != nil { - return fmt.Errorf("Failed to generate cobra doc: %s", err) - } - return nil - }, - } - rootCmd.AddCommand(cmdDocGen) - /*usage*/ - var cmdVersion = &cobra.Command{ - Use: "version", - Short: "Display version", - Args: cobra.ExactArgs(0), - DisableAutoGenTag: true, - Run: func(cmd *cobra.Command, args []string) { - cwversion.Show() - }, - } - rootCmd.AddCommand(cmdVersion) + cmd.PersistentFlags().StringVarP(&ConfigFilePath, "config", "c", csconfig.DefaultConfigPath("config.yaml"), "path to crowdsec config file") + cmd.PersistentFlags().StringVarP(&OutputFormat, "output", "o", "", "Output format: human, json, raw") + cmd.PersistentFlags().StringVarP(&OutputColor, "color", "", "auto", "Output color: yes, no, auto") + cmd.PersistentFlags().BoolVar(&dbg_lvl, "debug", false, "Set logging to debug") + cmd.PersistentFlags().BoolVar(&nfo_lvl, "info", false, "Set logging to info") + cmd.PersistentFlags().BoolVar(&wrn_lvl, "warning", false, "Set logging to warning") + cmd.PersistentFlags().BoolVar(&err_lvl, "error", false, "Set logging to error") + cmd.PersistentFlags().BoolVar(&trace_lvl, "trace", false, "Set logging to trace") - rootCmd.PersistentFlags().StringVarP(&ConfigFilePath, "config", "c", csconfig.DefaultConfigPath("config.yaml"), "path to crowdsec config file") - rootCmd.PersistentFlags().StringVarP(&OutputFormat, "output", "o", "", "Output format: human, json, raw") - rootCmd.PersistentFlags().StringVarP(&OutputColor, "color", "", "auto", "Output color: yes, no, auto") - rootCmd.PersistentFlags().BoolVar(&dbg_lvl, "debug", false, "Set logging to debug") - rootCmd.PersistentFlags().BoolVar(&nfo_lvl, "info", false, "Set logging to info") - rootCmd.PersistentFlags().BoolVar(&wrn_lvl, "warning", false, "Set logging to warning") - rootCmd.PersistentFlags().BoolVar(&err_lvl, "error", false, "Set logging to error") - rootCmd.PersistentFlags().BoolVar(&trace_lvl, "trace", false, "Set logging to trace") - - rootCmd.PersistentFlags().StringVar(&flagBranch, "branch", "", "Override hub branch on github") - if err := rootCmd.PersistentFlags().MarkHidden("branch"); err != nil { + cmd.PersistentFlags().StringVar(&flagBranch, "branch", "", "Override hub branch on github") + if err := cmd.PersistentFlags().MarkHidden("branch"); err != nil { log.Fatalf("failed to hide flag: %s", err) } @@ -222,44 +178,46 @@ It is meant to allow you to manage bans, parsers/scenarios/etc, api and generall } /*don't sort flags so we can enforce order*/ - rootCmd.Flags().SortFlags = false - rootCmd.PersistentFlags().SortFlags = false + cmd.Flags().SortFlags = false + cmd.PersistentFlags().SortFlags = false - rootCmd.AddCommand(NewConfigCmd()) - rootCmd.AddCommand(NewCLIHub().NewCommand()) - rootCmd.AddCommand(NewMetricsCmd()) - rootCmd.AddCommand(NewCLIDashboard().NewCommand()) - rootCmd.AddCommand(NewCLIDecisions().NewCommand()) - rootCmd.AddCommand(NewCLIAlerts().NewCommand()) - rootCmd.AddCommand(NewCLISimulation().NewCommand()) - rootCmd.AddCommand(NewCLIBouncers().NewCommand()) - rootCmd.AddCommand(NewCLIMachines().NewCommand()) - rootCmd.AddCommand(NewCLICapi().NewCommand()) - rootCmd.AddCommand(NewLapiCmd()) - rootCmd.AddCommand(NewCompletionCmd()) - rootCmd.AddCommand(NewConsoleCmd()) - rootCmd.AddCommand(NewCLIExplain().NewCommand()) - rootCmd.AddCommand(NewCLIHubTest().NewCommand()) - rootCmd.AddCommand(NewCLINotifications().NewCommand()) - rootCmd.AddCommand(NewCLISupport().NewCommand()) - rootCmd.AddCommand(NewCLIPapi().NewCommand()) - rootCmd.AddCommand(NewCLICollection().NewCommand()) - rootCmd.AddCommand(NewCLIParser().NewCommand()) - rootCmd.AddCommand(NewCLIScenario().NewCommand()) - rootCmd.AddCommand(NewCLIPostOverflow().NewCommand()) - rootCmd.AddCommand(NewCLIContext().NewCommand()) - rootCmd.AddCommand(NewCLIAppsecConfig().NewCommand()) - rootCmd.AddCommand(NewCLIAppsecRule().NewCommand()) + cmd.AddCommand(NewCLIDoc().NewCommand(cmd)) + cmd.AddCommand(NewCLIVersion().NewCommand()) + cmd.AddCommand(NewConfigCmd()) + cmd.AddCommand(NewCLIHub().NewCommand()) + cmd.AddCommand(NewMetricsCmd()) + cmd.AddCommand(NewCLIDashboard().NewCommand()) + cmd.AddCommand(NewCLIDecisions().NewCommand()) + cmd.AddCommand(NewCLIAlerts().NewCommand()) + cmd.AddCommand(NewCLISimulation().NewCommand()) + cmd.AddCommand(NewCLIBouncers().NewCommand()) + cmd.AddCommand(NewCLIMachines().NewCommand()) + cmd.AddCommand(NewCLICapi().NewCommand()) + cmd.AddCommand(NewLapiCmd()) + cmd.AddCommand(NewCompletionCmd()) + cmd.AddCommand(NewConsoleCmd()) + cmd.AddCommand(NewCLIExplain().NewCommand()) + cmd.AddCommand(NewCLIHubTest().NewCommand()) + cmd.AddCommand(NewCLINotifications().NewCommand()) + cmd.AddCommand(NewCLISupport().NewCommand()) + cmd.AddCommand(NewCLIPapi().NewCommand()) + cmd.AddCommand(NewCLICollection().NewCommand()) + cmd.AddCommand(NewCLIParser().NewCommand()) + cmd.AddCommand(NewCLIScenario().NewCommand()) + cmd.AddCommand(NewCLIPostOverflow().NewCommand()) + cmd.AddCommand(NewCLIContext().NewCommand()) + cmd.AddCommand(NewCLIAppsecConfig().NewCommand()) + cmd.AddCommand(NewCLIAppsecRule().NewCommand()) if fflag.CscliSetup.IsEnabled() { - rootCmd.AddCommand(NewSetupCmd()) + cmd.AddCommand(NewSetupCmd()) } if fflag.PapiClient.IsEnabled() { - rootCmd.AddCommand(NewCLIPapi().NewCommand()) + cmd.AddCommand(NewCLIPapi().NewCommand()) } - if err := rootCmd.Execute(); err != nil { + if err := cmd.Execute(); err != nil { log.Fatal(err) } } diff --git a/cmd/crowdsec-cli/version.go b/cmd/crowdsec-cli/version.go new file mode 100644 index 000000000..de36c9be2 --- /dev/null +++ b/cmd/crowdsec-cli/version.go @@ -0,0 +1,27 @@ +package main + +import ( + "github.com/spf13/cobra" + + "github.com/crowdsecurity/crowdsec/pkg/cwversion" +) + +type cliVersion struct{} + +func NewCLIVersion() *cliVersion { + return &cliVersion{} +} + +func (cli cliVersion) NewCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "version", + Short: "Display version", + Args: cobra.ExactArgs(0), + DisableAutoGenTag: true, + Run: func(_ *cobra.Command, _ []string) { + cwversion.Show() + }, + } + + return cmd +} diff --git a/mk/platform.mk b/mk/platform.mk index 9e375de3e..b639723b6 100644 --- a/mk/platform.mk +++ b/mk/platform.mk @@ -1,7 +1,7 @@ BUILD_CODENAME ?= alphaga GOARCH ?= $(shell go env GOARCH) -BUILD_TAG ?= $(shell git rev-parse HEAD) +BUILD_TAG ?= $(shell git rev-parse --short HEAD) ifeq ($(OS), Windows_NT) SHELL := pwsh.exe diff --git a/pkg/cwversion/version.go b/pkg/cwversion/version.go index 1ea5a0961..7ebce5375 100644 --- a/pkg/cwversion/version.go +++ b/pkg/cwversion/version.go @@ -9,32 +9,45 @@ import ( "strings" goversion "github.com/hashicorp/go-version" - + "github.com/crowdsecurity/go-cs-lib/version" ) var ( - Codename string // = "SoumSoum" - System = runtime.GOOS // = "linux" + Codename string // = "SoumSoum" + System = runtime.GOOS // = "linux" + Libre2 = "WebAssembly" +) + +const ( Constraint_parser = ">= 1.0, <= 2.0" Constraint_scenario = ">= 1.0, < 3.0" Constraint_api = "v1" Constraint_acquis = ">= 1.0, < 2.0" - Libre2 = "WebAssembly" ) +func versionWithTag() string { + ret := version.Version + + if !strings.HasSuffix(ret, version.Tag) { + ret += fmt.Sprintf("-%s", version.Tag) + } + + return ret +} + func ShowStr() string { - ret := "" - ret += fmt.Sprintf("version: %s-%s\n", version.Version, version.Tag) + ret := fmt.Sprintf("version: %s", versionWithTag()) ret += fmt.Sprintf("Codename: %s\n", Codename) ret += fmt.Sprintf("BuildDate: %s\n", version.BuildDate) ret += fmt.Sprintf("GoVersion: %s\n", version.GoVersion) ret += fmt.Sprintf("Platform: %s\n", System) + return ret } func Show() { - log.Printf("version: %s-%s", version.Version, version.Tag) + log.Printf("version: %s", versionWithTag()) log.Printf("Codename: %s", Codename) log.Printf("BuildDate: %s", version.BuildDate) log.Printf("GoVersion: %s", version.GoVersion) @@ -53,6 +66,7 @@ func VersionStr() string { func VersionStrip() string { version := strings.Split(version.Version, "~") version = strings.Split(version[0], "-") + return version[0] } @@ -61,13 +75,16 @@ func Satisfies(strvers string, constraint string) (bool, error) { if err != nil { return false, fmt.Errorf("failed to parse '%s' : %v", strvers, err) } + constraints, err := goversion.NewConstraint(constraint) if err != nil { return false, fmt.Errorf("failed to parse constraint '%s'", constraint) } + if !constraints.Check(vers) { return false, nil } + return true, nil } @@ -85,6 +102,7 @@ func Latest() (string, error) { if err != nil { return "", err } + if _, ok := latest["name"]; !ok { return "", fmt.Errorf("unable to find latest release name from github api: %+v", latest) } diff --git a/test/bats/01_cscli.bats b/test/bats/01_cscli.bats index 3f49a1299..d99510f98 100644 --- a/test/bats/01_cscli.bats +++ b/test/bats/01_cscli.bats @@ -334,7 +334,7 @@ teardown() { cd "$BATS_TEST_TMPDIR" rune -1 cscli doc refute_output - assert_stderr --regexp 'Failed to generate cobra doc: open doc/.*: no such file or directory' + assert_stderr --regexp 'failed to generate cobra doc: open doc/.*: no such file or directory' mkdir -p doc rune -0 cscli doc