From 35ea4e0460e756b7a5e0894f442f265ab39d3610 Mon Sep 17 00:00:00 2001 From: Valentin Maerten Date: Thu, 20 Feb 2025 20:08:14 +0100 Subject: [PATCH] feat: display allowed values when vars are not provided (#2052) --- errors/errors_task.go | 36 ++++++++++++++++++++++++---------- requires.go | 11 +++++++---- task_test.go | 13 +++++++++--- testdata/requires/Taskfile.yml | 2 +- 4 files changed, 44 insertions(+), 18 deletions(-) diff --git a/errors/errors_task.go b/errors/errors_task.go index 3349eb22..8e840c79 100644 --- a/errors/errors_task.go +++ b/errors/errors_task.go @@ -141,21 +141,37 @@ func (err *TaskCancelledNoTerminalError) Code() int { return CodeTaskCancelled } -// TaskMissingRequiredVars is returned when a task is missing required variables. -type TaskMissingRequiredVars struct { +// TaskMissingRequiredVarsError is returned when a task is missing required variables. + +type MissingVar struct { + Name string + AllowedValues []string +} +type TaskMissingRequiredVarsError struct { TaskName string - MissingVars []string + MissingVars []MissingVar } -func (err *TaskMissingRequiredVars) Error() string { +func (v MissingVar) String() string { + if len(v.AllowedValues) == 0 { + return v.Name + } + return fmt.Sprintf("%s (allowed values: %v)", v.Name, v.AllowedValues) +} + +func (err *TaskMissingRequiredVarsError) Error() string { + var vars []string + for _, v := range err.MissingVars { + vars = append(vars, v.String()) + } + return fmt.Sprintf( `task: Task %q cancelled because it is missing required variables: %s`, err.TaskName, - strings.Join(err.MissingVars, ", "), - ) + strings.Join(vars, ", ")) } -func (err *TaskMissingRequiredVars) Code() int { +func (err *TaskMissingRequiredVarsError) Code() int { return CodeTaskMissingRequiredVars } @@ -165,12 +181,12 @@ type NotAllowedVar struct { Name string } -type TaskNotAllowedVars struct { +type TaskNotAllowedVarsError struct { TaskName string NotAllowedVars []NotAllowedVar } -func (err *TaskNotAllowedVars) Error() string { +func (err *TaskNotAllowedVarsError) Error() string { var builder strings.Builder builder.WriteString(fmt.Sprintf("task: Task %q cancelled because it is missing required variables:\n", err.TaskName)) @@ -181,6 +197,6 @@ func (err *TaskNotAllowedVars) Error() string { return builder.String() } -func (err *TaskNotAllowedVars) Code() int { +func (err *TaskNotAllowedVarsError) Code() int { return CodeTaskNotAllowedVars } diff --git a/requires.go b/requires.go index 010a9964..119b073b 100644 --- a/requires.go +++ b/requires.go @@ -12,16 +12,19 @@ func (e *Executor) areTaskRequiredVarsSet(t *ast.Task) error { return nil } - var missingVars []string + var missingVars []errors.MissingVar for _, requiredVar := range t.Requires.Vars { _, ok := t.Vars.Get(requiredVar.Name) if !ok { - missingVars = append(missingVars, requiredVar.Name) + missingVars = append(missingVars, errors.MissingVar{ + Name: requiredVar.Name, + AllowedValues: requiredVar.Enum, + }) } } if len(missingVars) > 0 { - return &errors.TaskMissingRequiredVars{ + return &errors.TaskMissingRequiredVarsError{ TaskName: t.Name(), MissingVars: missingVars, } @@ -51,7 +54,7 @@ func (e *Executor) areTaskRequiredVarsAllowedValuesSet(t *ast.Task) error { } if len(notAllowedValuesVars) > 0 { - return &errors.TaskNotAllowedVars{ + return &errors.TaskNotAllowedVarsError{ TaskName: t.Name(), NotAllowedVars: notAllowedValuesVars, } diff --git a/task_test.go b/task_test.go index b1a7ed4a..dabdef98 100644 --- a/task_test.go +++ b/task_test.go @@ -186,23 +186,30 @@ func TestRequires(t *testing.T) { vars := ast.NewVars() vars.Set("FOO", ast.Var{Value: "bar"}) + require.NoError(t, e.Run(context.Background(), &ast.Call{ Task: "missing-var", Vars: vars, })) buff.Reset() + vars.Set("ENV", ast.Var{Value: "dev"}) require.NoError(t, e.Setup()) require.ErrorContains(t, e.Run(context.Background(), &ast.Call{Task: "validation-var", Vars: vars}), "task: Task \"validation-var\" cancelled because it is missing required variables:\n - FOO has an invalid value : 'bar' (allowed values : [one two])") buff.Reset() require.NoError(t, e.Setup()) - require.NoError(t, e.Run(context.Background(), &ast.Call{Task: "validation-var-dynamic", Vars: vars})) + vars.Set("FOO", ast.Var{Value: "one"}) + require.NoError(t, e.Run(context.Background(), &ast.Call{Task: "validation-var", Vars: vars})) + buff.Reset() + + vars = ast.NewVars() + require.NoError(t, e.Setup()) + require.ErrorContains(t, e.Run(context.Background(), &ast.Call{Task: "validation-var", Vars: vars}), "task: Task \"validation-var\" cancelled because it is missing required variables: ENV, FOO (allowed values: [one two])") buff.Reset() require.NoError(t, e.Setup()) - vars.Set("FOO", ast.Var{Value: "one"}) - require.NoError(t, e.Run(context.Background(), &ast.Call{Task: "validation-var", Vars: vars})) + require.NoError(t, e.Run(context.Background(), &ast.Call{Task: "validation-var-dynamic", Vars: vars})) buff.Reset() require.NoError(t, e.Setup()) diff --git a/testdata/requires/Taskfile.yml b/testdata/requires/Taskfile.yml index 1bc638e4..75b977a0 100644 --- a/testdata/requires/Taskfile.yml +++ b/testdata/requires/Taskfile.yml @@ -33,10 +33,10 @@ tasks: validation-var: requires: vars: + - ENV - name: FOO enum: ['one', 'two'] - require-before-compile: requires: vars: [ MY_VAR ]