From 51472e165696528972fba70c9d2751c63db90c57 Mon Sep 17 00:00:00 2001 From: "Kasper J. Hermansen" Date: Wed, 19 Jul 2023 14:02:58 +0200 Subject: [PATCH] feat: with redone ui Signed-off-by: Kasper J. Hermansen feat: with no interactive instead Signed-off-by: Kasper J. Hermansen Sets the interactive command as well as SHUTTLE_INTERACTIVE interactive is surfaced both in cli as well as env variable SHUTTLE_INTERACTIVE=true/default/false default=false Signed-off-by: Kasper J. Hermansen feat: introduce early parse flags to make sure we get root commands set before building run and ls Signed-off-by: Kasper J. Hermansen feat: with help comment Signed-off-by: Kasper J. Hermansen feat: fully compatible Signed-off-by: Kasper J. Hermansen refactor: run subcommand Signed-off-by: Kasper J. Hermansen docs: document sub run Signed-off-by: Kasper J. Hermansen docs: more docs Signed-off-by: Kasper J. Hermansen feat: make sure to print error properly Signed-off-by: Kasper J. Hermansen feat: return named runCmd Signed-off-by: Kasper J. Hermansen wip: still working on cmd help Signed-off-by: Kasper J. Hermansen feat: fixed interactive mode Signed-off-by: Kasper J. Hermansen feat: fix go mod Signed-off-by: Kasper J. Hermansen --- cmd/cmd.go | 29 +++- cmd/run.go | 193 ++++++++++++++++++---- cmd/run_test.go | 23 ++- cmd/telemetry.go | 1 - cmd/test.go | 20 ++- go.mod | 10 +- go.sum | 28 +++- pkg/executors/executor.go | 9 +- pkg/executors/golang/executer/executer.go | 1 + pkg/executors/shell.go | 4 + pkg/telemetry/telemetry.go | 4 +- 11 files changed, 264 insertions(+), 58 deletions(-) diff --git a/cmd/cmd.go b/cmd/cmd.go index c1a7027..3a79dea 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -120,8 +120,14 @@ If none of above is used, then the argument will expect a full plan spec.`) return rootCmd, ctxProvider } -func Execute(out, err io.Writer) { - rootCmd, uii := initializedRoot(out, err) +func Execute(stdout, stderr io.Writer) { + rootCmd, uii, err := initializedRoot(stdout, stderr) + if err != nil { + telemetry.TraceError(stdcontext.Background(), "init", err) + checkError(uii, err) + fmt.Printf("failed to initialize with error: %s", err) + return + } if err := rootCmd.Execute(); err != nil { telemetry.TraceError( @@ -134,13 +140,22 @@ func Execute(out, err io.Writer) { } } -func initializedRoot(out, err io.Writer) (*cobra.Command, *ui.UI) { +func initializedRootFromArgs(out, err io.Writer, args []string) (*cobra.Command, *ui.UI, error) { uii := ui.Create(out, err) rootCmd, ctxProvider := newRoot(uii) rootCmd.SetOut(out) rootCmd.SetErr(err) + // Parses falgs early such that we can build PersistentFlags on rootCmd used + // for building various subcommands in both run and ls. This is required otherwise + // Run and LS will not get closured variables from contextProvider + rootCmd.ParseFlags(args) + + runCmd, initErr := newRun(uii, ctxProvider) + if initErr != nil { + return nil, nil, initErr + } rootCmd.AddCommand( newDocumentation(uii, ctxProvider), newCompletion(uii), @@ -149,15 +164,19 @@ func initializedRoot(out, err io.Writer) (*cobra.Command, *ui.UI) { newHas(uii, ctxProvider), newLs(uii, ctxProvider), newPlan(uii, ctxProvider), + runCmd, newPrepare(uii, ctxProvider), - newRun(uii, ctxProvider), newTemplate(uii, ctxProvider), newVersion(uii), newConfig(uii, ctxProvider), newTelemetry(uii), ) - return rootCmd, uii + return rootCmd, uii, nil +} + +func initializedRoot(out, err io.Writer) (*cobra.Command, *ui.UI, error) { + return initializedRootFromArgs(out, err, os.Args[1:]) } type contextProvider func() (config.ShuttleProjectContext, error) diff --git a/cmd/run.go b/cmd/run.go index 11c7f17..ff65f01 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -2,21 +2,32 @@ package cmd import ( stdcontext "context" + "fmt" "os" "os/signal" + "sort" + "strings" + "github.com/AlecAivazis/survey/v2" + "github.com/iancoleman/strcase" "github.com/spf13/cobra" + "github.com/lunarway/shuttle/pkg/config" "github.com/lunarway/shuttle/pkg/executors" - "github.com/lunarway/shuttle/pkg/telemetry" "github.com/lunarway/shuttle/pkg/ui" ) -func newRun(uii *ui.UI, contextProvider contextProvider) *cobra.Command { +func newRun(uii *ui.UI, contextProvider contextProvider) (*cobra.Command, error) { var ( - flagTemplate string - validateArgs bool + flagTemplate string + validateArgs bool + interactiveArg bool ) + shuttleInteractive := os.Getenv("SHUTTLE_INTERACTIVE") + var shuttleInteractiveDefault bool + if shuttleInteractive == "true" { + shuttleInteractiveDefault = true + } executorRegistry := executors.NewRegistry(executors.ShellExecutor, executors.TaskExecutor) @@ -24,28 +35,158 @@ func newRun(uii *ui.UI, contextProvider contextProvider) *cobra.Command { Use: "run [command]", Short: "Run a plan script", Long: `Specify which plan script to run`, - Args: cobra.MinimumNArgs(1), SilenceUsage: true, + } + + context, err := contextProvider() + if err != nil { + return nil, err + } + + // For each script construct a run command specific for said script + for script, value := range context.Scripts { + runCmd.AddCommand( + newRunSubCommand( + uii, + context, + script, + value, + executorRegistry, + &interactiveArg, + validateArgs, + ), + ) + } + + runCmd.Flags(). + StringVar(&flagTemplate, "template", "", "Template string to use. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].") + runCmd.Flags(). + BoolVar(&validateArgs, "validate", true, "Validate arguments against script definition in plan and exit with 1 on unknown or missing arguments") + runCmd.PersistentFlags(). + BoolVar(&interactiveArg, "interactive", shuttleInteractiveDefault, "sets whether to enable ui for getting missing values via. prompt instead of failing immediadly, default is set by [SHUTTLE_INTERACTIVE=true/false]") + return runCmd, nil +} + +func newRunSubCommand( + uii *ui.UI, + context config.ShuttleProjectContext, + script string, + value config.ShuttlePlanScript, + executorRegistry *executors.Registry, + interactiveArg *bool, + validateArgs bool, +) *cobra.Command { + // Args are best suited as kebab-case on the command line + argName := func(input string) string { + return strcase.ToKebab(input) + } + + parseKeyValuePair := func(arg string) (string, string, bool) { + keyvaluearg := strings.Split(arg, "=") + if len(keyvaluearg) == 2 { + key := keyvaluearg[0] + value := keyvaluearg[1] + + return key, value, true + } + + return "", "", false + } + + // Legacy key=value pairs into standard args that cobra can understand + applyLegacyArgs := func(args []string, inputArgs map[string]*string) { + for _, inputArg := range args { + key, value, ok := parseKeyValuePair(inputArg) + if ok { + inputArgs[key] = &value + } + } + } + + // In case interactive is turned on and arg is missing, we ask for missing values + createPrompt := func(inputArgs map[string]*string, arg config.ShuttleScriptArgs) (string, error) { + prompt := []*survey.Question{ + { + Name: argName(arg.Name), + Prompt: &survey.Input{ + Message: argName(arg.Name), + Default: *inputArgs[arg.Name], + Help: arg.Description, + }, + }, + } + if arg.Required { + prompt[0].Validate = survey.Required + } + var output string + err := survey.Ask(prompt, &output) + if err != nil { + return "", err + } + + return output, nil + } + + // Decide whether to fall back on prompt or give a hard error + validateInputArgs := func(value config.ShuttlePlanScript, inputArgs map[string]*string) error { + for _, arg := range value.Args { + arg := arg + + if *inputArgs[arg.Name] == "" && *interactiveArg { + output, err := createPrompt(inputArgs, arg) + if err != nil { + return err + } + if output != "" { + inputArgs[arg.Name] = &output + } + + } else if *inputArgs[arg.Name] == "" && arg.Required { + return fmt.Errorf("Error: required flag(s) \"%s\" not set", argName(arg.Name)) + } + } + + return nil + } + + // Produce a stable list of arguments + sort.Slice(value.Args, func(i, j int) bool { + return value.Args[i].Name < value.Args[j].Name + }) + + // Initialize a collection of variables for use in args set pr command + inputArgs := make(map[string]*string, 0) + for _, arg := range value.Args { + arg := arg + inputArgs[arg.Name] = new(string) + } + + cmd := &cobra.Command{ + Use: script, + Short: value.Description, + Long: value.Description, RunE: func(cmd *cobra.Command, args []string) error { - commandName := args[0] + if *interactiveArg { + uii.Verboseln("Running using interactive mode!") + } + ctx := cmd.Context() - ctx, traceInfo, traceError, traceEnd := trace(ctx, commandName, args) + ctx, _, traceError, traceEnd := trace(ctx, script, args) defer traceEnd() - context, err := contextProvider() - if err != nil { - traceError(err) + applyLegacyArgs(args, inputArgs) + if err := validateInputArgs(value, inputArgs); err != nil { return err } - traceInfo( - telemetry.WithPhase("after-plan-pull"), - telemetry.WithEntry("plan", context.Config.Plan), - ) ctx, cancel := withSignal(ctx, uii) defer cancel() + actualArgs := make(map[string]string, len(inputArgs)) + for k, v := range inputArgs { + actualArgs[k] = *v + } - err = executorRegistry.Execute(ctx, context, commandName, args[1:], validateArgs) + err := executorRegistry.Execute(ctx, context, script, actualArgs, validateArgs) if err != nil { traceError(err) return err @@ -54,24 +195,12 @@ func newRun(uii *ui.UI, contextProvider contextProvider) *cobra.Command { return nil }, } + for _, arg := range value.Args { + arg := arg + cmd.Flags().StringVar(inputArgs[arg.Name], argName(arg.Name), "", arg.Description) + } - runCmd.SetHelpFunc(func(cmd *cobra.Command, args []string) { - scripts := cmd.Flags().Args() - if len(scripts) == 0 { - runCmd.Usage() - return - } - context, err := contextProvider() - checkError(uii, err) - - err = executors.Help(context.Scripts, scripts[0], cmd.OutOrStdout(), flagTemplate) - checkError(uii, err) - }) - runCmd.Flags(). - StringVar(&flagTemplate, "template", "", "Template string to use. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].") - runCmd.Flags(). - BoolVar(&validateArgs, "validate", true, "Validate arguments against script definition in plan and exit with 1 on unknown or missing arguments") - return runCmd + return cmd } // withSignal returns a copy of parent with a new Done channel. The returned diff --git a/cmd/run_test.go b/cmd/run_test.go index 5fbe720..350624f 100644 --- a/cmd/run_test.go +++ b/cmd/run_test.go @@ -73,13 +73,24 @@ Make sure you are in a project using shuttle and that a 'shuttle.yaml' file is a 'foo' not supplied but is required Script 'required_arg' accepts the following arguments: - foo (required) -`, - err: errors.New(`exit code 2 - Arguments not valid: - 'foo' not supplied but is required + foo (requiredshuttle run required_arg [flags] -Script 'required_arg' accepts the following arguments: - foo (required)`), + Flags: + --foo string + -h, --help help for required_arg + + Global Flags: + -c, --clean Start from clean setup + --interactive sets whether to enable ui for getting missing values via. prompt instead of failing immediadly, default is set by [SHUTTLE_INTERACTIVE=true/false] + --plan string Overload the plan used. + Specifying a local path with either an absolute path (/some/plan) or a relative path (../some/plan) to another location + for the selected plan. + Select a version of a git plan by using #branch, #sha or #tag + If none of above is used, then the argument will expect a full plan spec. + -p, --project string Project path (default ".") + --skip-pull Skip git plan pulling step + -v, --verbose Print verbose outpu)`, + err: errors.New(`EOF`), }, { name: "script succeeds with required argument", diff --git a/cmd/telemetry.go b/cmd/telemetry.go index 2b28867..0852f18 100644 --- a/cmd/telemetry.go +++ b/cmd/telemetry.go @@ -39,7 +39,6 @@ func WithRunTelemetry( ) stdcontext.Context { ctx = stdcontext.WithValue(ctx, telemetry.TelemetryCommand, commandName) if len(args) != 0 { - // TODO: Make sure we sanitize secrets, somehow ctx = stdcontext.WithValue(ctx, telemetry.TelemetryCommandArgs, strings.Join(args[1:], " ")) } return ctx diff --git a/cmd/test.go b/cmd/test.go index fea843d..bf39258 100644 --- a/cmd/test.go +++ b/cmd/test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func args(s ...string) []string { @@ -16,6 +17,7 @@ func args(s ...string) []string { type testCase struct { name string input []string + initErr error stdoutput string erroutput string err error @@ -38,10 +40,13 @@ func executeTestCasesWithCustomAssertion( stdBuf := new(bytes.Buffer) errBuf := new(bytes.Buffer) - rootCmd, _ := initializedRoot(stdBuf, errBuf) + rootCmd, _, err := initializedRootFromArgs(stdBuf, errBuf, tc.input) + if err != nil { + require.Equal(t, tc.initErr, err) + } rootCmd.SetArgs(tc.input) - err := rootCmd.Execute() + err = rootCmd.Execute() if tc.err == nil { assert.NoError(t, err) } else { @@ -77,10 +82,17 @@ func executeTestContainsCases(t *testing.T, testCases []testCase) { stdBuf := new(bytes.Buffer) errBuf := new(bytes.Buffer) - rootCmd, _ := initializedRoot(stdBuf, errBuf) + rootCmd, _, err := initializedRootFromArgs(stdBuf, errBuf, tc.input) + if err != nil { + if tc.initErr == nil { + require.NoError(t, err) + } else { + require.Equal(t, tc.initErr, err) + } + } rootCmd.SetArgs(tc.input) - err := rootCmd.Execute() + err = rootCmd.Execute() if tc.err == nil { assert.NoError(t, err) } else { diff --git a/go.mod b/go.mod index 47d4ec1..6db5912 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,9 @@ require ( ) require ( + github.com/AlecAivazis/survey/v2 v2.3.7 github.com/google/uuid v1.3.1 + github.com/iancoleman/strcase v0.3.0 github.com/matishsiao/goInfo v0.0.0-20210923090445-da2e3fa8d45f github.com/otiai10/copy v1.12.0 golang.org/x/mod v0.12.0 @@ -31,11 +33,17 @@ require ( github.com/huandu/xstrings v1.3.3 // indirect github.com/imdario/mergo v0.3.11 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect + github.com/mattn/go-colorable v0.1.2 // indirect + github.com/mattn/go-isatty v0.0.8 // indirect + github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/mitchellh/reflectwalk v1.0.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/shopspring/decimal v1.2.0 // indirect github.com/spf13/cast v1.4.1 // indirect github.com/spf13/pflag v1.0.5 // indirect - golang.org/x/crypto v0.3.0 // indirect + golang.org/x/crypto v0.9.0 // indirect golang.org/x/sys v0.12.0 // indirect + golang.org/x/term v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect ) diff --git a/go.sum b/go.sum index 92ec20a..71bcb15 100644 --- a/go.sum +++ b/go.sum @@ -1,12 +1,18 @@ +github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= +github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/cli/safeexec v1.0.1 h1:e/C79PbXF4yYTN/wauC4tviMxEV13BwljGj0N9j+N00= github.com/cli/safeexec v1.0.1/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= +github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -18,14 +24,26 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= +github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= +github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/matishsiao/goInfo v0.0.0-20210923090445-da2e3fa8d45f h1:B0OD7nYl2FPQEVrw8g2uyc1lGEzNbvrKh7fspGZcbvY= github.com/matishsiao/goInfo v0.0.0-20210923090445-da2e3fa8d45f/go.mod h1:aEt7p9Rvh67BYApmZwNDPpgircTO2kgdmDUoF/1QmwA= +github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.1.1 h1:Bp6x9R1Wn16SIz3OfeDr0b7RnCG2OB66Y7PQyC/cvq4= github.com/mitchellh/copystructure v1.1.1/go.mod h1:EBArHfARyrSWO/+Wyr9zwEkc6XMFB9XyNgFNmRkZZU4= @@ -52,13 +70,15 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -73,6 +93,7 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -83,10 +104,14 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= @@ -97,5 +122,6 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/executors/executor.go b/pkg/executors/executor.go index 0c6b517..ea51ece 100644 --- a/pkg/executors/executor.go +++ b/pkg/executors/executor.go @@ -46,7 +46,7 @@ func (r *Registry) Execute( ctx context.Context, p config.ShuttleProjectContext, command string, - args []string, + args map[string]string, validateArgs bool, ) error { script, ok := p.Scripts[command] @@ -54,16 +54,11 @@ func (r *Registry) Execute( return errors.NewExitCode(2, "Script '%s' not found", command) } - namedArgs, err := validateArguments(p, command, script.Args, args, validateArgs) - if err != nil { - return err - } - scriptContext := ScriptExecutionContext{ ScriptName: command, Script: script, Project: p, - Args: namedArgs, + Args: args, } for actionIndex, action := range script.Actions { diff --git a/pkg/executors/golang/executer/executer.go b/pkg/executors/golang/executer/executer.go index b91e569..1baa9da 100644 --- a/pkg/executors/golang/executer/executer.go +++ b/pkg/executors/golang/executer/executer.go @@ -61,6 +61,7 @@ func executeBinaryAction(ctx context.Context, binary *compile.Binary, args ...st execmd.Env = os.Environ() execmd.Env = append(execmd.Env, fmt.Sprintf("TASK_CONTEXT_DIR=%s", workdir)) + execmd.Env = append(execmd.Env, "SHUTTLE_INTERACTIVE=default") execmd.Env = append( execmd.Env, fmt.Sprintf("%s=%s", diff --git a/pkg/executors/shell.go b/pkg/executors/shell.go index bad5066..b0d8f7c 100644 --- a/pkg/executors/shell.go +++ b/pkg/executors/shell.go @@ -135,4 +135,8 @@ func setupCommandEnvironmentVariables(execCmd *cmd.Cmd, context ActionExecutionC context.ScriptContext.Project.LocalPlanPath, ), ) + execCmd.Env = append( + execCmd.Env, + "SHUTTLE_INTERACTIVE=default", + ) } diff --git a/pkg/telemetry/telemetry.go b/pkg/telemetry/telemetry.go index 9ef0911..1dd4806 100644 --- a/pkg/telemetry/telemetry.go +++ b/pkg/telemetry/telemetry.go @@ -14,7 +14,9 @@ func TraceError(ctx context.Context, label string, err error, options ...Telemet // TODO: consider enum for error (const list) properties["phase"] = "error" - properties["error"] = err.Error() + if err != nil { + properties["error"] = err.Error() + } client.Trace(ctx, properties) }