diff --git a/cmd/rhc/canonical_facts_cmd.go b/cmd/rhc/canonical_facts_cmd.go index f8266dfb..87a466ce 100644 --- a/cmd/rhc/canonical_facts_cmd.go +++ b/cmd/rhc/canonical_facts_cmd.go @@ -1,17 +1,17 @@ package main import ( + "context" "encoding/json" "fmt" - "github.com/urfave/cli/v2" - "github.com/redhatinsights/rhc/internal/canonical_facts" + "github.com/urfave/cli/v3" ) // canonicalFactAction tries to gather canonical facts about system, // and it prints JSON with facts to stdout. -func canonicalFactAction(_ *cli.Context) error { +func canonicalFactAction(_ context.Context, _ *cli.Command) error { // NOTE: CLI context is not useful for anything facts, err := canonical_facts.GetCanonicalFacts() if err != nil { diff --git a/cmd/rhc/collector_cmd.go b/cmd/rhc/collector_cmd.go index 45e7cc49..227a0e80 100644 --- a/cmd/rhc/collector_cmd.go +++ b/cmd/rhc/collector_cmd.go @@ -1,6 +1,7 @@ package main import ( + "context" "encoding/json" "fmt" "log/slog" @@ -8,11 +9,11 @@ import ( "strings" "github.com/emersion/go-varlink" - "github.com/urfave/cli/v2" "github.com/redhatinsights/rhc/internal/collector" "github.com/redhatinsights/rhc/internal/ui" "github.com/redhatinsights/rhc/varlink/collectorapi" + "github.com/urfave/cli/v3" ) const rhcServerSocket = "/run/rhc/com.redhat.rhc" @@ -36,19 +37,19 @@ func newCollectorClient() (*collectorapi.Client, func(), error) { } // beforeCollectorInfoAction validates the collector info command arguments and configuration. -func beforeCollectorInfoAction(ctx *cli.Context) error { - return validateCollectorCommand(ctx, true, true) +func beforeCollectorInfoAction(ctx context.Context, cmd *cli.Command) (context.Context, error) { + return ctx, validateCollectorCommand(cmd, true, true) } // collectorInfoAction retrieves and displays information for a specific collector. -func collectorInfoAction(ctx *cli.Context) error { - logCommandStart(ctx) +func collectorInfoAction(ctx context.Context, cmd *cli.Command) error { + logCommandStart(cmd) client, cleanup, err := newCollectorClient() if err != nil { return cli.Exit(fmt.Sprintf("failed to connect to rhc-server: %v", err), ExitCodeErr) } defer cleanup() - response, err := client.Info(&collectorapi.InfoIn{Id: ctx.Args().First()}) + response, err := client.Info(&collectorapi.InfoIn{Id: cmd.Args().First()}) if err != nil { return cli.Exit(fmt.Sprintf("failed to get collector info: %v", err), ExitCodeErr) } @@ -57,13 +58,13 @@ func collectorInfoAction(ctx *cli.Context) error { } // beforeCollectorListAction validates the collector list command configuration. -func beforeCollectorListAction(ctx *cli.Context) error { - return validateCollectorCommand(ctx, false, true) +func beforeCollectorListAction(ctx context.Context, cmd *cli.Command) (context.Context, error) { + return ctx, validateCollectorCommand(cmd, false, true) } // collectorListAction retrieves and displays a list of all available collectors. -func collectorListAction(ctx *cli.Context) error { - logCommandStart(ctx) +func collectorListAction(ctx context.Context, cmd *cli.Command) error { + logCommandStart(cmd) client, cleanup, err := newCollectorClient() if err != nil { @@ -100,13 +101,13 @@ func collectorListAction(ctx *cli.Context) error { } // beforeCollectorTimersAction validates the collector timers command configuration. -func beforeCollectorTimersAction(ctx *cli.Context) error { - return validateCollectorCommand(ctx, false, true) +func beforeCollectorTimersAction(ctx context.Context, cmd *cli.Command) (context.Context, error) { + return ctx, validateCollectorCommand(cmd, false, true) } // collectorTimersAction retrieves and displays timer information for all collectors. -func collectorTimersAction(ctx *cli.Context) error { - logCommandStart(ctx) +func collectorTimersAction(ctx context.Context, cmd *cli.Command) error { + logCommandStart(cmd) client, cleanup, err := newCollectorClient() if err != nil { @@ -129,15 +130,15 @@ func collectorTimersAction(ctx *cli.Context) error { } // beforeCollectorEnableAction validates the collector enable command arguments. -func beforeCollectorEnableAction(ctx *cli.Context) error { - return validateCollectorCommand(ctx, true, false) +func beforeCollectorEnableAction(ctx context.Context, cmd *cli.Command) (context.Context, error) { + return ctx, validateCollectorCommand(cmd, true, false) } // collectorEnableAction enables a collector timer and optionally triggers immediate collection. -func collectorEnableAction(ctx *cli.Context) error { - logCommandStart(ctx) - collectorId := ctx.Args().First() - nowFlag := ctx.Bool("now") +func collectorEnableAction(ctx context.Context, cmd *cli.Command) error { + logCommandStart(cmd) + collectorId := cmd.Args().First() + nowFlag := cmd.Bool("now") conn, timerName, err := collector.ValidateCollectorAndConnect(collectorId) if err != nil { return cli.Exit(fmt.Sprintf("%v", err), ExitCodeErr) @@ -166,15 +167,15 @@ func collectorEnableAction(ctx *cli.Context) error { } // beforeCollectorDisableAction validates the collector disable command arguments. -func beforeCollectorDisableAction(ctx *cli.Context) error { - return validateCollectorCommand(ctx, true, false) +func beforeCollectorDisableAction(ctx context.Context, cmd *cli.Command) (context.Context, error) { + return ctx, validateCollectorCommand(cmd, true, false) } // collectorDisableAction disables a collector timer and optionally stops immediate collection. -func collectorDisableAction(ctx *cli.Context) error { - logCommandStart(ctx) - collectorId := ctx.Args().First() - nowFlag := ctx.Bool("now") +func collectorDisableAction(ctx context.Context, cmd *cli.Command) error { + logCommandStart(cmd) + collectorId := cmd.Args().First() + nowFlag := cmd.Bool("now") conn, timerName, err := collector.ValidateCollectorAndConnect(collectorId) if err != nil { return cli.Exit(fmt.Sprintf("%v", err), ExitCodeErr) diff --git a/cmd/rhc/configure_features_cmd.go b/cmd/rhc/configure_features_cmd.go index 4bfa6f2d..2a1bf8f9 100644 --- a/cmd/rhc/configure_features_cmd.go +++ b/cmd/rhc/configure_features_cmd.go @@ -1,12 +1,13 @@ package main import ( + "context" "fmt" "log/slog" "os" "text/tabwriter" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" "github.com/redhatinsights/rhc/internal/rhsm" "github.com/redhatinsights/rhc/pkg/feature" @@ -21,30 +22,30 @@ import ( // TODO Use ui.Icons.Ok when we have UTF-8 capable tabwriter // beforeFeaturesStatusAction validates inputs before executing the status action. -func beforeFeaturesStatusAction(ctx *cli.Context) error { - err := checkFormatFlag(ctx) +func beforeFeaturesStatusAction(ctx context.Context, cmd *cli.Command) (context.Context, error) { + err := checkFormatFlag(cmd) if err != nil { - return err + return ctx, err } - configureUI(ctx) - return checkForUnknownArgs(ctx) + configureUI(cmd) + return ctx, checkForUnknownArgs(cmd) } // featuresStatusAction displays the current status or preferences of all features. -func featuresStatusAction(ctx *cli.Context) error { - logCommandStart(ctx) +func featuresStatusAction(ctx context.Context, cmd *cli.Command) error { + logCommandStart(cmd) isRegistered, err := rhsm.IsRHSMRegistered() if err != nil { return err } if isRegistered { - return featuresStatusActionRegistered(ctx) + return featuresStatusActionRegistered(ctx, cmd) } - return featuresStatusActionNotRegistered(ctx) + return featuresStatusActionNotRegistered(ctx, cmd) } -func featuresStatusActionNotRegistered(_ *cli.Context) error { +func featuresStatusActionNotRegistered(_ context.Context, _ *cli.Command) error { cache, err := prefcache.LoadCache(ConnectFeaturesPrefsPath) if err != nil { return err @@ -68,7 +69,7 @@ func featuresStatusActionNotRegistered(_ *cli.Context) error { return nil } -func featuresStatusActionRegistered(_ *cli.Context) error { +func featuresStatusActionRegistered(_ context.Context, _ *cli.Command) error { fmt.Println("Connected to Red Hat.") fmt.Println("") w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) @@ -88,39 +89,39 @@ func featuresStatusActionRegistered(_ *cli.Context) error { } // beforeFeaturesEnableAction validates inputs before executing the enable action. -func beforeFeaturesEnableAction(ctx *cli.Context) error { - err := checkFormatFlag(ctx) +func beforeFeaturesEnableAction(ctx context.Context, cmd *cli.Command) (context.Context, error) { + err := checkFormatFlag(cmd) if err != nil { - return err + return ctx, err } - configureUI(ctx) + configureUI(cmd) - if ctx.Args().Len() != 1 { - return cli.Exit("this command requires a single FEATURE argument", ExitCodeUsage) + if cmd.Args().Len() != 1 { + return ctx, cli.Exit("this command requires a single FEATURE argument", ExitCodeUsage) } - if _, err = feature.Get(ctx.Args().First()); err != nil { - return cli.Exit(err.Error(), ExitCodeDataErr) + if _, err = feature.Get(cmd.Args().First()); err != nil { + return ctx, cli.Exit(err.Error(), ExitCodeDataErr) } - return nil + return ctx, nil } // featuresEnableAction enables a single feature. -func featuresEnableAction(ctx *cli.Context) error { - logCommandStart(ctx) +func featuresEnableAction(ctx context.Context, cmd *cli.Command) error { + logCommandStart(cmd) isRegistered, err := rhsm.IsRHSMRegistered() if err != nil { return cli.Exit(fmt.Sprintf("failed to check registration status: %v", err), ExitCodeSoftware) } - requestedFeature := ctx.Args().First() + requestedFeature := cmd.Args().First() if isRegistered { - return featuresEnableActionRegistered(ctx, requestedFeature) + return featuresEnableActionRegistered(ctx, cmd, requestedFeature) } - return featuresEnableActionNotRegistered(ctx, requestedFeature) + return featuresEnableActionNotRegistered(ctx, cmd, requestedFeature) } // featuresEnableActionNotRegistered handles enabling a feature on a non-registered system. -func featuresEnableActionNotRegistered(_ *cli.Context, targetName string) error { +func featuresEnableActionNotRegistered(_ context.Context, _ *cli.Command, targetName string) error { cache, err := prefcache.LoadCache(ConnectFeaturesPrefsPath) if err != nil { return cli.Exit(fmt.Sprintf("failed to load feature preferences: %v", err), ExitCodeSoftware) @@ -164,7 +165,7 @@ func featuresEnableActionNotRegistered(_ *cli.Context, targetName string) error } // featuresEnableActionRegistered handles enabling a feature on a registered system. -func featuresEnableActionRegistered(_ *cli.Context, targetName string) error { +func featuresEnableActionRegistered(_ context.Context, _ *cli.Command, targetName string) error { target := feature.MustGet(targetName) // enable required features @@ -203,39 +204,39 @@ func featuresEnableActionRegistered(_ *cli.Context, targetName string) error { } // beforeFeaturesDisableAction validates inputs before executing the disable action. -func beforeFeaturesDisableAction(ctx *cli.Context) error { - err := checkFormatFlag(ctx) +func beforeFeaturesDisableAction(ctx context.Context, cmd *cli.Command) (context.Context, error) { + err := checkFormatFlag(cmd) if err != nil { - return err + return ctx, err } - configureUI(ctx) + configureUI(cmd) - if ctx.Args().Len() != 1 { - return cli.Exit("this command requires a single FEATURE argument", ExitCodeUsage) + if cmd.Args().Len() != 1 { + return ctx, cli.Exit("this command requires a single FEATURE argument", ExitCodeUsage) } - if _, err = feature.Get(ctx.Args().First()); err != nil { - return cli.Exit(err.Error(), ExitCodeDataErr) + if _, err = feature.Get(cmd.Args().First()); err != nil { + return ctx, cli.Exit(err.Error(), ExitCodeDataErr) } - return nil + return ctx, nil } // featuresDisableAction disables a single feature. -func featuresDisableAction(ctx *cli.Context) error { - logCommandStart(ctx) +func featuresDisableAction(ctx context.Context, cmd *cli.Command) error { + logCommandStart(cmd) isRegistered, err := rhsm.IsRHSMRegistered() if err != nil { return cli.Exit(fmt.Sprintf("failed to check registration status: %v", err), ExitCodeSoftware) } - requestedFeature := ctx.Args().First() + requestedFeature := cmd.Args().First() if isRegistered { - return featuresDisableActionRegistered(ctx, requestedFeature) + return featuresDisableActionRegistered(ctx, cmd, requestedFeature) } - return featuresDisableActionNotRegistered(ctx, requestedFeature) + return featuresDisableActionNotRegistered(ctx, cmd, requestedFeature) } // featuresDisableActionNotRegistered handles disabling a feature on a non-registered system. -func featuresDisableActionNotRegistered(_ *cli.Context, targetName string) error { +func featuresDisableActionNotRegistered(_ context.Context, _ *cli.Command, targetName string) error { cache, err := prefcache.LoadCache(ConnectFeaturesPrefsPath) if err != nil { return cli.Exit(fmt.Sprintf("failed to load feature preferences: %v", err), ExitCodeSoftware) @@ -279,7 +280,7 @@ func featuresDisableActionNotRegistered(_ *cli.Context, targetName string) error } // featuresDisableActionRegistered handles disabling a feature on a registered system. -func featuresDisableActionRegistered(_ *cli.Context, targetName string) error { +func featuresDisableActionRegistered(_ context.Context, _ *cli.Command, targetName string) error { target := feature.MustGet(targetName) // disable dependent features diff --git a/cmd/rhc/connect_cmd.go b/cmd/rhc/connect_cmd.go index a7eee42c..1520863e 100644 --- a/cmd/rhc/connect_cmd.go +++ b/cmd/rhc/connect_cmd.go @@ -1,6 +1,7 @@ package main import ( + "context" "encoding/json" "fmt" "log/slog" @@ -8,7 +9,7 @@ import ( "strings" "time" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" "github.com/redhatinsights/rhc/internal/datacollection" "github.com/redhatinsights/rhc/internal/remotemanagement" @@ -76,9 +77,9 @@ func (connectResult *ConnectResult) errorMessages() map[string]string { // TryRegisterRHSM will attempt to register the system with Red Hat Subscription Management. // If this fails, then both RHSMConnected and Features.Content.Successful will be set to false, and the error message // will be stored in RHSMConnectError. -func (connectResult *ConnectResult) TryRegisterRHSM(ctx *cli.Context, enableContent bool) { +func (connectResult *ConnectResult) TryRegisterRHSM(cmd *cli.Command, enableContent bool) { slog.Info("Registering the system with Red Hat Subscription Management") - returnedMsg, err := rhsm.RegisterRHSM(ctx, enableContent) + returnedMsg, err := rhsm.RegisterRHSM(cmd, enableContent) if err != nil { connectResult.RHSMConnected = false connectResult.RHSMConnectError = fmt.Sprintf("cannot connect to Red Hat Subscription Management: %s", err) @@ -209,43 +210,43 @@ func checkFeatureFlags(toEnable, toDisable []string) error { // beforeConnectAction ensures correct CLI flags have been passed in: // correct values, no conflicts. On error, this method invokes cli.Exit() // with appropriate message and error code. -func beforeConnectAction(ctx *cli.Context) error { +func beforeConnectAction(ctx context.Context, cmd *cli.Command) (context.Context, error) { // Verify --format contains valid value - err := checkFormatFlag(ctx) + err := checkFormatFlag(cmd) if err != nil { - return err + return ctx, err } // Configure UI globals - configureUI(ctx) + configureUI(cmd) // Validate --enable-feature/--disable-feature combinations make sense err = checkFeatureFlags( - ctx.StringSlice("enable-feature"), - ctx.StringSlice("disable-feature"), + cmd.StringSlice("enable-feature"), + cmd.StringSlice("disable-feature"), ) if err != nil { - return cli.Exit(err.Error(), ExitCodeUsage) + return ctx, cli.Exit(err.Error(), ExitCodeUsage) } // Do not continue if the host is already registered slog.Info("Checking system connection status") uuid, err := rhsm.GetConsumerUUID() if err != nil { - return cli.Exit( + return ctx, cli.Exit( fmt.Sprintf("unable to get consumer UUID: %s", err), ExitCodeSoftware, ) } if uuid != "" { slog.Info("Consumer UUID is set, system is already connected") - return cli.Exit("this system is already connected", ExitCodeUsage) + return ctx, cli.Exit("this system is already connected", ExitCodeUsage) } - username := ctx.String("username") - password := ctx.String("password") - organization := ctx.String("organization") - activationKeys := ctx.StringSlice("activation-key") - contentTemplates := ctx.StringSlice("content-template") + username := cmd.String("username") + password := cmd.String("password") + organization := cmd.String("organization") + activationKeys := cmd.StringSlice("activation-key") + contentTemplates := cmd.StringSlice("content-template") if len(activationKeys) > 0 { if username != "" { @@ -253,7 +254,7 @@ func beforeConnectAction(ctx *cli.Context) error { "--username and --activation-key can not be used together", ExitCodeUsage, ) - return exitErr + return ctx, exitErr } if password != "" { @@ -261,7 +262,7 @@ func beforeConnectAction(ctx *cli.Context) error { "--password and --activation-key can not be used together", ExitCodeUsage, ) - return exitErr + return ctx, exitErr } if organization == "" { @@ -269,7 +270,7 @@ func beforeConnectAction(ctx *cli.Context) error { "--organization is required, when --activation-key is used", ExitCodeUsage, ) - return exitErr + return ctx, exitErr } } @@ -281,7 +282,7 @@ func beforeConnectAction(ctx *cli.Context) error { "--username/--password or --organization/--activation-key are required when a machine-readable format is used", ExitCodeUsage, ) - return exitErr + return ctx, exitErr } } @@ -289,19 +290,19 @@ func beforeConnectAction(ctx *cli.Context) error { // If --enable-feature or --disable-feature flags are provided, ignore the cache file // and start with defaults. var cache *prefcache.PreferenceCache - if len(ctx.StringSlice("enable-feature")) > 0 || len(ctx.StringSlice("disable-feature")) > 0 { + if len(cmd.StringSlice("enable-feature")) > 0 || len(cmd.StringSlice("disable-feature")) > 0 { cache, err = prefcache.NewDefaultCache(ConnectFeaturesPrefsPath) if err != nil { - return cli.Exit(fmt.Sprintf("failed to create default cache: %v", err), ExitCodeSoftware) + return ctx, cli.Exit(fmt.Sprintf("failed to create default cache: %v", err), ExitCodeSoftware) } - for _, f := range ctx.StringSlice("enable-feature") { + for _, f := range cmd.StringSlice("enable-feature") { if err = cache.Set(f, true); err != nil { - return cli.Exit(err.Error(), ExitCodeDataErr) + return ctx, cli.Exit(err.Error(), ExitCodeDataErr) } } - for _, f := range ctx.StringSlice("disable-feature") { + for _, f := range cmd.StringSlice("disable-feature") { if err = cache.Set(f, false); err != nil { - return cli.Exit(err.Error(), ExitCodeDataErr) + return ctx, cli.Exit(err.Error(), ExitCodeDataErr) } } ui.Printf("Notice: ignoring preferences set via 'rhc configure features'.\n") @@ -310,35 +311,36 @@ func beforeConnectAction(ctx *cli.Context) error { // No flags provided, load cache from file (or defaults if file doesn't exist) cache, err = prefcache.LoadCache(ConnectFeaturesPrefsPath) if err != nil { - return cli.Exit(fmt.Sprintf("failed to load preferences: %v", err), ExitCodeSoftware) + return ctx, cli.Exit(fmt.Sprintf("failed to load preferences: %v", err), ExitCodeSoftware) } } - ctx.App.Metadata[ctxConnectCache] = cache + + cmd.Root().Metadata[connectCacheKey] = cache // Error out if we're trying to set content templates without having enabling content contentEnabled, err := cache.Get("content") if err != nil { - return cli.Exit(fmt.Sprintf("failed to get content preference: %v", err), ExitCodeSoftware) + return ctx, cli.Exit(fmt.Sprintf("failed to get content preference: %v", err), ExitCodeSoftware) } if !contentEnabled && len(contentTemplates) > 0 { - return cli.Exit("content feature is disabled, cannot use --content-template", ExitCodeUsage) + return ctx, cli.Exit("content feature is disabled, cannot use --content-template", ExitCodeUsage) } - err = checkForUnknownArgs(ctx) + err = checkForUnknownArgs(cmd) if err != nil { - return cli.Exit(err.Error(), ExitCodeUsage) + return ctx, cli.Exit(err.Error(), ExitCodeUsage) } - return nil + return ctx, nil } // connectAction manages 'rhc connect' steps: // first we register against Red Hat Subscription Management, // then we enable data collection for Red Hat Lightspeed services, // then we start remote management service yggdrasil. -func connectAction(ctx *cli.Context) error { - logCommandStart(ctx) - cache := ctx.App.Metadata[ctxConnectCache].(*prefcache.PreferenceCache) +func connectAction(ctx context.Context, cmd *cli.Command) error { + logCommandStart(cmd) + cache := cmd.Root().Metadata[connectCacheKey].(*prefcache.PreferenceCache) // FIXME Refactor // - Either implement cache.MustGet, or convert it to use enum instead of strings @@ -348,7 +350,7 @@ func connectAction(ctx *cli.Context) error { // - Move error handling to consistent and understandable pattern var connectResult ConnectResult - connectResult.format = ctx.String("format") + connectResult.format = cmd.String("format") uid := os.Getuid() if uid != 0 { @@ -414,7 +416,7 @@ func connectAction(ctx *cli.Context) error { return cli.Exit(fmt.Sprintf("failed to get content preference: %v", err), ExitCodeSoftware) } connectResult.TryRegisterRHSM( - ctx, + cmd, contentRequested, ) durations["rhsm"] = time.Since(start) @@ -492,7 +494,7 @@ func connectAction(ctx *cli.Context) error { fmt.Println(connectResult.Error()) } - err = ctx.App.Metadata[ctxConnectCache].(*prefcache.PreferenceCache).Delete() + err = cmd.Root().Metadata[connectCacheKey].(*prefcache.PreferenceCache).Delete() if err != nil { slog.Debug("could not delete preferences cache", "err", err) } diff --git a/cmd/rhc/constants.go b/cmd/rhc/constants.go index 99d7a985..81fb9754 100644 --- a/cmd/rhc/constants.go +++ b/cmd/rhc/constants.go @@ -21,8 +21,10 @@ const ( // ConnectFeaturesPrefsPath is the path to the feature preferences cache file ConnectFeaturesPrefsPath = "/var/lib/rhc/rhc-connect-features-prefs.json" +) - ctxConnectCache = "connect-cache" +const ( + connectCacheKey = "connect-cache" ) var ( diff --git a/cmd/rhc/disconnect_cmd.go b/cmd/rhc/disconnect_cmd.go index 9a17d166..2e80ed8c 100644 --- a/cmd/rhc/disconnect_cmd.go +++ b/cmd/rhc/disconnect_cmd.go @@ -1,6 +1,7 @@ package main import ( + "context" "encoding/json" "fmt" "log/slog" @@ -8,7 +9,7 @@ import ( "time" "github.com/redhatinsights/rhc/internal/rhsm" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" "github.com/redhatinsights/rhc/internal/datacollection" "github.com/redhatinsights/rhc/internal/remotemanagement" @@ -166,24 +167,24 @@ func (disconnectResult *DisconnectResult) TryUnregisterRHSM() error { } // beforeDisconnectAction ensures the user has supplied a correct `--format` flag -func beforeDisconnectAction(ctx *cli.Context) error { - err := checkFormatFlag(ctx) +func beforeDisconnectAction(ctx context.Context, cmd *cli.Command) (context.Context, error) { + err := checkFormatFlag(cmd) if err != nil { - return err + return ctx, err } - configureUI(ctx) + configureUI(cmd) - return checkForUnknownArgs(ctx) + return ctx, checkForUnknownArgs(cmd) } // disconnectAction tries to stop (yggdrasil) rhcd service, disconnect from Red Hat Lightspeed, // and finally it unregisters system from Red Hat Subscription Management -func disconnectAction(ctx *cli.Context) error { - logCommandStart(ctx) +func disconnectAction(ctx context.Context, cmd *cli.Command) error { + logCommandStart(cmd) var disconnectResult DisconnectResult - disconnectResult.format = ctx.String("format") + disconnectResult.format = cmd.String("format") uid := os.Getuid() if uid != 0 { diff --git a/cmd/rhc/interactive.go b/cmd/rhc/interactive.go index 22153d12..6c54a00d 100644 --- a/cmd/rhc/interactive.go +++ b/cmd/rhc/interactive.go @@ -7,7 +7,7 @@ import ( "text/tabwriter" "time" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" "github.com/redhatinsights/rhc/internal/conf" "github.com/redhatinsights/rhc/internal/ui" diff --git a/cmd/rhc/main.go b/cmd/rhc/main.go index 75d24201..7f04c4da 100644 --- a/cmd/rhc/main.go +++ b/cmd/rhc/main.go @@ -1,13 +1,18 @@ package main import ( + "context" "fmt" "log/slog" "os" + "os/signal" "strings" + "syscall" - "github.com/urfave/cli/v2" - "github.com/urfave/cli/v2/altsrc" + altsrc "github.com/urfave/cli-altsrc/v3" + altsrctoml "github.com/urfave/cli-altsrc/v3/toml" + docs "github.com/urfave/cli-docs/v3" + "github.com/urfave/cli/v3" "github.com/redhatinsights/rhc/internal/conf" "github.com/redhatinsights/rhc/internal/ui" @@ -23,17 +28,17 @@ const ( ) // mainAction is triggered in the case, when no sub-command is specified -func mainAction(c *cli.Context) error { - type GenerationFunc func() (string, error) +func mainAction(ctx context.Context, cmd *cli.Command) error { + type GenerationFunc func(*cli.Command) (string, error) var generationFunc GenerationFunc - if c.Bool("generate-man-page") { - generationFunc = c.App.ToMan - } else if c.Bool("generate-markdown") { - generationFunc = c.App.ToMarkdown + if cmd.Bool("generate-man-page") { + generationFunc = docs.ToMan + } else if cmd.Bool("generate-markdown") { + generationFunc = docs.ToMarkdown } else { - cli.ShowAppHelpAndExit(c, 0) + cli.ShowAppHelpAndExit(cmd, 0) } - data, err := generationFunc() + data, err := generationFunc(cmd.Root()) if err != nil { return cli.Exit(err, ExitCodeErr) } @@ -43,61 +48,49 @@ func mainAction(c *cli.Context) error { // configureUI sets up the global UI state by calling ui.ConfigureOutput // with appropriate parameters. -func configureUI(ctx *cli.Context) { +func configureUI(cmd *cli.Command) { ui.ConfigureOutput( // Rich output (animations) is only enabled when all are true: // - we're printing in human-friendly format, // - stdout is an interactive console. - !ctx.IsSet("format") && ui.IsInteractive(), + !cmd.IsSet("format") && ui.IsInteractive(), // Colors are only enabled when all are true: // output is rich, // --no-color/$NO_COLOR are not set. - !ctx.IsSet("no-color"), + !cmd.IsSet("no-color"), // Machine-readable output is enabled when all are true: // - we're printing in JSON or other parseable format. - ctx.IsSet("format"), + cmd.IsSet("format"), ) } // beforeAction is triggered before other actions are triggered -func beforeAction(c *cli.Context) error { +func beforeAction(ctx context.Context, cmd *cli.Command) (context.Context, error) { // check if --log-level was set via command line var logLevelSrc string - if c.IsSet(cliLogLevel) { + if cmd.IsSet(cliLogLevel) { logLevelSrc = "command line" } - /* Load the configuration values from the config file specified*/ - filePath := c.String("config") - if filePath != "" { - inputSource, err := altsrc.NewTomlSourceFromFile(filePath) - if err != nil { - return err - } - if err := altsrc.ApplyInputSourceValues(c, inputSource, c.App.Flags); err != nil { - return err - } - } - // check if log-level was set via config file (command line has precedence) - if logLevelSrc == "" && c.IsSet(cliLogLevel) { - logLevelSrc = fmt.Sprintf("config file: '%s'", c.String("config")) + if logLevelSrc == "" && cmd.IsSet(cliLogLevel) { + logLevelSrc = fmt.Sprintf("config file: '%s'", cmd.String("config")) } conf.Config = conf.Conf{ - CertFile: c.String(cliCertFile), - KeyFile: c.String(cliKeyFile), + CertFile: cmd.String(cliCertFile), + KeyFile: cmd.String(cliKeyFile), } - logLevelStr := c.String(cliLogLevel) + logLevelStr := cmd.String(cliLogLevel) if err := conf.Config.LogLevel.UnmarshalText([]byte(logLevelStr)); err != nil { slog.Error(fmt.Sprintf("invalid log level '%s' set via %s", logLevelStr, logLevelSrc)) conf.Config.LogLevel = slog.LevelInfo } - if !c.Bool("generate-man-page") && !c.Bool("generate-markdown") { + if !cmd.Bool("generate-man-page") && !cmd.Bool("generate-markdown") { configureFileLogging(conf.Config.LogLevel) - slog.Info(c.App.Name+" started", "version", version.Version, "pid", os.Getpid()) + slog.Info(cmd.Root().Name+" started", "version", version.Version, "pid", os.Getpid()) } // When environment variable NO_COLOR or --no-color CLI option is set, then do not display colors @@ -106,25 +99,25 @@ func beforeAction(c *cli.Context) error { // When no-color is not set, then try to detect if the output goes to some file. In this case // colors nor animations will not be printed to file. if !isTerminal(os.Stdout.Fd()) { - err := c.Set("no-color", "true") + err := cmd.Set("no-color", "true") if err != nil { slog.Debug("Unable to set no-color flag to \"true\"") } } // Set up standard output preference: colors, icons, etc. - configureUI(c) + configureUI(cmd) - return nil + return ctx, nil } // afterAction is triggered after other actions are triggered -func afterAction(c *cli.Context) error { +func afterAction(ctx context.Context, cmd *cli.Command) error { return closeLogFile() } // exitErrHandler is triggered when an action returns a cli.ExitCoder (e.g cli.Exit("error", 1)) -func exitErrHandler(c *cli.Context, err error) { +func exitErrHandler(ctx context.Context, cmd *cli.Command, err error) { _ = closeLogFile() // continue with default ExitErrHandler behavior @@ -132,7 +125,7 @@ func exitErrHandler(c *cli.Context, err error) { } func main() { - app := cli.NewApp() + app := &cli.Command{} app.Name = "rhc" app.Version = version.Version app.Usage = "control the system's connection to Red Hat" @@ -151,12 +144,14 @@ func main() { } featureIDs := strings.Join(featureIdSlice, ", ") - defaultConfigFilePath, err := ConfigPath() + configFilePath, err := ConfigPath() if err != nil { slog.Error(err.Error()) os.Exit(ExitCodeErr) } + configSource := altsrc.NewStringPtrSourcer(&configFilePath) + app.Flags = []cli.Flag{ &cli.BoolFlag{ Name: "generate-man-page", @@ -170,31 +165,41 @@ func main() { Name: "no-color", Hidden: false, Value: false, - EnvVars: []string{"NO_COLOR"}, + Sources: cli.EnvVars("NO_COLOR"), }, &cli.StringFlag{ - Name: "config", - Hidden: true, - Value: defaultConfigFilePath, - TakesFile: true, - Usage: "Read config values from `FILE`", + Name: "config", + Hidden: true, + Value: configFilePath, + Destination: &configFilePath, + TakesFile: true, + Usage: "Read config values from `FILE`", }, - altsrc.NewStringFlag(&cli.StringFlag{ + &cli.StringFlag{ Name: cliCertFile, Hidden: true, Usage: "Use `FILE` as the client certificate", - }), - altsrc.NewStringFlag(&cli.StringFlag{ + Sources: cli.NewValueSourceChain( + altsrctoml.TOML(cliCertFile, configSource), + ), + }, + &cli.StringFlag{ Name: cliKeyFile, Hidden: true, Usage: "Use `FILE` as the client's private key", - }), - altsrc.NewStringFlag(&cli.StringFlag{ + Sources: cli.NewValueSourceChain( + altsrctoml.TOML(cliKeyFile, configSource), + ), + }, + &cli.StringFlag{ Name: cliLogLevel, Value: "info", Hidden: true, Usage: "Set the logging output level to `LEVEL`", - }), + Sources: cli.NewValueSourceChain( + altsrctoml.TOML(cliLogLevel, configSource), + ), + }, } app.Commands = []*cli.Command{ @@ -268,13 +273,13 @@ func main() { Usage: "Configure system features", UsageText: fmt.Sprintf("%v configure COMMAND", app.Name), Description: "The configure command allows you to manage feature preferences before or after system registration.", - Subcommands: []*cli.Command{ + Commands: []*cli.Command{ { Name: "features", Usage: "Manage feature levels", UsageText: fmt.Sprintf("%v configure features COMMAND", app.Name), Description: "Enable or disable content management, analytics, or remote management.", - Subcommands: []*cli.Command{ + Commands: []*cli.Command{ { Name: "status", Usage: "Show status", @@ -326,7 +331,7 @@ func main() { Name: "collector", Usage: "Collect data for analysis", UsageText: fmt.Sprintf("%v collector COMMAND [command options]", app.Name), - Subcommands: []*cli.Command{ + Commands: []*cli.Command{ { Name: "info", Flags: []cli.Flag{ @@ -398,14 +403,17 @@ func main() { }, }, } - app.EnableBashCompletion = true - app.BashComplete = BashComplete + app.EnableShellCompletion = true + app.ShellComplete = ShellComplete app.Action = mainAction app.Before = beforeAction app.After = afterAction app.ExitErrHandler = exitErrHandler - if err := app.Run(os.Args); err != nil { + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) + defer stop() + + if err := app.Run(ctx, os.Args); err != nil { slog.Error(err.Error()) } } diff --git a/cmd/rhc/status_cmd.go b/cmd/rhc/status_cmd.go index 38b1b718..72189a38 100644 --- a/cmd/rhc/status_cmd.go +++ b/cmd/rhc/status_cmd.go @@ -11,7 +11,7 @@ import ( "github.com/godbus/dbus/v5" "github.com/redhatinsights/rhc/internal/rhsm" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" "github.com/briandowns/spinner" systemd "github.com/coreos/go-systemd/v22/dbus" @@ -230,15 +230,15 @@ func printJSONStatus(systemStatus *SystemStatus) error { } // beforeStatusAction ensures the user has supplied a correct `--format` flag. -func beforeStatusAction(ctx *cli.Context) error { - err := checkFormatFlag(ctx) +func beforeStatusAction(ctx context.Context, cmd *cli.Command) (context.Context, error) { + err := checkFormatFlag(cmd) if err != nil { - return err + return ctx, err } - configureUI(ctx) + configureUI(cmd) - return checkForUnknownArgs(ctx) + return ctx, checkForUnknownArgs(cmd) } // statusAction tries to print status of system. It means that it gives @@ -248,13 +248,13 @@ func beforeStatusAction(ctx *cli.Context) error { // 3. Is yggdrasil.service (rhcd.service) running? // Status can be printed as human-readable text or machine-readable JSON document. // Format is influenced by --format json CLI option stored in CLI context -func statusAction(ctx *cli.Context) (err error) { - logCommandStart(ctx) +func statusAction(ctx context.Context, cmd *cli.Command) (err error) { + logCommandStart(cmd) var systemStatus SystemStatus var machineReadablePrintFunc func(systemStatus *SystemStatus) error - format := ctx.String("format") + format := cmd.String("format") switch format { case "json": machineReadablePrintFunc = printJSONStatus diff --git a/cmd/rhc/util.go b/cmd/rhc/util.go index f7cff824..6040bb0c 100644 --- a/cmd/rhc/util.go +++ b/cmd/rhc/util.go @@ -1,6 +1,7 @@ package main import ( + "context" "fmt" "io" "log/slog" @@ -8,7 +9,7 @@ import ( "path/filepath" "strings" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" "golang.org/x/sys/unix" ) @@ -27,7 +28,7 @@ func BashCompleteCommand(cmd *cli.Command, w io.Writer) { PrintFlagNames(cmd.VisibleFlags(), w) - for _, command := range cmd.Subcommands { + for _, command := range cmd.Commands { BashCompleteCommand(command, w) } } @@ -47,12 +48,12 @@ func PrintFlagNames(flags []cli.Flag, w io.Writer) { // BashComplete prints all commands, subcommands and flags to the application // writer. -func BashComplete(c *cli.Context) { - for _, command := range c.App.VisibleCommands() { - BashCompleteCommand(command, c.App.Writer) +func ShellComplete(ctx context.Context, cmd *cli.Command) { + for _, command := range cmd.Root().Commands { + BashCompleteCommand(command, cmd.Root().Writer) // global flags - PrintFlagNames(c.App.VisibleFlags(), c.App.Writer) + PrintFlagNames(cmd.Root().Flags, cmd.Root().Writer) } } @@ -68,17 +69,17 @@ func ConfigPath() (string, error) { } // checkForUnknownArgs returns an error if any unknown arguments are present. -func checkForUnknownArgs(ctx *cli.Context) error { - if ctx.Args().Len() != 0 { +func checkForUnknownArgs(cmd *cli.Command) error { + if cmd.Args().Len() != 0 { return fmt.Errorf("unknown option(s): %s", - strings.Join(ctx.Args().Slice(), " ")) + strings.Join(cmd.Args().Slice(), " ")) } return nil } // checkFormatFlag ensures the user has supplied a correct `--format` flag. -func checkFormatFlag(ctx *cli.Context) error { - format := ctx.String("format") +func checkFormatFlag(cmd *cli.Command) error { + format := cmd.String("format") switch format { case "", "json": return nil @@ -94,11 +95,11 @@ func checkFormatFlag(ctx *cli.Context) error { // getFullCommandName uses ctx.Lineage() to reconstruct the full command name including parent commands, // excluding flags and arguments -func getFullCommandName(ctx *cli.Context) string { +func getFullCommandName(cmd *cli.Command) string { var commandParts []string - for _, c := range ctx.Lineage() { - if c.Command != nil { - commandParts = append([]string{c.Command.Name}, commandParts...) + for _, c := range cmd.Lineage() { + if c != nil { + commandParts = append([]string{c.Name}, commandParts...) } } @@ -108,22 +109,22 @@ func getFullCommandName(ctx *cli.Context) string { // logCommandStart logs the start of a command execution. This should be called at the beginning // of each command's Action function to ensure the full command name (including all subcommands) // is properly logged. -func logCommandStart(ctx *cli.Context) { - fullCommandName := getFullCommandName(ctx) +func logCommandStart(cmd *cli.Command) { + fullCommandName := getFullCommandName(cmd) slog.Info(fmt.Sprintf("Command '%s' started", fullCommandName)) } // validateCollectorCommand performs common validation for collector commands. -func validateCollectorCommand(ctx *cli.Context, requiresCollectorID, requiresFormat bool) error { +func validateCollectorCommand(cmd *cli.Command, requiresCollectorID, requiresFormat bool) error { if requiresFormat { - if err := checkFormatFlag(ctx); err != nil { + if err := checkFormatFlag(cmd); err != nil { return err } } - if requiresCollectorID && ctx.Args().Len() == 0 { - commandName := getFullCommandName(ctx) + if requiresCollectorID && cmd.Args().Len() == 0 { + commandName := getFullCommandName(cmd) return cli.Exit(fmt.Sprintf("%s requires a collector ID", commandName), ExitCodeUsage) } - configureUI(ctx) + configureUI(cmd) return nil } diff --git a/go-vendor-tools.toml b/go-vendor-tools.toml index 2c22c5e0..6ab4062a 100644 --- a/go-vendor-tools.toml +++ b/go-vendor-tools.toml @@ -2,7 +2,3 @@ [licensing] detector = "askalono" -[[licensing.licenses]] -path = "vendor/gopkg.in/yaml.v3/LICENSE" -sha256sum = "d18f6323b71b0b768bb5e9616e36da390fbd39369a81807cca352de4e4e6aa0b" -expression = "MIT AND (MIT AND Apache-2.0)" diff --git a/go.mod b/go.mod index fbcb0c26..e98d35e7 100644 --- a/go.mod +++ b/go.mod @@ -10,9 +10,11 @@ require ( github.com/godbus/dbus/v5 v5.2.2 github.com/google/go-cmp v0.7.0 github.com/google/uuid v1.6.0 - github.com/urfave/cli/v2 v2.27.7 - golang.org/x/sys v0.44.0 - golang.org/x/term v0.43.0 + github.com/urfave/cli-altsrc/v3 v3.1.0 + github.com/urfave/cli-docs/v3 v3.1.0 + github.com/urfave/cli/v3 v3.8.0 + golang.org/x/sys v0.43.0 + golang.org/x/term v0.42.0 ) require ( @@ -21,6 +23,4 @@ require ( github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 2bd425ae..3c2e85b3 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w= github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emersion/go-varlink v0.1.1-0.20260122150447-9c0e29254dd5 h1:gVuw6Mvi85SQpLkVxmW5xA8HGg/6nX3BYKdMAVpXMio= github.com/emersion/go-varlink v0.1.1-0.20260122150447-9c0e29254dd5/go.mod h1:0/V0Ta8VUzKRLXUtyZS49soMI93Taqlm63wX5nx6YEo= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= @@ -20,18 +22,22 @@ github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHP github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= -github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= -github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= -github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/urfave/cli-altsrc/v3 v3.1.0 h1:6E5+kXeAWmRxXlPgdEVf9VqVoTJ2MJci0UMpUi/w/bA= +github.com/urfave/cli-altsrc/v3 v3.1.0/go.mod h1:VcWVTGXcL3nrXUDJZagHAeUX702La3PKeWav7KpISqA= +github.com/urfave/cli-docs/v3 v3.1.0 h1:Sa5xm19IpE5gpm6tZzXdfjdFxn67PnEsE4dpXF7vsKw= +github.com/urfave/cli-docs/v3 v3.1.0/go.mod h1:59d+5Hz1h6GSGJ10cvcEkbIe3j233t4XDqI72UIx7to= +github.com/urfave/cli/v3 v3.8.0 h1:XqKPrm0q4P0q5JpoclYoCAv0/MIvH/jZ2umzuf8pNTI= +github.com/urfave/cli/v3 v3.8.0/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= -golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= -golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= +golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY= +golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/integration-tests/test_man_page.py b/integration-tests/test_man_page.py index 8a6ed57b..55cdc4b7 100644 --- a/integration-tests/test_man_page.py +++ b/integration-tests/test_man_page.py @@ -21,12 +21,12 @@ def test_man_page_synopsis(): 1. Display the `rhc` man page content. :expectedresults: 1. The man page content includes the exact synopsis string: - "rhc [GLOBAL OPTIONS] command [COMMAND OPTIONS] [ARGUMENTS...]" + "rhc [GLOBAL OPTIONS] [command [COMMAND OPTIONS]] [ARGUMENTS...]" """ command_op = subprocess.check_output(["man", "rhc"]).decode("utf-8") assert ( - "rhc [GLOBAL OPTIONS] command [COMMAND OPTIONS] " "[ARGUMENTS...]" + "rhc [GLOBAL OPTIONS] [command [COMMAND OPTIONS]] " "[ARGUMENTS...]" ) in command_op diff --git a/internal/rhsm/rhsm.go b/internal/rhsm/rhsm.go index 1efb1024..ba800401 100644 --- a/internal/rhsm/rhsm.go +++ b/internal/rhsm/rhsm.go @@ -11,7 +11,7 @@ import ( "time" "github.com/briandowns/spinner" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" "golang.org/x/term" "github.com/godbus/dbus/v5" @@ -363,7 +363,7 @@ func UnpackDBusError(err error) error { } // RegisterRHSM tries to register system against Red Hat Subscription Management server (candlepin server) -func RegisterRHSM(ctx *cli.Context, enableContent bool) (string, error) { +func RegisterRHSM(cmd *cli.Command, enableContent bool) (string, error) { uuid, err := GetConsumerUUID() if err != nil { return "unable to get consumer UUID", cli.Exit(err, ExitCodeErr) @@ -371,11 +371,11 @@ func RegisterRHSM(ctx *cli.Context, enableContent bool) (string, error) { var successMsg string if uuid == "" { - username := ctx.String("username") - password := ctx.String("password") - organization := ctx.String("organization") - activationKeys := ctx.StringSlice("activation-key") - contentTemplates := ctx.StringSlice("content-template") + username := cmd.String("username") + password := cmd.String("password") + organization := cmd.String("organization") + activationKeys := cmd.StringSlice("activation-key") + contentTemplates := cmd.StringSlice("content-template") if len(activationKeys) == 0 { if username == "" { @@ -410,7 +410,7 @@ func RegisterRHSM(ctx *cli.Context, enableContent bool) (string, error) { slog.Debug("Registering system with activation keys") err = registerActivationKey( organization, - ctx.StringSlice("activation-key"), + cmd.StringSlice("activation-key"), contentTemplates, enableContent) } else {