forked from coop-cloud/abra
fix: app cmd parsing, usage & tests
Note: the integration tests don't work due to ValidateApp still attempting to validate the host key for the test app which doesn't exist. This will be fixed in a future commit.
This commit is contained in:
parent
8f709c05bf
commit
42a6818ff4
|
@ -25,21 +25,6 @@ import (
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
var localCmd bool
|
|
||||||
var localCmdFlag = &cli.BoolFlag{
|
|
||||||
Name: "local, l",
|
|
||||||
Usage: "Run command locally",
|
|
||||||
Destination: &localCmd,
|
|
||||||
}
|
|
||||||
|
|
||||||
var remoteUser string
|
|
||||||
var remoteUserFlag = &cli.StringFlag{
|
|
||||||
Name: "user, u",
|
|
||||||
Value: "",
|
|
||||||
Usage: "User to run command within a service context",
|
|
||||||
Destination: &remoteUser,
|
|
||||||
}
|
|
||||||
|
|
||||||
var appCmdCommand = cli.Command{
|
var appCmdCommand = cli.Command{
|
||||||
Name: "command",
|
Name: "command",
|
||||||
Aliases: []string{"cmd"},
|
Aliases: []string{"cmd"},
|
||||||
|
@ -56,21 +41,23 @@ Example:
|
||||||
|
|
||||||
abra app cmd example.com app create_user -- me@example.com
|
abra app cmd example.com app create_user -- me@example.com
|
||||||
`,
|
`,
|
||||||
ArgsUsage: "<domain> [<service>] <command>",
|
ArgsUsage: "<domain> [<service>] <command> [-- <args>]",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
internal.DebugFlag,
|
internal.DebugFlag,
|
||||||
localCmdFlag,
|
internal.LocalCmdFlag,
|
||||||
remoteUserFlag,
|
internal.RemoteUserFlag,
|
||||||
},
|
},
|
||||||
BashComplete: autocomplete.AppNameComplete,
|
BashComplete: autocomplete.AppNameComplete,
|
||||||
Before: internal.SubCommandBefore,
|
Before: internal.SubCommandBefore,
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
app := internal.ValidateApp(c)
|
app := internal.ValidateApp(c)
|
||||||
|
|
||||||
if localCmd && remoteUser != "" {
|
if internal.LocalCmd && internal.RemoteUser != "" {
|
||||||
internal.ShowSubcommandHelpAndError(c, errors.New("cannot use --local & <user> together"))
|
internal.ShowSubcommandHelpAndError(c, errors.New("cannot use --local & --user together"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasCmdArgs, parsedCmdArgs := parseCmdArgs(c.Args(), internal.LocalCmd)
|
||||||
|
|
||||||
abraSh := path.Join(config.RECIPES_DIR, app.Recipe, "abra.sh")
|
abraSh := path.Join(config.RECIPES_DIR, app.Recipe, "abra.sh")
|
||||||
if _, err := os.Stat(abraSh); err != nil {
|
if _, err := os.Stat(abraSh); err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
|
@ -79,21 +66,7 @@ Example:
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var parsedCmdArgs string
|
if internal.LocalCmd {
|
||||||
var cmdArgsIdx int
|
|
||||||
var hasCmdArgs bool
|
|
||||||
for idx, arg := range c.Args() {
|
|
||||||
if arg == "--" {
|
|
||||||
cmdArgsIdx = idx
|
|
||||||
hasCmdArgs = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if hasCmdArgs && idx > cmdArgsIdx {
|
|
||||||
parsedCmdArgs += fmt.Sprintf("%s ", c.Args().Get(idx))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if localCmd {
|
|
||||||
cmdName := c.Args().Get(1)
|
cmdName := c.Args().Get(1)
|
||||||
if err := ensureCommand(abraSh, app.Recipe, cmdName); err != nil {
|
if err := ensureCommand(abraSh, app.Recipe, cmdName); err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
|
@ -156,6 +129,25 @@ Example:
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseCmdArgs(args []string, isLocal bool) (bool, string) {
|
||||||
|
var (
|
||||||
|
parsedCmdArgs string
|
||||||
|
hasCmdArgs bool
|
||||||
|
)
|
||||||
|
|
||||||
|
if isLocal {
|
||||||
|
if len(args) > 2 {
|
||||||
|
return true, fmt.Sprintf("%s ", strings.Join(args[2:], " "))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if len(args) > 3 {
|
||||||
|
return true, fmt.Sprintf("%s ", strings.Join(args[3:], " "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasCmdArgs, parsedCmdArgs
|
||||||
|
}
|
||||||
|
|
||||||
func ensureCommand(abraSh, recipeName, execCmd string) error {
|
func ensureCommand(abraSh, recipeName, execCmd string) error {
|
||||||
bytes, err := ioutil.ReadFile(abraSh)
|
bytes, err := ioutil.ReadFile(abraSh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -214,9 +206,9 @@ func runCmdRemote(app config.App, abraSh, serviceName, cmdName, cmdArgs string)
|
||||||
Tty: true,
|
Tty: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
if remoteUser != "" {
|
if internal.RemoteUser != "" {
|
||||||
logrus.Debugf("running command with user %s", remoteUser)
|
logrus.Debugf("running command with user %s", internal.RemoteUser)
|
||||||
execCreateOpts.User = remoteUser
|
execCreateOpts.User = internal.RemoteUser
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: avoid instantiating a new CLI
|
// FIXME: avoid instantiating a new CLI
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseCmdArgs(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
input []string
|
||||||
|
shouldParse bool
|
||||||
|
expectedOutput string
|
||||||
|
}{
|
||||||
|
// `--` is not parsed when passed in from the command-line e.g. -- foo bar baz
|
||||||
|
// so we need to eumlate that as missing when testing if bash args are passed in
|
||||||
|
// see https://git.coopcloud.tech/coop-cloud/organising/issues/336 for more
|
||||||
|
{[]string{"foo.com", "app", "test"}, false, ""},
|
||||||
|
{[]string{"foo.com", "app", "test", "foo"}, true, "foo "},
|
||||||
|
{[]string{"foo.com", "app", "test", "foo", "bar", "baz"}, true, "foo bar baz "},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
ok, parsed := parseCmdArgs(test.input, false)
|
||||||
|
if ok != test.shouldParse {
|
||||||
|
t.Fatalf("[%s] should not parse", strings.Join(test.input, " "))
|
||||||
|
}
|
||||||
|
if parsed != test.expectedOutput {
|
||||||
|
t.Fatalf("%s does not match %s", parsed, test.expectedOutput)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -353,6 +353,21 @@ var AllTagsFlag = &cli.BoolFlag{
|
||||||
Destination: &AllTags,
|
Destination: &AllTags,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var LocalCmd bool
|
||||||
|
var LocalCmdFlag = &cli.BoolFlag{
|
||||||
|
Name: "local, l",
|
||||||
|
Usage: "Run command locally",
|
||||||
|
Destination: &LocalCmd,
|
||||||
|
}
|
||||||
|
|
||||||
|
var RemoteUser string
|
||||||
|
var RemoteUserFlag = &cli.StringFlag{
|
||||||
|
Name: "user, u",
|
||||||
|
Value: "",
|
||||||
|
Usage: "User to run command within a service context",
|
||||||
|
Destination: &RemoteUser,
|
||||||
|
}
|
||||||
|
|
||||||
// SSHFailMsg is a hopefully helpful SSH failure message
|
// SSHFailMsg is a hopefully helpful SSH failure message
|
||||||
var SSHFailMsg = `
|
var SSHFailMsg = `
|
||||||
Woops, Abra is unable to connect to connect to %s.
|
Woops, Abra is unable to connect to connect to %s.
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -46,7 +46,7 @@ require (
|
||||||
github.com/sergi/go-diff v1.2.0 // indirect
|
github.com/sergi/go-diff v1.2.0 // indirect
|
||||||
github.com/spf13/cobra v1.3.0 // indirect
|
github.com/spf13/cobra v1.3.0 // indirect
|
||||||
github.com/theupdateframework/notary v0.7.0 // indirect
|
github.com/theupdateframework/notary v0.7.0 // indirect
|
||||||
github.com/urfave/cli v1.22.5
|
github.com/urfave/cli v1.22.9
|
||||||
github.com/xanzy/ssh-agent v0.3.1 // indirect
|
github.com/xanzy/ssh-agent v0.3.1 // indirect
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b // indirect
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b // indirect
|
||||||
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838
|
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -982,8 +982,8 @@ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijb
|
||||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
|
github.com/urfave/cli v1.22.9 h1:cv3/KhXGBGjEXLC4bH0sLuJ9BewaAbpk5oyMOveu4pw=
|
||||||
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
github.com/urfave/cli v1.22.9/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI=
|
github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI=
|
||||||
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
|
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
|
||||||
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RmServerAppRecipe deletes the test server / app / recipe.
|
||||||
|
func RmServerAppRecipe() {
|
||||||
|
testAppLink := os.ExpandEnv("$HOME/.abra/servers/foo.com")
|
||||||
|
if err := os.Remove(testAppLink); err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
testRecipeLink := os.ExpandEnv("$HOME/.abra/recipes/test")
|
||||||
|
if err := os.Remove(testRecipeLink); err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MkServerAppRecipe symlinks the test server / app / recipe.
|
||||||
|
func MkServerAppRecipe() {
|
||||||
|
RmServerAppRecipe()
|
||||||
|
|
||||||
|
testAppDir := os.ExpandEnv("$PWD/../../tests/resources/testapp")
|
||||||
|
testAppLink := os.ExpandEnv("$HOME/.abra/servers/foo.com")
|
||||||
|
if err := os.Symlink(testAppDir, testAppLink); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
testRecipeDir := os.ExpandEnv("$PWD/../../tests/resources/testrecipe")
|
||||||
|
testRecipeLink := os.ExpandEnv("$HOME/.abra/recipes/test")
|
||||||
|
if err := os.Symlink(testRecipeDir, testRecipeLink); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
logs
|
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
source ./testfunctions.sh
|
||||||
|
source ./common.sh
|
||||||
|
|
||||||
|
create_server_app_recipe
|
||||||
|
|
||||||
|
run_test '$ABRA app cmd foo.com test --local'
|
||||||
|
|
||||||
|
run_test '$ABRA app cmd foo.com test --local -- foo'
|
||||||
|
|
||||||
|
run_test '$ABRA app cmd foo.com test --local -- foo bar baz'
|
||||||
|
|
||||||
|
clean_server_app_recipe
|
|
@ -2,6 +2,16 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
create_server_app_recipe() {
|
||||||
|
ln -srf ../resources/testapp ~/.abra/servers/foo.com
|
||||||
|
ln -srf ../resources/testrecipe ~/.abra/recipes
|
||||||
|
}
|
||||||
|
|
||||||
|
clean_server_app_recipe() {
|
||||||
|
unlink ~/.abra/servers/foo.com
|
||||||
|
unlink ~/.abra/recipes/testrecipe
|
||||||
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
ABRA="$(pwd)/../../abra"
|
ABRA="$(pwd)/../../abra"
|
||||||
INSTALLER_URL="https://git.coopcloud.tech/coop-cloud/abra/raw/branch/main/scripts/installer/installer"
|
INSTALLER_URL="https://git.coopcloud.tech/coop-cloud/abra/raw/branch/main/scripts/installer/installer"
|
||||||
|
|
|
@ -16,7 +16,7 @@ run_test () {
|
||||||
echo $logfile
|
echo $logfile
|
||||||
}
|
}
|
||||||
|
|
||||||
testScripts=("app.sh" "autocomplete.sh" "catalogue.sh" "install.sh" "recipe.sh" "records.sh" "server.sh")
|
testScripts=("app.sh" "autocomplete.sh" "catalogue.sh" "install.sh" "recipe.sh" "records.sh" "server.sh", "cmd.sh")
|
||||||
|
|
||||||
for i in "${testScripts[@]}"; do
|
for i in "${testScripts[@]}"; do
|
||||||
cmd="./$i $res_dir${i/sh/log}"
|
cmd="./$i $res_dir${i/sh/log}"
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
TYPE=test
|
|
@ -0,0 +1 @@
|
||||||
|
.
|
|
@ -0,0 +1,5 @@
|
||||||
|
test(){
|
||||||
|
echo "1: $1"
|
||||||
|
echo "2: $2"
|
||||||
|
echo "all: $@"
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
app: []
|
Loading…
Reference in New Issue