feat(cli): support env var UNCLOUD_DAEMON_VERSION to specify daemon version for "uc machine add/init" (#409)

This commit is contained in:
Anton Ovchinnikov
2026-07-06 10:47:56 +10:00
committed by GitHub
parent d36b28c55a
commit 7c4fcde88d
6 changed files with 90 additions and 10 deletions
+6 -3
View File
@@ -47,9 +47,12 @@ Connection methods:
[ssh://]user@host - Use system 'ssh' command with full SSH config support (default, no prefix required) [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`, ssh+go://user@host - Use Go's built-in SSH library`,
Args: cobra.ExactArgs(1), 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, "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) uncli := cmd.Context().Value("cli").(*cli.CLI)
// Determine connection mode and strip scheme. // Determine connection mode and strip scheme.
@@ -97,7 +100,7 @@ Connection methods:
) )
cmd.Flags().StringVar( cmd.Flags().StringVar(
&opts.version, "version", "latest", &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( cmd.Flags().StringSliceVar(
&opts.wgEndpoints, "wg-endpoint", nil, &opts.wgEndpoints, "wg-endpoint", nil,
+72
View File
@@ -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)
}
+6 -3
View File
@@ -65,9 +65,12 @@ Connection methods:
uc machine init root@<your-server-ip> --no-caddy --no-dns`, uc machine init root@<your-server-ip> --no-caddy --no-dns`,
// TODO: support initialising a cluster on the local machine. // TODO: support initialising a cluster on the local machine.
Args: cobra.MaximumNArgs(1), 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, "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) uncli := cmd.Context().Value("cli").(*cli.CLI)
var remoteMachine *cli.RemoteMachine var remoteMachine *cli.RemoteMachine
@@ -135,7 +138,7 @@ Connection methods:
) )
cmd.Flags().StringVar( cmd.Flags().StringVar(
&opts.version, "version", "latest", &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( cmd.Flags().StringSliceVar(
&opts.wgEndpoints, "wg-endpoint", nil, &opts.wgEndpoints, "wg-endpoint", nil,
+4 -2
View File
@@ -30,9 +30,11 @@ func NewScaleCommand(groupID string) *cobra.Command {
Short: "Scale a replicated service by changing the number of replicas.", Short: "Scale a replicated service by changing the number of replicas.",
Long: "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), 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") cli.BindEnvToFlag(cmd, "yes", "UNCLOUD_AUTO_CONFIRM")
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
uncli := cmd.Context().Value("cli").(*cli.CLI) uncli := cmd.Context().Value("cli").(*cli.CLI)
opts.service = args[0] opts.service = args[0]
@@ -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. --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") --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") -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 --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. 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. Format: IP, IP:PORT, IPv6, or [IPv6]:PORT. Default port is the value of --wg-port if omitted.
@@ -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. --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") --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") -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 --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. 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. Format: IP, IP:PORT, IPv6, or [IPv6]:PORT. Default port is the value of --wg-port if omitted.