From 404fc16d7492f124a56da3768aa2bb637b2b60b0 Mon Sep 17 00:00:00 2001 From: Julien Breux Date: Fri, 9 Aug 2019 16:03:31 +0200 Subject: [PATCH 1/6] Change Taskfile struct and add Inputs and Input (#235) --- internal/taskfile/input.go | 12 ++++++++++++ internal/taskfile/task.go | 31 ++++++++++++++++--------------- 2 files changed, 28 insertions(+), 15 deletions(-) create mode 100644 internal/taskfile/input.go diff --git a/internal/taskfile/input.go b/internal/taskfile/input.go new file mode 100644 index 0000000000..1f34e5ea7c --- /dev/null +++ b/internal/taskfile/input.go @@ -0,0 +1,12 @@ +package taskfile + +// Inputs represents a group of Input +type Inputs map[string]*Input + +// Input represents an interactive input variable +type Input struct { + Desc string + Required bool + Default string + Validator string +} diff --git a/internal/taskfile/task.go b/internal/taskfile/task.go index bc4bf9812b..03e1b656ba 100644 --- a/internal/taskfile/task.go +++ b/internal/taskfile/task.go @@ -5,20 +5,21 @@ type Tasks map[string]*Task // Task represents a task type Task struct { - Task string - Cmds []*Cmd - Deps []*Dep - Desc string - Summary string - Sources []string - Generates []string - Status []string + Task string + Inputs Inputs + Cmds []*Cmd + Deps []*Dep + Desc string + Summary string + Sources []string + Generates []string + Status []string Preconditions []*Precondition - Dir string - Vars Vars - Env Vars - Silent bool - Method string - Prefix string - IgnoreError bool `yaml:"ignore_error"` + Dir string + Vars Vars + Env Vars + Silent bool + Method string + Prefix string + IgnoreError bool `yaml:"ignore_error"` } From df2c025f472fd9a77a1e69f05df341963a6795dc Mon Sep 17 00:00:00 2001 From: Julien Breux Date: Fri, 9 Aug 2019 16:14:12 +0200 Subject: [PATCH 2/6] Add --interactive flag to disable prompt inputs (#235) --- cmd/task/task.go | 22 +++++++++++++--------- task.go | 19 +++++++++++-------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/cmd/task/task.go b/cmd/task/task.go index 72f73bd87d..304927951b 100644 --- a/cmd/task/task.go +++ b/cmd/task/task.go @@ -18,7 +18,7 @@ var ( version = "master" ) -const usage = `Usage: task [-ilfwvsd] [--init] [--list] [--force] [--watch] [--verbose] [--silent] [--dir] [--dry] [--summary] [task...] +const usage = `Usage: task [-ilfwvsd] [--init] [--list] [--force] [--watch] [--verbose] [--silent] [--dir] [--dry] [--summary] [--interactive] [task...] Runs the specified task(s). Falls back to the "default" task if no task name was specified, or lists all tasks if an unknown task name was specified. @@ -58,6 +58,7 @@ func main() { silent bool dry bool summary bool + interactive bool dir string output string color bool @@ -73,6 +74,7 @@ func main() { pflag.BoolVarP(&silent, "silent", "s", false, "disables echoing") pflag.BoolVar(&dry, "dry", false, "compiles and prints tasks in the order that they would be run, without executing them") pflag.BoolVar(&summary, "summary", false, "show summary about a task") + pflag.BoolVar(&interactive, "interactive", true, "interactive prompt inputs") pflag.StringVarP(&dir, "dir", "d", "", "sets directory of execution") pflag.StringVarP(&output, "output", "o", "", "sets output style: [interleaved|group|prefixed]") pflag.BoolVarP(&color, "color", "c", true, "colored output") @@ -95,14 +97,16 @@ func main() { } e := task.Executor{ - Force: force, - Watch: watch, - Verbose: verbose, - Silent: silent, - Dir: dir, - Dry: dry, - Summary: summary, - Color: color, + Force: force, + Watch: watch, + Verbose: verbose, + Silent: silent, + Dir: dir, + Dry: dry, + Entrypoint: entrypoint, + Summary: summary, + Color: color, + Interactive: interactive, Stdin: os.Stdin, Stdout: os.Stdout, diff --git a/task.go b/task.go index 72e3e0b5ea..9c20acce52 100644 --- a/task.go +++ b/task.go @@ -32,14 +32,17 @@ const ( // Executor executes a Taskfile type Executor struct { Taskfile *taskfile.Taskfile - Dir string - Force bool - Watch bool - Verbose bool - Silent bool - Dry bool - Summary bool - Color bool + + Dir string + Entrypoint string + Force bool + Watch bool + Verbose bool + Silent bool + Dry bool + Summary bool + Color bool + Interactive bool Stdin io.Reader Stdout io.Writer From 35b4f943491ec495a2a5c5dfa36020e31a3bea48 Mon Sep 17 00:00:00 2001 From: Julien Breux Date: Fri, 9 Aug 2019 16:30:07 +0200 Subject: [PATCH 3/6] Add --interactive flag to completion (#235) --- completion/zsh/_task | 1 + 1 file changed, 1 insertion(+) diff --git a/completion/zsh/_task b/completion/zsh/_task index f2bd81de01..b65c0dbec5 100755 --- a/completion/zsh/_task +++ b/completion/zsh/_task @@ -18,6 +18,7 @@ _arguments \ '(-l --list)'{-l,--list} \ '(-s --silent)'{-s,--silent} \ '(--status)'--status \ + '(--interactive)'--interactive \ '(-v --verbose)'{-v,--verbose} \ '(--version)'--version \ '(-w --watch)'{-w,--watch} \ From a27fd1d79bca499591f60f3dc3be1d7ae2e8f366 Mon Sep 17 00:00:00 2001 From: Julien Breux Date: Fri, 9 Aug 2019 18:41:42 +0200 Subject: [PATCH 4/6] Add missing reference to Inputs struct (#235) --- variables.go | 1 + 1 file changed, 1 insertion(+) diff --git a/variables.go b/variables.go index 9c22737255..315ba254f8 100644 --- a/variables.go +++ b/variables.go @@ -24,6 +24,7 @@ func (e *Executor) CompiledTask(call taskfile.Call) (*taskfile.Task, error) { new := taskfile.Task{ Task: origTask.Task, + Inputs: origTask.Inputs, Desc: r.Replace(origTask.Desc), Sources: r.ReplaceSlice(origTask.Sources), Generates: r.ReplaceSlice(origTask.Generates), From f13e602357a052196e55eb4e4f07ca0097182e80 Mon Sep 17 00:00:00 2001 From: Julien Breux Date: Fri, 9 Aug 2019 18:42:50 +0200 Subject: [PATCH 5/6] Add Input.FullTitle to print prompt (#235) --- internal/taskfile/input.go | 55 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/internal/taskfile/input.go b/internal/taskfile/input.go index 1f34e5ea7c..aeab41a1be 100644 --- a/internal/taskfile/input.go +++ b/internal/taskfile/input.go @@ -1,5 +1,11 @@ package taskfile +import ( + "fmt" + "regexp" + "strings" +) + // Inputs represents a group of Input type Inputs map[string]*Input @@ -10,3 +16,52 @@ type Input struct { Default string Validator string } + +// FullTitle returns the input full title suffixed +func (i *Input) FullTitle(name string) (t string) { + t = i.Desc + if t == "" { + t = name + } + + st := i.subtitle() + if st == "" { + return fmt.Sprintf("%s:", t) + } + + return fmt.Sprintf("%s (%s):", t, st) +} + +// subtitle returns the input subtitle infos +func (i *Input) subtitle() (subtitle string) { + infos := []string{} + + // Required input + if i.Required { + infos = append(infos, "required: yes") + } + // Default value + if i.Default != "" { + infos = append(infos, fmt.Sprintf("default: \"%s\"", i.Default)) + } + // Validator value + if i.Validator != "" { + infos = append(infos, fmt.Sprintf("validator: \"%s\"", i.Validator)) + } + + if len(infos) > 0 { + subtitle = fmt.Sprintf("%s", strings.Join(infos, ",")) + } + + return +} + +// Validate returns if the input is validate +func (i *Input) Validate(val string) bool { + if i.Validator == "" { + return true + } + + m, _ := regexp.MatchString(i.Validator, val) + return m +} From 173b9925bd90f2deb797de1fb784691803d1a367 Mon Sep 17 00:00:00 2001 From: Julien Breux Date: Fri, 9 Aug 2019 18:43:26 +0200 Subject: [PATCH 6/6] Add input system (#235) --- task.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/task.go b/task.go index 9c20acce52..abe3328612 100644 --- a/task.go +++ b/task.go @@ -207,6 +207,8 @@ func (e *Executor) Setup() error { // RunTask runs a task by its name func (e *Executor) RunTask(ctx context.Context, call taskfile.Call) error { + e.runInputs(ctx, &call) + t, err := e.CompiledTask(call) if err != nil { return err @@ -276,6 +278,34 @@ func (e *Executor) mkdir(t *taskfile.Task) error { return nil } +func (e *Executor) runInputs(ctx context.Context, call *taskfile.Call) { + if origTask, ok := e.Taskfile.Tasks[call.Task]; ok { + if call.Vars == nil { + call.Vars = taskfile.Vars{} + } + for name, input := range origTask.Inputs { + var in string + if e.Interactive { + fmt.Println(input.FullTitle(name)) + fmt.Fscanln(e.Stdin, &in) + } + if in == "" { + if input.Required { + e.Logger.Errf("Input required") + continue + } + in = input.Default + } + if !input.Validate(in) { + e.Logger.Errf("Input invalid") + continue + } + + call.Vars[name] = taskfile.Var{Static: in} + } + } +} + func (e *Executor) runDeps(ctx context.Context, t *taskfile.Task) error { g, ctx := errgroup.WithContext(ctx)