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:
appleboy 2025-11-28 21:44:27 +08:00
parent 7a94dda076
commit 36b01aed49
No known key found for this signature in database
4 changed files with 166 additions and 65 deletions

View File

@ -46,6 +46,7 @@ formatters:
- gci - gci
- gofmt - gofmt
- goimports - goimports
- golines
exclusions: exclusions:
generated: lax generated: lax
paths: paths:

71
main.go
View File

@ -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",

View File

@ -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;",
)
} }
} }

View File

@ -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 {