diff --git a/cmd/uc/machine/add.go b/cmd/uc/machine/add.go index 3adbbfea..ff9332c2 100644 --- a/cmd/uc/machine/add.go +++ b/cmd/uc/machine/add.go @@ -47,9 +47,12 @@ Connection methods: [ssh://]user@host - Use system 'ssh' command with full SSH config support (default, no prefix required) ssh+go://user@host - Use Go's built-in SSH library`, Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { + PreRunE: func(cmd *cobra.Command, args []string) error { cli.BindEnvToFlag(cmd, "yes", "UNCLOUD_AUTO_CONFIRM") - + cli.BindEnvToFlag(cmd, "version", "UNCLOUD_DAEMON_VERSION") + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { uncli := cmd.Context().Value("cli").(*cli.CLI) // Determine connection mode and strip scheme. @@ -97,7 +100,7 @@ Connection methods: ) cmd.Flags().StringVar( &opts.version, "version", "latest", - "Version of the Uncloud daemon to install on the machine.", + "Version of the Uncloud daemon to install on the machine. [$UNCLOUD_DAEMON_VERSION]", ) cmd.Flags().StringSliceVar( &opts.wgEndpoints, "wg-endpoint", nil, diff --git a/cmd/uc/machine/flags_test.go b/cmd/uc/machine/flags_test.go new file mode 100644 index 00000000..13b07062 --- /dev/null +++ b/cmd/uc/machine/flags_test.go @@ -0,0 +1,72 @@ +package machine + +import ( + "testing" + + "github.com/spf13/cobra" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// runVersionFlagEnvTest builds the given command for each case, stubs out RunE so only flag +// parsing and PreRunE run (no SSH calls), and asserts the resolved --version flag value. +// Note: cannot use t.Parallel() because subtests use t.Setenv(). +func runVersionFlagEnvTest(t *testing.T, newCommand func() *cobra.Command) { + t.Helper() + + tests := []struct { + name string + args []string + env string + want string + }{ + { + name: "env var sets version when flag not passed", + args: []string{"root@localhost"}, + env: "v1.2.3", + want: "v1.2.3", + }, + { + name: "explicit flag wins over env var", + args: []string{"root@localhost", "--version", "v9.9.9"}, + env: "v1.2.3", + want: "v9.9.9", + }, + { + name: "defaults to latest when neither flag nor env var set", + args: []string{"root@localhost"}, + want: "latest", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.env != "" { + t.Setenv("UNCLOUD_DAEMON_VERSION", tt.env) + } + + cmd := newCommand() + cmd.RunE = func(*cobra.Command, []string) error { + return nil + } + cmd.SetArgs(tt.args) + require.NoError(t, cmd.Execute()) + + version, err := cmd.Flags().GetString("version") + require.NoError(t, err) + assert.Equal(t, tt.want, version) + }) + } +} + +// TestInitCommandVersionFlagEnvVar verifies that the UNCLOUD_DAEMON_VERSION environment variable +// is bound to the --version flag of 'machine init', and that an explicit flag wins. +func TestInitCommandVersionFlagEnvVar(t *testing.T) { + runVersionFlagEnvTest(t, NewInitCommand) +} + +// TestAddCommandVersionFlagEnvVar verifies that the UNCLOUD_DAEMON_VERSION environment variable +// is bound to the --version flag of 'machine add', and that an explicit flag wins. +func TestAddCommandVersionFlagEnvVar(t *testing.T) { + runVersionFlagEnvTest(t, NewAddCommand) +} diff --git a/cmd/uc/machine/init.go b/cmd/uc/machine/init.go index 19a16b3c..738e0b08 100644 --- a/cmd/uc/machine/init.go +++ b/cmd/uc/machine/init.go @@ -65,9 +65,12 @@ Connection methods: uc machine init root@ --no-caddy --no-dns`, // TODO: support initialising a cluster on the local machine. Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { + PreRunE: func(cmd *cobra.Command, args []string) error { cli.BindEnvToFlag(cmd, "yes", "UNCLOUD_AUTO_CONFIRM") - + cli.BindEnvToFlag(cmd, "version", "UNCLOUD_DAEMON_VERSION") + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { uncli := cmd.Context().Value("cli").(*cli.CLI) var remoteMachine *cli.RemoteMachine @@ -135,7 +138,7 @@ Connection methods: ) cmd.Flags().StringVar( &opts.version, "version", "latest", - "Version of the Uncloud daemon to install on the machine.", + "Version of the Uncloud daemon to install on the machine. [$UNCLOUD_DAEMON_VERSION]", ) cmd.Flags().StringSliceVar( &opts.wgEndpoints, "wg-endpoint", nil, diff --git a/cmd/uc/service/scale.go b/cmd/uc/service/scale.go index e67a3168..76a40a96 100644 --- a/cmd/uc/service/scale.go +++ b/cmd/uc/service/scale.go @@ -30,9 +30,11 @@ func NewScaleCommand(groupID string) *cobra.Command { Short: "Scale a replicated service by changing the number of replicas.", Long: "Scale a replicated service by changing the number of replicas.", Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) error { + PreRunE: func(cmd *cobra.Command, args []string) error { cli.BindEnvToFlag(cmd, "yes", "UNCLOUD_AUTO_CONFIRM") - + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { uncli := cmd.Context().Value("cli").(*cli.CLI) opts.service = args[0] diff --git a/website/docs/9-cli-reference/uc_machine_add.md b/website/docs/9-cli-reference/uc_machine_add.md index 017d2d09..2275732d 100644 --- a/website/docs/9-cli-reference/uc_machine_add.md +++ b/website/docs/9-cli-reference/uc_machine_add.md @@ -26,7 +26,7 @@ uc machine add [USER@]HOST[:PORT] [flags] --no-install Skip installation of Docker and the Uncloud daemon on the machine. Assumes they're already installed and running. --public-ip string Public IP address of the machine for ingress configuration. Use 'auto' for automatic detection, blank '' or 'none' to disable ingress on this machine, or specify an IP address. (default "auto") -i, --ssh-key string Path to SSH private key for remote login (if not already added to SSH agent). (default "~/.ssh/id_ed25519") - --version string Version of the Uncloud daemon to install on the machine. (default "latest") + --version string Version of the Uncloud daemon to install on the machine. [$UNCLOUD_DAEMON_VERSION] (default "latest") --wg-endpoint strings WireGuard endpoint address that other machines in the cluster should use to establish WireGuard connections to this machine. This doesn't change the address/port WireGuard listens on the machine. Format: IP, IP:PORT, IPv6, or [IPv6]:PORT. Default port is the value of --wg-port if omitted. diff --git a/website/docs/9-cli-reference/uc_machine_init.md b/website/docs/9-cli-reference/uc_machine_init.md index 3197cbe0..72a3e0f4 100644 --- a/website/docs/9-cli-reference/uc_machine_init.md +++ b/website/docs/9-cli-reference/uc_machine_init.md @@ -48,7 +48,7 @@ uc machine init [schema://]USER@HOST[:PORT] [flags] --no-install Skip installation of Docker and the Uncloud daemon on the machine. Assumes they're already installed and running. --public-ip string Public IP address of the machine for ingress configuration. Use 'auto' for automatic detection, blank '' or 'none' to disable ingress on this machine, or specify an IP address. (default "auto") -i, --ssh-key string Path to SSH private key for remote login (if not already added to SSH agent). (default "~/.ssh/id_ed25519") - --version string Version of the Uncloud daemon to install on the machine. (default "latest") + --version string Version of the Uncloud daemon to install on the machine. [$UNCLOUD_DAEMON_VERSION] (default "latest") --wg-endpoint strings WireGuard endpoint address that other machines in the cluster should use to establish WireGuard connections to this machine. This doesn't change the address/port WireGuard listens on the machine. Format: IP, IP:PORT, IPv6, or [IPv6]:PORT. Default port is the value of --wg-port if omitted.