refactor(ansible): rename cli helpers for clarity
This commit is contained in:
parent
103b5ed255
commit
8ebfafd6cc
5 changed files with 42 additions and 42 deletions
|
|
@ -1,4 +1,4 @@
|
|||
package anscmd
|
||||
package ansiblecmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
@ -15,8 +15,8 @@ import (
|
|||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// args extracts all positional arguments from Options.
|
||||
func args(opts core.Options) []string {
|
||||
// positionalArgs extracts all positional arguments from Options.
|
||||
func positionalArgs(opts core.Options) []string {
|
||||
var out []string
|
||||
for _, o := range opts.Items() {
|
||||
if o.Key == "_arg" {
|
||||
|
|
@ -28,8 +28,8 @@ func args(opts core.Options) []string {
|
|||
return out
|
||||
}
|
||||
|
||||
// firstString returns the first non-empty string for any of the provided keys.
|
||||
func firstString(opts core.Options, keys ...string) string {
|
||||
// firstStringOption returns the first non-empty string for any of the provided keys.
|
||||
func firstStringOption(opts core.Options, keys ...string) string {
|
||||
for _, key := range keys {
|
||||
if value := opts.String(key); value != "" {
|
||||
return value
|
||||
|
|
@ -38,8 +38,8 @@ func firstString(opts core.Options, keys ...string) string {
|
|||
return ""
|
||||
}
|
||||
|
||||
// firstBool returns true when any of the provided keys is set to true.
|
||||
func firstBool(opts core.Options, keys ...string) bool {
|
||||
// firstBoolOption returns true when any of the provided keys is set to true.
|
||||
func firstBoolOption(opts core.Options, keys ...string) bool {
|
||||
for _, key := range keys {
|
||||
if opts.Bool(key) {
|
||||
return true
|
||||
|
|
@ -53,7 +53,7 @@ func firstBool(opts core.Options, keys ...string) bool {
|
|||
// `-v` tokens, so we count them from os.Args as a fallback.
|
||||
func verbosityLevel(opts core.Options, rawArgs []string) int {
|
||||
level := opts.Int("verbose")
|
||||
if firstBool(opts, "v") && level < 1 {
|
||||
if firstBoolOption(opts, "v") && level < 1 {
|
||||
level = 1
|
||||
}
|
||||
|
||||
|
|
@ -182,18 +182,18 @@ func parseKeyValueExtraVars(value string) map[string]any {
|
|||
return vars
|
||||
}
|
||||
|
||||
// testKeyFile resolves the SSH key flag used by the ansible test subcommand.
|
||||
func testKeyFile(opts core.Options) string {
|
||||
// resolveTestSSHKeyFile resolves the SSH key flag used by the ansible test subcommand.
|
||||
func resolveTestSSHKeyFile(opts core.Options) string {
|
||||
if key := opts.String("key"); key != "" {
|
||||
return key
|
||||
}
|
||||
return opts.String("i")
|
||||
}
|
||||
|
||||
func runAnsible(opts core.Options) core.Result {
|
||||
positional := args(opts)
|
||||
func runPlaybookCommand(opts core.Options) core.Result {
|
||||
positional := positionalArgs(opts)
|
||||
if len(positional) < 1 {
|
||||
return core.Result{Value: coreerr.E("runAnsible", "usage: ansible <playbook>", nil)}
|
||||
return core.Result{Value: coreerr.E("runPlaybookCommand", "usage: ansible <playbook>", nil)}
|
||||
}
|
||||
playbookPath := positional[0]
|
||||
|
||||
|
|
@ -203,7 +203,7 @@ func runAnsible(opts core.Options) core.Result {
|
|||
}
|
||||
|
||||
if !coreio.Local.Exists(playbookPath) {
|
||||
return core.Result{Value: coreerr.E("runAnsible", sprintf("playbook not found: %s", playbookPath), nil)}
|
||||
return core.Result{Value: coreerr.E("runPlaybookCommand", sprintf("playbook not found: %s", playbookPath), nil)}
|
||||
}
|
||||
|
||||
// Create executor
|
||||
|
|
@ -212,12 +212,12 @@ func runAnsible(opts core.Options) core.Result {
|
|||
defer executor.Close()
|
||||
|
||||
// Set options
|
||||
executor.Limit = firstString(opts, "limit", "l")
|
||||
executor.Limit = firstStringOption(opts, "limit", "l")
|
||||
executor.CheckMode = opts.Bool("check")
|
||||
executor.Diff = opts.Bool("diff")
|
||||
executor.Verbose = verbosityLevel(opts, os.Args[1:])
|
||||
|
||||
if tags := firstString(opts, "tags", "t"); tags != "" {
|
||||
if tags := firstStringOption(opts, "tags", "t"); tags != "" {
|
||||
executor.Tags = split(tags, ",")
|
||||
}
|
||||
if skipTags := opts.String("skip-tags"); skipTags != "" {
|
||||
|
|
@ -227,20 +227,20 @@ func runAnsible(opts core.Options) core.Result {
|
|||
// Parse extra vars
|
||||
vars, err := extraVars(opts)
|
||||
if err != nil {
|
||||
return core.Result{Value: coreerr.E("runAnsible", "parse extra vars", err)}
|
||||
return core.Result{Value: coreerr.E("runPlaybookCommand", "parse extra vars", err)}
|
||||
}
|
||||
for key, value := range vars {
|
||||
executor.SetVar(key, value)
|
||||
}
|
||||
|
||||
// Load inventory
|
||||
if invPath := firstString(opts, "inventory", "i"); invPath != "" {
|
||||
if invPath := firstStringOption(opts, "inventory", "i"); invPath != "" {
|
||||
if !pathIsAbs(invPath) {
|
||||
invPath = absPath(invPath)
|
||||
}
|
||||
|
||||
if !coreio.Local.Exists(invPath) {
|
||||
return core.Result{Value: coreerr.E("runAnsible", sprintf("inventory not found: %s", invPath), nil)}
|
||||
return core.Result{Value: coreerr.E("runPlaybookCommand", sprintf("inventory not found: %s", invPath), nil)}
|
||||
}
|
||||
|
||||
if coreio.Local.IsDir(invPath) {
|
||||
|
|
@ -254,7 +254,7 @@ func runAnsible(opts core.Options) core.Result {
|
|||
}
|
||||
|
||||
if err := executor.SetInventory(invPath); err != nil {
|
||||
return core.Result{Value: coreerr.E("runAnsible", "load inventory", err)}
|
||||
return core.Result{Value: coreerr.E("runPlaybookCommand", "load inventory", err)}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -330,7 +330,7 @@ func runAnsible(opts core.Options) core.Result {
|
|||
print("Running playbook: %s", playbookPath)
|
||||
|
||||
if err := executor.Run(ctx, playbookPath); err != nil {
|
||||
return core.Result{Value: coreerr.E("runAnsible", "playbook failed", err)}
|
||||
return core.Result{Value: coreerr.E("runPlaybookCommand", "playbook failed", err)}
|
||||
}
|
||||
|
||||
print("")
|
||||
|
|
@ -339,10 +339,10 @@ func runAnsible(opts core.Options) core.Result {
|
|||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
func runAnsibleTest(opts core.Options) core.Result {
|
||||
positional := args(opts)
|
||||
func runSSHTestCommand(opts core.Options) core.Result {
|
||||
positional := positionalArgs(opts)
|
||||
if len(positional) < 1 {
|
||||
return core.Result{Value: coreerr.E("runAnsibleTest", "usage: ansible test <host>", nil)}
|
||||
return core.Result{Value: coreerr.E("runSSHTestCommand", "usage: ansible test <host>", nil)}
|
||||
}
|
||||
host := positional[0]
|
||||
|
||||
|
|
@ -351,15 +351,15 @@ func runAnsibleTest(opts core.Options) core.Result {
|
|||
cfg := ansible.SSHConfig{
|
||||
Host: host,
|
||||
Port: opts.Int("port"),
|
||||
User: firstString(opts, "user", "u"),
|
||||
User: firstStringOption(opts, "user", "u"),
|
||||
Password: opts.String("password"),
|
||||
KeyFile: testKeyFile(opts),
|
||||
KeyFile: resolveTestSSHKeyFile(opts),
|
||||
Timeout: 30 * time.Second,
|
||||
}
|
||||
|
||||
client, err := ansible.NewSSHClient(cfg)
|
||||
if err != nil {
|
||||
return core.Result{Value: coreerr.E("runAnsibleTest", "create client", err)}
|
||||
return core.Result{Value: coreerr.E("runSSHTestCommand", "create client", err)}
|
||||
}
|
||||
defer func() { _ = client.Close() }()
|
||||
|
||||
|
|
@ -369,7 +369,7 @@ func runAnsibleTest(opts core.Options) core.Result {
|
|||
// Test connection
|
||||
start := time.Now()
|
||||
if err := client.Connect(ctx); err != nil {
|
||||
return core.Result{Value: coreerr.E("runAnsibleTest", "connect failed", err)}
|
||||
return core.Result{Value: coreerr.E("runSSHTestCommand", "connect failed", err)}
|
||||
}
|
||||
connectTime := time.Since(start)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package anscmd
|
||||
package ansiblecmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
|
@ -110,7 +110,7 @@ func TestFirstString_Good_PrefersFirstNonEmptyKey(t *testing.T) {
|
|||
core.Option{Key: "i", Value: "/tmp/inventory.yml"},
|
||||
)
|
||||
|
||||
assert.Equal(t, "/tmp/inventory.yml", firstString(opts, "inventory", "i"))
|
||||
assert.Equal(t, "/tmp/inventory.yml", firstStringOption(opts, "inventory", "i"))
|
||||
}
|
||||
|
||||
func TestFirstBool_Good_UsesAlias(t *testing.T) {
|
||||
|
|
@ -118,7 +118,7 @@ func TestFirstBool_Good_UsesAlias(t *testing.T) {
|
|||
core.Option{Key: "v", Value: true},
|
||||
)
|
||||
|
||||
assert.True(t, firstBool(opts, "verbose", "v"))
|
||||
assert.True(t, firstBoolOption(opts, "verbose", "v"))
|
||||
}
|
||||
|
||||
func TestVerbosityLevel_Good_CountsStackedShortFlags(t *testing.T) {
|
||||
|
|
@ -145,7 +145,7 @@ func TestTestKeyFile_Good_PrefersExplicitKey(t *testing.T) {
|
|||
core.Option{Key: "i", Value: "/tmp/ignored"},
|
||||
)
|
||||
|
||||
assert.Equal(t, "/tmp/id_ed25519", testKeyFile(opts))
|
||||
assert.Equal(t, "/tmp/id_ed25519", resolveTestSSHKeyFile(opts))
|
||||
}
|
||||
|
||||
func TestTestKeyFile_Good_FallsBackToShortAlias(t *testing.T) {
|
||||
|
|
@ -153,7 +153,7 @@ func TestTestKeyFile_Good_FallsBackToShortAlias(t *testing.T) {
|
|||
core.Option{Key: "i", Value: "/tmp/id_ed25519"},
|
||||
)
|
||||
|
||||
assert.Equal(t, "/tmp/id_ed25519", testKeyFile(opts))
|
||||
assert.Equal(t, "/tmp/id_ed25519", resolveTestSSHKeyFile(opts))
|
||||
}
|
||||
|
||||
func TestFirstString_Good_ResolvesShortUserAlias(t *testing.T) {
|
||||
|
|
@ -161,7 +161,7 @@ func TestFirstString_Good_ResolvesShortUserAlias(t *testing.T) {
|
|||
core.Option{Key: "u", Value: "deploy"},
|
||||
)
|
||||
|
||||
cfgUser := firstString(opts, "user", "u")
|
||||
cfgUser := firstStringOption(opts, "user", "u")
|
||||
|
||||
assert.Equal(t, "deploy", cfgUser)
|
||||
}
|
||||
|
|
@ -245,7 +245,7 @@ func TestRegister_Good_ExposesExpectedFlags(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRunAnsible_Bad_MissingPlaybook(t *testing.T) {
|
||||
result := runAnsible(core.NewOptions())
|
||||
result := runPlaybookCommand(core.NewOptions())
|
||||
|
||||
require.False(t, result.OK)
|
||||
err, ok := result.Value.(error)
|
||||
|
|
@ -254,7 +254,7 @@ func TestRunAnsible_Bad_MissingPlaybook(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRunAnsibleTest_Bad_MissingHost(t *testing.T) {
|
||||
result := runAnsibleTest(core.NewOptions())
|
||||
result := runSSHTestCommand(core.NewOptions())
|
||||
|
||||
require.False(t, result.OK)
|
||||
err, ok := result.Value.(error)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
package anscmd
|
||||
package ansiblecmd
|
||||
|
||||
import (
|
||||
"dappco.re/go/core"
|
||||
)
|
||||
|
||||
// Register registers the 'ansible' command and all subcommands on the given Core instance.
|
||||
// Register registers the `ansible` command and its `ansible/test` subcommand.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
|
|
@ -13,7 +13,7 @@ import (
|
|||
func Register(c *core.Core) {
|
||||
c.Command("ansible", core.Command{
|
||||
Description: "Run Ansible playbooks natively (no Python required)",
|
||||
Action: runAnsible,
|
||||
Action: runPlaybookCommand,
|
||||
Flags: core.NewOptions(
|
||||
core.Option{Key: "inventory", Value: ""},
|
||||
core.Option{Key: "i", Value: ""},
|
||||
|
|
@ -33,7 +33,7 @@ func Register(c *core.Core) {
|
|||
|
||||
c.Command("ansible/test", core.Command{
|
||||
Description: "Test SSH connectivity to a host",
|
||||
Action: runAnsibleTest,
|
||||
Action: runSSHTestCommand,
|
||||
Flags: core.NewOptions(
|
||||
core.Option{Key: "user", Value: "root"},
|
||||
core.Option{Key: "u", Value: "root"},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package anscmd
|
||||
package ansiblecmd
|
||||
|
||||
import (
|
||||
"unicode"
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ Function and method coverage percentages below come from `go test -coverprofile=
|
|||
| `(*SSHClient).Stat` | `func (c *SSHClient) Stat(ctx context.Context, path string) (map[string]any, error)` | Returns a minimal remote stat map describing existence and directory state. | `0.0%`; no automated tests found. |
|
||||
| `(*SSHClient).SetBecome` | `func (c *SSHClient) SetBecome(become bool, user, password string)` | Updates the privilege-escalation settings stored on the client. | `100.0%`; covered by `modules_infra_test.go: TestBecome_Infra_Good_*`. |
|
||||
|
||||
## Package `anscmd`: CLI API
|
||||
## Package `ansiblecmd`: CLI API
|
||||
|
||||
| Name | Signature | Description | Test coverage |
|
||||
| --- | --- | --- | --- |
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue