mirror of
https://github.com/go-task/task.git
synced 2025-01-20 04:59:37 +02:00
feat: add ability to specify which vars are required (#1204)
This commit is contained in:
parent
f346015d8c
commit
307f39cee3
@ -76,6 +76,7 @@ A full list of the exit codes and their descriptions can be found below:
|
||||
| 203 | There a multiple tasks with the same name or alias |
|
||||
| 204 | A task was called too many times |
|
||||
| 205 | A task was cancelled by the user |
|
||||
| 206 | A task was not executed due to missing required variables |
|
||||
|
||||
These codes can also be found in the repository in
|
||||
[`errors/errors.go`](https://github.com/go-task/task/blob/main/errors/errors.go).
|
||||
@ -219,7 +220,9 @@ vars:
|
||||
| `sources` | `[]string` | | A list of sources to check before running this task. Relevant for `checksum` and `timestamp` methods. Can be file paths or star globs. |
|
||||
| `generates` | `[]string` | | A list of files meant to be generated by this task. Relevant for `timestamp` method. Can be file paths or star globs. |
|
||||
| `status` | `[]string` | | A list of commands to check if this task should run. The task is skipped otherwise. This overrides `method`, `sources` and `generates`. |
|
||||
| `requires` | `[]string` | | A list of variables which should be set if this task is to run, if any of these variables are unset the task will error and not run. |
|
||||
| `preconditions` | [`[]Precondition`](#precondition) | | A list of commands to check if this task should run. If a condition is not met, the task will error. |
|
||||
| `requires` | [`Requires`](#requires) | | A list of required variables which should be set if this task is to run, if any variables listed are unset the task will error and not run. |
|
||||
| `dir` | `string` | | The directory in which this task should run. Defaults to the current working directory. |
|
||||
| `vars` | [`map[string]Variable`](#variable) | | A set of variables that can be used in the task. |
|
||||
| `env` | [`map[string]Variable`](#variable) | | A set of environment variables that will be made available to shell commands. |
|
||||
@ -322,3 +325,9 @@ tasks:
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#### Requires
|
||||
|
||||
| Attribute | Type | Default | Description |
|
||||
| --------- | ---------- | ------- | -------------------------------------------------------------------------------------------------- |
|
||||
| `vars` | `[]string` | | List of variable or environment variable names that must be set if this task is to execute and run |
|
||||
|
@ -876,6 +876,48 @@ tasks:
|
||||
- sleep 5 # long operation like installing packages
|
||||
```
|
||||
|
||||
### Ensuring required variables are set
|
||||
|
||||
If you want to check that certain variables are set before running a task then
|
||||
you can use `requires`. This is useful when might not be clear to users which
|
||||
variables are needed, or if you want clear message about what is required. Also
|
||||
some tasks could have dangerous side effects if run with un-set variables.
|
||||
|
||||
Using `requires` you specify an array of strings in the `vars` sub-section
|
||||
under `requires`, these strings are variable names which are checked prior to
|
||||
running the task. If any variables are un-set the the task will error and not
|
||||
run.
|
||||
|
||||
Environmental variables are also checked.
|
||||
|
||||
Syntax:
|
||||
|
||||
```yaml
|
||||
requires:
|
||||
vars: [] # Array of strings
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
Variables set to empty zero length strings, will pass the `requires` check.
|
||||
|
||||
:::
|
||||
|
||||
Example of using `requires`:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
docker-build:
|
||||
cmds:
|
||||
- 'docker build . -t {{.IMAGE_NAME}}:{{.IMAGE_TAG}}'
|
||||
|
||||
# Make sure these variables are set before running
|
||||
requires:
|
||||
vars: [IMAGE_NAME, IMAGE_TAG]
|
||||
```
|
||||
|
||||
## Variables
|
||||
|
||||
When doing interpolation of variables, Task will look for the below. They are
|
||||
|
36
docs/static/schema.json
vendored
36
docs/static/schema.json
vendored
@ -184,6 +184,10 @@
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"requires": {
|
||||
"description": "A list of variables which should be set if this task is to run, if any of these variables are unset the task will error and not run",
|
||||
"$ref": "#/definitions/3/requires_obj"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -208,7 +212,21 @@
|
||||
},
|
||||
"set": {
|
||||
"type": "string",
|
||||
"enum": ["allexport", "a", "errexit", "e", "noexec", "n", "noglob", "f", "nounset", "u", "xtrace", "x", "pipefail"]
|
||||
"enum": [
|
||||
"allexport",
|
||||
"a",
|
||||
"errexit",
|
||||
"e",
|
||||
"noexec",
|
||||
"n",
|
||||
"noglob",
|
||||
"f",
|
||||
"nounset",
|
||||
"u",
|
||||
"xtrace",
|
||||
"x",
|
||||
"pipefail"
|
||||
]
|
||||
},
|
||||
"shopt": {
|
||||
"type": "string",
|
||||
@ -352,6 +370,18 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"requires_obj": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"vars": {
|
||||
"description": "List of variables that must be defined for the task to run",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -375,8 +405,8 @@
|
||||
"output": {
|
||||
"description": "Defines how the STDOUT and STDERR are printed when running tasks in parallel. The interleaved output prints lines in real time (default). The group output will print the entire output of a command once, after it finishes, so you won't have live feedback for commands that take a long time to run. The prefix output will prefix every line printed by a command with [task-name] as the prefix, but you can customize the prefix for a command with the prefix: attribute.",
|
||||
"anyOf": [
|
||||
{"$ref": "#/definitions/3/outputString"},
|
||||
{"$ref": "#/definitions/3/outputObject"}
|
||||
{ "$ref": "#/definitions/3/outputString" },
|
||||
{ "$ref": "#/definitions/3/outputObject" }
|
||||
]
|
||||
},
|
||||
"method": {
|
||||
|
@ -23,6 +23,7 @@ const (
|
||||
CodeTaskNameConflict
|
||||
CodeTaskCalledTooManyTimes
|
||||
CodeTaskCancelled
|
||||
CodeTaskMissingRequiredVars
|
||||
)
|
||||
|
||||
// TaskError extends the standard error interface with a Code method. This code will
|
||||
|
@ -130,3 +130,21 @@ func (err *TaskCancelledNoTerminalError) Error() string {
|
||||
func (err *TaskCancelledNoTerminalError) Code() int {
|
||||
return CodeTaskCancelled
|
||||
}
|
||||
|
||||
// TaskMissingRequiredVars is returned when a task is missing required variables.
|
||||
type TaskMissingRequiredVars struct {
|
||||
TaskName string
|
||||
MissingVars []string
|
||||
}
|
||||
|
||||
func (err *TaskMissingRequiredVars) Error() string {
|
||||
return fmt.Sprintf(
|
||||
`task: Task %q cancelled because it is missing required variables: %s`,
|
||||
err.TaskName,
|
||||
strings.Join(err.MissingVars, ", "),
|
||||
)
|
||||
}
|
||||
|
||||
func (err *TaskMissingRequiredVars) Code() int {
|
||||
return CodeTaskMissingRequiredVars
|
||||
}
|
||||
|
35
requires.go
Normal file
35
requires.go
Normal file
@ -0,0 +1,35 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-task/task/v3/errors"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
)
|
||||
|
||||
func (e *Executor) areTaskRequiredVarsSet(ctx context.Context, t *taskfile.Task, call taskfile.Call) error {
|
||||
if t.Requires == nil || len(t.Requires.Vars) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
vars, err := e.Compiler.GetVariables(t, call)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var missingVars []string
|
||||
for _, requiredVar := range t.Requires.Vars {
|
||||
if !vars.Exists(requiredVar) {
|
||||
missingVars = append(missingVars, requiredVar)
|
||||
}
|
||||
}
|
||||
|
||||
if len(missingVars) > 0 {
|
||||
return &errors.TaskMissingRequiredVars{
|
||||
TaskName: t.Name(),
|
||||
MissingVars: missingVars,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
4
task.go
4
task.go
@ -186,6 +186,10 @@ func (e *Executor) RunTask(ctx context.Context, call taskfile.Call) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := e.areTaskRequiredVarsSet(ctx, t, call); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
preCondMet, err := e.areTaskPreconditionsMet(ctx, t)
|
||||
if err != nil {
|
||||
return err
|
||||
|
18
taskfile/requires.go
Normal file
18
taskfile/requires.go
Normal file
@ -0,0 +1,18 @@
|
||||
package taskfile
|
||||
|
||||
import "github.com/go-task/task/v3/internal/deepcopy"
|
||||
|
||||
// Requires represents a set of required variables necessary for a task to run
|
||||
type Requires struct {
|
||||
Vars []string
|
||||
}
|
||||
|
||||
func (r *Requires) DeepCopy() *Requires {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &Requires{
|
||||
Vars: deepcopy.Slice(r.Vars),
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@ type Task struct {
|
||||
Desc string
|
||||
Prompt string
|
||||
Summary string
|
||||
Requires *Requires
|
||||
Aliases []string
|
||||
Sources []string
|
||||
Generates []string
|
||||
@ -99,6 +100,7 @@ func (t *Task) UnmarshalYAML(node *yaml.Node) error {
|
||||
IgnoreError bool `yaml:"ignore_error"`
|
||||
Run string
|
||||
Platforms []*Platform
|
||||
Requires *Requires
|
||||
}
|
||||
if err := node.Decode(&task); err != nil {
|
||||
return err
|
||||
@ -135,6 +137,7 @@ func (t *Task) UnmarshalYAML(node *yaml.Node) error {
|
||||
t.IgnoreError = task.IgnoreError
|
||||
t.Run = task.Run
|
||||
t.Platforms = task.Platforms
|
||||
t.Requires = task.Requires
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -178,6 +181,7 @@ func (t *Task) DeepCopy() *Task {
|
||||
IncludedTaskfile: t.IncludedTaskfile.DeepCopy(),
|
||||
Platforms: deepcopy.Slice(t.Platforms),
|
||||
Location: t.Location.DeepCopy(),
|
||||
Requires: t.Requires.DeepCopy(),
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
@ -68,6 +68,7 @@ func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskf
|
||||
IncludedTaskfileVars: origTask.IncludedTaskfileVars,
|
||||
Platforms: origTask.Platforms,
|
||||
Location: origTask.Location,
|
||||
Requires: origTask.Requires,
|
||||
}
|
||||
new.Dir, err = execext.Expand(new.Dir)
|
||||
if err != nil {
|
||||
|
Loading…
x
Reference in New Issue
Block a user