From 939645e1441a2e348445bb0e347b5b1ba377ebc1 Mon Sep 17 00:00:00 2001 From: Justin Bradford Date: Wed, 19 Nov 2025 02:30:32 -0800 Subject: [PATCH] refactor: Make `--context` cli flag a global option (#174) * Make `--context` flag a global option and remove duplication * Remove unused dns showOptions struct * First pass of refactoring "active context" determination and validation * Undo some refactoring in cli.go to keep diff more focused --- cmd/uncloud/build.go | 2 -- cmd/uncloud/caddy/config.go | 7 +------ cmd/uncloud/caddy/deploy.go | 7 +------ cmd/uncloud/deploy.go | 6 +----- cmd/uncloud/dns/release.go | 17 +++-------------- cmd/uncloud/dns/reserve.go | 7 +------ cmd/uncloud/dns/show.go | 17 +++-------------- cmd/uncloud/image/ls.go | 7 +------ cmd/uncloud/image/push.go | 7 +------ cmd/uncloud/machine/add.go | 6 ------ cmd/uncloud/machine/ls.go | 11 +++-------- cmd/uncloud/machine/rename.go | 11 +++-------- cmd/uncloud/machine/rm.go | 5 +---- cmd/uncloud/machine/update.go | 7 +------ cmd/uncloud/main.go | 7 +++++-- cmd/uncloud/service/exec.go | 6 +----- cmd/uncloud/service/inspect.go | 7 +------ cmd/uncloud/service/ls.go | 11 +++-------- cmd/uncloud/service/rm.go | 7 +------ cmd/uncloud/service/run.go | 9 +-------- cmd/uncloud/service/scale.go | 8 +------- cmd/uncloud/volume/create.go | 5 +---- cmd/uncloud/volume/inspect.go | 5 +---- cmd/uncloud/volume/ls.go | 6 +----- cmd/uncloud/volume/rm.go | 6 +----- internal/cli/build.go | 4 +--- internal/cli/cli.go | 32 +++++++++++++++++--------------- 27 files changed, 55 insertions(+), 175 deletions(-) diff --git a/cmd/uncloud/build.go b/cmd/uncloud/build.go index e31062b6..fc9a7410 100644 --- a/cmd/uncloud/build.go +++ b/cmd/uncloud/build.go @@ -74,8 +74,6 @@ to cluster machines or --push-registry to upload them to external registries.`, "Use --machine to specify which machines. (default is all machines)") cmd.Flags().BoolVar(&opts.PushRegistry, "push-registry", false, "Upload the built images to external registries (e.g., Docker Hub) after building.") - cmd.Flags().StringVarP(&opts.Context, "context", "c", "", - "Name of the cluster context. (default is the current context)") return cmd } diff --git a/cmd/uncloud/caddy/config.go b/cmd/uncloud/caddy/config.go index ffe16832..356af55b 100644 --- a/cmd/uncloud/caddy/config.go +++ b/cmd/uncloud/caddy/config.go @@ -14,7 +14,6 @@ import ( type configOptions struct { machine string noColor bool - context string } func NewConfigCommand() *cobra.Command { @@ -34,16 +33,12 @@ func NewConfigCommand() *cobra.Command { "Name or ID of the machine to get the configuration from. (default is connected machine)") cmd.Flags().BoolVar(&opts.noColor, "no-color", false, "Disable syntax highlighting for the output.") - cmd.Flags().StringVarP( - &opts.context, "context", "c", "", - "Name of the cluster context. (default is the current context)", - ) return cmd } func runConfig(ctx context.Context, uncli *cli.CLI, opts configOptions) error { - clusterClient, err := uncli.ConnectCluster(ctx, opts.context) + clusterClient, err := uncli.ConnectCluster(ctx) if err != nil { return fmt.Errorf("connect to cluster: %w", err) } diff --git a/cmd/uncloud/caddy/deploy.go b/cmd/uncloud/caddy/deploy.go index f7886fcc..05559a25 100644 --- a/cmd/uncloud/caddy/deploy.go +++ b/cmd/uncloud/caddy/deploy.go @@ -22,7 +22,6 @@ type deployOptions struct { caddyfile string image string machines []string - context string } func NewDeployCommand() *cobra.Command { @@ -46,10 +45,6 @@ func NewDeployCommand() *cobra.Command { cmd.Flags().StringSliceVarP(&opts.machines, "machine", "m", nil, "Machine names or IDs to deploy to. Can be specified multiple times or as a comma-separated "+ "list. (default is all machines)") - cmd.Flags().StringVarP( - &opts.context, "context", "c", "", - "Name of the cluster context to deploy to. (default is the current context)", - ) return cmd } @@ -64,7 +59,7 @@ func runDeploy(ctx context.Context, uncli *cli.CLI, opts deployOptions) error { caddyfile = strings.TrimSpace(string(data)) } - clusterClient, err := uncli.ConnectCluster(ctx, opts.context) + clusterClient, err := uncli.ConnectCluster(ctx) if err != nil { return fmt.Errorf("connect to cluster: %w", err) } diff --git a/cmd/uncloud/deploy.go b/cmd/uncloud/deploy.go index e1e12438..b16353b4 100644 --- a/cmd/uncloud/deploy.go +++ b/cmd/uncloud/deploy.go @@ -26,8 +26,6 @@ type deployOptions struct { noBuild bool recreate bool yes bool - - context string } // NewDeployCommand creates a new command to deploy services from a Compose file. @@ -51,8 +49,6 @@ func NewDeployCommand() *cobra.Command { "Can be specified multiple times. Format: --build-arg VAR=VALUE") cmd.Flags().BoolVar(&opts.BuildServicesOptions.Pull, "build-pull", false, "Always attempt to pull newer versions of base images before building service images.") - cmd.Flags().StringVarP(&opts.context, "context", "c", "", - "Name of the cluster context to deploy to (default is the current context)") cmd.Flags().StringSliceVarP(&opts.files, "file", "f", nil, "One or more Compose files to deploy services from. (default compose.yaml)") cmd.Flags().BoolVar(&opts.noBuild, "no-build", false, @@ -108,7 +104,7 @@ func runDeploy(ctx context.Context, uncli *cli.CLI, opts deployOptions) error { fmt.Println() } - clusterClient, err := uncli.ConnectCluster(ctx, opts.context) + clusterClient, err := uncli.ConnectCluster(ctx) if err != nil { return fmt.Errorf("connect to cluster: %w", err) } diff --git a/cmd/uncloud/dns/release.go b/cmd/uncloud/dns/release.go index 1b250fad..6c8fb2da 100644 --- a/cmd/uncloud/dns/release.go +++ b/cmd/uncloud/dns/release.go @@ -12,32 +12,21 @@ import ( "google.golang.org/protobuf/types/known/emptypb" ) -type releaseOptions struct { - context string -} - func NewReleaseCommand() *cobra.Command { - opts := releaseOptions{} - cmd := &cobra.Command{ Use: "release", Short: "Release the reserved cluster domain.", RunE: func(cmd *cobra.Command, args []string) error { uncli := cmd.Context().Value("cli").(*cli.CLI) - return release(cmd.Context(), uncli, opts) + return release(cmd.Context(), uncli) }, } - cmd.Flags().StringVarP( - &opts.context, "context", "c", "", - "Name of the cluster context. (default is the current context)", - ) - return cmd } -func release(ctx context.Context, uncli *cli.CLI, opts releaseOptions) error { - client, err := uncli.ConnectCluster(ctx, opts.context) +func release(ctx context.Context, uncli *cli.CLI) error { + client, err := uncli.ConnectCluster(ctx) if err != nil { return fmt.Errorf("connect to cluster: %w", err) } diff --git a/cmd/uncloud/dns/reserve.go b/cmd/uncloud/dns/reserve.go index 9a475cd0..2d4107d8 100644 --- a/cmd/uncloud/dns/reserve.go +++ b/cmd/uncloud/dns/reserve.go @@ -19,7 +19,6 @@ const DefaultUncloudDNSAPIEndpoint = "https://dns.uncloud.run/v1" type reserveOptions struct { endpoint string - context string } func NewReserveCommand() *cobra.Command { @@ -36,16 +35,12 @@ func NewReserveCommand() *cobra.Command { cmd.Flags().StringVar(&opts.endpoint, "endpoint", DefaultUncloudDNSAPIEndpoint, "API endpoint for the Uncloud DNS service.") - cmd.Flags().StringVarP( - &opts.context, "context", "c", "", - "Name of the cluster context. (default is the current context)", - ) return cmd } func reserve(ctx context.Context, uncli *cli.CLI, opts reserveOptions) error { - clusterClient, err := uncli.ConnectCluster(ctx, opts.context) + clusterClient, err := uncli.ConnectCluster(ctx) if err != nil { return fmt.Errorf("connect to cluster: %w", err) } diff --git a/cmd/uncloud/dns/show.go b/cmd/uncloud/dns/show.go index adcdc958..b9a1fc64 100644 --- a/cmd/uncloud/dns/show.go +++ b/cmd/uncloud/dns/show.go @@ -10,32 +10,21 @@ import ( "github.com/spf13/cobra" ) -type showOptions struct { - context string -} - func NewShowCommand() *cobra.Command { - opts := showOptions{} - cmd := &cobra.Command{ Use: "show", Short: "Print the cluster domain name.", RunE: func(cmd *cobra.Command, args []string) error { uncli := cmd.Context().Value("cli").(*cli.CLI) - return show(cmd.Context(), uncli, opts) + return show(cmd.Context(), uncli) }, } - cmd.Flags().StringVarP( - &opts.context, "context", "c", "", - "Name of the cluster context. (default is the current context)", - ) - return cmd } -func show(ctx context.Context, uncli *cli.CLI, opts showOptions) error { - clusterClient, err := uncli.ConnectCluster(ctx, opts.context) +func show(ctx context.Context, uncli *cli.CLI) error { + clusterClient, err := uncli.ConnectCluster(ctx) if err != nil { return fmt.Errorf("connect to cluster: %w", err) } diff --git a/cmd/uncloud/image/ls.go b/cmd/uncloud/image/ls.go index 835c3ac8..f3e432cc 100644 --- a/cmd/uncloud/image/ls.go +++ b/cmd/uncloud/image/ls.go @@ -22,7 +22,6 @@ import ( type listOptions struct { machines []string nameFilter string - context string } func NewListCommand() *cobra.Command { @@ -60,10 +59,6 @@ func NewListCommand() *cobra.Command { cmd.Flags().StringSliceVarP(&opts.machines, "machine", "m", nil, "Filter images by machine name or ID. Can be specified multiple times or as a comma-separated list. "+ "(default is include all machines)") - cmd.Flags().StringVarP( - &opts.context, "context", "c", "", - "Name of the cluster context. (default is the current context)", - ) return cmd } @@ -82,7 +77,7 @@ type imageRow struct { } func list(ctx context.Context, uncli *cli.CLI, opts listOptions) error { - clusterClient, err := uncli.ConnectCluster(ctx, opts.context) + clusterClient, err := uncli.ConnectCluster(ctx) if err != nil { return fmt.Errorf("connect to cluster: %w", err) } diff --git a/cmd/uncloud/image/push.go b/cmd/uncloud/image/push.go index a051b221..fca1bd36 100644 --- a/cmd/uncloud/image/push.go +++ b/cmd/uncloud/image/push.go @@ -15,7 +15,6 @@ type pushOptions struct { image string machines []string platform string - context string } func NewPushCommand() *cobra.Command { @@ -54,16 +53,12 @@ The image is uploaded to all cluster machines (default) or the specified machine "Push a specific platform of a multi-platform image (e.g., linux/amd64, linux/arm64).\n"+ "Local Docker must be configured to use containerd image store to support multi-platform images.", ) - cmd.Flags().StringVarP( - &opts.context, "context", "c", "", - "Name of the cluster context. (default is the current context)", - ) return cmd } func push(ctx context.Context, uncli *cli.CLI, opts pushOptions) error { - clusterClient, err := uncli.ConnectCluster(ctx, opts.context) + clusterClient, err := uncli.ConnectCluster(ctx) if err != nil { return fmt.Errorf("connect to cluster: %w", err) } diff --git a/cmd/uncloud/machine/add.go b/cmd/uncloud/machine/add.go index 204e327a..66e59486 100644 --- a/cmd/uncloud/machine/add.go +++ b/cmd/uncloud/machine/add.go @@ -26,7 +26,6 @@ type addOptions struct { noInstall bool publicIP string sshKey string - context string version string } @@ -89,10 +88,6 @@ Connection methods: &opts.version, "version", "latest", "Version of the Uncloud daemon to install on the machine.", ) - cmd.Flags().StringVarP( - &opts.context, "context", "c", "", - "Name of the cluster context to add the machine to. (default is the current context)", - ) return cmd } @@ -113,7 +108,6 @@ func add(ctx context.Context, uncli *cli.CLI, remoteMachine *cli.RemoteMachine, } clusterClient, machineClient, err := uncli.AddMachine(ctx, cli.AddMachineOptions{ - Context: opts.context, MachineName: opts.name, PublicIP: publicIP, RemoteMachine: remoteMachine, diff --git a/cmd/uncloud/machine/ls.go b/cmd/uncloud/machine/ls.go index 99e0ff65..de6eeabc 100644 --- a/cmd/uncloud/machine/ls.go +++ b/cmd/uncloud/machine/ls.go @@ -14,25 +14,20 @@ import ( ) func NewListCommand() *cobra.Command { - var contextName string cmd := &cobra.Command{ Use: "ls", Aliases: []string{"list"}, Short: "List machines in a cluster.", RunE: func(cmd *cobra.Command, args []string) error { uncli := cmd.Context().Value("cli").(*cli.CLI) - return list(cmd.Context(), uncli, contextName) + return list(cmd.Context(), uncli) }, } - cmd.Flags().StringVarP( - &contextName, "context", "c", "", - "Name of the cluster context. (default is the current context)", - ) return cmd } -func list(ctx context.Context, uncli *cli.CLI, clusterName string) error { - client, err := uncli.ConnectCluster(ctx, clusterName) +func list(ctx context.Context, uncli *cli.CLI) error { + client, err := uncli.ConnectCluster(ctx) if err != nil { return fmt.Errorf("connect to cluster: %w", err) } diff --git a/cmd/uncloud/machine/rename.go b/cmd/uncloud/machine/rename.go index 9a8a8407..848d4b2b 100644 --- a/cmd/uncloud/machine/rename.go +++ b/cmd/uncloud/machine/rename.go @@ -9,7 +9,6 @@ import ( ) func NewRenameCommand() *cobra.Command { - var contextName string cmd := &cobra.Command{ Use: "rename OLD_NAME NEW_NAME", Short: "Rename a machine in the cluster.", @@ -20,18 +19,14 @@ configuration including network settings, public IP, and cluster membership.`, Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { uncli := cmd.Context().Value("cli").(*cli.CLI) - return rename(cmd.Context(), uncli, contextName, args[0], args[1]) + return rename(cmd.Context(), uncli, args[0], args[1]) }, } - cmd.Flags().StringVarP( - &contextName, "context", "c", "", - "Name of the cluster context. (default is the current context)", - ) return cmd } -func rename(ctx context.Context, uncli *cli.CLI, contextName, oldName, newName string) error { - client, err := uncli.ConnectCluster(ctx, contextName) +func rename(ctx context.Context, uncli *cli.CLI, oldName, newName string) error { + client, err := uncli.ConnectCluster(ctx) if err != nil { return err } diff --git a/cmd/uncloud/machine/rm.go b/cmd/uncloud/machine/rm.go index 4a3c5348..0516ceb7 100644 --- a/cmd/uncloud/machine/rm.go +++ b/cmd/uncloud/machine/rm.go @@ -22,7 +22,6 @@ import ( type removeOptions struct { noReset bool yes bool - context string } func NewRmCommand() *cobra.Command { @@ -39,8 +38,6 @@ func NewRmCommand() *cobra.Command { }, } - cmd.Flags().StringVarP(&opts.context, "context", "c", "", - "Name of the cluster context. (default is the current context)") cmd.Flags().BoolVarP(&opts.yes, "yes", "y", false, "Do not prompt for confirmation before removing the machine.") cmd.Flags().BoolVar(&opts.noReset, "no-reset", false, @@ -51,7 +48,7 @@ func NewRmCommand() *cobra.Command { func remove(ctx context.Context, uncli *cli.CLI, nameOrID string, opts removeOptions) error { // TODO: automatically choose a connection to the machine that is not being removed. - client, err := uncli.ConnectCluster(ctx, opts.context) + client, err := uncli.ConnectCluster(ctx) if err != nil { return fmt.Errorf("connect to cluster: %w", err) } diff --git a/cmd/uncloud/machine/update.go b/cmd/uncloud/machine/update.go index 7349a1c8..c4905f48 100644 --- a/cmd/uncloud/machine/update.go +++ b/cmd/uncloud/machine/update.go @@ -13,7 +13,6 @@ import ( type updateOptions struct { name string publicIP string - context string } func NewUpdateCommand() *cobra.Command { @@ -43,10 +42,6 @@ At least one flag must be specified to perform an update operation.`, &opts.publicIP, "public-ip", "", fmt.Sprintf("Public IP address of the machine for ingress configuration. Use '%s' or '' to remove the public IP.", PublicIPNone), ) - cmd.Flags().StringVarP( - &opts.context, "context", "c", "", - "Name of the cluster context. (default is the current context)", - ) return cmd } @@ -57,7 +52,7 @@ func update(ctx context.Context, uncli *cli.CLI, cmd *cobra.Command, opts update return fmt.Errorf("at least one update flag must be specified (--name, --public-ip)") } - client, err := uncli.ConnectCluster(ctx, opts.context) + client, err := uncli.ConnectCluster(ctx) if err != nil { return err } diff --git a/cmd/uncloud/main.go b/cmd/uncloud/main.go index 44a180ab..4fb9e2db 100644 --- a/cmd/uncloud/main.go +++ b/cmd/uncloud/main.go @@ -24,6 +24,7 @@ import ( type globalOptions struct { configPath string connect string + context string } func main() { @@ -39,6 +40,7 @@ func main() { PersistentPreRunE: func(cmd *cobra.Command, args []string) error { cli.BindEnvToFlag(cmd, "connect", "UNCLOUD_CONNECT") cli.BindEnvToFlag(cmd, "uncloud-config", "UNCLOUD_CONFIG") + cli.BindEnvToFlag(cmd, "context", "UNCLOUD_CONTEXT") var conn *config.MachineConnection if opts.connect != "" { @@ -67,7 +69,7 @@ func main() { } configPath := fs.ExpandHomeDir(opts.configPath) - uncli, err := cli.New(configPath, conn) + uncli, err := cli.New(configPath, conn, opts.context) if err != nil { return fmt.Errorf("initialise CLI: %w", err) } @@ -82,7 +84,8 @@ func main() { cmd.PersistentFlags().StringVar(&opts.configPath, "uncloud-config", "~/.config/uncloud/config.yaml", "Path to the Uncloud configuration file. [$UNCLOUD_CONFIG]") _ = cmd.MarkPersistentFlagFilename("uncloud-config", "yaml", "yml") - // TODO: make --context a global flag and pass it as a value of the command context. + cmd.PersistentFlags().StringVarP(&opts.context, "context", "c", "", + "Name of the cluster context to use (default is the current context). [$UNCLOUD_CONTEXT]") cmd.AddCommand( NewDeployCommand(), diff --git a/cmd/uncloud/service/exec.go b/cmd/uncloud/service/exec.go index 95b8c26e..98271699 100644 --- a/cmd/uncloud/service/exec.go +++ b/cmd/uncloud/service/exec.go @@ -15,7 +15,6 @@ type execCliOptions struct { detach bool interactive bool noTty bool - context string containerId string } @@ -69,9 +68,6 @@ If the service has multiple replicas and no container ID is specified, the comma execCmd.Flags().BoolP("tty", "t", false, "Allocate a pseudo-TTY") execCmd.Flags().MarkHidden("tty") - execCmd.Flags().StringVarP(&opts.context, "context", "c", "", - "Name of the cluster context. (default is the current context)") - // Common flags execCmd.Flags().StringVar(&opts.containerId, "container", "", "ID of the container to exec into. Accepts full ID or a unique prefix "+ @@ -95,7 +91,7 @@ func runExec(ctx context.Context, uncli *cli.CLI, serviceName string, command [] } } - client, err := uncli.ConnectClusterWithOptions(ctx, opts.context, cli.ConnectOptions{ + client, err := uncli.ConnectClusterWithOptions(ctx, cli.ConnectOptions{ ShowProgress: false, }) if err != nil { diff --git a/cmd/uncloud/service/inspect.go b/cmd/uncloud/service/inspect.go index c37f3b75..63c96558 100644 --- a/cmd/uncloud/service/inspect.go +++ b/cmd/uncloud/service/inspect.go @@ -15,7 +15,6 @@ import ( type inspectOptions struct { service string - context string } func NewInspectCommand() *cobra.Command { @@ -30,15 +29,11 @@ func NewInspectCommand() *cobra.Command { return inspect(cmd.Context(), uncli, opts) }, } - cmd.Flags().StringVarP( - &opts.context, "context", "c", "", - "Name of the cluster context. (default is the current context)", - ) return cmd } func inspect(ctx context.Context, uncli *cli.CLI, opts inspectOptions) error { - client, err := uncli.ConnectCluster(ctx, opts.context) + client, err := uncli.ConnectCluster(ctx) if err != nil { return fmt.Errorf("connect to cluster: %w", err) } diff --git a/cmd/uncloud/service/ls.go b/cmd/uncloud/service/ls.go index e910cbe7..c004d951 100644 --- a/cmd/uncloud/service/ls.go +++ b/cmd/uncloud/service/ls.go @@ -12,25 +12,20 @@ import ( ) func NewListCommand() *cobra.Command { - var contextName string cmd := &cobra.Command{ Use: "ls", Aliases: []string{"list"}, Short: "List services.", RunE: func(cmd *cobra.Command, args []string) error { uncli := cmd.Context().Value("cli").(*cli.CLI) - return list(cmd.Context(), uncli, contextName) + return list(cmd.Context(), uncli) }, } - cmd.Flags().StringVarP( - &contextName, "context", "c", "", - "Name of the cluster context. (default is the current context)", - ) return cmd } -func list(ctx context.Context, uncli *cli.CLI, contextName string) error { - client, err := uncli.ConnectCluster(ctx, contextName) +func list(ctx context.Context, uncli *cli.CLI) error { + client, err := uncli.ConnectCluster(ctx) if err != nil { return fmt.Errorf("connect to cluster: %w", err) } diff --git a/cmd/uncloud/service/rm.go b/cmd/uncloud/service/rm.go index a76c7bb1..74c6a345 100644 --- a/cmd/uncloud/service/rm.go +++ b/cmd/uncloud/service/rm.go @@ -11,7 +11,6 @@ import ( type rmOptions struct { services []string - context string } func NewRmCommand() *cobra.Command { @@ -27,15 +26,11 @@ func NewRmCommand() *cobra.Command { return rm(cmd.Context(), uncli, opts) }, } - cmd.Flags().StringVarP( - &opts.context, "context", "c", "", - "Name of the cluster context. (default is the current context)", - ) return cmd } func rm(ctx context.Context, uncli *cli.CLI, opts rmOptions) error { - client, err := uncli.ConnectCluster(ctx, opts.context) + client, err := uncli.ConnectCluster(ctx) if err != nil { return fmt.Errorf("connect to cluster: %w", err) } diff --git a/cmd/uncloud/service/run.go b/cmd/uncloud/service/run.go index f6f3120a..45dc04af 100644 --- a/cmd/uncloud/service/run.go +++ b/cmd/uncloud/service/run.go @@ -34,8 +34,6 @@ type runOptions struct { replicas uint user string volumes []string - - context string } func NewRunCommand() *cobra.Command { @@ -112,11 +110,6 @@ func NewRunCommand() *cobra.Command { " -v /data/uploads:/app/uploads Bind mount /data/uploads host directory to /app/uploads in container\n"+ " -v /host/path:/container/path:ro Bind mount a host directory or file as read-only") - cmd.Flags().StringVarP( - &opts.context, "context", "c", "", - "Name of the cluster context to run the service in. (default is the current context)", - ) - return cmd } @@ -126,7 +119,7 @@ func run(ctx context.Context, uncli *cli.CLI, opts runOptions) error { return err } - clusterClient, err := uncli.ConnectCluster(ctx, opts.context) + clusterClient, err := uncli.ConnectCluster(ctx) if err != nil { return fmt.Errorf("connect to cluster: %w", err) } diff --git a/cmd/uncloud/service/scale.go b/cmd/uncloud/service/scale.go index d7a590d8..a9838131 100644 --- a/cmd/uncloud/service/scale.go +++ b/cmd/uncloud/service/scale.go @@ -15,7 +15,6 @@ import ( type scaleOptions struct { service string replicas uint - context string } func NewScaleCommand() *cobra.Command { @@ -39,11 +38,6 @@ func NewScaleCommand() *cobra.Command { }, } - cmd.Flags().StringVarP( - &opts.context, "context", "c", "", - "Name of the cluster context. (default is the current context)", - ) - return cmd } @@ -57,7 +51,7 @@ func scale(ctx context.Context, uncli *cli.CLI, opts scaleOptions) error { ) } - clusterClient, err := uncli.ConnectCluster(ctx, opts.context) + clusterClient, err := uncli.ConnectCluster(ctx) if err != nil { return fmt.Errorf("connect to cluster: %w", err) } diff --git a/cmd/uncloud/volume/create.go b/cmd/uncloud/volume/create.go index e4fdc190..0508c893 100644 --- a/cmd/uncloud/volume/create.go +++ b/cmd/uncloud/volume/create.go @@ -19,7 +19,6 @@ type createOptions struct { driverOpts []string labels []string machine string - context string } func NewCreateCommand() *cobra.Command { @@ -50,14 +49,12 @@ func NewCreateCommand() *cobra.Command { "Labels to assign to the volume in the form of 'key=value' pairs. Can be specified multiple times.") cmd.Flags().StringVarP(&opts.machine, "machine", "m", "", "Name or ID of the machine to create the volume on.") - cmd.Flags().StringVarP(&opts.context, "context", "c", "", - "Name of the cluster context. (default is the current context)") return cmd } func create(ctx context.Context, uncli *cli.CLI, name string, opts createOptions) error { - client, err := uncli.ConnectCluster(ctx, opts.context) + client, err := uncli.ConnectCluster(ctx) if err != nil { return fmt.Errorf("connect to cluster: %w", err) } diff --git a/cmd/uncloud/volume/inspect.go b/cmd/uncloud/volume/inspect.go index d0a5454f..dd8f66e0 100644 --- a/cmd/uncloud/volume/inspect.go +++ b/cmd/uncloud/volume/inspect.go @@ -13,7 +13,6 @@ import ( type inspectOptions struct { machine string - context string } func NewInspectCommand() *cobra.Command { @@ -32,14 +31,12 @@ func NewInspectCommand() *cobra.Command { cmd.Flags().StringVarP(&opts.machine, "machine", "m", "", "Name or ID of the machine where the volume is located. "+ "If not specified, the volume will be searched across all machines.") - cmd.Flags().StringVarP(&opts.context, "context", "c", "", - "Name of the cluster context. (default is the current context)") return cmd } func inspect(ctx context.Context, uncli *cli.CLI, name string, opts inspectOptions) error { - client, err := uncli.ConnectCluster(ctx, opts.context) + client, err := uncli.ConnectCluster(ctx) if err != nil { return fmt.Errorf("connect to cluster: %w", err) } diff --git a/cmd/uncloud/volume/ls.go b/cmd/uncloud/volume/ls.go index de237f37..19949c31 100644 --- a/cmd/uncloud/volume/ls.go +++ b/cmd/uncloud/volume/ls.go @@ -16,7 +16,6 @@ import ( type listOptions struct { machines []string quiet bool - context string } func NewListCommand() *cobra.Command { @@ -38,14 +37,11 @@ func NewListCommand() *cobra.Command { cmd.Flags().BoolVarP(&opts.quiet, "quiet", "q", false, "Only display volume names.") - cmd.Flags().StringVarP(&opts.context, "context", "c", "", - "Name of the cluster context. (default is the current context)") - return cmd } func list(ctx context.Context, uncli *cli.CLI, opts listOptions) error { - client, err := uncli.ConnectCluster(ctx, opts.context) + client, err := uncli.ConnectCluster(ctx) if err != nil { return fmt.Errorf("connect to cluster: %w", err) } diff --git a/cmd/uncloud/volume/rm.go b/cmd/uncloud/volume/rm.go index e877d03a..dd31e9e8 100644 --- a/cmd/uncloud/volume/rm.go +++ b/cmd/uncloud/volume/rm.go @@ -14,7 +14,6 @@ type removeOptions struct { force bool machines []string yes bool - context string } func NewRemoveCommand() *cobra.Command { @@ -41,14 +40,11 @@ func NewRemoveCommand() *cobra.Command { cmd.Flags().BoolVarP(&opts.yes, "yes", "y", false, "Do not prompt for confirmation before removing the volume(s).") - cmd.Flags().StringVarP(&opts.context, "context", "c", "", - "Name of the cluster context. (default is the current context)") - return cmd } func remove(ctx context.Context, uncli *cli.CLI, names []string, opts removeOptions) error { - client, err := uncli.ConnectCluster(ctx, opts.context) + client, err := uncli.ConnectCluster(ctx) if err != nil { return fmt.Errorf("connect to cluster: %w", err) } diff --git a/internal/cli/build.go b/internal/cli/build.go index 46e1c5e3..247b790d 100644 --- a/internal/cli/build.go +++ b/internal/cli/build.go @@ -40,8 +40,6 @@ type BuildServicesOptions struct { PushRegistry bool // Cluster-specific options (only used if PushCluster is true). - // Context is the name of the cluster context. - Context string // Machines is a list of machine names or IDs to push the image to. If empty, images are pushed to all machines. Machines []string } @@ -95,7 +93,7 @@ func (cli *CLI) BuildServices(ctx context.Context, project *composetypes.Project // Add a line break after the build output. fmt.Fprintln(cli.ProgressOut()) - clusterClient, err := cli.ConnectCluster(ctx, opts.Context) + clusterClient, err := cli.ConnectCluster(ctx) if err != nil { return fmt.Errorf("connect to cluster: %w", err) } diff --git a/internal/cli/cli.go b/internal/cli/cli.go index 9ef6bd73..1bc93fba 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -28,14 +28,16 @@ const ( ) type CLI struct { - Config *config.Config - conn *config.MachineConnection + Config *config.Config + conn *config.MachineConnection + contextOverride string } // New creates a new CLI instance with the given config path or remote machine connection. // If the connection is provided, the config is ignored for all operations which is useful for interacting with // a cluster without creating a config. -func New(configPath string, conn *config.MachineConnection) (*CLI, error) { +// If a non-empty context name is given, it will override the current default. +func New(configPath string, conn *config.MachineConnection, contextName string) (*CLI, error) { if conn != nil { return &CLI{conn: conn}, nil } @@ -46,7 +48,8 @@ func New(configPath string, conn *config.MachineConnection) (*CLI, error) { } return &CLI{ - Config: cfg, + Config: cfg, + contextOverride: contextName, }, nil } @@ -68,19 +71,20 @@ func (cli *CLI) SetCurrentContext(name string) error { return cli.Config.Save() } -// ConnectCluster connects to a cluster using the given context name or the current context if not specified. +// ConnectCluster connects to a cluster using the context override or the current context if not specified. // If the CLI was initialised with a machine connection, the config is ignored and the connection is used instead. -func (cli *CLI) ConnectCluster(ctx context.Context, contextName string) (*client.Client, error) { - return cli.ConnectClusterWithOptions(ctx, contextName, ConnectOptions{ +func (cli *CLI) ConnectCluster(ctx context.Context) (*client.Client, error) { + return cli.ConnectClusterWithOptions(ctx, ConnectOptions{ // Default to showing progress for CLI usage. ShowProgress: true, }) } -// ConnectClusterWithOptions connects to a cluster using the given context name and options. +// ConnectClusterWithOptions connects to a cluster with the given options. // If the CLI was initialised with a machine connection, the config is ignored and the connection is used instead. +// If the CLI has an override context, it is used instead of the current default. // Options are useful when using the CLI as a library where you may want to disable visual feedback. -func (cli *CLI) ConnectClusterWithOptions(ctx context.Context, contextName string, opts ConnectOptions) (*client.Client, error) { +func (cli *CLI) ConnectClusterWithOptions(ctx context.Context, opts ConnectOptions) (*client.Client, error) { if cli.conn != nil { return ConnectCluster(ctx, *cli.conn, opts) } @@ -92,6 +96,8 @@ func (cli *CLI) ConnectClusterWithOptions(ctx context.Context, contextName strin cli.Config.Path(), ) } + + contextName := cli.contextOverride if contextName == "" { // If the cluster is not specified, use the current cluster if set. if cli.Config.CurrentContext == "" { @@ -269,7 +275,6 @@ func (cli *CLI) newContextName(name string) (string, error) { } type AddMachineOptions struct { - Context string MachineName string PublicIP *netip.Addr RemoteMachine *RemoteMachine @@ -282,11 +287,11 @@ type AddMachineOptions struct { // cluster. The machine client is connected to the new machine and can be used to interact with it. // Both client should be closed after use by the caller. func (cli *CLI) AddMachine(ctx context.Context, opts AddMachineOptions) (*client.Client, *client.Client, error) { - contextName := opts.Context + contextName := cli.contextOverride if contextName == "" { contextName = cli.Config.CurrentContext } - c, err := cli.ConnectCluster(ctx, contextName) + c, err := cli.ConnectCluster(ctx) if err != nil { return nil, nil, fmt.Errorf("connect to cluster (context '%s'): %w", contextName, err) } @@ -407,9 +412,6 @@ func (cli *CLI) AddMachine(ctx context.Context, opts AddMachineOptions) (*client } else { connCfg.SSH = config.NewSSHDestination(opts.RemoteMachine.User, opts.RemoteMachine.Host, opts.RemoteMachine.Port) } - if contextName == "" { - contextName = cli.Config.CurrentContext - } cli.Config.Contexts[contextName].Connections = append(cli.Config.Contexts[contextName].Connections, connCfg) if err = cli.Config.Save(); err != nil { return nil, nil, fmt.Errorf("save config: %w", err)