mirror of
				https://github.com/go-task/task.git
				synced 2025-10-30 23:58:01 +02:00 
			
		
		
		
	feat: set and shopt directives (#929)
Co-authored-by: Andrey Nering <andrey@nering.com.br>
This commit is contained in:
		| @@ -2,6 +2,9 @@ | ||||
|  | ||||
| ## Unreleased | ||||
|  | ||||
| - Add ability to configure options for the [`set`](https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html) | ||||
|   and [`shopt`](https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html) builtins | ||||
|   ([#908](https://github.com/go-task/task/issues/908), [#929](https://github.com/go-task/task/pull/929) by @pd93, [Documentation](http://taskfile.dev/usage/#set-and-shopt)). | ||||
| - Add new `platforms:` attribute to `task` and `cmd`, so it's now possible to | ||||
|   choose in which platforms that given task or command will be run on. Possible | ||||
|   values are operating system (GOOS), architecture (GOARCH) or a combination of | ||||
|   | ||||
| @@ -91,6 +91,8 @@ Some environment variables can be overriden to adjust Task behavior. | ||||
| | `dotenv` | `[]string` | | A list of `.env` file paths to be parsed. | | ||||
| | `run` | `string` | `always` | Default 'run' option for this Taskfile. Available options: `always`, `once` and `when_changed`. | | ||||
| | `interval` | `string` | `5s` | Sets a different watch interval when using `--watch`, the default being 5 seconds. This string should be a valid [Go Duration](https://pkg.go.dev/time#ParseDuration). | | ||||
| | `set` | `[]string` | | Specify options for the [`set` builtin](https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html). | | ||||
| | `shopt` | `[]string` | | Specify option for the [`shopt` builtin](https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html). | | ||||
|  | ||||
| ### Include | ||||
|  | ||||
| @@ -140,6 +142,8 @@ includes: | ||||
| | `ignore_error` | `bool` | `false` | Continue execution if errors happen while executing commands. | | ||||
| | `run` | `string` | The one declared globally in the Taskfile or `always` | Specifies whether the task should run again or not if called more than once. Available options: `always`, `once` and `when_changed`. | | ||||
| | `platforms` | `[]string` | All platforms | Specifies which platforms the task should be run on. [Valid GOOS and GOARCH values allowed](https://github.com/golang/go/blob/master/src/go/build/syslist.go). Task will be skipped otherwise. | | ||||
| | `set` | `[]string` | | Specify options for the [`set` builtin](https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html). | | ||||
| | `shopt` | `[]string` | | Specify option for the [`shopt` builtin](https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html). | | ||||
|  | ||||
| :::info | ||||
|  | ||||
| @@ -191,6 +195,8 @@ tasks: | ||||
| | `ignore_error` | `bool` | `false` | Continue execution if errors happen while executing the command. | | ||||
| | `defer` | `string` | | Alternative to `cmd`, but schedules the command to be executed at the end of this task instead of immediately. This cannot be used together with `cmd`. | | ||||
| | `platforms` | `[]string` | All platforms | Specifies which platforms the command should be run on. [Valid GOOS and GOARCH values allowed](https://github.com/golang/go/blob/master/src/go/build/syslist.go). Command will be skipped otherwise. | | ||||
| | `set` | `[]string` | | Specify options for the [`set` builtin](https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html). | | ||||
| | `shopt` | `[]string` | | Specify option for the [`shopt` builtin](https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html). | | ||||
|  | ||||
| :::info | ||||
|  | ||||
|   | ||||
| @@ -1420,6 +1420,31 @@ tasks: | ||||
|     - ./app{{exeExt}} -h localhost -p 8080 | ||||
| ``` | ||||
|  | ||||
| ## `set` and `shopt` | ||||
|  | ||||
| It's possible to specify options to the | ||||
| [`set`](https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html) | ||||
| and [`shopt`](https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html) | ||||
| builtins. This can be added at global, task or command level. | ||||
|  | ||||
| ```yaml | ||||
| version: '2' | ||||
|  | ||||
| set: [pipefail] | ||||
| shopt: [globstar] | ||||
|  | ||||
| tasks: | ||||
|   # `globstar` required for double star globs to work | ||||
|   default: echo **/*.go | ||||
| ``` | ||||
|  | ||||
| :::info | ||||
|  | ||||
| Keep in mind that not all options are available in the | ||||
| [shell interpreter library](https://github.com/mvdan/sh) that Task uses. | ||||
|  | ||||
| ::: | ||||
|  | ||||
| ## Watch tasks | ||||
|  | ||||
| With the flags `--watch` or `-w` task will watch for file changes | ||||
|   | ||||
							
								
								
									
										50
									
								
								docs/static/schema.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										50
									
								
								docs/static/schema.json
									
									
									
									
										vendored
									
									
								
							| @@ -108,6 +108,20 @@ | ||||
|             "description": "The directory in which this task should run. Defaults to the current working directory.", | ||||
|             "type": "string" | ||||
|           }, | ||||
|           "set": { | ||||
|             "description": "Enables POSIX shell options for all of a task's commands. See https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html", | ||||
|             "type": "array", | ||||
|             "items": { | ||||
|               "$ref": "#/definitions/3/set" | ||||
|             } | ||||
|           }, | ||||
|           "shopt": { | ||||
|             "description": "Enables Bash shell options for all of a task's commands. See https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html", | ||||
|             "type": "array", | ||||
|             "items": { | ||||
|               "$ref": "#/definitions/3/shopt" | ||||
|             } | ||||
|           }, | ||||
|           "vars": { | ||||
|             "description": "A set of variables that can be used in the task.", | ||||
|             "$ref": "#/definitions/3/vars" | ||||
| @@ -184,6 +198,14 @@ | ||||
|           } | ||||
|         ] | ||||
|       }, | ||||
|       "set": { | ||||
|         "type": "string", | ||||
|         "enum": ["allexport", "a", "errexit", "e", "noexec", "n", "noglob", "f", "nounset", "u", "xtrace", "x", "pipefail"] | ||||
|       }, | ||||
|       "shopt": { | ||||
|         "type": "string", | ||||
|         "enum": ["expand_aliases", "globstar", "nullglob"] | ||||
|       }, | ||||
|       "vars": { | ||||
|         "type": "object", | ||||
|         "patternProperties": { | ||||
| @@ -233,6 +255,20 @@ | ||||
|             "description": "Silent mode disables echoing of command before Task runs it", | ||||
|             "type": "boolean" | ||||
|           }, | ||||
|           "set": { | ||||
|             "description": "Enables POSIX shell options for this command. See https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html", | ||||
|             "type": "array", | ||||
|             "items": { | ||||
|               "$ref": "#/definitions/3/set" | ||||
|             } | ||||
|           }, | ||||
|           "shopt": { | ||||
|             "description": "Enables Bash shell options for this command. See https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html", | ||||
|             "type": "array", | ||||
|             "items": { | ||||
|               "$ref": "#/definitions/3/shopt" | ||||
|             } | ||||
|           }, | ||||
|           "ignore_error": { | ||||
|             "description": "Prevent command from aborting the execution of task even after receiving a status code of 1", | ||||
|             "type": "boolean" | ||||
| @@ -371,6 +407,20 @@ | ||||
|           "description": "Default 'silent' options for this Taskfile. If `false`, can be overidden with `true` in a task by task basis.", | ||||
|           "type": "boolean" | ||||
|         }, | ||||
|         "set": { | ||||
|           "description": "Enables POSIX shell options for all commands in the Taskfile. See https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html", | ||||
|           "type": "array", | ||||
|           "items": { | ||||
|             "$ref": "#/definitions/3/set" | ||||
|           } | ||||
|         }, | ||||
|         "shopt": { | ||||
|           "description": "Enables Bash shell options for all commands in the Taskfile. See https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html", | ||||
|           "type": "array", | ||||
|           "items": { | ||||
|             "$ref": "#/definitions/3/shopt" | ||||
|           } | ||||
|         }, | ||||
|         "dotenv": { | ||||
|           "type": "array", | ||||
|           "description": "A list of `.env` file paths to be parsed.", | ||||
|   | ||||
| @@ -3,6 +3,7 @@ package execext | ||||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| @@ -17,12 +18,14 @@ import ( | ||||
|  | ||||
| // RunCommandOptions is the options for the RunCommand func | ||||
| type RunCommandOptions struct { | ||||
| 	Command string | ||||
| 	Dir     string | ||||
| 	Env     []string | ||||
| 	Stdin   io.Reader | ||||
| 	Stdout  io.Writer | ||||
| 	Stderr  io.Writer | ||||
| 	Command   string | ||||
| 	Dir       string | ||||
| 	Env       []string | ||||
| 	PosixOpts []string | ||||
| 	BashOpts  []string | ||||
| 	Stdin     io.Reader | ||||
| 	Stdout    io.Writer | ||||
| 	Stderr    io.Writer | ||||
| } | ||||
|  | ||||
| var ( | ||||
| @@ -36,9 +39,18 @@ func RunCommand(ctx context.Context, opts *RunCommandOptions) error { | ||||
| 		return ErrNilOptions | ||||
| 	} | ||||
|  | ||||
| 	p, err := syntax.NewParser().Parse(strings.NewReader(opts.Command), "") | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	// Set "-e" or "errexit" by default | ||||
| 	opts.PosixOpts = append(opts.PosixOpts, "e") | ||||
|  | ||||
| 	// Format POSIX options into a slice that mvdan/sh understands | ||||
| 	var params []string | ||||
| 	for _, opt := range opts.PosixOpts { | ||||
| 		if len(opt) == 1 { | ||||
| 			params = append(params, fmt.Sprintf("-%s", opt)) | ||||
| 		} else { | ||||
| 			params = append(params, "-o") | ||||
| 			params = append(params, opt) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	environ := opts.Env | ||||
| @@ -47,7 +59,7 @@ func RunCommand(ctx context.Context, opts *RunCommandOptions) error { | ||||
| 	} | ||||
|  | ||||
| 	r, err := interp.New( | ||||
| 		interp.Params("-e"), | ||||
| 		interp.Params(params...), | ||||
| 		interp.Env(expand.ListEnviron(environ...)), | ||||
| 		interp.ExecHandler(interp.DefaultExecHandler(15*time.Second)), | ||||
| 		interp.OpenHandler(openHandler), | ||||
| @@ -58,6 +70,25 @@ func RunCommand(ctx context.Context, opts *RunCommandOptions) error { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	parser := syntax.NewParser() | ||||
|  | ||||
| 	// Run any shopt commands | ||||
| 	if len(opts.BashOpts) > 0 { | ||||
| 		shoptCmdStr := fmt.Sprintf("shopt -s %s", strings.Join(opts.BashOpts, " ")) | ||||
| 		shoptCmd, err := parser.Parse(strings.NewReader(shoptCmdStr), "") | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if err := r.Run(ctx, shoptCmd); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Run the user-defined command | ||||
| 	p, err := parser.Parse(strings.NewReader(opts.Command), "") | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return r.Run(ctx, p) | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										20
									
								
								internal/slicesext/slicesext.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								internal/slicesext/slicesext.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| package slicesext | ||||
|  | ||||
| import ( | ||||
| 	"golang.org/x/exp/constraints" | ||||
| 	"golang.org/x/exp/slices" | ||||
| ) | ||||
|  | ||||
| func UniqueJoin[T constraints.Ordered](ss ...[]T) []T { | ||||
| 	var length int | ||||
| 	for _, s := range ss { | ||||
| 		length += len(s) | ||||
| 	} | ||||
| 	r := make([]T, length) | ||||
| 	var i int | ||||
| 	for _, s := range ss { | ||||
| 		i += copy(r[i:], s) | ||||
| 	} | ||||
| 	slices.Sort(r) | ||||
| 	return slices.Compact(r) | ||||
| } | ||||
							
								
								
									
										17
									
								
								task.go
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								task.go
									
									
									
									
									
								
							| @@ -16,6 +16,7 @@ import ( | ||||
| 	"github.com/go-task/task/v3/internal/execext" | ||||
| 	"github.com/go-task/task/v3/internal/logger" | ||||
| 	"github.com/go-task/task/v3/internal/output" | ||||
| 	"github.com/go-task/task/v3/internal/slicesext" | ||||
| 	"github.com/go-task/task/v3/internal/summary" | ||||
| 	"github.com/go-task/task/v3/internal/templater" | ||||
| 	"github.com/go-task/task/v3/taskfile" | ||||
| @@ -283,17 +284,19 @@ func (e *Executor) runCommand(ctx context.Context, t *taskfile.Task, call taskfi | ||||
| 		stdOut, stdErr, close := outputWrapper.WrapWriter(e.Stdout, e.Stderr, t.Prefix, outputTemplater) | ||||
| 		defer func() { | ||||
| 			if err := close(); err != nil { | ||||
| 				e.Logger.Errf(logger.Red, "task: unable to close writter: %v", err) | ||||
| 				e.Logger.Errf(logger.Red, "task: unable to close writer: %v", err) | ||||
| 			} | ||||
| 		}() | ||||
|  | ||||
| 		err = execext.RunCommand(ctx, &execext.RunCommandOptions{ | ||||
| 			Command: cmd.Cmd, | ||||
| 			Dir:     t.Dir, | ||||
| 			Env:     getEnviron(t), | ||||
| 			Stdin:   e.Stdin, | ||||
| 			Stdout:  stdOut, | ||||
| 			Stderr:  stdErr, | ||||
| 			Command:   cmd.Cmd, | ||||
| 			Dir:       t.Dir, | ||||
| 			Env:       getEnviron(t), | ||||
| 			PosixOpts: slicesext.UniqueJoin(e.Taskfile.Set, t.Set, cmd.Set), | ||||
| 			BashOpts:  slicesext.UniqueJoin(e.Taskfile.Shopt, t.Shopt, cmd.Shopt), | ||||
| 			Stdin:     e.Stdin, | ||||
| 			Stdout:    stdOut, | ||||
| 			Stderr:    stdErr, | ||||
| 		}) | ||||
| 		if execext.IsExitError(err) && cmd.IgnoreError { | ||||
| 			e.Logger.VerboseErrf(logger.Yellow, "task: [%s] command error ignored: %v", t.Name(), err) | ||||
|   | ||||
							
								
								
									
										85
									
								
								task_test.go
									
									
									
									
									
								
							
							
						
						
									
										85
									
								
								task_test.go
									
									
									
									
									
								
							| @@ -1696,6 +1696,7 @@ func TestUserWorkingDirectory(t *testing.T) { | ||||
| 	assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "default"})) | ||||
| 	assert.Equal(t, fmt.Sprintf("%s\n", wd), buff.String()) | ||||
| } | ||||
|  | ||||
| func TestPlatforms(t *testing.T) { | ||||
| 	var buff bytes.Buffer | ||||
| 	e := task.Executor{ | ||||
| @@ -1707,3 +1708,87 @@ func TestPlatforms(t *testing.T) { | ||||
| 	assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "build-" + runtime.GOOS})) | ||||
| 	assert.Equal(t, fmt.Sprintf("task: [build-%s] echo 'Running task on %s'\nRunning task on %s\n", runtime.GOOS, runtime.GOOS, runtime.GOOS), buff.String()) | ||||
| } | ||||
|  | ||||
| func TestPOSIXShellOptsGlobalLevel(t *testing.T) { | ||||
| 	var buff bytes.Buffer | ||||
| 	e := task.Executor{ | ||||
| 		Dir:    "testdata/shopts/global_level", | ||||
| 		Stdout: &buff, | ||||
| 		Stderr: &buff, | ||||
| 	} | ||||
| 	assert.NoError(t, e.Setup()) | ||||
|  | ||||
| 	err := e.Run(context.Background(), taskfile.Call{Task: "pipefail"}) | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.Equal(t, "pipefail\ton\n", buff.String()) | ||||
| } | ||||
|  | ||||
| func TestPOSIXShellOptsTaskLevel(t *testing.T) { | ||||
| 	var buff bytes.Buffer | ||||
| 	e := task.Executor{ | ||||
| 		Dir:    "testdata/shopts/task_level", | ||||
| 		Stdout: &buff, | ||||
| 		Stderr: &buff, | ||||
| 	} | ||||
| 	assert.NoError(t, e.Setup()) | ||||
|  | ||||
| 	err := e.Run(context.Background(), taskfile.Call{Task: "pipefail"}) | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.Equal(t, "pipefail\ton\n", buff.String()) | ||||
| } | ||||
|  | ||||
| func TestPOSIXShellOptsCommandLevel(t *testing.T) { | ||||
| 	var buff bytes.Buffer | ||||
| 	e := task.Executor{ | ||||
| 		Dir:    "testdata/shopts/command_level", | ||||
| 		Stdout: &buff, | ||||
| 		Stderr: &buff, | ||||
| 	} | ||||
| 	assert.NoError(t, e.Setup()) | ||||
|  | ||||
| 	err := e.Run(context.Background(), taskfile.Call{Task: "pipefail"}) | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.Equal(t, "pipefail\ton\n", buff.String()) | ||||
| } | ||||
|  | ||||
| func TestBashShellOptsGlobalLevel(t *testing.T) { | ||||
| 	var buff bytes.Buffer | ||||
| 	e := task.Executor{ | ||||
| 		Dir:    "testdata/shopts/global_level", | ||||
| 		Stdout: &buff, | ||||
| 		Stderr: &buff, | ||||
| 	} | ||||
| 	assert.NoError(t, e.Setup()) | ||||
|  | ||||
| 	err := e.Run(context.Background(), taskfile.Call{Task: "globstar"}) | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.Equal(t, "globstar\ton\n", buff.String()) | ||||
| } | ||||
|  | ||||
| func TestBashShellOptsTaskLevel(t *testing.T) { | ||||
| 	var buff bytes.Buffer | ||||
| 	e := task.Executor{ | ||||
| 		Dir:    "testdata/shopts/task_level", | ||||
| 		Stdout: &buff, | ||||
| 		Stderr: &buff, | ||||
| 	} | ||||
| 	assert.NoError(t, e.Setup()) | ||||
|  | ||||
| 	err := e.Run(context.Background(), taskfile.Call{Task: "globstar"}) | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.Equal(t, "globstar\ton\n", buff.String()) | ||||
| } | ||||
|  | ||||
| func TestBashShellOptsCommandLevel(t *testing.T) { | ||||
| 	var buff bytes.Buffer | ||||
| 	e := task.Executor{ | ||||
| 		Dir:    "testdata/shopts/command_level", | ||||
| 		Stdout: &buff, | ||||
| 		Stderr: &buff, | ||||
| 	} | ||||
| 	assert.NoError(t, e.Setup()) | ||||
|  | ||||
| 	err := e.Run(context.Background(), taskfile.Call{Task: "globstar"}) | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.Equal(t, "globstar\ton\n", buff.String()) | ||||
| } | ||||
|   | ||||
| @@ -11,6 +11,8 @@ type Cmd struct { | ||||
| 	Cmd         string | ||||
| 	Silent      bool | ||||
| 	Task        string | ||||
| 	Set         []string | ||||
| 	Shopt       []string | ||||
| 	Vars        *Vars | ||||
| 	IgnoreError bool | ||||
| 	Defer       bool | ||||
| @@ -40,12 +42,16 @@ func (c *Cmd) UnmarshalYAML(node *yaml.Node) error { | ||||
| 		var cmdStruct struct { | ||||
| 			Cmd         string | ||||
| 			Silent      bool | ||||
| 			Set         []string | ||||
| 			Shopt       []string | ||||
| 			IgnoreError bool `yaml:"ignore_error"` | ||||
| 			Platforms   []*Platform | ||||
| 		} | ||||
| 		if err := node.Decode(&cmdStruct); err == nil && cmdStruct.Cmd != "" { | ||||
| 			c.Cmd = cmdStruct.Cmd | ||||
| 			c.Silent = cmdStruct.Silent | ||||
| 			c.Set = cmdStruct.Set | ||||
| 			c.Shopt = cmdStruct.Shopt | ||||
| 			c.IgnoreError = cmdStruct.IgnoreError | ||||
| 			c.Platforms = cmdStruct.Platforms | ||||
| 			return nil | ||||
|   | ||||
| @@ -23,6 +23,8 @@ type Task struct { | ||||
| 	Status               []string | ||||
| 	Preconditions        []*Precondition | ||||
| 	Dir                  string | ||||
| 	Set                  []string | ||||
| 	Shopt                []string | ||||
| 	Vars                 *Vars | ||||
| 	Env                  *Vars | ||||
| 	Dotenv               []string | ||||
| @@ -81,6 +83,8 @@ func (t *Task) UnmarshalYAML(node *yaml.Node) error { | ||||
| 			Status        []string | ||||
| 			Preconditions []*Precondition | ||||
| 			Dir           string | ||||
| 			Set           []string | ||||
| 			Shopt         []string | ||||
| 			Vars          *Vars | ||||
| 			Env           *Vars | ||||
| 			Dotenv        []string | ||||
| @@ -107,6 +111,8 @@ func (t *Task) UnmarshalYAML(node *yaml.Node) error { | ||||
| 		t.Status = task.Status | ||||
| 		t.Preconditions = task.Preconditions | ||||
| 		t.Dir = task.Dir | ||||
| 		t.Set = task.Set | ||||
| 		t.Shopt = task.Shopt | ||||
| 		t.Vars = task.Vars | ||||
| 		t.Env = task.Env | ||||
| 		t.Dotenv = task.Dotenv | ||||
| @@ -140,6 +146,8 @@ func (t *Task) DeepCopy() *Task { | ||||
| 		Status:               deepCopySlice(t.Status), | ||||
| 		Preconditions:        deepCopySlice(t.Preconditions), | ||||
| 		Dir:                  t.Dir, | ||||
| 		Set:                  deepCopySlice(t.Set), | ||||
| 		Shopt:                deepCopySlice(t.Shopt), | ||||
| 		Vars:                 t.Vars.DeepCopy(), | ||||
| 		Env:                  t.Env.DeepCopy(), | ||||
| 		Dotenv:               deepCopySlice(t.Dotenv), | ||||
|   | ||||
| @@ -15,6 +15,8 @@ type Taskfile struct { | ||||
| 	Output     Output | ||||
| 	Method     string | ||||
| 	Includes   *IncludedTaskfiles | ||||
| 	Set        []string | ||||
| 	Shopt      []string | ||||
| 	Vars       *Vars | ||||
| 	Env        *Vars | ||||
| 	Tasks      Tasks | ||||
| @@ -34,6 +36,8 @@ func (tf *Taskfile) UnmarshalYAML(node *yaml.Node) error { | ||||
| 			Output     Output | ||||
| 			Method     string | ||||
| 			Includes   *IncludedTaskfiles | ||||
| 			Set        []string | ||||
| 			Shopt      []string | ||||
| 			Vars       *Vars | ||||
| 			Env        *Vars | ||||
| 			Tasks      Tasks | ||||
| @@ -50,6 +54,8 @@ func (tf *Taskfile) UnmarshalYAML(node *yaml.Node) error { | ||||
| 		tf.Output = taskfile.Output | ||||
| 		tf.Method = taskfile.Method | ||||
| 		tf.Includes = taskfile.Includes | ||||
| 		tf.Set = taskfile.Set | ||||
| 		tf.Shopt = taskfile.Shopt | ||||
| 		tf.Vars = taskfile.Vars | ||||
| 		tf.Env = taskfile.Env | ||||
| 		tf.Tasks = taskfile.Tasks | ||||
|   | ||||
							
								
								
									
										14
									
								
								testdata/shopts/command_level/Taskfile.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								testdata/shopts/command_level/Taskfile.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| version: '3' | ||||
|  | ||||
| silent: true | ||||
|  | ||||
| tasks: | ||||
|   pipefail: | ||||
|     cmds: | ||||
|       - cmd: set -o | grep pipefail | ||||
|         set: [pipefail] | ||||
|  | ||||
|   globstar: | ||||
|     cmds: | ||||
|       - cmd: shopt | grep globstar | ||||
|         shopt: [globstar] | ||||
							
								
								
									
										14
									
								
								testdata/shopts/global_level/Taskfile.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								testdata/shopts/global_level/Taskfile.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| version: '3' | ||||
|  | ||||
| silent: true | ||||
| set: [pipefail] | ||||
| shopt: [globstar] | ||||
|  | ||||
| tasks: | ||||
|   pipefail: | ||||
|     cmds: | ||||
|       - set -o | grep pipefail | ||||
|  | ||||
|   globstar: | ||||
|     cmds: | ||||
|       - shopt | grep globstar | ||||
							
								
								
									
										14
									
								
								testdata/shopts/task_level/Taskfile.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								testdata/shopts/task_level/Taskfile.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| version: '3' | ||||
|  | ||||
| silent: true | ||||
|  | ||||
| tasks: | ||||
|   pipefail: | ||||
|     set: [pipefail] | ||||
|     cmds: | ||||
|       - set -o | grep pipefail | ||||
|  | ||||
|   globstar: | ||||
|     shopt: [globstar] | ||||
|     cmds: | ||||
|       - shopt | grep globstar | ||||
| @@ -56,6 +56,8 @@ func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskf | ||||
| 		Sources:              r.ReplaceSlice(origTask.Sources), | ||||
| 		Generates:            r.ReplaceSlice(origTask.Generates), | ||||
| 		Dir:                  r.Replace(origTask.Dir), | ||||
| 		Set:                  origTask.Set, | ||||
| 		Shopt:                origTask.Shopt, | ||||
| 		Vars:                 nil, | ||||
| 		Env:                  nil, | ||||
| 		Dotenv:               r.ReplaceSlice(origTask.Dotenv), | ||||
| @@ -125,9 +127,11 @@ func (e *Executor) compiledTask(call taskfile.Call, evaluateShVars bool) (*taskf | ||||
| 				continue | ||||
| 			} | ||||
| 			new.Cmds = append(new.Cmds, &taskfile.Cmd{ | ||||
| 				Task:        r.Replace(cmd.Task), | ||||
| 				Silent:      cmd.Silent, | ||||
| 				Cmd:         r.Replace(cmd.Cmd), | ||||
| 				Silent:      cmd.Silent, | ||||
| 				Task:        r.Replace(cmd.Task), | ||||
| 				Set:         cmd.Set, | ||||
| 				Shopt:       cmd.Shopt, | ||||
| 				Vars:        r.ReplaceVars(cmd.Vars), | ||||
| 				IgnoreError: cmd.IgnoreError, | ||||
| 				Defer:       cmd.Defer, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user