mirror of
https://github.com/appleboy/drone-ssh.git
synced 2026-03-05 22:57:00 -05:00
style: improve code readability with consistent multi-line formatting
- Add golines to the list of golangci-lint formatters - Format multi-line env variable declarations for CLI flags for consistency - Split string slice initializations onto multiple lines for improved readability in tests - Use multi-line function calls for better readability in plugin and test code - Improve readability of script command appends in logic and tests Signed-off-by: appleboy <appleboy.tw@gmail.com>
This commit is contained in:
parent
7a94dda076
commit
36b01aed49
@ -46,6 +46,7 @@ formatters:
|
|||||||
- gci
|
- gci
|
||||||
- gofmt
|
- gofmt
|
||||||
- goimports
|
- goimports
|
||||||
|
- golines
|
||||||
exclusions:
|
exclusions:
|
||||||
generated: lax
|
generated: lax
|
||||||
paths:
|
paths:
|
||||||
|
|||||||
71
main.go
71
main.go
@ -86,7 +86,12 @@ func main() {
|
|||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "ssh-passphrase",
|
Name: "ssh-passphrase",
|
||||||
Usage: "The purpose of the passphrase is usually to encrypt the private key.",
|
Usage: "The purpose of the passphrase is usually to encrypt the private key.",
|
||||||
EnvVars: []string{"PLUGIN_SSH_PASSPHRASE", "PLUGIN_PASSPHRASE", "SSH_PASSPHRASE", "INPUT_PASSPHRASE"},
|
EnvVars: []string{
|
||||||
|
"PLUGIN_SSH_PASSPHRASE",
|
||||||
|
"PLUGIN_PASSPHRASE",
|
||||||
|
"SSH_PASSPHRASE",
|
||||||
|
"INPUT_PASSPHRASE",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "key-path",
|
Name: "key-path",
|
||||||
@ -102,7 +107,11 @@ func main() {
|
|||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "useInsecureCipher",
|
Name: "useInsecureCipher",
|
||||||
Usage: "include more ciphers with use_insecure_cipher",
|
Usage: "include more ciphers with use_insecure_cipher",
|
||||||
EnvVars: []string{"PLUGIN_USE_INSECURE_CIPHER", "SSH_USE_INSECURE_CIPHER", "INPUT_USE_INSECURE_CIPHER"},
|
EnvVars: []string{
|
||||||
|
"PLUGIN_USE_INSECURE_CIPHER",
|
||||||
|
"SSH_USE_INSECURE_CIPHER",
|
||||||
|
"INPUT_USE_INSECURE_CIPHER",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "fingerprint",
|
Name: "fingerprint",
|
||||||
@ -118,7 +127,11 @@ func main() {
|
|||||||
Name: "command.timeout",
|
Name: "command.timeout",
|
||||||
Aliases: []string{"T"},
|
Aliases: []string{"T"},
|
||||||
Usage: "command timeout",
|
Usage: "command timeout",
|
||||||
EnvVars: []string{"PLUGIN_COMMAND_TIMEOUT", "SSH_COMMAND_TIMEOUT", "INPUT_COMMAND_TIMEOUT"},
|
EnvVars: []string{
|
||||||
|
"PLUGIN_COMMAND_TIMEOUT",
|
||||||
|
"SSH_COMMAND_TIMEOUT",
|
||||||
|
"INPUT_COMMAND_TIMEOUT",
|
||||||
|
},
|
||||||
Value: 10 * time.Minute,
|
Value: 10 * time.Minute,
|
||||||
},
|
},
|
||||||
&cli.StringSliceFlag{
|
&cli.StringSliceFlag{
|
||||||
@ -156,34 +169,61 @@ func main() {
|
|||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "proxy.protocol",
|
Name: "proxy.protocol",
|
||||||
Usage: "The IP protocol to use for the proxy. Valid values are \"tcp\". \"tcp4\" or \"tcp6\". Default to tcp.",
|
Usage: "The IP protocol to use for the proxy. Valid values are \"tcp\". \"tcp4\" or \"tcp6\". Default to tcp.",
|
||||||
EnvVars: []string{"PLUGIN_PROXY_PROTOCOL", "SSH_PROXY_PROTOCOL", "INPUT_PROXY_PROTOCOL"},
|
EnvVars: []string{
|
||||||
|
"PLUGIN_PROXY_PROTOCOL",
|
||||||
|
"SSH_PROXY_PROTOCOL",
|
||||||
|
"INPUT_PROXY_PROTOCOL",
|
||||||
|
},
|
||||||
Value: "tcp",
|
Value: "tcp",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "proxy.username",
|
Name: "proxy.username",
|
||||||
Usage: "connect as user of proxy",
|
Usage: "connect as user of proxy",
|
||||||
EnvVars: []string{"PLUGIN_PROXY_USERNAME", "PLUGIN_PROXY_USER", "PROXY_SSH_USERNAME", "INPUT_PROXY_USERNAME"},
|
EnvVars: []string{
|
||||||
|
"PLUGIN_PROXY_USERNAME",
|
||||||
|
"PLUGIN_PROXY_USER",
|
||||||
|
"PROXY_SSH_USERNAME",
|
||||||
|
"INPUT_PROXY_USERNAME",
|
||||||
|
},
|
||||||
Value: "root",
|
Value: "root",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "proxy.password",
|
Name: "proxy.password",
|
||||||
Usage: "user password of proxy",
|
Usage: "user password of proxy",
|
||||||
EnvVars: []string{"PLUGIN_PROXY_PASSWORD", "PROXY_SSH_PASSWORD", "INPUT_PROXY_PASSWORD"},
|
EnvVars: []string{
|
||||||
|
"PLUGIN_PROXY_PASSWORD",
|
||||||
|
"PROXY_SSH_PASSWORD",
|
||||||
|
"INPUT_PROXY_PASSWORD",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "proxy.ssh-key",
|
Name: "proxy.ssh-key",
|
||||||
Usage: "private ssh key of proxy",
|
Usage: "private ssh key of proxy",
|
||||||
EnvVars: []string{"PLUGIN_PROXY_SSH_KEY", "PLUGIN_PROXY_KEY", "PROXY_SSH_KEY", "INPUT_PROXY_KEY"},
|
EnvVars: []string{
|
||||||
|
"PLUGIN_PROXY_SSH_KEY",
|
||||||
|
"PLUGIN_PROXY_KEY",
|
||||||
|
"PROXY_SSH_KEY",
|
||||||
|
"INPUT_PROXY_KEY",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "proxy.ssh-passphrase",
|
Name: "proxy.ssh-passphrase",
|
||||||
Usage: "The purpose of the passphrase is usually to encrypt the private key.",
|
Usage: "The purpose of the passphrase is usually to encrypt the private key.",
|
||||||
EnvVars: []string{"PLUGIN_PROXY_SSH_PASSPHRASE", "PLUGIN_PROXY_PASSPHRASE", "PROXY_SSH_PASSPHRASE", "INPUT_PROXY_PASSPHRASE"},
|
EnvVars: []string{
|
||||||
|
"PLUGIN_PROXY_SSH_PASSPHRASE",
|
||||||
|
"PLUGIN_PROXY_PASSPHRASE",
|
||||||
|
"PROXY_SSH_PASSPHRASE",
|
||||||
|
"INPUT_PROXY_PASSPHRASE",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "proxy.key-path",
|
Name: "proxy.key-path",
|
||||||
Usage: "ssh private key path of proxy",
|
Usage: "ssh private key path of proxy",
|
||||||
EnvVars: []string{"PLUGIN_PROXY_KEY_PATH", "PROXY_SSH_KEY_PATH", "INPUT_PROXY_KEY_PATH"},
|
EnvVars: []string{
|
||||||
|
"PLUGIN_PROXY_KEY_PATH",
|
||||||
|
"PROXY_SSH_KEY_PATH",
|
||||||
|
"INPUT_PROXY_KEY_PATH",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.DurationFlag{
|
&cli.DurationFlag{
|
||||||
Name: "proxy.timeout",
|
Name: "proxy.timeout",
|
||||||
@ -198,12 +238,21 @@ func main() {
|
|||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "proxy.useInsecureCipher",
|
Name: "proxy.useInsecureCipher",
|
||||||
Usage: "include more ciphers with use_insecure_cipher",
|
Usage: "include more ciphers with use_insecure_cipher",
|
||||||
EnvVars: []string{"PLUGIN_PROXY_USE_INSECURE_CIPHER", "PROXY_SSH_USE_INSECURE_CIPHER", "INPUT_PROXY_USE_INSECURE_CIPHER"},
|
EnvVars: []string{
|
||||||
|
"PLUGIN_PROXY_USE_INSECURE_CIPHER",
|
||||||
|
"PROXY_SSH_USE_INSECURE_CIPHER",
|
||||||
|
"INPUT_PROXY_USE_INSECURE_CIPHER",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "proxy.fingerprint",
|
Name: "proxy.fingerprint",
|
||||||
Usage: "fingerprint SHA256 of the host public key, default is to skip verification",
|
Usage: "fingerprint SHA256 of the host public key, default is to skip verification",
|
||||||
EnvVars: []string{"PLUGIN_PROXY_FINGERPRINT", "PROXY_SSH_FINGERPRINT", "PROXY_FINGERPRINT", "INPUT_PROXY_FINGERPRINT"},
|
EnvVars: []string{
|
||||||
|
"PLUGIN_PROXY_FINGERPRINT",
|
||||||
|
"PROXY_SSH_FINGERPRINT",
|
||||||
|
"PROXY_FINGERPRINT",
|
||||||
|
"INPUT_PROXY_FINGERPRINT",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringSliceFlag{
|
&cli.StringSliceFlag{
|
||||||
Name: "envs",
|
Name: "envs",
|
||||||
|
|||||||
19
plugin.go
19
plugin.go
@ -15,7 +15,9 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
errMissingHost = errors.New("error: missing server host")
|
errMissingHost = errors.New("error: missing server host")
|
||||||
errMissingPasswordOrKey = errors.New("error: can't connect without a private SSH key or password")
|
errMissingPasswordOrKey = errors.New(
|
||||||
|
"error: can't connect without a private SSH key or password",
|
||||||
|
)
|
||||||
errCommandTimeOut = errors.New("error: command timeout")
|
errCommandTimeOut = errors.New("error: command timeout")
|
||||||
envsFormat = "export {NAME}={VALUE}"
|
envsFormat = "export {NAME}={VALUE}"
|
||||||
)
|
)
|
||||||
@ -119,7 +121,10 @@ func (p Plugin) exec(host string, wg *sync.WaitGroup, errChannel chan error) {
|
|||||||
for _, key := range p.Config.Envs {
|
for _, key := range p.Config.Envs {
|
||||||
key = strings.ToUpper(key)
|
key = strings.ToUpper(key)
|
||||||
if val, found := os.LookupEnv(key); found {
|
if val, found := os.LookupEnv(key); found {
|
||||||
env = append(env, p.format(p.Config.EnvsFormat, "{NAME}", key, "{VALUE}", escapeArg(val)))
|
env = append(
|
||||||
|
env,
|
||||||
|
p.format(p.Config.EnvsFormat, "{NAME}", key, "{VALUE}", escapeArg(val)),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +136,10 @@ func (p Plugin) exec(host string, wg *sync.WaitGroup, errChannel chan error) {
|
|||||||
p.log(host, "======END======")
|
p.log(host, "======END======")
|
||||||
}
|
}
|
||||||
|
|
||||||
stdoutChan, stderrChan, doneChan, errChan, err := ssh.Stream(strings.Join(p.Config.Script, "\n"), p.Config.CommandTimeout)
|
stdoutChan, stderrChan, doneChan, errChan, err := ssh.Stream(
|
||||||
|
strings.Join(p.Config.Script, "\n"),
|
||||||
|
p.Config.CommandTimeout,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errChannel <- err
|
errChannel <- err
|
||||||
return
|
return
|
||||||
@ -257,7 +265,10 @@ func (p Plugin) scriptCommands() []string {
|
|||||||
}
|
}
|
||||||
commands = append(commands, cmd)
|
commands = append(commands, cmd)
|
||||||
if p.Config.ScriptStop && cmd[(len(cmd)-1):] != "\\" {
|
if p.Config.ScriptStop && cmd[(len(cmd)-1):] != "\\" {
|
||||||
commands = append(commands, "DRONE_SSH_PREV_COMMAND_EXIT_CODE=$? ; if [ $DRONE_SSH_PREV_COMMAND_EXIT_CODE -ne 0 ]; then exit $DRONE_SSH_PREV_COMMAND_EXIT_CODE; fi;")
|
commands = append(
|
||||||
|
commands,
|
||||||
|
"DRONE_SSH_PREV_COMMAND_EXIT_CODE=$? ; if [ $DRONE_SSH_PREV_COMMAND_EXIT_CODE -ne 0 ]; then exit $DRONE_SSH_PREV_COMMAND_EXIT_CODE; fi;",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -157,7 +157,11 @@ func TestStreamFromSSHCommand(t *testing.T) {
|
|||||||
Username: "drone-scp",
|
Username: "drone-scp",
|
||||||
Port: 22,
|
Port: 22,
|
||||||
KeyPath: "./tests/.ssh/id_rsa",
|
KeyPath: "./tests/.ssh/id_rsa",
|
||||||
Script: []string{"whoami", "for i in {1..5}; do echo ${i}; sleep 1; done", "echo 'done'"},
|
Script: []string{
|
||||||
|
"whoami",
|
||||||
|
"for i in {1..5}; do echo ${i}; sleep 1; done",
|
||||||
|
"echo 'done'",
|
||||||
|
},
|
||||||
CommandTimeout: 60 * time.Second,
|
CommandTimeout: 60 * time.Second,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -295,7 +299,14 @@ func TestSetExistingENV(t *testing.T) {
|
|||||||
KeyPath: "./tests/.ssh/id_rsa",
|
KeyPath: "./tests/.ssh/id_rsa",
|
||||||
Envs: []string{"foo", "bar", "baz"},
|
Envs: []string{"foo", "bar", "baz"},
|
||||||
Debug: true,
|
Debug: true,
|
||||||
Script: []string{"export FOO", "export BAR", "export BAZ", "env | grep -q '^FOO=Value for foo$'", "env | grep -q '^BAR=$'", "if env | grep -q BAZ; then false; else true; fi"},
|
Script: []string{
|
||||||
|
"export FOO",
|
||||||
|
"export BAR",
|
||||||
|
"export BAZ",
|
||||||
|
"env | grep -q '^FOO=Value for foo$'",
|
||||||
|
"env | grep -q '^BAR=$'",
|
||||||
|
"if env | grep -q BAZ; then false; else true; fi",
|
||||||
|
},
|
||||||
CommandTimeout: 1 * time.Second,
|
CommandTimeout: 1 * time.Second,
|
||||||
Proxy: easyssh.DefaultConfig{
|
Proxy: easyssh.DefaultConfig{
|
||||||
Server: "localhost",
|
Server: "localhost",
|
||||||
@ -317,7 +328,11 @@ func TestSyncMode(t *testing.T) {
|
|||||||
Username: "drone-scp",
|
Username: "drone-scp",
|
||||||
Port: 22,
|
Port: 22,
|
||||||
KeyPath: "./tests/.ssh/id_rsa",
|
KeyPath: "./tests/.ssh/id_rsa",
|
||||||
Script: []string{"whoami", "for i in {1..3}; do echo ${i}; sleep 1; done", "echo 'done'"},
|
Script: []string{
|
||||||
|
"whoami",
|
||||||
|
"for i in {1..3}; do echo ${i}; sleep 1; done",
|
||||||
|
"echo 'done'",
|
||||||
|
},
|
||||||
CommandTimeout: 60 * time.Second,
|
CommandTimeout: 60 * time.Second,
|
||||||
Sync: true,
|
Sync: true,
|
||||||
},
|
},
|
||||||
@ -671,7 +686,12 @@ func TestPlugin_scriptCommands(t *testing.T) {
|
|||||||
ScriptStop: true,
|
ScriptStop: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: []string{"mkdir a", "DRONE_SSH_PREV_COMMAND_EXIT_CODE=$? ; if [ $DRONE_SSH_PREV_COMMAND_EXIT_CODE -ne 0 ]; then exit $DRONE_SSH_PREV_COMMAND_EXIT_CODE; fi;", "mkdir b", "DRONE_SSH_PREV_COMMAND_EXIT_CODE=$? ; if [ $DRONE_SSH_PREV_COMMAND_EXIT_CODE -ne 0 ]; then exit $DRONE_SSH_PREV_COMMAND_EXIT_CODE; fi;"},
|
want: []string{
|
||||||
|
"mkdir a",
|
||||||
|
"DRONE_SSH_PREV_COMMAND_EXIT_CODE=$? ; if [ $DRONE_SSH_PREV_COMMAND_EXIT_CODE -ne 0 ]; then exit $DRONE_SSH_PREV_COMMAND_EXIT_CODE; fi;",
|
||||||
|
"mkdir b",
|
||||||
|
"DRONE_SSH_PREV_COMMAND_EXIT_CODE=$? ; if [ $DRONE_SSH_PREV_COMMAND_EXIT_CODE -ne 0 ]; then exit $DRONE_SSH_PREV_COMMAND_EXIT_CODE; fi;",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "normal testing 2",
|
name: "normal testing 2",
|
||||||
@ -681,7 +701,14 @@ func TestPlugin_scriptCommands(t *testing.T) {
|
|||||||
ScriptStop: true,
|
ScriptStop: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: []string{"mkdir a", "DRONE_SSH_PREV_COMMAND_EXIT_CODE=$? ; if [ $DRONE_SSH_PREV_COMMAND_EXIT_CODE -ne 0 ]; then exit $DRONE_SSH_PREV_COMMAND_EXIT_CODE; fi;", "mkdir c", "DRONE_SSH_PREV_COMMAND_EXIT_CODE=$? ; if [ $DRONE_SSH_PREV_COMMAND_EXIT_CODE -ne 0 ]; then exit $DRONE_SSH_PREV_COMMAND_EXIT_CODE; fi;", "mkdir b", "DRONE_SSH_PREV_COMMAND_EXIT_CODE=$? ; if [ $DRONE_SSH_PREV_COMMAND_EXIT_CODE -ne 0 ]; then exit $DRONE_SSH_PREV_COMMAND_EXIT_CODE; fi;"},
|
want: []string{
|
||||||
|
"mkdir a",
|
||||||
|
"DRONE_SSH_PREV_COMMAND_EXIT_CODE=$? ; if [ $DRONE_SSH_PREV_COMMAND_EXIT_CODE -ne 0 ]; then exit $DRONE_SSH_PREV_COMMAND_EXIT_CODE; fi;",
|
||||||
|
"mkdir c",
|
||||||
|
"DRONE_SSH_PREV_COMMAND_EXIT_CODE=$? ; if [ $DRONE_SSH_PREV_COMMAND_EXIT_CODE -ne 0 ]; then exit $DRONE_SSH_PREV_COMMAND_EXIT_CODE; fi;",
|
||||||
|
"mkdir b",
|
||||||
|
"DRONE_SSH_PREV_COMMAND_EXIT_CODE=$? ; if [ $DRONE_SSH_PREV_COMMAND_EXIT_CODE -ne 0 ]; then exit $DRONE_SSH_PREV_COMMAND_EXIT_CODE; fi;",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
// See: https://github.com/appleboy/ssh-action/issues/75#issuecomment-668314271
|
// See: https://github.com/appleboy/ssh-action/issues/75#issuecomment-668314271
|
||||||
{
|
{
|
||||||
@ -692,7 +719,13 @@ func TestPlugin_scriptCommands(t *testing.T) {
|
|||||||
ScriptStop: true,
|
ScriptStop: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: []string{"ls \\", "-lah", "DRONE_SSH_PREV_COMMAND_EXIT_CODE=$? ; if [ $DRONE_SSH_PREV_COMMAND_EXIT_CODE -ne 0 ]; then exit $DRONE_SSH_PREV_COMMAND_EXIT_CODE; fi;", "mkdir a", "DRONE_SSH_PREV_COMMAND_EXIT_CODE=$? ; if [ $DRONE_SSH_PREV_COMMAND_EXIT_CODE -ne 0 ]; then exit $DRONE_SSH_PREV_COMMAND_EXIT_CODE; fi;"},
|
want: []string{
|
||||||
|
"ls \\",
|
||||||
|
"-lah",
|
||||||
|
"DRONE_SSH_PREV_COMMAND_EXIT_CODE=$? ; if [ $DRONE_SSH_PREV_COMMAND_EXIT_CODE -ne 0 ]; then exit $DRONE_SSH_PREV_COMMAND_EXIT_CODE; fi;",
|
||||||
|
"mkdir a",
|
||||||
|
"DRONE_SSH_PREV_COMMAND_EXIT_CODE=$? ; if [ $DRONE_SSH_PREV_COMMAND_EXIT_CODE -ne 0 ]; then exit $DRONE_SSH_PREV_COMMAND_EXIT_CODE; fi;",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "trim space",
|
name: "trim space",
|
||||||
@ -938,12 +971,19 @@ func runSSHContainerTest(t *testing.T, cfg SSHTestConfig) {
|
|||||||
WaitingFor: wait.ForListeningPort("2222/tcp").WithStartupTimeout(180 * time.Second),
|
WaitingFor: wait.ForListeningPort("2222/tcp").WithStartupTimeout(180 * time.Second),
|
||||||
}
|
}
|
||||||
|
|
||||||
sshContainer, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
|
sshContainer, err := testcontainers.GenericContainer(
|
||||||
|
ctx,
|
||||||
|
testcontainers.GenericContainerRequest{
|
||||||
ContainerRequest: req,
|
ContainerRequest: req,
|
||||||
Started: true,
|
Started: true,
|
||||||
})
|
},
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Skipf("Could not start container with image %s: %v. Check Docker environment and image availability. Skipping test.", req.Image, err)
|
t.Skipf(
|
||||||
|
"Could not start container with image %s: %v. Check Docker environment and image availability. Skipping test.",
|
||||||
|
req.Image,
|
||||||
|
err,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := sshContainer.Terminate(ctx); err != nil {
|
if err := sshContainer.Terminate(ctx); err != nil {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user