diff --git a/Taskfile.yml b/Taskfile.yml index ee9bcf9a..cd984e4c 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -43,6 +43,13 @@ tasks: - "{{.BIN}}/mockery --dir ./internal/fingerprint --name SourcesCheckable" - "{{.BIN}}/mockery --dir ./internal/fingerprint --name StatusCheckable" + generate:fixtures: + desc: Runs tests and generates golden fixture files + aliases: [gen:fixtures, g:fixtures] + cmds: + - find ./testdata -name '*.golden' -delete + - go test -update ./... + install:mockery: desc: Installs mockgen; a tool to generate mock files vars: diff --git a/executor.go b/executor.go index c7d5f64c..d73f9f3b 100644 --- a/executor.go +++ b/executor.go @@ -217,6 +217,14 @@ func ExecutorWithAssumeYes(assumeYes bool) ExecutorOption { } // WithAssumeTerm is used for testing purposes to simulate a terminal. +func ExecutorWithAssumeTerm(assumeTerm bool) ExecutorOption { + return func(e *Executor) { + e.AssumeTerm = assumeTerm + } +} + +// ExecutorWithDry tells the [Executor] to output the commands that would be run +// without actually running them. func ExecutorWithDry(dry bool) ExecutorOption { return func(e *Executor) { e.Dry = dry diff --git a/executor_test.go b/executor_test.go new file mode 100644 index 00000000..3d922387 --- /dev/null +++ b/executor_test.go @@ -0,0 +1,946 @@ +package task_test + +import ( + "bytes" + "cmp" + "context" + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/sebdah/goldie/v2" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/go-task/task/v3" + "github.com/go-task/task/v3/internal/experiments" + "github.com/go-task/task/v3/internal/filepathext" + "github.com/go-task/task/v3/taskfile/ast" +) + +type ( + // A ExecutorTestOption is a function that configures an [ExecutorTest]. + ExecutorTestOption interface { + applyToExecutorTest(*ExecutorTest) + } + // A ExecutorTest is a test wrapper around a [task.Executor] to make it easy + // to write tests for tasks. See [NewExecutorTest] for information on + // creating and running ExecutorTests. These tests use fixture files to + // assert whether the result of a task is correct. If Task's behavior has + // been changed, the fixture files can be updated by running `task + // gen:fixtures`. + ExecutorTest struct { + TaskTest + task string + vars map[string]any + input string + executorOpts []task.ExecutorOption + wantSetupError bool + wantRunError bool + wantStatusError bool + } +) + +// NewExecutorTest sets up a new [task.Executor] with the given options and runs +// a task with the given [ExecutorTestOption]s. The output of the task is +// written to a set of fixture files depending on the configuration of the test. +func NewExecutorTest(t *testing.T, opts ...ExecutorTestOption) { + t.Helper() + tt := &ExecutorTest{ + task: "default", + vars: map[string]any{}, + TaskTest: TaskTest{ + experiments: map[*experiments.Experiment]int{}, + }, + } + // Apply the functional options + for _, opt := range opts { + opt.applyToExecutorTest(tt) + } + // Enable any experiments that have been set + for x, v := range tt.experiments { + prev := *x + *x = experiments.Experiment{ + Name: prev.Name, + AllowedValues: []int{v}, + Value: v, + } + t.Cleanup(func() { + *x = prev + }) + } + tt.run(t) +} + +// Functional options + +// WithInput tells the test to create a reader with the given input. This can be +// used to simulate user input when a task requires it. +func WithInput(input string) ExecutorTestOption { + return &inputTestOption{input} +} + +type inputTestOption struct { + input string +} + +func (opt *inputTestOption) applyToExecutorTest(t *ExecutorTest) { + t.input = opt.input +} + +// WithRunError tells the test to expect an error during the run phase of the +// task execution. A fixture will be created with the output of any errors. +func WithRunError() ExecutorTestOption { + return &runErrorTestOption{} +} + +type runErrorTestOption struct{} + +func (opt *runErrorTestOption) applyToExecutorTest(t *ExecutorTest) { + t.wantRunError = true +} + +// WithStatusError tells the test to make an additional call to +// [task.Executor.Status] after the task has been run. A fixture will be created +// with the output of any errors. +func WithStatusError() ExecutorTestOption { + return &statusErrorTestOption{} +} + +type statusErrorTestOption struct{} + +func (opt *statusErrorTestOption) applyToExecutorTest(t *ExecutorTest) { + t.wantStatusError = true +} + +// Helpers + +// writeFixtureErrRun is a wrapper for writing the output of an error during the +// run phase of the task to a fixture file. +func (tt *ExecutorTest) writeFixtureErrRun( + t *testing.T, + g *goldie.Goldie, + err error, +) { + t.Helper() + tt.writeFixture(t, g, "err-run", []byte(err.Error())) +} + +// writeFixtureStatus is a wrapper for writing the output of an error when +// making an additional call to [task.Executor.Status] to a fixture file. +func (tt *ExecutorTest) writeFixtureStatus( + t *testing.T, + g *goldie.Goldie, + status string, +) { + t.Helper() + tt.writeFixture(t, g, "err-status", []byte(status)) +} + +// run is the main function for running the test. It sets up the task executor, +// runs the task, and writes the output to a fixture file. +func (tt *ExecutorTest) run(t *testing.T) { + t.Helper() + f := func(t *testing.T) { + t.Helper() + var buf bytes.Buffer + + opts := append( + tt.executorOpts, + task.ExecutorWithStdout(&buf), + task.ExecutorWithStderr(&buf), + ) + + // If the test has input, create a reader for it and add it to the + // executor options + if tt.input != "" { + var reader bytes.Buffer + reader.WriteString(tt.input) + opts = append(opts, task.ExecutorWithStdin(&reader)) + } + + // Set up the task executor + e := task.NewExecutor(opts...) + + // Create a golden fixture file for the output + g := goldie.New(t, + goldie.WithFixtureDir(filepath.Join(e.Dir, "testdata")), + ) + + // Call setup and check for errors + if err := e.Setup(); tt.wantSetupError { + require.Error(t, err) + tt.writeFixtureErrSetup(t, g, err) + tt.writeFixtureBuffer(t, g, buf) + return + } else { + require.NoError(t, err) + } + + // Create the task call + vars := ast.NewVars() + for key, value := range tt.vars { + vars.Set(key, ast.Var{Value: value}) + } + call := &task.Call{ + Task: tt.task, + Vars: vars, + } + + // Run the task and check for errors + ctx := context.Background() + if err := e.Run(ctx, call); tt.wantRunError { + require.Error(t, err) + tt.writeFixtureErrRun(t, g, err) + tt.writeFixtureBuffer(t, g, buf) + return + } else { + require.NoError(t, err) + } + + // If the status flag is set, run the status check + if tt.wantStatusError { + if err := e.Status(ctx, call); err != nil { + tt.writeFixtureStatus(t, g, err.Error()) + } + } + + tt.writeFixtureBuffer(t, g, buf) + } + + // Run the test (with a name if it has one) + if tt.name != "" { + t.Run(tt.name, f) + } else { + f(t) + } +} + +func TestEmptyTask(t *testing.T) { + t.Parallel() + NewExecutorTest(t, + WithExecutorOptions( + task.ExecutorWithDir("testdata/empty_task"), + ), + ) +} + +func TestEmptyTaskfile(t *testing.T) { + t.Parallel() + NewExecutorTest(t, + WithExecutorOptions( + task.ExecutorWithDir("testdata/empty_taskfile"), + ), + WithSetupError(), + WithPostProcessFn(PPRemoveAbsolutePaths), + ) +} + +func TestEnv(t *testing.T) { + t.Setenv("QUX", "from_os") + NewExecutorTest(t, + WithName("env precedence disabled"), + WithExecutorOptions( + task.ExecutorWithDir("testdata/env"), + task.ExecutorWithSilent(true), + ), + ) + NewExecutorTest(t, + WithName("env precedence enabled"), + WithExecutorOptions( + task.ExecutorWithDir("testdata/env"), + task.ExecutorWithSilent(true), + ), + WithExperiment(&experiments.EnvPrecedence, 1), + ) +} + +func TestVars(t *testing.T) { + t.Parallel() + NewExecutorTest(t, + WithExecutorOptions( + task.ExecutorWithDir("testdata/vars"), + task.ExecutorWithSilent(true), + ), + ) +} + +func TestRequires(t *testing.T) { + t.Parallel() + NewExecutorTest(t, + WithName("required var missing"), + WithExecutorOptions( + task.ExecutorWithDir("testdata/requires"), + ), + WithTask("missing-var"), + WithRunError(), + ) + NewExecutorTest(t, + WithName("required var ok"), + WithExecutorOptions( + task.ExecutorWithDir("testdata/requires"), + ), + WithTask("missing-var"), + WithVar("FOO", "bar"), + ) + NewExecutorTest(t, + WithName("fails validation"), + WithExecutorOptions( + task.ExecutorWithDir("testdata/requires"), + ), + WithTask("validation-var"), + WithVar("ENV", "dev"), + WithVar("FOO", "bar"), + WithRunError(), + ) + NewExecutorTest(t, + WithName("passes validation"), + WithExecutorOptions( + task.ExecutorWithDir("testdata/requires"), + ), + WithTask("validation-var"), + WithVar("FOO", "one"), + WithVar("ENV", "dev"), + ) + NewExecutorTest(t, + WithName("required var missing + fails validation"), + WithExecutorOptions( + task.ExecutorWithDir("testdata/requires"), + ), + WithTask("validation-var"), + WithRunError(), + ) + NewExecutorTest(t, + WithName("required var missing + fails validation"), + WithExecutorOptions( + task.ExecutorWithDir("testdata/requires"), + ), + WithTask("validation-var-dynamic"), + WithVar("FOO", "one"), + WithVar("ENV", "dev"), + ) + NewExecutorTest(t, + WithName("require before compile"), + WithExecutorOptions( + task.ExecutorWithDir("testdata/requires"), + ), + WithTask("require-before-compile"), + WithRunError(), + ) + NewExecutorTest(t, + WithName("var defined in task"), + WithExecutorOptions( + task.ExecutorWithDir("testdata/requires"), + ), + WithTask("var-defined-in-task"), + ) +} + +// TODO: mock fs +func TestSpecialVars(t *testing.T) { + t.Parallel() + + const dir = "testdata/special_vars" + const subdir = "testdata/special_vars/subdir" + toAbs := func(rel string) string { + abs, err := filepath.Abs(rel) + assert.NoError(t, err) + return abs + } + + tests := []struct { + target string + expected string + }{ + // Root + {target: "print-task", expected: "print-task"}, + {target: "print-root-dir", expected: toAbs(dir)}, + {target: "print-taskfile", expected: toAbs(dir) + "/Taskfile.yml"}, + {target: "print-taskfile-dir", expected: toAbs(dir)}, + {target: "print-task-version", expected: "unknown"}, + {target: "print-task-dir", expected: toAbs(dir) + "/foo"}, + // Included + {target: "included:print-task", expected: "included:print-task"}, + {target: "included:print-root-dir", expected: toAbs(dir)}, + {target: "included:print-taskfile", expected: toAbs(dir) + "/included/Taskfile.yml"}, + {target: "included:print-taskfile-dir", expected: toAbs(dir) + "/included"}, + {target: "included:print-task-version", expected: "unknown"}, + } + + for _, dir := range []string{dir, subdir} { + for _, test := range tests { + NewExecutorTest(t, + WithName(fmt.Sprintf("%s-%s", dir, test.target)), + WithExecutorOptions( + task.ExecutorWithDir(dir), + task.ExecutorWithSilent(true), + task.ExecutorWithVersionCheck(true), + ), + WithTask(test.target), + WithPostProcessFn(PPRemoveAbsolutePaths), + ) + } + } +} + +func TestConcurrency(t *testing.T) { + t.Parallel() + NewExecutorTest(t, + WithExecutorOptions( + task.ExecutorWithDir("testdata/concurrency"), + task.ExecutorWithConcurrency(1), + ), + WithPostProcessFn(PPSortedLines), + ) +} + +func TestParams(t *testing.T) { + t.Parallel() + NewExecutorTest(t, + WithExecutorOptions( + task.ExecutorWithDir("testdata/params"), + task.ExecutorWithSilent(true), + ), + WithPostProcessFn(PPSortedLines), + ) +} + +func TestDeps(t *testing.T) { + t.Parallel() + NewExecutorTest(t, + WithExecutorOptions( + task.ExecutorWithDir("testdata/deps"), + task.ExecutorWithSilent(true), + ), + WithPostProcessFn(PPSortedLines), + ) +} + +// TODO: mock fs +func TestStatus(t *testing.T) { + t.Parallel() + + const dir = "testdata/status" + + files := []string{ + "foo.txt", + "bar.txt", + "baz.txt", + } + + for _, f := range files { + path := filepathext.SmartJoin(dir, f) + _ = os.Remove(path) + if _, err := os.Stat(path); err == nil { + t.Errorf("File should not exist: %v", err) + } + } + + // gen-foo creates foo.txt, and will always fail it's status check. + NewExecutorTest(t, + WithName("run gen-foo 1 silent"), + WithExecutorOptions( + task.ExecutorWithDir(dir), + task.ExecutorWithSilent(true), + ), + WithTask("gen-foo"), + ) + // gen-foo creates bar.txt, and will pass its status-check the 3. time it + // is run. It creates bar.txt, but also lists it as its source. So, the checksum + // for the file won't match before after the second run as we the file + // only exists after the first run. + NewExecutorTest(t, + WithName("run gen-bar 1 silent"), + WithExecutorOptions( + task.ExecutorWithDir(dir), + task.ExecutorWithSilent(true), + ), + WithTask("gen-bar"), + ) + // gen-silent-baz is marked as being silent, and should only produce output + // if e.Verbose is set to true. + NewExecutorTest(t, + WithName("run gen-baz silent"), + WithExecutorOptions( + task.ExecutorWithDir(dir), + task.ExecutorWithSilent(true), + ), + WithTask("gen-silent-baz"), + ) + + for _, f := range files { + if _, err := os.Stat(filepathext.SmartJoin(dir, f)); err != nil { + t.Errorf("File should exist: %v", err) + } + } + + // Run gen-bar a second time to produce a checksum file that matches bar.txt + NewExecutorTest(t, + WithName("run gen-bar 2 silent"), + WithExecutorOptions( + task.ExecutorWithDir(dir), + task.ExecutorWithSilent(true), + ), + WithTask("gen-bar"), + ) + // Run gen-bar a third time, to make sure we've triggered the status check. + NewExecutorTest(t, + WithName("run gen-bar 3 silent"), + WithExecutorOptions( + task.ExecutorWithDir(dir), + task.ExecutorWithSilent(true), + ), + WithTask("gen-bar"), + ) + + // Now, let's remove source file, and run the task again to to prepare + // for the next test. + err := os.Remove(filepathext.SmartJoin(dir, "bar.txt")) + require.NoError(t, err) + NewExecutorTest(t, + WithName("run gen-bar 4 silent"), + WithExecutorOptions( + task.ExecutorWithDir(dir), + task.ExecutorWithSilent(true), + ), + WithTask("gen-bar"), + ) + // all: not up-to-date + NewExecutorTest(t, + WithName("run gen-foo 2"), + WithExecutorOptions( + task.ExecutorWithDir(dir), + ), + WithTask("gen-foo"), + ) + // status: not up-to-date + NewExecutorTest(t, + WithName("run gen-foo 3"), + WithExecutorOptions( + task.ExecutorWithDir(dir), + ), + WithTask("gen-foo"), + ) + // sources: not up-to-date + NewExecutorTest(t, + WithName("run gen-bar 5"), + WithExecutorOptions( + task.ExecutorWithDir(dir), + ), + WithTask("gen-bar"), + ) + // all: up-to-date + NewExecutorTest(t, + WithName("run gen-bar 6"), + WithExecutorOptions( + task.ExecutorWithDir(dir), + ), + WithTask("gen-bar"), + ) + // sources: not up-to-date, no output produced. + NewExecutorTest(t, + WithName("run gen-baz 2"), + WithExecutorOptions( + task.ExecutorWithDir(dir), + ), + WithTask("gen-silent-baz"), + ) + // up-to-date, no output produced + NewExecutorTest(t, + WithName("run gen-baz 3"), + WithExecutorOptions( + task.ExecutorWithDir(dir), + ), + WithTask("gen-silent-baz"), + ) + // up-to-date, output produced due to Verbose mode. + NewExecutorTest(t, + WithName("run gen-baz 4 verbose"), + WithExecutorOptions( + task.ExecutorWithDir(dir), + task.ExecutorWithVerbose(true), + ), + WithTask("gen-silent-baz"), + WithPostProcessFn(PPRemoveAbsolutePaths), + ) +} + +func TestPrecondition(t *testing.T) { + t.Parallel() + const dir = "testdata/precondition" + NewExecutorTest(t, + WithName("a precondition has been met"), + WithExecutorOptions( + task.ExecutorWithDir(dir), + ), + WithTask("foo"), + ) + NewExecutorTest(t, + WithName("a precondition was not met"), + WithExecutorOptions( + task.ExecutorWithDir(dir), + ), + WithTask("impossible"), + WithRunError(), + ) + NewExecutorTest(t, + WithName("precondition in dependency fails the task"), + WithExecutorOptions( + task.ExecutorWithDir(dir), + ), + WithTask("depends_on_impossible"), + WithRunError(), + ) + NewExecutorTest(t, + WithName("precondition in cmd fails the task"), + WithExecutorOptions( + task.ExecutorWithDir(dir), + ), + WithTask("executes_failing_task_as_cmd"), + WithRunError(), + ) +} + +func TestAlias(t *testing.T) { + t.Parallel() + + NewExecutorTest(t, + WithName("alias"), + WithExecutorOptions( + task.ExecutorWithDir("testdata/alias"), + ), + WithTask("f"), + ) + + NewExecutorTest(t, + WithName("duplicate alias"), + WithExecutorOptions( + task.ExecutorWithDir("testdata/alias"), + ), + WithTask("x"), + WithRunError(), + ) + + NewExecutorTest(t, + WithName("alias summary"), + WithExecutorOptions( + task.ExecutorWithDir("testdata/alias"), + task.ExecutorWithSummary(true), + ), + WithTask("f"), + ) +} + +func TestLabel(t *testing.T) { + t.Parallel() + + NewExecutorTest(t, + WithName("up to date"), + WithExecutorOptions( + task.ExecutorWithDir("testdata/label_uptodate"), + ), + WithTask("foo"), + ) + + NewExecutorTest(t, + WithName("summary"), + WithExecutorOptions( + task.ExecutorWithDir("testdata/label_summary"), + task.ExecutorWithSummary(true), + ), + WithTask("foo"), + ) + + NewExecutorTest(t, + WithName("status"), + WithExecutorOptions( + task.ExecutorWithDir("testdata/label_status"), + ), + WithTask("foo"), + WithStatusError(), + ) + + NewExecutorTest(t, + WithName("var"), + WithExecutorOptions( + task.ExecutorWithDir("testdata/label_var"), + ), + WithTask("foo"), + ) + + NewExecutorTest(t, + WithName("label in summary"), + WithExecutorOptions( + task.ExecutorWithDir("testdata/label_summary"), + ), + WithTask("foo"), + ) +} + +func TestPromptInSummary(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + input string + wantError bool + }{ + {"test short approval", "y\n", false}, + {"test long approval", "yes\n", false}, + {"test uppercase approval", "Y\n", false}, + {"test stops task", "n\n", true}, + {"test junk value stops task", "foobar\n", true}, + {"test Enter stops task", "\n", true}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + opts := []ExecutorTestOption{ + WithName(test.name), + WithExecutorOptions( + task.ExecutorWithDir("testdata/prompt"), + task.ExecutorWithAssumeTerm(true), + ), + WithTask("foo"), + WithInput(test.input), + } + if test.wantError { + opts = append(opts, WithRunError()) + } + NewExecutorTest(t, opts...) + }) + } +} + +func TestPromptWithIndirectTask(t *testing.T) { + t.Parallel() + + NewExecutorTest(t, + WithExecutorOptions( + task.ExecutorWithDir("testdata/prompt"), + task.ExecutorWithAssumeTerm(true), + ), + WithTask("bar"), + WithInput("y\n"), + ) +} + +func TestPromptAssumeYes(t *testing.T) { + t.Parallel() + + NewExecutorTest(t, + WithName("--yes flag should skip prompt"), + WithExecutorOptions( + task.ExecutorWithDir("testdata/prompt"), + task.ExecutorWithAssumeTerm(true), + task.ExecutorWithAssumeYes(true), + ), + WithTask("foo"), + WithInput("\n"), + ) + + NewExecutorTest(t, + WithName("task should raise errors.TaskCancelledError"), + WithExecutorOptions( + task.ExecutorWithDir("testdata/prompt"), + task.ExecutorWithAssumeTerm(true), + ), + WithTask("foo"), + WithInput("\n"), + WithRunError(), + ) +} + +func TestForCmds(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + wantErr bool + }{ + {name: "loop-explicit"}, + {name: "loop-matrix"}, + {name: "loop-matrix-ref"}, + { + name: "loop-matrix-ref-error", + wantErr: true, + }, + {name: "loop-sources"}, + {name: "loop-sources-glob"}, + {name: "loop-vars"}, + {name: "loop-vars-sh"}, + {name: "loop-task"}, + {name: "loop-task-as"}, + {name: "loop-different-tasks"}, + } + + for _, test := range tests { + opts := []ExecutorTestOption{ + WithName(test.name), + WithExecutorOptions( + task.ExecutorWithDir("testdata/for/cmds"), + task.ExecutorWithSilent(true), + task.ExecutorWithForce(true), + ), + WithTask(test.name), + WithPostProcessFn(PPRemoveAbsolutePaths), + } + if test.wantErr { + opts = append(opts, WithRunError()) + } + NewExecutorTest(t, opts...) + } +} + +func TestForDeps(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + wantErr bool + }{ + {name: "loop-explicit"}, + {name: "loop-matrix"}, + {name: "loop-matrix-ref"}, + { + name: "loop-matrix-ref-error", + wantErr: true, + }, + {name: "loop-sources"}, + {name: "loop-sources-glob"}, + {name: "loop-vars"}, + {name: "loop-vars-sh"}, + {name: "loop-task"}, + {name: "loop-task-as"}, + {name: "loop-different-tasks"}, + } + + for _, test := range tests { + opts := []ExecutorTestOption{ + WithName(test.name), + WithExecutorOptions( + task.ExecutorWithDir("testdata/for/deps"), + task.ExecutorWithSilent(true), + task.ExecutorWithForce(true), + // Force output of each dep to be grouped together to prevent interleaving + task.ExecutorWithOutputStyle(ast.Output{Name: "group"}), + ), + WithTask(test.name), + WithPostProcessFn(PPRemoveAbsolutePaths), + WithPostProcessFn(PPSortedLines), + } + if test.wantErr { + opts = append(opts, WithRunError()) + } + NewExecutorTest(t, opts...) + } +} + +func TestReference(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + call string + }{ + { + name: "reference in command", + call: "ref-cmd", + }, + { + name: "reference in dependency", + call: "ref-dep", + }, + { + name: "reference using templating resolver", + call: "ref-resolver", + }, + { + name: "reference using templating resolver and dynamic var", + call: "ref-resolver-sh", + }, + } + + for _, test := range tests { + NewExecutorTest(t, + WithName(test.name), + WithExecutorOptions( + task.ExecutorWithDir("testdata/var_references"), + task.ExecutorWithSilent(true), + task.ExecutorWithForce(true), + ), + WithTask(cmp.Or(test.call, "default")), + ) + } +} + +func TestVarInheritance(t *testing.T) { + enableExperimentForTest(t, &experiments.EnvPrecedence, 1) + tests := []struct { + name string + call string + }{ + {name: "shell"}, + {name: "entrypoint-global-dotenv"}, + {name: "entrypoint-global-vars"}, + // We can't send env vars to a called task, so the env var is not overridden + {name: "entrypoint-task-call-vars"}, + // Dotenv doesn't set variables + {name: "entrypoint-task-call-dotenv"}, + {name: "entrypoint-task-call-task-vars"}, + // Dotenv doesn't set variables + {name: "entrypoint-task-dotenv"}, + {name: "entrypoint-task-vars"}, + // { + // // Dotenv not currently allowed in included taskfiles + // name: "included-global-dotenv", + // want: "included-global-dotenv\nincluded-global-dotenv\n", + // }, + { + name: "included-global-vars", + call: "included", + }, + { + // We can't send env vars to a called task, so the env var is not overridden + name: "included-task-call-vars", + call: "included", + }, + { + // Dotenv doesn't set variables + // Dotenv not currently allowed in included taskfiles (but doesn't error in a task) + name: "included-task-call-dotenv", + call: "included", + }, + { + name: "included-task-call-task-vars", + call: "included", + }, + { + // Dotenv doesn't set variables + // Somehow dotenv is working here! + name: "included-task-dotenv", + call: "included", + }, + { + name: "included-task-vars", + call: "included", + }, + } + + t.Setenv("VAR", "shell") + t.Setenv("ENV", "shell") + for _, test := range tests { + NewExecutorTest(t, + WithName(test.name), + WithExecutorOptions( + task.ExecutorWithDir(fmt.Sprintf("testdata/var_inheritance/v3/%s", test.name)), + task.ExecutorWithSilent(true), + task.ExecutorWithForce(true), + ), + WithTask(cmp.Or(test.call, "default")), + ) + } +} diff --git a/formatter_test.go b/formatter_test.go new file mode 100644 index 00000000..ec4ca1dc --- /dev/null +++ b/formatter_test.go @@ -0,0 +1,220 @@ +package task_test + +import ( + "bytes" + "path/filepath" + "testing" + + "github.com/sebdah/goldie/v2" + "github.com/stretchr/testify/require" + + "github.com/go-task/task/v3" + "github.com/go-task/task/v3/internal/experiments" + "github.com/go-task/task/v3/taskfile/ast" +) + +type ( + // A FormatterTestOption is a function that configures an [FormatterTest]. + FormatterTestOption interface { + applyToFormatterTest(*FormatterTest) + } + // A FormatterTest is a test wrapper around a [task.Executor] to make it + // easy to write tests for the task formatter. See [NewFormatterTest] for + // information on creating and running FormatterTests. These tests use + // fixture files to assert whether the result of the output is correct. If + // Task's behavior has been changed, the fixture files can be updated by + // running `task gen:fixtures`. + FormatterTest struct { + TaskTest + task string + vars map[string]any + executorOpts []task.ExecutorOption + listOptions task.ListOptions + wantSetupError bool + wantListError bool + } +) + +// NewFormatterTest sets up a new [task.Executor] with the given options and +// runs a task with the given [FormatterTestOption]s. The output of the task is +// written to a set of fixture files depending on the configuration of the test. +func NewFormatterTest(t *testing.T, opts ...FormatterTestOption) { + t.Helper() + tt := &FormatterTest{ + task: "default", + vars: map[string]any{}, + TaskTest: TaskTest{ + experiments: map[*experiments.Experiment]int{}, + }, + } + // Apply the functional options + for _, opt := range opts { + opt.applyToFormatterTest(tt) + } + // Enable any experiments that have been set + for x, v := range tt.experiments { + prev := *x + *x = experiments.Experiment{ + Name: prev.Name, + AllowedValues: []int{v}, + Value: v, + } + t.Cleanup(func() { + *x = prev + }) + } + tt.run(t) +} + +// Functional options + +// WithListOptions sets the list options for the formatter. +func WithListOptions(opts task.ListOptions) FormatterTestOption { + return &listOptionsTestOption{opts} +} + +type listOptionsTestOption struct { + listOptions task.ListOptions +} + +func (opt *listOptionsTestOption) applyToFormatterTest(t *FormatterTest) { + t.listOptions = opt.listOptions +} + +// WithListError tells the test to expect an error when running the formatter. +// A fixture will be created with the output of any errors. +func WithListError() FormatterTestOption { + return &listErrorTestOption{} +} + +type listErrorTestOption struct{} + +func (opt *listErrorTestOption) applyToFormatterTest(t *FormatterTest) { + t.wantListError = true +} + +// Helpers + +// writeFixtureErrList is a wrapper for writing the output of an error when +// running the formatter to a fixture file. +func (tt *FormatterTest) writeFixtureErrList( + t *testing.T, + g *goldie.Goldie, + err error, +) { + t.Helper() + tt.writeFixture(t, g, "err-list", []byte(err.Error())) +} + +// run is the main function for running the test. It sets up the task executor, +// runs the task, and writes the output to a fixture file. +func (tt *FormatterTest) run(t *testing.T) { + t.Helper() + f := func(t *testing.T) { + t.Helper() + var buf bytes.Buffer + + opts := append( + tt.executorOpts, + task.ExecutorWithStdout(&buf), + task.ExecutorWithStderr(&buf), + ) + + // Set up the task executor + e := task.NewExecutor(opts...) + + // Create a golden fixture file for the output + g := goldie.New(t, + goldie.WithFixtureDir(filepath.Join(e.Dir, "testdata")), + ) + + // Call setup and check for errors + if err := e.Setup(); tt.wantSetupError { + require.Error(t, err) + tt.writeFixtureErrSetup(t, g, err) + tt.writeFixtureBuffer(t, g, buf) + return + } else { + require.NoError(t, err) + } + + // Create the task call + vars := ast.NewVars() + for key, value := range tt.vars { + vars.Set(key, ast.Var{Value: value}) + } + + // Run the formatter and check for errors + if _, err := e.ListTasks(tt.listOptions); tt.wantListError { + require.Error(t, err) + tt.writeFixtureErrList(t, g, err) + tt.writeFixtureBuffer(t, g, buf) + return + } else { + require.NoError(t, err) + } + + tt.writeFixtureBuffer(t, g, buf) + } + + // Run the test (with a name if it has one) + if tt.name != "" { + t.Run(tt.name, f) + } else { + f(t) + } +} + +func TestNoLabelInList(t *testing.T) { + t.Parallel() + + NewFormatterTest(t, + WithExecutorOptions( + task.ExecutorWithDir("testdata/label_list"), + ), + WithListOptions(task.ListOptions{ + ListOnlyTasksWithDescriptions: true, + }), + ) +} + +// task -al case 1: listAll list all tasks +func TestListAllShowsNoDesc(t *testing.T) { + t.Parallel() + + NewFormatterTest(t, + WithExecutorOptions( + task.ExecutorWithDir("testdata/list_mixed_desc"), + ), + WithListOptions(task.ListOptions{ + ListAllTasks: true, + }), + ) +} + +// task -al case 2: !listAll list some tasks (only those with desc) +func TestListCanListDescOnly(t *testing.T) { + t.Parallel() + + NewFormatterTest(t, + WithExecutorOptions( + task.ExecutorWithDir("testdata/list_mixed_desc"), + ), + WithListOptions(task.ListOptions{ + ListOnlyTasksWithDescriptions: true, + }), + ) +} + +func TestListDescInterpolation(t *testing.T) { + t.Parallel() + + NewFormatterTest(t, + WithExecutorOptions( + task.ExecutorWithDir("testdata/list_desc_interpolation"), + ), + WithListOptions(task.ListOptions{ + ListOnlyTasksWithDescriptions: true, + }), + ) +} diff --git a/go.mod b/go.mod index bc5fda63..e3bacab1 100644 --- a/go.mod +++ b/go.mod @@ -22,6 +22,7 @@ require ( github.com/otiai10/copy v1.14.1 github.com/puzpuzpuz/xsync/v3 v3.5.1 github.com/sajari/fuzzy v1.0.0 + github.com/sebdah/goldie/v2 v2.5.5 github.com/spf13/pflag v1.0.6 github.com/stretchr/testify v1.10.0 github.com/zeebo/xxh3 v1.0.2 diff --git a/go.sum b/go.sum index c9898452..b92a5340 100644 --- a/go.sum +++ b/go.sum @@ -98,6 +98,7 @@ github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs= github.com/otiai10/mint v1.6.3/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM= github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -108,6 +109,9 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/sajari/fuzzy v1.0.0 h1:+FmwVvJErsd0d0hAPlj4CxqxUtQY/fOoY0DwX4ykpRY= github.com/sajari/fuzzy v1.0.0/go.mod h1:OjYR6KxoWOe9+dOlXeiCJd4dIbED4Oo8wpS89o0pwOo= +github.com/sebdah/goldie/v2 v2.5.5 h1:rx1mwF95RxZ3/83sdS4Yp7t2C5TCokvWP4TBRbAyEWY= +github.com/sebdah/goldie/v2 v2.5.5/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= @@ -119,6 +123,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= diff --git a/task_test.go b/task_test.go index 94109c32..d1ba8abf 100644 --- a/task_test.go +++ b/task_test.go @@ -2,7 +2,6 @@ package task_test import ( "bytes" - "cmp" "context" "fmt" "io" @@ -14,12 +13,15 @@ import ( "path/filepath" "regexp" "runtime" + "slices" + "sort" "strings" "sync" "testing" "time" "github.com/Masterminds/semver/v3" + "github.com/sebdah/goldie/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -34,6 +36,231 @@ func init() { _ = os.Setenv("NO_COLOR", "1") } +type ( + TestOption interface { + ExecutorTestOption + FormatterTestOption + } + TaskTest struct { + name string + experiments map[*experiments.Experiment]int + postProcessFns []PostProcessFn + } +) + +// goldenFileName makes the file path for fixture files safe for all well-known +// operating systems. Windows in particular has a lot of restrictions the +// characters that can be used in file paths. +func goldenFileName(t *testing.T) string { + t.Helper() + name := t.Name() + for _, c := range []string{` `, `<`, `>`, `:`, `"`, `/`, `\`, `|`, `?`, `*`} { + name = strings.ReplaceAll(name, c, "-") + } + return name +} + +// writeFixture writes a fixture file for the test. The fixture file is created +// using the [goldie.Goldie] package. The fixture file is created with the +// output of the task, after any post-process functions have been applied. +func (tt *TaskTest) writeFixture( + t *testing.T, + g *goldie.Goldie, + goldenFileSuffix string, + b []byte, +) { + t.Helper() + // Apply any post-process functions + for _, fn := range tt.postProcessFns { + b = fn(t, b) + } + // Write the fixture file + goldenFileName := goldenFileName(t) + if goldenFileSuffix != "" { + goldenFileName += "-" + goldenFileSuffix + } + g.Assert(t, goldenFileName, b) +} + +// writeFixtureBuffer is a wrapper for writing the main output of the task to a +// fixture file. +func (tt *TaskTest) writeFixtureBuffer( + t *testing.T, + g *goldie.Goldie, + buff bytes.Buffer, +) { + t.Helper() + tt.writeFixture(t, g, "", buff.Bytes()) +} + +// writeFixtureErrSetup is a wrapper for writing the output of an error during +// the setup phase of the task to a fixture file. +func (tt *TaskTest) writeFixtureErrSetup( + t *testing.T, + g *goldie.Goldie, + err error, +) { + t.Helper() + tt.writeFixture(t, g, "err-setup", []byte(err.Error())) +} + +// Functional options + +// WithName gives the test fixture output a name. This should be used when +// running multiple tests in a single test function. +func WithName(name string) TestOption { + return &nameTestOption{name: name} +} + +type nameTestOption struct { + name string +} + +func (opt *nameTestOption) applyToExecutorTest(t *ExecutorTest) { + t.name = opt.name +} + +func (opt *nameTestOption) applyToFormatterTest(t *FormatterTest) { + t.name = opt.name +} + +// WithTask sets the name of the task to run. This should be used when the task +// to run is not the default task. +func WithTask(task string) TestOption { + return &taskTestOption{task: task} +} + +type taskTestOption struct { + task string +} + +func (opt *taskTestOption) applyToExecutorTest(t *ExecutorTest) { + t.task = opt.task +} + +func (opt *taskTestOption) applyToFormatterTest(t *FormatterTest) { + t.task = opt.task +} + +// WithVar sets a variable to be passed to the task. This can be called multiple +// times to set more than one variable. +func WithVar(key string, value any) TestOption { + return &varTestOption{key: key, value: value} +} + +type varTestOption struct { + key string + value any +} + +func (opt *varTestOption) applyToExecutorTest(t *ExecutorTest) { + t.vars[opt.key] = opt.value +} + +func (opt *varTestOption) applyToFormatterTest(t *FormatterTest) { + t.vars[opt.key] = opt.value +} + +// WithExecutorOptions sets the [task.ExecutorOption]s to be used when creating +// a [task.Executor]. +func WithExecutorOptions(executorOpts ...task.ExecutorOption) TestOption { + return &executorOptionsTestOption{executorOpts: executorOpts} +} + +type executorOptionsTestOption struct { + executorOpts []task.ExecutorOption +} + +func (opt *executorOptionsTestOption) applyToExecutorTest(t *ExecutorTest) { + t.executorOpts = slices.Concat(t.executorOpts, opt.executorOpts) +} + +func (opt *executorOptionsTestOption) applyToFormatterTest(t *FormatterTest) { + t.executorOpts = slices.Concat(t.executorOpts, opt.executorOpts) +} + +// WithExperiment sets an experiment to be enabled for the test. This can be +// called multiple times to enable more than one experiment. +func WithExperiment(experiment *experiments.Experiment, value int) TestOption { + return &experimentTestOption{experiment: experiment, value: value} +} + +type experimentTestOption struct { + experiment *experiments.Experiment + value int +} + +func (opt *experimentTestOption) applyToExecutorTest(t *ExecutorTest) { + t.experiments[opt.experiment] = opt.value +} + +func (opt *experimentTestOption) applyToFormatterTest(t *FormatterTest) { + t.experiments[opt.experiment] = opt.value +} + +// WithPostProcessFn adds a [PostProcessFn] function to the test. Post-process +// functions are run on the output of the task before a fixture is created. This +// can be used to remove absolute paths, sort lines, etc. This can be called +// multiple times to add more than one post-process function. +func WithPostProcessFn(fn PostProcessFn) TestOption { + return &postProcessFnTestOption{fn: fn} +} + +type postProcessFnTestOption struct { + fn PostProcessFn +} + +func (opt *postProcessFnTestOption) applyToExecutorTest(t *ExecutorTest) { + t.postProcessFns = append(t.postProcessFns, opt.fn) +} + +func (opt *postProcessFnTestOption) applyToFormatterTest(t *FormatterTest) { + t.postProcessFns = append(t.postProcessFns, opt.fn) +} + +// WithSetupError sets the test to expect an error during the setup phase of the +// task execution. A fixture will be created with the output of any errors. +func WithSetupError() TestOption { + return &setupErrorTestOption{} +} + +type setupErrorTestOption struct{} + +func (opt *setupErrorTestOption) applyToExecutorTest(t *ExecutorTest) { + t.wantSetupError = true +} + +func (opt *setupErrorTestOption) applyToFormatterTest(t *FormatterTest) { + t.wantSetupError = true +} + +// Post-processing + +// A PostProcessFn is a function that can be applied to the output of a test +// fixture before the file is written. +type PostProcessFn func(*testing.T, []byte) []byte + +// PPRemoveAbsolutePaths removes any absolute paths from the output of the task. +// This is useful when the task output contains paths that are can be different +// in different environments such as home directories. The function looks for +// any paths that contain the current working directory and truncates them. +func PPRemoveAbsolutePaths(t *testing.T, b []byte) []byte { + t.Helper() + wd, err := os.Getwd() + require.NoError(t, err) + return bytes.ReplaceAll(b, []byte(wd), nil) +} + +// PPSortedLines sorts the lines of the output of the task. This is useful when +// the order of the output is not important, but the output is expected to be +// the same each time the task is run (e.g. when running tasks in parallel). +func PPSortedLines(t *testing.T, b []byte) []byte { + t.Helper() + lines := strings.Split(strings.TrimSpace(string(b)), "\n") + sort.Strings(lines) + return []byte(strings.Join(lines, "\n") + "\n") +} + // SyncBuffer is a threadsafe buffer for testing. // Some times replace stdout/stderr with a buffer to capture output. // stdout and stderr are threadsafe, but a regular bytes.Buffer is not. @@ -97,409 +324,6 @@ func (fct fileContentTest) Run(t *testing.T) { } } -func TestEmptyTask(t *testing.T) { - t.Parallel() - - e := task.NewExecutor( - task.ExecutorWithDir("testdata/empty_task"), - task.ExecutorWithStdout(io.Discard), - task.ExecutorWithStderr(io.Discard), - ) - - require.NoError(t, e.Setup(), "e.Setup()") - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "default"})) -} - -func TestEmptyTaskfile(t *testing.T) { - t.Parallel() - - e := task.NewExecutor( - task.ExecutorWithDir("testdata/empty_taskfile"), - task.ExecutorWithStdout(io.Discard), - task.ExecutorWithStderr(io.Discard), - ) - - require.Error(t, e.Setup(), "e.Setup()") -} - -func TestEnv(t *testing.T) { - t.Setenv("QUX", "from_os") - tt := fileContentTest{ - Dir: "testdata/env", - Target: "default", - TrimSpace: false, - Files: map[string]string{ - "local.txt": "GOOS='linux' GOARCH='amd64' CGO_ENABLED='0'\n", - "global.txt": "FOO='foo' BAR='overridden' BAZ='baz'\n", - "multiple_type.txt": "FOO='1' BAR='true' BAZ='1.1'\n", - "not-overridden.txt": "QUX='from_os'\n", - "dynamic.txt": "foo\n", - }, - } - tt.Run(t) - enableExperimentForTest(t, &experiments.EnvPrecedence, 1) - ttt := fileContentTest{ - Dir: "testdata/env", - Target: "overridden", - TrimSpace: false, - Files: map[string]string{ - "overridden.txt": "QUX='from_taskfile'\n", - }, - } - ttt.Run(t) -} - -func TestVars(t *testing.T) { - t.Parallel() - - tt := fileContentTest{ - Dir: "testdata/vars", - Target: "default", - Files: map[string]string{ - "missing-var.txt": "\n", - "var-order.txt": "ABCDEF\n", - "dependent-sh.txt": "123456\n", - "with-call.txt": "Hi, ABC123!\n", - "from-dot-env.txt": "From .env file\n", - }, - } - t.Run("", func(t *testing.T) { - t.Parallel() - tt.Run(t) - }) -} - -func TestRequires(t *testing.T) { - t.Parallel() - - const dir = "testdata/requires" - - var buff bytes.Buffer - e := task.NewExecutor( - task.ExecutorWithDir(dir), - task.ExecutorWithStdout(&buff), - task.ExecutorWithStderr(&buff), - ) - - require.NoError(t, e.Setup()) - require.ErrorContains(t, e.Run(context.Background(), &task.Call{Task: "missing-var"}), "task: Task \"missing-var\" cancelled because it is missing required variables: FOO") - buff.Reset() - require.NoError(t, e.Setup()) - - vars := ast.NewVars() - vars.Set("FOO", ast.Var{Value: "bar"}) - - require.NoError(t, e.Run(context.Background(), &task.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(), &task.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()) - vars.Set("FOO", ast.Var{Value: "one"}) - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "validation-var", Vars: vars})) - buff.Reset() - - vars = ast.NewVars() - require.NoError(t, e.Setup()) - require.ErrorContains(t, e.Run(context.Background(), &task.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()) - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "validation-var-dynamic", Vars: vars})) - buff.Reset() - - require.NoError(t, e.Setup()) - require.ErrorContains(t, e.Run(context.Background(), &task.Call{Task: "require-before-compile"}), "task: Task \"require-before-compile\" cancelled because it is missing required variables: MY_VAR") - buff.Reset() - - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "var-defined-in-task"})) - buff.Reset() -} - -func TestSpecialVars(t *testing.T) { - t.Parallel() - - const dir = "testdata/special_vars" - const subdir = "testdata/special_vars/subdir" - toAbs := func(rel string) string { - abs, err := filepath.Abs(rel) - assert.NoError(t, err) - return abs - } - - tests := []struct { - target string - expected string - }{ - // Root - {target: "print-task", expected: "print-task"}, - {target: "print-root-dir", expected: toAbs(dir)}, - {target: "print-taskfile", expected: toAbs(dir) + "/Taskfile.yml"}, - {target: "print-taskfile-dir", expected: toAbs(dir)}, - {target: "print-task-version", expected: "unknown"}, - {target: "print-task-dir", expected: toAbs(dir) + "/foo"}, - // Included - {target: "included:print-task", expected: "included:print-task"}, - {target: "included:print-root-dir", expected: toAbs(dir)}, - {target: "included:print-taskfile", expected: toAbs(dir) + "/included/Taskfile.yml"}, - {target: "included:print-taskfile-dir", expected: toAbs(dir) + "/included"}, - {target: "included:print-task-version", expected: "unknown"}, - } - - for _, dir := range []string{dir, subdir} { - for _, test := range tests { - t.Run(test.target, func(t *testing.T) { - t.Parallel() - - var buff bytes.Buffer - e := task.NewExecutor( - task.ExecutorWithDir(dir), - task.ExecutorWithStdout(&buff), - task.ExecutorWithStderr(&buff), - task.ExecutorWithSilent(true), - task.ExecutorWithVersionCheck(true), - ) - require.NoError(t, e.Setup()) - require.NoError(t, e.Run(context.Background(), &task.Call{Task: test.target})) - assert.Equal(t, test.expected+"\n", buff.String()) - }) - } - } -} - -func TestConcurrency(t *testing.T) { - t.Parallel() - - const ( - dir = "testdata/concurrency" - target = "default" - ) - e := task.NewExecutor( - task.ExecutorWithDir(dir), - task.ExecutorWithStdout(io.Discard), - task.ExecutorWithStderr(io.Discard), - task.ExecutorWithConcurrency(1), - ) - require.NoError(t, e.Setup(), "e.Setup()") - require.NoError(t, e.Run(context.Background(), &task.Call{Task: target}), "e.Run(target)") -} - -func TestParams(t *testing.T) { - t.Parallel() - - tt := fileContentTest{ - Dir: "testdata/params", - Target: "default", - TrimSpace: false, - Files: map[string]string{ - "hello.txt": "Hello\n", - "world.txt": "World\n", - "exclamation.txt": "!\n", - "dep1.txt": "Dependence1\n", - "dep2.txt": "Dependence2\n", - "spanish.txt": "¡Holla mundo!\n", - "spanish-dep.txt": "¡Holla dependencia!\n", - "portuguese.txt": "Olá, mundo!\n", - "portuguese2.txt": "Olá, mundo!\n", - "german.txt": "Welt!\n", - }, - } - t.Run("", func(t *testing.T) { - t.Parallel() - tt.Run(t) - }) -} - -func TestDeps(t *testing.T) { - t.Parallel() - - const dir = "testdata/deps" - - files := []string{ - "d1.txt", - "d2.txt", - "d3.txt", - "d11.txt", - "d12.txt", - "d13.txt", - "d21.txt", - "d22.txt", - "d23.txt", - "d31.txt", - "d32.txt", - "d33.txt", - } - - for _, f := range files { - _ = os.Remove(filepathext.SmartJoin(dir, f)) - } - - e := task.NewExecutor( - task.ExecutorWithDir(dir), - task.ExecutorWithStdout(io.Discard), - task.ExecutorWithStderr(io.Discard), - ) - require.NoError(t, e.Setup()) - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "default"})) - - for _, f := range files { - f = filepathext.SmartJoin(dir, f) - if _, err := os.Stat(f); err != nil { - t.Errorf("File %s should exist", f) - } - } -} - -func TestStatus(t *testing.T) { - t.Parallel() - - const dir = "testdata/status" - - files := []string{ - "foo.txt", - "bar.txt", - "baz.txt", - } - - for _, f := range files { - path := filepathext.SmartJoin(dir, f) - _ = os.Remove(path) - if _, err := os.Stat(path); err == nil { - t.Errorf("File should not exist: %v", err) - } - } - - var buff bytes.Buffer - e := task.NewExecutor( - task.ExecutorWithDir(dir), - task.ExecutorWithStdout(&buff), - task.ExecutorWithStderr(&buff), - task.ExecutorWithSilent(true), - task.ExecutorWithTempDir(task.TempDir{ - Remote: filepathext.SmartJoin(dir, ".task"), - Fingerprint: filepathext.SmartJoin(dir, ".task"), - }), - ) - require.NoError(t, e.Setup()) - // gen-foo creates foo.txt, and will always fail it's status check. - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "gen-foo"})) - // gen-foo creates bar.txt, and will pass its status-check the 3. time it - // is run. It creates bar.txt, but also lists it as its source. So, the checksum - // for the file won't match before after the second run as we the file - // only exists after the first run. - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "gen-bar"})) - // gen-silent-baz is marked as being silent, and should only produce output - // if e.Verbose is set to true. - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "gen-silent-baz"})) - - for _, f := range files { - if _, err := os.Stat(filepathext.SmartJoin(dir, f)); err != nil { - t.Errorf("File should exist: %v", err) - } - } - - // Run gen-bar a second time to produce a checksum file that matches bar.txt - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "gen-bar"})) - - // Run gen-bar a third time, to make sure we've triggered the status check. - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "gen-bar"})) - - // We're silent, so no output should have been produced. - assert.Empty(t, buff.String()) - - // Now, let's remove source file, and run the task again to to prepare - // for the next test. - err := os.Remove(filepathext.SmartJoin(dir, "bar.txt")) - require.NoError(t, err) - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "gen-bar"})) - buff.Reset() - - // Global silence switched of, so we should see output unless the task itself - // is silent. - e.Silent = false - - // all: not up-to-date - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "gen-foo"})) - assert.Equal(t, "task: [gen-foo] touch foo.txt", strings.TrimSpace(buff.String())) - buff.Reset() - // status: not up-to-date - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "gen-foo"})) - assert.Equal(t, "task: [gen-foo] touch foo.txt", strings.TrimSpace(buff.String())) - buff.Reset() - - // sources: not up-to-date - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "gen-bar"})) - assert.Equal(t, "task: [gen-bar] touch bar.txt", strings.TrimSpace(buff.String())) - buff.Reset() - // all: up-to-date - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "gen-bar"})) - assert.Equal(t, `task: Task "gen-bar" is up to date`, strings.TrimSpace(buff.String())) - buff.Reset() - - // sources: not up-to-date, no output produced. - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "gen-silent-baz"})) - assert.Empty(t, buff.String()) - - // up-to-date, no output produced - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "gen-silent-baz"})) - assert.Empty(t, buff.String()) - - e.Verbose = true - // up-to-date, output produced due to Verbose mode. - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "gen-silent-baz"})) - assert.Equal(t, `task: Task "gen-silent-baz" is up to date`, strings.TrimSpace(buff.String())) - buff.Reset() -} - -func TestPrecondition(t *testing.T) { - t.Parallel() - - const dir = "testdata/precondition" - - var buff bytes.Buffer - e := task.NewExecutor( - task.ExecutorWithDir(dir), - task.ExecutorWithStdout(&buff), - task.ExecutorWithStderr(&buff), - ) - - // A precondition that has been met - require.NoError(t, e.Setup()) - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "foo"})) - if buff.String() != "" { - t.Errorf("Got Output when none was expected: %s", buff.String()) - } - - // A precondition that was not met - require.Error(t, e.Run(context.Background(), &task.Call{Task: "impossible"})) - - if buff.String() != "task: 1 != 0 obviously!\n" { - t.Errorf("Wrong output message: %s", buff.String()) - } - buff.Reset() - - // Calling a task with a precondition in a dependency fails the task - require.Error(t, e.Run(context.Background(), &task.Call{Task: "depends_on_impossible"})) - - if buff.String() != "task: 1 != 0 obviously!\n" { - t.Errorf("Wrong output message: %s", buff.String()) - } - buff.Reset() - - // Calling a task with a precondition in a cmd fails the task - require.Error(t, e.Run(context.Background(), &task.Call{Task: "executes_failing_task_as_cmd"})) - if buff.String() != "task: 1 != 0 obviously!\n" { - t.Errorf("Wrong output message: %s", buff.String()) - } - buff.Reset() -} - func TestGenerates(t *testing.T) { t.Parallel() @@ -615,344 +439,6 @@ func TestStatusChecksum(t *testing.T) { // nolint:paralleltest // cannot run in } } -func TestAlias(t *testing.T) { - t.Parallel() - - const dir = "testdata/alias" - - data, err := os.ReadFile(filepathext.SmartJoin(dir, "alias.txt")) - require.NoError(t, err) - - var buff bytes.Buffer - e := task.NewExecutor( - task.ExecutorWithDir(dir), - task.ExecutorWithStdout(&buff), - task.ExecutorWithStderr(&buff), - ) - require.NoError(t, e.Setup()) - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "f"})) - assert.Equal(t, string(data), buff.String()) -} - -func TestDuplicateAlias(t *testing.T) { - t.Parallel() - - const dir = "testdata/alias" - - var buff bytes.Buffer - e := task.NewExecutor( - task.ExecutorWithDir(dir), - task.ExecutorWithStdout(&buff), - task.ExecutorWithStderr(&buff), - ) - require.NoError(t, e.Setup()) - require.Error(t, e.Run(context.Background(), &task.Call{Task: "x"})) - assert.Equal(t, "", buff.String()) -} - -func TestAliasSummary(t *testing.T) { - t.Parallel() - - const dir = "testdata/alias" - - data, err := os.ReadFile(filepathext.SmartJoin(dir, "alias-summary.txt")) - require.NoError(t, err) - - var buff bytes.Buffer - e := task.NewExecutor( - task.ExecutorWithDir(dir), - task.ExecutorWithStdout(&buff), - task.ExecutorWithStderr(&buff), - task.ExecutorWithSummary(true), - ) - require.NoError(t, e.Setup()) - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "f"})) - assert.Equal(t, string(data), buff.String()) -} - -func TestLabelUpToDate(t *testing.T) { - t.Parallel() - - const dir = "testdata/label_uptodate" - - var buff bytes.Buffer - e := task.NewExecutor( - task.ExecutorWithDir(dir), - task.ExecutorWithStdout(&buff), - task.ExecutorWithStderr(&buff), - ) - require.NoError(t, e.Setup()) - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "foo"})) - assert.Contains(t, buff.String(), "foobar") -} - -func TestLabelSummary(t *testing.T) { - t.Parallel() - - const dir = "testdata/label_summary" - - var buff bytes.Buffer - e := task.NewExecutor( - task.ExecutorWithDir(dir), - task.ExecutorWithStdout(&buff), - task.ExecutorWithStderr(&buff), - task.ExecutorWithSummary(true), - ) - require.NoError(t, e.Setup()) - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "foo"})) - assert.Contains(t, buff.String(), "foobar") -} - -func TestLabelInStatus(t *testing.T) { - t.Parallel() - - const dir = "testdata/label_status" - - e := task.NewExecutor( - task.ExecutorWithDir(dir), - ) - require.NoError(t, e.Setup()) - err := e.Status(context.Background(), &task.Call{Task: "foo"}) - assert.ErrorContains(t, err, "foobar") -} - -func TestLabelWithVariableExpansion(t *testing.T) { - t.Parallel() - - const dir = "testdata/label_var" - - var buff bytes.Buffer - e := task.NewExecutor( - task.ExecutorWithDir(dir), - task.ExecutorWithStdout(&buff), - task.ExecutorWithStderr(&buff), - ) - require.NoError(t, e.Setup()) - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "foo"})) - assert.Contains(t, buff.String(), "foobaz") -} - -func TestLabelInSummary(t *testing.T) { - t.Parallel() - - const dir = "testdata/label_summary" - - var buff bytes.Buffer - e := task.NewExecutor( - task.ExecutorWithDir(dir), - task.ExecutorWithStdout(&buff), - task.ExecutorWithStderr(&buff), - ) - require.NoError(t, e.Setup()) - require.NoError(t, e.Run(context.Background(), &task.Call{Task: "foo"})) - assert.Contains(t, buff.String(), "foobar") -} - -func TestPromptInSummary(t *testing.T) { - t.Parallel() - - const dir = "testdata/prompt" - tests := []struct { - name string - input string - wantError bool - }{ - {"test short approval", "y\n", false}, - {"test long approval", "yes\n", false}, - {"test uppercase approval", "Y\n", false}, - {"test stops task", "n\n", true}, - {"test junk value stops task", "foobar\n", true}, - {"test Enter stops task", "\n", true}, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - t.Parallel() - - var inBuff bytes.Buffer - var outBuff bytes.Buffer - var errBuff bytes.Buffer - - inBuff.WriteString(test.input) - - e := task.NewExecutor( - task.ExecutorWithDir(dir), - task.ExecutorWithStdin(&inBuff), - task.ExecutorWithStdout(&outBuff), - task.ExecutorWithStderr(&errBuff), - ) - e.AssumeTerm = true - require.NoError(t, e.Setup()) - - err := e.Run(context.Background(), &task.Call{Task: "foo"}) - - if test.wantError { - require.Error(t, err) - } else { - require.NoError(t, err) - } - }) - } -} - -func TestPromptWithIndirectTask(t *testing.T) { - t.Parallel() - - const dir = "testdata/prompt" - var inBuff bytes.Buffer - var outBuff bytes.Buffer - var errBuff bytes.Buffer - - inBuff.WriteString("y\n") - - e := task.NewExecutor( - task.ExecutorWithDir(dir), - task.ExecutorWithStdin(&inBuff), - task.ExecutorWithStdout(&outBuff), - task.ExecutorWithStderr(&errBuff), - ) - e.AssumeTerm = true - require.NoError(t, e.Setup()) - - err := e.Run(context.Background(), &task.Call{Task: "bar"}) - assert.Contains(t, outBuff.String(), "show-prompt") - require.NoError(t, err) -} - -func TestPromptAssumeYes(t *testing.T) { - t.Parallel() - - const dir = "testdata/prompt" - tests := []struct { - name string - assumeYes bool - }{ - {"--yes flag should skip prompt", true}, - {"task should raise errors.TaskCancelledError", false}, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - t.Parallel() - - var inBuff bytes.Buffer - var outBuff bytes.Buffer - var errBuff bytes.Buffer - - // always cancel the prompt so we can require.Error - inBuff.WriteByte('\n') - - e := task.NewExecutor( - task.ExecutorWithDir(dir), - task.ExecutorWithStdin(&inBuff), - task.ExecutorWithStdout(&outBuff), - task.ExecutorWithStderr(&errBuff), - ) - e.AssumeTerm = true - require.NoError(t, e.Setup()) - - err := e.Run(context.Background(), &task.Call{Task: "foo"}) - - if !test.assumeYes { - require.Error(t, err) - return - } - }) - } -} - -func TestNoLabelInList(t *testing.T) { - t.Parallel() - - const dir = "testdata/label_list" - - var buff bytes.Buffer - e := task.NewExecutor( - task.ExecutorWithDir(dir), - task.ExecutorWithStdout(&buff), - task.ExecutorWithStderr(&buff), - ) - require.NoError(t, e.Setup()) - if _, err := e.ListTasks(task.ListOptions{ListOnlyTasksWithDescriptions: true}); err != nil { - t.Error(err) - } - assert.Contains(t, buff.String(), "foo") -} - -// task -al case 1: listAll list all tasks -func TestListAllShowsNoDesc(t *testing.T) { - t.Parallel() - - const dir = "testdata/list_mixed_desc" - - var buff bytes.Buffer - e := task.NewExecutor( - task.ExecutorWithDir(dir), - task.ExecutorWithStdout(&buff), - task.ExecutorWithStderr(&buff), - ) - require.NoError(t, e.Setup()) - - var title string - if _, err := e.ListTasks(task.ListOptions{ListAllTasks: true}); err != nil { - t.Error(err) - } - for _, title = range []string{ - "foo", - "voo", - "doo", - } { - assert.Contains(t, buff.String(), title) - } -} - -// task -al case 2: !listAll list some tasks (only those with desc) -func TestListCanListDescOnly(t *testing.T) { - t.Parallel() - - const dir = "testdata/list_mixed_desc" - - var buff bytes.Buffer - e := task.NewExecutor( - task.ExecutorWithDir(dir), - task.ExecutorWithStdout(&buff), - task.ExecutorWithStderr(&buff), - ) - require.NoError(t, e.Setup()) - if _, err := e.ListTasks(task.ListOptions{ListOnlyTasksWithDescriptions: true}); err != nil { - t.Error(err) - } - - var title string - assert.Contains(t, buff.String(), "foo") - for _, title = range []string{ - "voo", - "doo", - } { - assert.NotContains(t, buff.String(), title) - } -} - -func TestListDescInterpolation(t *testing.T) { - t.Parallel() - - const dir = "testdata/list_desc_interpolation" - - var buff bytes.Buffer - e := task.NewExecutor( - task.ExecutorWithDir(dir), - task.ExecutorWithStdout(&buff), - task.ExecutorWithStderr(&buff), - ) - require.NoError(t, e.Setup()) - if _, err := e.ListTasks(task.ListOptions{ListOnlyTasksWithDescriptions: true}); err != nil { - t.Error(err) - } - - assert.Contains(t, buff.String(), "foo-var") - assert.Contains(t, buff.String(), "bar-var") -} - func TestStatusVariables(t *testing.T) { t.Parallel() @@ -2986,181 +2472,6 @@ func TestForce(t *testing.T) { } } -func TestForCmds(t *testing.T) { - t.Parallel() - - tests := []struct { - name string - expectedOutput string - wantErr bool - }{ - { - name: "loop-explicit", - expectedOutput: "a\nb\nc\n", - }, - { - name: "loop-matrix", - expectedOutput: "windows/amd64\nwindows/arm64\nlinux/amd64\nlinux/arm64\ndarwin/amd64\ndarwin/arm64\n", - }, - { - name: "loop-matrix-ref", - expectedOutput: "windows/amd64\nwindows/arm64\nlinux/amd64\nlinux/arm64\ndarwin/amd64\ndarwin/arm64\n", - }, - { - name: "loop-matrix-ref-error", - wantErr: true, - }, - { - name: "loop-sources", - expectedOutput: "bar\nfoo\n", - }, - { - name: "loop-sources-glob", - expectedOutput: "bar\nfoo\n", - }, - { - name: "loop-vars", - expectedOutput: "foo\nbar\n", - }, - { - name: "loop-vars-sh", - expectedOutput: "bar\nfoo\n", - }, - { - name: "loop-task", - expectedOutput: "foo\nbar\n", - }, - { - name: "loop-task-as", - expectedOutput: "foo\nbar\n", - }, - { - name: "loop-different-tasks", - expectedOutput: "1\n2\n3\n", - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - t.Parallel() - - buf := &bytes.Buffer{} - e := task.NewExecutor( - task.ExecutorWithDir("testdata/for/cmds"), - task.ExecutorWithStdout(buf), - task.ExecutorWithStderr(buf), - task.ExecutorWithSilent(true), - task.ExecutorWithForce(true), - ) - require.NoError(t, e.Setup()) - err := e.Run(context.Background(), &task.Call{Task: test.name}) - if test.wantErr { - require.Error(t, err) - } else { - require.NoError(t, err) - } - assert.Equal(t, test.expectedOutput, buf.String()) - }) - } -} - -func TestForDeps(t *testing.T) { - t.Parallel() - - tests := []struct { - name string - expectedOutputContains []string - wantErr bool - }{ - { - name: "loop-explicit", - expectedOutputContains: []string{"a\n", "b\n", "c\n"}, - }, - { - name: "loop-matrix", - expectedOutputContains: []string{ - "windows/amd64\n", - "windows/arm64\n", - "linux/amd64\n", - "linux/arm64\n", - "darwin/amd64\n", - "darwin/arm64\n", - }, - }, - { - name: "loop-matrix-ref", - expectedOutputContains: []string{ - "windows/amd64\n", - "windows/arm64\n", - "linux/amd64\n", - "linux/arm64\n", - "darwin/amd64\n", - "darwin/arm64\n", - }, - }, - { - name: "loop-matrix-ref-error", - wantErr: true, - }, - { - name: "loop-sources", - expectedOutputContains: []string{"bar\n", "foo\n"}, - }, - { - name: "loop-sources-glob", - expectedOutputContains: []string{"bar\n", "foo\n"}, - }, - { - name: "loop-vars", - expectedOutputContains: []string{"foo\n", "bar\n"}, - }, - { - name: "loop-vars-sh", - expectedOutputContains: []string{"bar\n", "foo\n"}, - }, - { - name: "loop-task", - expectedOutputContains: []string{"foo\n", "bar\n"}, - }, - { - name: "loop-task-as", - expectedOutputContains: []string{"foo\n", "bar\n"}, - }, - { - name: "loop-different-tasks", - expectedOutputContains: []string{"1\n", "2\n", "3\n"}, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - t.Parallel() - - // We need to use a sync buffer here as deps are run concurrently - buf := &SyncBuffer{} - e := task.NewExecutor( - task.ExecutorWithDir("testdata/for/deps"), - task.ExecutorWithStdout(buf), - task.ExecutorWithStderr(buf), - task.ExecutorWithSilent(true), - task.ExecutorWithForce(true), - // Force output of each dep to be grouped together to prevent interleaving - task.ExecutorWithOutputStyle(ast.Output{Name: "group"}), - ) - require.NoError(t, e.Setup()) - err := e.Run(context.Background(), &task.Call{Task: test.name}) - if test.wantErr { - require.Error(t, err) - } else { - require.NoError(t, err) - } - for _, expectedOutputContains := range test.expectedOutputContains { - assert.Contains(t, buf.buf.String(), expectedOutputContains) - } - }) - } -} - func TestWildcard(t *testing.T) { t.Parallel() @@ -3225,159 +2536,6 @@ func TestWildcard(t *testing.T) { } } -func TestReference(t *testing.T) { - t.Parallel() - - tests := []struct { - name string - call string - expectedOutput string - }{ - { - name: "reference in command", - call: "ref-cmd", - expectedOutput: "1\n", - }, - { - name: "reference in dependency", - call: "ref-dep", - expectedOutput: "1\n", - }, - { - name: "reference using templating resolver", - call: "ref-resolver", - expectedOutput: "1\n", - }, - { - name: "reference using templating resolver and dynamic var", - call: "ref-resolver-sh", - expectedOutput: "Alice has 3 children called Bob, Charlie, and Diane\n", - }, - } - - for _, test := range tests { - t.Run(test.call, func(t *testing.T) { - t.Parallel() - - var buff bytes.Buffer - e := task.NewExecutor( - task.ExecutorWithDir("testdata/var_references"), - task.ExecutorWithStdout(&buff), - task.ExecutorWithStderr(&buff), - task.ExecutorWithSilent(true), - task.ExecutorWithForce(true), - ) - require.NoError(t, e.Setup()) - require.NoError(t, e.Run(context.Background(), &task.Call{Task: test.call})) - assert.Equal(t, test.expectedOutput, buff.String()) - }) - } -} - -func TestVarInheritance(t *testing.T) { - enableExperimentForTest(t, &experiments.EnvPrecedence, 1) - tests := []struct { - name string - want string - call string - }{ - { - name: "shell", - want: "shell\nshell\n", - }, - { - name: "entrypoint-global-dotenv", - want: "entrypoint-global-dotenv\nentrypoint-global-dotenv\n", - }, - { - name: "entrypoint-global-vars", - want: "entrypoint-global-vars\nentrypoint-global-vars\n", - }, - { - // We can't send env vars to a called task, so the env var is not overridden - name: "entrypoint-task-call-vars", - want: "entrypoint-task-call-vars\nentrypoint-global-vars\n", - }, - { - // Dotenv doesn't set variables - name: "entrypoint-task-call-dotenv", - want: "entrypoint-task-call-vars\nentrypoint-task-call-dotenv\n", - }, - { - name: "entrypoint-task-call-task-vars", - want: "entrypoint-task-call-task-vars\nentrypoint-task-call-task-vars\n", - }, - { - // Dotenv doesn't set variables - name: "entrypoint-task-dotenv", - want: "entrypoint-global-vars\nentrypoint-task-dotenv\n", - }, - { - name: "entrypoint-task-vars", - want: "entrypoint-task-vars\nentrypoint-task-vars\n", - }, - // { - // // Dotenv not currently allowed in included taskfiles - // name: "included-global-dotenv", - // want: "included-global-dotenv\nincluded-global-dotenv\n", - // }, - { - name: "included-global-vars", - want: "included-global-vars\nincluded-global-vars\n", - call: "included", - }, - { - // We can't send env vars to a called task, so the env var is not overridden - name: "included-task-call-vars", - want: "included-task-call-vars\nincluded-global-vars\n", - call: "included", - }, - { - // Dotenv doesn't set variables - // Dotenv not currently allowed in included taskfiles (but doesn't error in a task) - name: "included-task-call-dotenv", - want: "included-task-call-vars\nincluded-global-vars\n", - call: "included", - }, - { - name: "included-task-call-task-vars", - want: "included-task-call-task-vars\nincluded-task-call-task-vars\n", - call: "included", - }, - { - // Dotenv doesn't set variables - // Somehow dotenv is working here! - name: "included-task-dotenv", - want: "included-global-vars\nincluded-task-dotenv\n", - call: "included", - }, - { - name: "included-task-vars", - want: "included-task-vars\nincluded-task-vars\n", - call: "included", - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - var buff bytes.Buffer - t.Setenv("VAR", "shell") - t.Setenv("ENV", "shell") - e := task.NewExecutor( - task.ExecutorWithDir(fmt.Sprintf("testdata/var_inheritance/v3/%s", test.name)), - task.ExecutorWithStdout(&buff), - task.ExecutorWithStderr(&buff), - task.ExecutorWithSilent(true), - task.ExecutorWithForce(true), - ) - call := cmp.Or(test.call, "default") - require.NoError(t, e.Setup()) - require.NoError(t, e.Run(context.Background(), &task.Call{Task: call})) - assert.Equal(t, test.want, buff.String()) - }) - } -} - // enableExperimentForTest enables the experiment behind pointer e for the duration of test t and sub-tests, // with the experiment being restored to its previous state when tests complete. // diff --git a/testdata/alias/alias.txt b/testdata/alias/testdata/TestAlias-alias.golden similarity index 100% rename from testdata/alias/alias.txt rename to testdata/alias/testdata/TestAlias-alias.golden diff --git a/testdata/alias/alias-summary.txt b/testdata/alias/testdata/TestAlias-alias_summary.golden similarity index 100% rename from testdata/alias/alias-summary.txt rename to testdata/alias/testdata/TestAlias-alias_summary.golden diff --git a/testdata/alias/testdata/TestAlias-duplicate_alias-err-run.golden b/testdata/alias/testdata/TestAlias-duplicate_alias-err-run.golden new file mode 100644 index 00000000..bcffc9a4 --- /dev/null +++ b/testdata/alias/testdata/TestAlias-duplicate_alias-err-run.golden @@ -0,0 +1 @@ +task: Found multiple tasks (foo, bar) that match "x" \ No newline at end of file diff --git a/testdata/alias/testdata/TestAlias-duplicate_alias.golden b/testdata/alias/testdata/TestAlias-duplicate_alias.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/concurrency/testdata/TestConcurrency.golden b/testdata/concurrency/testdata/TestConcurrency.golden new file mode 100644 index 00000000..066fc1f6 --- /dev/null +++ b/testdata/concurrency/testdata/TestConcurrency.golden @@ -0,0 +1,12 @@ +done 1 +done 2 +done 3 +done 4 +done 5 +done 6 +task: [t1] echo done 1 +task: [t2] echo done 2 +task: [t3] echo done 3 +task: [t4] echo done 4 +task: [t5] echo done 5 +task: [t6] echo done 6 diff --git a/testdata/deps/.gitignore b/testdata/deps/.gitignore deleted file mode 100644 index 2211df63..00000000 --- a/testdata/deps/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.txt diff --git a/testdata/deps/Taskfile.yml b/testdata/deps/Taskfile.yml index bc2aa71c..e120120e 100644 --- a/testdata/deps/Taskfile.yml +++ b/testdata/deps/Taskfile.yml @@ -7,50 +7,50 @@ tasks: d1: deps: [d11, d12, d13] cmds: - - echo 'Text' > d1.txt + - echo 'd1' d2: deps: [d21, d22, d23] cmds: - - echo 'Text' > d2.txt + - echo 'd2' d3: deps: [d31, d32, d33] cmds: - - echo 'Text' > d3.txt + - echo 'd3' d11: cmds: - - echo 'Text' > d11.txt + - echo 'd11' d12: cmds: - - echo 'Text' > d12.txt + - echo 'd12' d13: cmds: - - echo 'Text' > d13.txt + - echo 'd13' d21: cmds: - - echo 'Text' > d21.txt + - echo 'd21' d22: cmds: - - echo 'Text' > d22.txt + - echo 'd22' d23: cmds: - - echo 'Text' > d23.txt + - echo 'd23' d31: cmds: - - echo 'Text' > d31.txt + - echo 'd31' d32: cmds: - - echo 'Text' > d32.txt + - echo 'd32' d33: cmds: - - echo 'Text' > d33.txt + - echo 'd33' diff --git a/testdata/deps/d1.txt b/testdata/deps/d1.txt new file mode 100644 index 00000000..3de705a4 --- /dev/null +++ b/testdata/deps/d1.txt @@ -0,0 +1 @@ +Text diff --git a/testdata/deps/d11.txt b/testdata/deps/d11.txt new file mode 100644 index 00000000..3de705a4 --- /dev/null +++ b/testdata/deps/d11.txt @@ -0,0 +1 @@ +Text diff --git a/testdata/deps/d12.txt b/testdata/deps/d12.txt new file mode 100644 index 00000000..3de705a4 --- /dev/null +++ b/testdata/deps/d12.txt @@ -0,0 +1 @@ +Text diff --git a/testdata/deps/d13.txt b/testdata/deps/d13.txt new file mode 100644 index 00000000..3de705a4 --- /dev/null +++ b/testdata/deps/d13.txt @@ -0,0 +1 @@ +Text diff --git a/testdata/deps/d2.txt b/testdata/deps/d2.txt new file mode 100644 index 00000000..3de705a4 --- /dev/null +++ b/testdata/deps/d2.txt @@ -0,0 +1 @@ +Text diff --git a/testdata/deps/d21.txt b/testdata/deps/d21.txt new file mode 100644 index 00000000..3de705a4 --- /dev/null +++ b/testdata/deps/d21.txt @@ -0,0 +1 @@ +Text diff --git a/testdata/deps/d22.txt b/testdata/deps/d22.txt new file mode 100644 index 00000000..3de705a4 --- /dev/null +++ b/testdata/deps/d22.txt @@ -0,0 +1 @@ +Text diff --git a/testdata/deps/d23.txt b/testdata/deps/d23.txt new file mode 100644 index 00000000..3de705a4 --- /dev/null +++ b/testdata/deps/d23.txt @@ -0,0 +1 @@ +Text diff --git a/testdata/deps/d3.txt b/testdata/deps/d3.txt new file mode 100644 index 00000000..3de705a4 --- /dev/null +++ b/testdata/deps/d3.txt @@ -0,0 +1 @@ +Text diff --git a/testdata/deps/d31.txt b/testdata/deps/d31.txt new file mode 100644 index 00000000..3de705a4 --- /dev/null +++ b/testdata/deps/d31.txt @@ -0,0 +1 @@ +Text diff --git a/testdata/deps/d32.txt b/testdata/deps/d32.txt new file mode 100644 index 00000000..3de705a4 --- /dev/null +++ b/testdata/deps/d32.txt @@ -0,0 +1 @@ +Text diff --git a/testdata/deps/d33.txt b/testdata/deps/d33.txt new file mode 100644 index 00000000..3de705a4 --- /dev/null +++ b/testdata/deps/d33.txt @@ -0,0 +1 @@ +Text diff --git a/testdata/deps/testdata/TestDeps.golden b/testdata/deps/testdata/TestDeps.golden new file mode 100644 index 00000000..0f0c8cd0 --- /dev/null +++ b/testdata/deps/testdata/TestDeps.golden @@ -0,0 +1,12 @@ +d1 +d11 +d12 +d13 +d2 +d21 +d22 +d23 +d3 +d31 +d32 +d33 diff --git a/testdata/empty_task/testdata/TestEmptyTask.golden b/testdata/empty_task/testdata/TestEmptyTask.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/empty_taskfile/testdata/TestEmptyTaskfile-err-setup.golden b/testdata/empty_taskfile/testdata/TestEmptyTaskfile-err-setup.golden new file mode 100644 index 00000000..270d5182 --- /dev/null +++ b/testdata/empty_taskfile/testdata/TestEmptyTaskfile-err-setup.golden @@ -0,0 +1 @@ +task: Missing schema version in Taskfile "/testdata/empty_taskfile/Taskfile.yml" \ No newline at end of file diff --git a/testdata/empty_taskfile/testdata/TestEmptyTaskfile.golden b/testdata/empty_taskfile/testdata/TestEmptyTaskfile.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/env/.gitignore b/testdata/env/.gitignore deleted file mode 100644 index 2211df63..00000000 --- a/testdata/env/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.txt diff --git a/testdata/env/Taskfile.yml b/testdata/env/Taskfile.yml index b81a1d1f..70d48190 100644 --- a/testdata/env/Taskfile.yml +++ b/testdata/env/Taskfile.yml @@ -28,13 +28,13 @@ tasks: CGO_ENABLED: sh: echo '0' cmds: - - echo "GOOS='$GOOS' GOARCH='$GOARCH' CGO_ENABLED='$CGO_ENABLED'" > local.txt + - echo "GOOS='$GOOS' GOARCH='$GOARCH' CGO_ENABLED='$CGO_ENABLED'" global: env: BAR: overridden cmds: - - echo "FOO='$FOO' BAR='$BAR' BAZ='$BAZ'" > global.txt + - echo "FOO='$FOO' BAR='$BAR' BAZ='$BAZ'" multiple_type: env: @@ -42,15 +42,15 @@ tasks: BAR: true BAZ: 1.1 cmds: - - echo "FOO='$FOO' BAR='$BAR' BAZ='$BAZ'" > multiple_type.txt + - echo "FOO='$FOO' BAR='$BAR' BAZ='$BAZ'" not-overridden: cmds: - - echo "QUX='$QUX'" > not-overridden.txt + - echo "QUX='$QUX'" overridden: cmds: - - echo "QUX='$QUX'" > overridden.txt + - echo "QUX='$QUX'" dynamic: silent: true @@ -58,4 +58,4 @@ tasks: DYNAMIC_FOO: sh: echo $FOO cmds: - - echo "{{ .DYNAMIC_FOO }}" > dynamic.txt + - echo "{{ .DYNAMIC_FOO }}" diff --git a/testdata/env/dynamic.txt b/testdata/env/dynamic.txt new file mode 100644 index 00000000..257cc564 --- /dev/null +++ b/testdata/env/dynamic.txt @@ -0,0 +1 @@ +foo diff --git a/testdata/env/global.txt b/testdata/env/global.txt new file mode 100644 index 00000000..bdcb9e38 --- /dev/null +++ b/testdata/env/global.txt @@ -0,0 +1 @@ +FOO='foo' BAR='overridden' BAZ='baz' diff --git a/testdata/env/local.txt b/testdata/env/local.txt new file mode 100644 index 00000000..9f1f355b --- /dev/null +++ b/testdata/env/local.txt @@ -0,0 +1 @@ +GOOS='linux' GOARCH='amd64' CGO_ENABLED='0' diff --git a/testdata/env/multiple_type.txt b/testdata/env/multiple_type.txt new file mode 100644 index 00000000..7f23603a --- /dev/null +++ b/testdata/env/multiple_type.txt @@ -0,0 +1 @@ +FOO='1' BAR='true' BAZ='1.1' diff --git a/testdata/env/not-overridden.txt b/testdata/env/not-overridden.txt new file mode 100644 index 00000000..7be48445 --- /dev/null +++ b/testdata/env/not-overridden.txt @@ -0,0 +1 @@ +QUX='from_os' diff --git a/testdata/env/overridden.txt b/testdata/env/overridden.txt new file mode 100644 index 00000000..8d4db05a --- /dev/null +++ b/testdata/env/overridden.txt @@ -0,0 +1 @@ +QUX='from_taskfile' diff --git a/testdata/env/testdata/TestEnv-env_precedence_disabled.golden b/testdata/env/testdata/TestEnv-env_precedence_disabled.golden new file mode 100644 index 00000000..a56fff4d --- /dev/null +++ b/testdata/env/testdata/TestEnv-env_precedence_disabled.golden @@ -0,0 +1,5 @@ +GOOS='linux' GOARCH='amd64' CGO_ENABLED='0' +FOO='foo' BAR='overridden' BAZ='baz' +QUX='from_os' +FOO='1' BAR='true' BAZ='1.1' +foo diff --git a/testdata/env/testdata/TestEnv-env_precedence_enabled.golden b/testdata/env/testdata/TestEnv-env_precedence_enabled.golden new file mode 100644 index 00000000..6ac1cf97 --- /dev/null +++ b/testdata/env/testdata/TestEnv-env_precedence_enabled.golden @@ -0,0 +1,5 @@ +GOOS='linux' GOARCH='amd64' CGO_ENABLED='0' +FOO='foo' BAR='overridden' BAZ='baz' +QUX='from_taskfile' +FOO='1' BAR='true' BAZ='1.1' +foo diff --git a/testdata/for/cmds/testdata/TestForCmds-loop-different-tasks.golden b/testdata/for/cmds/testdata/TestForCmds-loop-different-tasks.golden new file mode 100644 index 00000000..01e79c32 --- /dev/null +++ b/testdata/for/cmds/testdata/TestForCmds-loop-different-tasks.golden @@ -0,0 +1,3 @@ +1 +2 +3 diff --git a/testdata/for/cmds/testdata/TestForCmds-loop-explicit.golden b/testdata/for/cmds/testdata/TestForCmds-loop-explicit.golden new file mode 100644 index 00000000..de980441 --- /dev/null +++ b/testdata/for/cmds/testdata/TestForCmds-loop-explicit.golden @@ -0,0 +1,3 @@ +a +b +c diff --git a/testdata/for/cmds/testdata/TestForCmds-loop-matrix-ref-error-err-run.golden b/testdata/for/cmds/testdata/TestForCmds-loop-matrix-ref-error-err-run.golden new file mode 100644 index 00000000..c04ae8c5 --- /dev/null +++ b/testdata/for/cmds/testdata/TestForCmds-loop-matrix-ref-error-err-run.golden @@ -0,0 +1,2 @@ +task: Failed to parse /testdata/for/cmds/Taskfile.yml: +matrix reference ".NOT_A_LIST" must resolve to a list \ No newline at end of file diff --git a/testdata/for/cmds/testdata/TestForCmds-loop-matrix-ref-error.golden b/testdata/for/cmds/testdata/TestForCmds-loop-matrix-ref-error.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/for/cmds/testdata/TestForCmds-loop-matrix-ref.golden b/testdata/for/cmds/testdata/TestForCmds-loop-matrix-ref.golden new file mode 100644 index 00000000..fcfed9c8 --- /dev/null +++ b/testdata/for/cmds/testdata/TestForCmds-loop-matrix-ref.golden @@ -0,0 +1,6 @@ +windows/amd64 +windows/arm64 +linux/amd64 +linux/arm64 +darwin/amd64 +darwin/arm64 diff --git a/testdata/for/cmds/testdata/TestForCmds-loop-matrix.golden b/testdata/for/cmds/testdata/TestForCmds-loop-matrix.golden new file mode 100644 index 00000000..fcfed9c8 --- /dev/null +++ b/testdata/for/cmds/testdata/TestForCmds-loop-matrix.golden @@ -0,0 +1,6 @@ +windows/amd64 +windows/arm64 +linux/amd64 +linux/arm64 +darwin/amd64 +darwin/arm64 diff --git a/testdata/for/cmds/testdata/TestForCmds-loop-sources-glob.golden b/testdata/for/cmds/testdata/TestForCmds-loop-sources-glob.golden new file mode 100644 index 00000000..12897652 --- /dev/null +++ b/testdata/for/cmds/testdata/TestForCmds-loop-sources-glob.golden @@ -0,0 +1,2 @@ +bar +foo diff --git a/testdata/for/cmds/testdata/TestForCmds-loop-sources.golden b/testdata/for/cmds/testdata/TestForCmds-loop-sources.golden new file mode 100644 index 00000000..12897652 --- /dev/null +++ b/testdata/for/cmds/testdata/TestForCmds-loop-sources.golden @@ -0,0 +1,2 @@ +bar +foo diff --git a/testdata/for/cmds/testdata/TestForCmds-loop-task-as.golden b/testdata/for/cmds/testdata/TestForCmds-loop-task-as.golden new file mode 100644 index 00000000..3bd1f0e2 --- /dev/null +++ b/testdata/for/cmds/testdata/TestForCmds-loop-task-as.golden @@ -0,0 +1,2 @@ +foo +bar diff --git a/testdata/for/cmds/testdata/TestForCmds-loop-task.golden b/testdata/for/cmds/testdata/TestForCmds-loop-task.golden new file mode 100644 index 00000000..3bd1f0e2 --- /dev/null +++ b/testdata/for/cmds/testdata/TestForCmds-loop-task.golden @@ -0,0 +1,2 @@ +foo +bar diff --git a/testdata/for/cmds/testdata/TestForCmds-loop-vars-sh.golden b/testdata/for/cmds/testdata/TestForCmds-loop-vars-sh.golden new file mode 100644 index 00000000..12897652 --- /dev/null +++ b/testdata/for/cmds/testdata/TestForCmds-loop-vars-sh.golden @@ -0,0 +1,2 @@ +bar +foo diff --git a/testdata/for/cmds/testdata/TestForCmds-loop-vars.golden b/testdata/for/cmds/testdata/TestForCmds-loop-vars.golden new file mode 100644 index 00000000..3bd1f0e2 --- /dev/null +++ b/testdata/for/cmds/testdata/TestForCmds-loop-vars.golden @@ -0,0 +1,2 @@ +foo +bar diff --git a/testdata/for/deps/testdata/TestForDeps-loop-different-tasks.golden b/testdata/for/deps/testdata/TestForDeps-loop-different-tasks.golden new file mode 100644 index 00000000..01e79c32 --- /dev/null +++ b/testdata/for/deps/testdata/TestForDeps-loop-different-tasks.golden @@ -0,0 +1,3 @@ +1 +2 +3 diff --git a/testdata/for/deps/testdata/TestForDeps-loop-explicit.golden b/testdata/for/deps/testdata/TestForDeps-loop-explicit.golden new file mode 100644 index 00000000..de980441 --- /dev/null +++ b/testdata/for/deps/testdata/TestForDeps-loop-explicit.golden @@ -0,0 +1,3 @@ +a +b +c diff --git a/testdata/for/deps/testdata/TestForDeps-loop-matrix-ref-error-err-run.golden b/testdata/for/deps/testdata/TestForDeps-loop-matrix-ref-error-err-run.golden new file mode 100644 index 00000000..e43c1af3 --- /dev/null +++ b/testdata/for/deps/testdata/TestForDeps-loop-matrix-ref-error-err-run.golden @@ -0,0 +1,2 @@ +matrix reference ".NOT_A_LIST" must resolve to a list +task: Failed to parse /testdata/for/deps/Taskfile.yml: diff --git a/testdata/for/deps/testdata/TestForDeps-loop-matrix-ref-error.golden b/testdata/for/deps/testdata/TestForDeps-loop-matrix-ref-error.golden new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/testdata/for/deps/testdata/TestForDeps-loop-matrix-ref-error.golden @@ -0,0 +1 @@ + diff --git a/testdata/for/deps/testdata/TestForDeps-loop-matrix-ref.golden b/testdata/for/deps/testdata/TestForDeps-loop-matrix-ref.golden new file mode 100644 index 00000000..0eead1f9 --- /dev/null +++ b/testdata/for/deps/testdata/TestForDeps-loop-matrix-ref.golden @@ -0,0 +1,6 @@ +darwin/amd64 +darwin/arm64 +linux/amd64 +linux/arm64 +windows/amd64 +windows/arm64 diff --git a/testdata/for/deps/testdata/TestForDeps-loop-matrix.golden b/testdata/for/deps/testdata/TestForDeps-loop-matrix.golden new file mode 100644 index 00000000..0eead1f9 --- /dev/null +++ b/testdata/for/deps/testdata/TestForDeps-loop-matrix.golden @@ -0,0 +1,6 @@ +darwin/amd64 +darwin/arm64 +linux/amd64 +linux/arm64 +windows/amd64 +windows/arm64 diff --git a/testdata/for/deps/testdata/TestForDeps-loop-sources-glob.golden b/testdata/for/deps/testdata/TestForDeps-loop-sources-glob.golden new file mode 100644 index 00000000..12897652 --- /dev/null +++ b/testdata/for/deps/testdata/TestForDeps-loop-sources-glob.golden @@ -0,0 +1,2 @@ +bar +foo diff --git a/testdata/for/deps/testdata/TestForDeps-loop-sources.golden b/testdata/for/deps/testdata/TestForDeps-loop-sources.golden new file mode 100644 index 00000000..12897652 --- /dev/null +++ b/testdata/for/deps/testdata/TestForDeps-loop-sources.golden @@ -0,0 +1,2 @@ +bar +foo diff --git a/testdata/for/deps/testdata/TestForDeps-loop-task-as.golden b/testdata/for/deps/testdata/TestForDeps-loop-task-as.golden new file mode 100644 index 00000000..12897652 --- /dev/null +++ b/testdata/for/deps/testdata/TestForDeps-loop-task-as.golden @@ -0,0 +1,2 @@ +bar +foo diff --git a/testdata/for/deps/testdata/TestForDeps-loop-task.golden b/testdata/for/deps/testdata/TestForDeps-loop-task.golden new file mode 100644 index 00000000..12897652 --- /dev/null +++ b/testdata/for/deps/testdata/TestForDeps-loop-task.golden @@ -0,0 +1,2 @@ +bar +foo diff --git a/testdata/for/deps/testdata/TestForDeps-loop-vars-sh.golden b/testdata/for/deps/testdata/TestForDeps-loop-vars-sh.golden new file mode 100644 index 00000000..12897652 --- /dev/null +++ b/testdata/for/deps/testdata/TestForDeps-loop-vars-sh.golden @@ -0,0 +1,2 @@ +bar +foo diff --git a/testdata/for/deps/testdata/TestForDeps-loop-vars.golden b/testdata/for/deps/testdata/TestForDeps-loop-vars.golden new file mode 100644 index 00000000..12897652 --- /dev/null +++ b/testdata/for/deps/testdata/TestForDeps-loop-vars.golden @@ -0,0 +1,2 @@ +bar +foo diff --git a/testdata/label_list/testdata/TestNoLabelInList.golden b/testdata/label_list/testdata/TestNoLabelInList.golden new file mode 100644 index 00000000..ec08a1e9 --- /dev/null +++ b/testdata/label_list/testdata/TestNoLabelInList.golden @@ -0,0 +1,2 @@ +task: Available tasks for this project: +* foo: task description diff --git a/testdata/label_status/testdata/TestLabel-status-err-status.golden b/testdata/label_status/testdata/TestLabel-status-err-status.golden new file mode 100644 index 00000000..da931c1e --- /dev/null +++ b/testdata/label_status/testdata/TestLabel-status-err-status.golden @@ -0,0 +1 @@ +task: Task "foobar" is not up-to-date \ No newline at end of file diff --git a/testdata/label_status/testdata/TestLabel-status.golden b/testdata/label_status/testdata/TestLabel-status.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/label_summary/testdata/TestLabel-label_in_summary.golden b/testdata/label_summary/testdata/TestLabel-label_in_summary.golden new file mode 100644 index 00000000..c7c7928b --- /dev/null +++ b/testdata/label_summary/testdata/TestLabel-label_in_summary.golden @@ -0,0 +1 @@ +task: Task "foobar" is up to date diff --git a/testdata/label_summary/testdata/TestLabel-summary.golden b/testdata/label_summary/testdata/TestLabel-summary.golden new file mode 100644 index 00000000..fb0a71e9 --- /dev/null +++ b/testdata/label_summary/testdata/TestLabel-summary.golden @@ -0,0 +1,3 @@ +task: foobar + +description diff --git a/testdata/label_uptodate/testdata/TestLabel-up_to_date.golden b/testdata/label_uptodate/testdata/TestLabel-up_to_date.golden new file mode 100644 index 00000000..c7c7928b --- /dev/null +++ b/testdata/label_uptodate/testdata/TestLabel-up_to_date.golden @@ -0,0 +1 @@ +task: Task "foobar" is up to date diff --git a/testdata/label_var/testdata/TestLabel-var.golden b/testdata/label_var/testdata/TestLabel-var.golden new file mode 100644 index 00000000..989a22da --- /dev/null +++ b/testdata/label_var/testdata/TestLabel-var.golden @@ -0,0 +1 @@ +task: Task "foobaz" is up to date diff --git a/testdata/list_desc_interpolation/testdata/TestListDescInterpolation.golden b/testdata/list_desc_interpolation/testdata/TestListDescInterpolation.golden new file mode 100644 index 00000000..040f7675 --- /dev/null +++ b/testdata/list_desc_interpolation/testdata/TestListDescInterpolation.golden @@ -0,0 +1,3 @@ +task: Available tasks for this project: +* bar: task has desc with bar-var +* foo: task has desc with foo-var diff --git a/testdata/list_mixed_desc/testdata/TestListAllShowsNoDesc.golden b/testdata/list_mixed_desc/testdata/TestListAllShowsNoDesc.golden new file mode 100644 index 00000000..bd1d2f09 --- /dev/null +++ b/testdata/list_mixed_desc/testdata/TestListAllShowsNoDesc.golden @@ -0,0 +1,4 @@ +task: Available tasks for this project: +* doo: +* foo: foo has desc and label +* voo: diff --git a/testdata/list_mixed_desc/testdata/TestListCanListDescOnly.golden b/testdata/list_mixed_desc/testdata/TestListCanListDescOnly.golden new file mode 100644 index 00000000..3915bd8e --- /dev/null +++ b/testdata/list_mixed_desc/testdata/TestListCanListDescOnly.golden @@ -0,0 +1,2 @@ +task: Available tasks for this project: +* foo: foo has desc and label diff --git a/testdata/params/.gitignore b/testdata/params/.gitignore deleted file mode 100644 index 2211df63..00000000 --- a/testdata/params/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.txt diff --git a/testdata/params/Taskfile.yml b/testdata/params/Taskfile.yml index 06cbe488..f8f14382 100644 --- a/testdata/params/Taskfile.yml +++ b/testdata/params/Taskfile.yml @@ -12,33 +12,33 @@ tasks: GERMAN: "Welt!" deps: - task: write-file - vars: {CONTENT: Dependence1, FILE: dep1.txt} + vars: {CONTENT: Dependence1} - task: write-file - vars: {CONTENT: Dependence2, FILE: dep2.txt} + vars: {CONTENT: Dependence2} - task: write-file - vars: {CONTENT: "{{.SPANISH|replace \"mundo\" \"dependencia\"}}", FILE: spanish-dep.txt} + vars: {CONTENT: "{{.SPANISH|replace \"mundo\" \"dependencia\"}}"} cmds: - task: write-file - vars: {CONTENT: Hello, FILE: hello.txt} + vars: {CONTENT: Hello} - task: write-file - vars: {CONTENT: "$echo 'World'", FILE: world.txt} + vars: {CONTENT: "$echo 'World'"} - task: write-file - vars: {CONTENT: "!", FILE: exclamation.txt} + vars: {CONTENT: "!"} - task: write-file - vars: {CONTENT: "{{.SPANISH}}", FILE: spanish.txt} + vars: {CONTENT: "{{.SPANISH}}"} - task: write-file - vars: {CONTENT: "{{.PORTUGUESE}}", FILE: portuguese.txt} + vars: {CONTENT: "{{.PORTUGUESE}}"} - task: write-file - vars: {CONTENT: "{{.GERMAN}}", FILE: german.txt} + vars: {CONTENT: "{{.GERMAN}}"} - task: non-default write-file: cmds: - - echo {{.CONTENT}} > {{.FILE}} + - echo {{.CONTENT}} non-default: vars: PORTUGUESE: "{{.PORTUGUESE_HELLO_WORLD}}" cmds: - task: write-file - vars: {CONTENT: "{{.PORTUGUESE}}", FILE: portuguese2.txt} + vars: {CONTENT: "{{.PORTUGUESE}}"} diff --git a/testdata/params/dep1.txt b/testdata/params/dep1.txt new file mode 100644 index 00000000..bd7e6aba --- /dev/null +++ b/testdata/params/dep1.txt @@ -0,0 +1 @@ +Dependence1 diff --git a/testdata/params/dep2.txt b/testdata/params/dep2.txt new file mode 100644 index 00000000..1e010f66 --- /dev/null +++ b/testdata/params/dep2.txt @@ -0,0 +1 @@ +Dependence2 diff --git a/testdata/params/exclamation.txt b/testdata/params/exclamation.txt new file mode 100644 index 00000000..cdf4cb4f --- /dev/null +++ b/testdata/params/exclamation.txt @@ -0,0 +1 @@ +! diff --git a/testdata/params/german.txt b/testdata/params/german.txt new file mode 100644 index 00000000..01d82dcd --- /dev/null +++ b/testdata/params/german.txt @@ -0,0 +1 @@ +Welt! diff --git a/testdata/params/hello.txt b/testdata/params/hello.txt new file mode 100644 index 00000000..e965047a --- /dev/null +++ b/testdata/params/hello.txt @@ -0,0 +1 @@ +Hello diff --git a/testdata/params/portuguese.txt b/testdata/params/portuguese.txt new file mode 100644 index 00000000..71a93ccb --- /dev/null +++ b/testdata/params/portuguese.txt @@ -0,0 +1 @@ +Olá, mundo! diff --git a/testdata/params/portuguese2.txt b/testdata/params/portuguese2.txt new file mode 100644 index 00000000..71a93ccb --- /dev/null +++ b/testdata/params/portuguese2.txt @@ -0,0 +1 @@ +Olá, mundo! diff --git a/testdata/params/spanish-dep.txt b/testdata/params/spanish-dep.txt new file mode 100644 index 00000000..2b52a743 --- /dev/null +++ b/testdata/params/spanish-dep.txt @@ -0,0 +1 @@ +¡Holla dependencia! diff --git a/testdata/params/spanish.txt b/testdata/params/spanish.txt new file mode 100644 index 00000000..75ab6500 --- /dev/null +++ b/testdata/params/spanish.txt @@ -0,0 +1 @@ +¡Holla mundo! diff --git a/testdata/params/testdata/TestParams.golden b/testdata/params/testdata/TestParams.golden new file mode 100644 index 00000000..918811bf --- /dev/null +++ b/testdata/params/testdata/TestParams.golden @@ -0,0 +1,10 @@ +! +Dependence1 +Dependence2 +Hello +Olá, mundo! +Olá, mundo! +Welt! +World +¡Holla dependencia! +¡Holla mundo! diff --git a/testdata/params/world.txt b/testdata/params/world.txt new file mode 100644 index 00000000..216e97ce --- /dev/null +++ b/testdata/params/world.txt @@ -0,0 +1 @@ +World diff --git a/testdata/precondition/testdata/TestPrecondition-a_precondition_has_been_met.golden b/testdata/precondition/testdata/TestPrecondition-a_precondition_has_been_met.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/precondition/testdata/TestPrecondition-a_precondition_was_not_met-err-run.golden b/testdata/precondition/testdata/TestPrecondition-a_precondition_was_not_met-err-run.golden new file mode 100644 index 00000000..6952491e --- /dev/null +++ b/testdata/precondition/testdata/TestPrecondition-a_precondition_was_not_met-err-run.golden @@ -0,0 +1 @@ +task: precondition not met \ No newline at end of file diff --git a/testdata/precondition/testdata/TestPrecondition-a_precondition_was_not_met.golden b/testdata/precondition/testdata/TestPrecondition-a_precondition_was_not_met.golden new file mode 100644 index 00000000..8f4b5a4b --- /dev/null +++ b/testdata/precondition/testdata/TestPrecondition-a_precondition_was_not_met.golden @@ -0,0 +1 @@ +task: 1 != 0 obviously! diff --git a/testdata/precondition/testdata/TestPrecondition-precondition_in_cmd_fails_the_task-err-run.golden b/testdata/precondition/testdata/TestPrecondition-precondition_in_cmd_fails_the_task-err-run.golden new file mode 100644 index 00000000..7e115563 --- /dev/null +++ b/testdata/precondition/testdata/TestPrecondition-precondition_in_cmd_fails_the_task-err-run.golden @@ -0,0 +1 @@ +task: Failed to run task "executes_failing_task_as_cmd": task: precondition not met \ No newline at end of file diff --git a/testdata/precondition/testdata/TestPrecondition-precondition_in_cmd_fails_the_task.golden b/testdata/precondition/testdata/TestPrecondition-precondition_in_cmd_fails_the_task.golden new file mode 100644 index 00000000..8f4b5a4b --- /dev/null +++ b/testdata/precondition/testdata/TestPrecondition-precondition_in_cmd_fails_the_task.golden @@ -0,0 +1 @@ +task: 1 != 0 obviously! diff --git a/testdata/precondition/testdata/TestPrecondition-precondition_in_dependency_fails_the_task-err-run.golden b/testdata/precondition/testdata/TestPrecondition-precondition_in_dependency_fails_the_task-err-run.golden new file mode 100644 index 00000000..6952491e --- /dev/null +++ b/testdata/precondition/testdata/TestPrecondition-precondition_in_dependency_fails_the_task-err-run.golden @@ -0,0 +1 @@ +task: precondition not met \ No newline at end of file diff --git a/testdata/precondition/testdata/TestPrecondition-precondition_in_dependency_fails_the_task.golden b/testdata/precondition/testdata/TestPrecondition-precondition_in_dependency_fails_the_task.golden new file mode 100644 index 00000000..8f4b5a4b --- /dev/null +++ b/testdata/precondition/testdata/TestPrecondition-precondition_in_dependency_fails_the_task.golden @@ -0,0 +1 @@ +task: 1 != 0 obviously! diff --git a/testdata/prompt/testdata/TestPromptAssumeYes---yes_flag_should_skip_prompt.golden b/testdata/prompt/testdata/TestPromptAssumeYes---yes_flag_should_skip_prompt.golden new file mode 100644 index 00000000..dc6b63e7 --- /dev/null +++ b/testdata/prompt/testdata/TestPromptAssumeYes---yes_flag_should_skip_prompt.golden @@ -0,0 +1,3 @@ +Do you want to continue? [assuming yes] +task: [foo] echo 'foo' +foo diff --git a/testdata/prompt/testdata/TestPromptAssumeYes-task_should_raise_errors.TaskCancelledError-err-run.golden b/testdata/prompt/testdata/TestPromptAssumeYes-task_should_raise_errors.TaskCancelledError-err-run.golden new file mode 100644 index 00000000..8e264302 --- /dev/null +++ b/testdata/prompt/testdata/TestPromptAssumeYes-task_should_raise_errors.TaskCancelledError-err-run.golden @@ -0,0 +1 @@ +task: Task "foo" cancelled by user \ No newline at end of file diff --git a/testdata/prompt/testdata/TestPromptAssumeYes-task_should_raise_errors.TaskCancelledError.golden b/testdata/prompt/testdata/TestPromptAssumeYes-task_should_raise_errors.TaskCancelledError.golden new file mode 100644 index 00000000..3db23b98 --- /dev/null +++ b/testdata/prompt/testdata/TestPromptAssumeYes-task_should_raise_errors.TaskCancelledError.golden @@ -0,0 +1 @@ +Do you want to continue? [y/N]: \ No newline at end of file diff --git a/testdata/prompt/testdata/TestPromptInSummary-test_Enter_stops_task-test_Enter_stops_task-err-run.golden b/testdata/prompt/testdata/TestPromptInSummary-test_Enter_stops_task-test_Enter_stops_task-err-run.golden new file mode 100644 index 00000000..8e264302 --- /dev/null +++ b/testdata/prompt/testdata/TestPromptInSummary-test_Enter_stops_task-test_Enter_stops_task-err-run.golden @@ -0,0 +1 @@ +task: Task "foo" cancelled by user \ No newline at end of file diff --git a/testdata/prompt/testdata/TestPromptInSummary-test_Enter_stops_task-test_Enter_stops_task.golden b/testdata/prompt/testdata/TestPromptInSummary-test_Enter_stops_task-test_Enter_stops_task.golden new file mode 100644 index 00000000..3db23b98 --- /dev/null +++ b/testdata/prompt/testdata/TestPromptInSummary-test_Enter_stops_task-test_Enter_stops_task.golden @@ -0,0 +1 @@ +Do you want to continue? [y/N]: \ No newline at end of file diff --git a/testdata/prompt/testdata/TestPromptInSummary-test_junk_value_stops_task-test_junk_value_stops_task-err-run.golden b/testdata/prompt/testdata/TestPromptInSummary-test_junk_value_stops_task-test_junk_value_stops_task-err-run.golden new file mode 100644 index 00000000..8e264302 --- /dev/null +++ b/testdata/prompt/testdata/TestPromptInSummary-test_junk_value_stops_task-test_junk_value_stops_task-err-run.golden @@ -0,0 +1 @@ +task: Task "foo" cancelled by user \ No newline at end of file diff --git a/testdata/prompt/testdata/TestPromptInSummary-test_junk_value_stops_task-test_junk_value_stops_task.golden b/testdata/prompt/testdata/TestPromptInSummary-test_junk_value_stops_task-test_junk_value_stops_task.golden new file mode 100644 index 00000000..3db23b98 --- /dev/null +++ b/testdata/prompt/testdata/TestPromptInSummary-test_junk_value_stops_task-test_junk_value_stops_task.golden @@ -0,0 +1 @@ +Do you want to continue? [y/N]: \ No newline at end of file diff --git a/testdata/prompt/testdata/TestPromptInSummary-test_long_approval-test_long_approval.golden b/testdata/prompt/testdata/TestPromptInSummary-test_long_approval-test_long_approval.golden new file mode 100644 index 00000000..deb3b3d9 --- /dev/null +++ b/testdata/prompt/testdata/TestPromptInSummary-test_long_approval-test_long_approval.golden @@ -0,0 +1,2 @@ +Do you want to continue? [y/N]: task: [foo] echo 'foo' +foo diff --git a/testdata/prompt/testdata/TestPromptInSummary-test_short_approval-test_short_approval.golden b/testdata/prompt/testdata/TestPromptInSummary-test_short_approval-test_short_approval.golden new file mode 100644 index 00000000..deb3b3d9 --- /dev/null +++ b/testdata/prompt/testdata/TestPromptInSummary-test_short_approval-test_short_approval.golden @@ -0,0 +1,2 @@ +Do you want to continue? [y/N]: task: [foo] echo 'foo' +foo diff --git a/testdata/prompt/testdata/TestPromptInSummary-test_stops_task-test_stops_task-err-run.golden b/testdata/prompt/testdata/TestPromptInSummary-test_stops_task-test_stops_task-err-run.golden new file mode 100644 index 00000000..8e264302 --- /dev/null +++ b/testdata/prompt/testdata/TestPromptInSummary-test_stops_task-test_stops_task-err-run.golden @@ -0,0 +1 @@ +task: Task "foo" cancelled by user \ No newline at end of file diff --git a/testdata/prompt/testdata/TestPromptInSummary-test_stops_task-test_stops_task.golden b/testdata/prompt/testdata/TestPromptInSummary-test_stops_task-test_stops_task.golden new file mode 100644 index 00000000..3db23b98 --- /dev/null +++ b/testdata/prompt/testdata/TestPromptInSummary-test_stops_task-test_stops_task.golden @@ -0,0 +1 @@ +Do you want to continue? [y/N]: \ No newline at end of file diff --git a/testdata/prompt/testdata/TestPromptInSummary-test_uppercase_approval-test_uppercase_approval.golden b/testdata/prompt/testdata/TestPromptInSummary-test_uppercase_approval-test_uppercase_approval.golden new file mode 100644 index 00000000..deb3b3d9 --- /dev/null +++ b/testdata/prompt/testdata/TestPromptInSummary-test_uppercase_approval-test_uppercase_approval.golden @@ -0,0 +1,2 @@ +Do you want to continue? [y/N]: task: [foo] echo 'foo' +foo diff --git a/testdata/prompt/testdata/TestPromptWithIndirectTask.golden b/testdata/prompt/testdata/TestPromptWithIndirectTask.golden new file mode 100644 index 00000000..c7819cf1 --- /dev/null +++ b/testdata/prompt/testdata/TestPromptWithIndirectTask.golden @@ -0,0 +1,2 @@ +Do you want to continue? [y/N]: task: [show-prompt] echo 'show-prompt' +show-prompt diff --git a/testdata/requires/Taskfile.yml b/testdata/requires/Taskfile.yml index 75b977a0..0c5f954b 100644 --- a/testdata/requires/Taskfile.yml +++ b/testdata/requires/Taskfile.yml @@ -8,7 +8,7 @@ tasks: requires: vars: - FOO - cmd: echo "{{.foo}}" + cmd: echo "{{.FOO}}" var-defined-in-task: vars: @@ -18,18 +18,15 @@ tasks: - FOO cmd: echo "{{.FOO}}" - validation-var-dynamic: vars: FOO: sh: echo "one" - requires: vars: - name: FOO enum: ['one', 'two'] - validation-var: requires: vars: diff --git a/testdata/requires/testdata/TestRequires-fails_validation-err-run.golden b/testdata/requires/testdata/TestRequires-fails_validation-err-run.golden new file mode 100644 index 00000000..c1e1523b --- /dev/null +++ b/testdata/requires/testdata/TestRequires-fails_validation-err-run.golden @@ -0,0 +1,2 @@ +task: Task "validation-var" cancelled because it is missing required variables: + - FOO has an invalid value : 'bar' (allowed values : [one two]) diff --git a/testdata/requires/testdata/TestRequires-fails_validation.golden b/testdata/requires/testdata/TestRequires-fails_validation.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/requires/testdata/TestRequires-passes_validation.golden b/testdata/requires/testdata/TestRequires-passes_validation.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/requires/testdata/TestRequires-require_before_compile-err-run.golden b/testdata/requires/testdata/TestRequires-require_before_compile-err-run.golden new file mode 100644 index 00000000..eebae1e6 --- /dev/null +++ b/testdata/requires/testdata/TestRequires-require_before_compile-err-run.golden @@ -0,0 +1 @@ +task: Task "require-before-compile" cancelled because it is missing required variables: MY_VAR \ No newline at end of file diff --git a/testdata/requires/testdata/TestRequires-require_before_compile.golden b/testdata/requires/testdata/TestRequires-require_before_compile.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/requires/testdata/TestRequires-required_var_missing-err-run.golden b/testdata/requires/testdata/TestRequires-required_var_missing-err-run.golden new file mode 100644 index 00000000..e042f442 --- /dev/null +++ b/testdata/requires/testdata/TestRequires-required_var_missing-err-run.golden @@ -0,0 +1 @@ +task: Task "missing-var" cancelled because it is missing required variables: FOO \ No newline at end of file diff --git a/testdata/requires/testdata/TestRequires-required_var_missing.golden b/testdata/requires/testdata/TestRequires-required_var_missing.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/requires/testdata/TestRequires-required_var_missing_+_fails_validation#01.golden b/testdata/requires/testdata/TestRequires-required_var_missing_+_fails_validation#01.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/requires/testdata/TestRequires-required_var_missing_+_fails_validation-err-run.golden b/testdata/requires/testdata/TestRequires-required_var_missing_+_fails_validation-err-run.golden new file mode 100644 index 00000000..8914d6ed --- /dev/null +++ b/testdata/requires/testdata/TestRequires-required_var_missing_+_fails_validation-err-run.golden @@ -0,0 +1 @@ +task: Task "validation-var" cancelled because it is missing required variables: ENV, FOO (allowed values: [one two]) \ No newline at end of file diff --git a/testdata/requires/testdata/TestRequires-required_var_missing_+_fails_validation.golden b/testdata/requires/testdata/TestRequires-required_var_missing_+_fails_validation.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/requires/testdata/TestRequires-required_var_ok.golden b/testdata/requires/testdata/TestRequires-required_var_ok.golden new file mode 100644 index 00000000..d60cc372 --- /dev/null +++ b/testdata/requires/testdata/TestRequires-required_var_ok.golden @@ -0,0 +1,2 @@ +task: [missing-var] echo "bar" +bar diff --git a/testdata/requires/testdata/TestRequires-var_defined_in_task.golden b/testdata/requires/testdata/TestRequires-var_defined_in_task.golden new file mode 100644 index 00000000..9d71de96 --- /dev/null +++ b/testdata/requires/testdata/TestRequires-var_defined_in_task.golden @@ -0,0 +1,2 @@ +task: [var-defined-in-task] echo "bar" +bar diff --git a/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-included-print-root-dir.golden b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-included-print-root-dir.golden new file mode 100644 index 00000000..53fb1b33 --- /dev/null +++ b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-included-print-root-dir.golden @@ -0,0 +1 @@ +/testdata/special_vars diff --git a/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-included-print-task-version.golden b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-included-print-task-version.golden new file mode 100644 index 00000000..35466456 --- /dev/null +++ b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-included-print-task-version.golden @@ -0,0 +1 @@ +unknown diff --git a/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-included-print-task.golden b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-included-print-task.golden new file mode 100644 index 00000000..b38fb17a --- /dev/null +++ b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-included-print-task.golden @@ -0,0 +1 @@ +included:print-task diff --git a/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-included-print-taskfile-dir.golden b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-included-print-taskfile-dir.golden new file mode 100644 index 00000000..d1e887b1 --- /dev/null +++ b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-included-print-taskfile-dir.golden @@ -0,0 +1 @@ +/testdata/special_vars/included diff --git a/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-included-print-taskfile.golden b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-included-print-taskfile.golden new file mode 100644 index 00000000..193f3dcc --- /dev/null +++ b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-included-print-taskfile.golden @@ -0,0 +1 @@ +/testdata/special_vars/included/Taskfile.yml diff --git a/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-print-root-dir.golden b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-print-root-dir.golden new file mode 100644 index 00000000..53fb1b33 --- /dev/null +++ b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-print-root-dir.golden @@ -0,0 +1 @@ +/testdata/special_vars diff --git a/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-print-task-dir.golden b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-print-task-dir.golden new file mode 100644 index 00000000..f9d92450 --- /dev/null +++ b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-print-task-dir.golden @@ -0,0 +1 @@ +/testdata/special_vars/foo diff --git a/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-print-task-version.golden b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-print-task-version.golden new file mode 100644 index 00000000..35466456 --- /dev/null +++ b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-print-task-version.golden @@ -0,0 +1 @@ +unknown diff --git a/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-print-task.golden b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-print-task.golden new file mode 100644 index 00000000..6a295366 --- /dev/null +++ b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-print-task.golden @@ -0,0 +1 @@ +print-task diff --git a/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-print-taskfile-dir.golden b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-print-taskfile-dir.golden new file mode 100644 index 00000000..53fb1b33 --- /dev/null +++ b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-print-taskfile-dir.golden @@ -0,0 +1 @@ +/testdata/special_vars diff --git a/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-print-taskfile.golden b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-print-taskfile.golden new file mode 100644 index 00000000..1e59e1e4 --- /dev/null +++ b/testdata/special_vars/subdir/testdata/TestSpecialVars-testdata-special_vars-subdir-print-taskfile.golden @@ -0,0 +1 @@ +/testdata/special_vars/Taskfile.yml diff --git a/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-included-print-root-dir.golden b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-included-print-root-dir.golden new file mode 100644 index 00000000..53fb1b33 --- /dev/null +++ b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-included-print-root-dir.golden @@ -0,0 +1 @@ +/testdata/special_vars diff --git a/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-included-print-task-version.golden b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-included-print-task-version.golden new file mode 100644 index 00000000..35466456 --- /dev/null +++ b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-included-print-task-version.golden @@ -0,0 +1 @@ +unknown diff --git a/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-included-print-task.golden b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-included-print-task.golden new file mode 100644 index 00000000..b38fb17a --- /dev/null +++ b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-included-print-task.golden @@ -0,0 +1 @@ +included:print-task diff --git a/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-included-print-taskfile-dir.golden b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-included-print-taskfile-dir.golden new file mode 100644 index 00000000..d1e887b1 --- /dev/null +++ b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-included-print-taskfile-dir.golden @@ -0,0 +1 @@ +/testdata/special_vars/included diff --git a/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-included-print-taskfile.golden b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-included-print-taskfile.golden new file mode 100644 index 00000000..193f3dcc --- /dev/null +++ b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-included-print-taskfile.golden @@ -0,0 +1 @@ +/testdata/special_vars/included/Taskfile.yml diff --git a/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-print-root-dir.golden b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-print-root-dir.golden new file mode 100644 index 00000000..53fb1b33 --- /dev/null +++ b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-print-root-dir.golden @@ -0,0 +1 @@ +/testdata/special_vars diff --git a/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-print-task-dir.golden b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-print-task-dir.golden new file mode 100644 index 00000000..f9d92450 --- /dev/null +++ b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-print-task-dir.golden @@ -0,0 +1 @@ +/testdata/special_vars/foo diff --git a/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-print-task-version.golden b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-print-task-version.golden new file mode 100644 index 00000000..35466456 --- /dev/null +++ b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-print-task-version.golden @@ -0,0 +1 @@ +unknown diff --git a/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-print-task.golden b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-print-task.golden new file mode 100644 index 00000000..6a295366 --- /dev/null +++ b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-print-task.golden @@ -0,0 +1 @@ +print-task diff --git a/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-print-taskfile-dir.golden b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-print-taskfile-dir.golden new file mode 100644 index 00000000..53fb1b33 --- /dev/null +++ b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-print-taskfile-dir.golden @@ -0,0 +1 @@ +/testdata/special_vars diff --git a/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-print-taskfile.golden b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-print-taskfile.golden new file mode 100644 index 00000000..1e59e1e4 --- /dev/null +++ b/testdata/special_vars/testdata/TestSpecialVars-testdata-special_vars-print-taskfile.golden @@ -0,0 +1 @@ +/testdata/special_vars/Taskfile.yml diff --git a/testdata/status/testdata/TestStatus-run_gen-bar_1_silent.golden b/testdata/status/testdata/TestStatus-run_gen-bar_1_silent.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/status/testdata/TestStatus-run_gen-bar_2_silent.golden b/testdata/status/testdata/TestStatus-run_gen-bar_2_silent.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/status/testdata/TestStatus-run_gen-bar_3_silent.golden b/testdata/status/testdata/TestStatus-run_gen-bar_3_silent.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/status/testdata/TestStatus-run_gen-bar_4_silent.golden b/testdata/status/testdata/TestStatus-run_gen-bar_4_silent.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/status/testdata/TestStatus-run_gen-bar_5.golden b/testdata/status/testdata/TestStatus-run_gen-bar_5.golden new file mode 100644 index 00000000..b68e5f5d --- /dev/null +++ b/testdata/status/testdata/TestStatus-run_gen-bar_5.golden @@ -0,0 +1 @@ +task: [gen-bar] touch bar.txt diff --git a/testdata/status/testdata/TestStatus-run_gen-bar_6.golden b/testdata/status/testdata/TestStatus-run_gen-bar_6.golden new file mode 100644 index 00000000..114d8035 --- /dev/null +++ b/testdata/status/testdata/TestStatus-run_gen-bar_6.golden @@ -0,0 +1 @@ +task: Task "gen-bar" is up to date diff --git a/testdata/status/testdata/TestStatus-run_gen-baz_2.golden b/testdata/status/testdata/TestStatus-run_gen-baz_2.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/status/testdata/TestStatus-run_gen-baz_3.golden b/testdata/status/testdata/TestStatus-run_gen-baz_3.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/status/testdata/TestStatus-run_gen-baz_4_verbose.golden b/testdata/status/testdata/TestStatus-run_gen-baz_4_verbose.golden new file mode 100644 index 00000000..3aa3c036 --- /dev/null +++ b/testdata/status/testdata/TestStatus-run_gen-baz_4_verbose.golden @@ -0,0 +1,2 @@ +task: "gen-silent-baz" started +task: Task "gen-silent-baz" is up to date diff --git a/testdata/status/testdata/TestStatus-run_gen-baz_silent.golden b/testdata/status/testdata/TestStatus-run_gen-baz_silent.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/status/testdata/TestStatus-run_gen-foo_1_silent.golden b/testdata/status/testdata/TestStatus-run_gen-foo_1_silent.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/status/testdata/TestStatus-run_gen-foo_2.golden b/testdata/status/testdata/TestStatus-run_gen-foo_2.golden new file mode 100644 index 00000000..bed0a8eb --- /dev/null +++ b/testdata/status/testdata/TestStatus-run_gen-foo_2.golden @@ -0,0 +1 @@ +task: [gen-foo] touch foo.txt diff --git a/testdata/status/testdata/TestStatus-run_gen-foo_3.golden b/testdata/status/testdata/TestStatus-run_gen-foo_3.golden new file mode 100644 index 00000000..bed0a8eb --- /dev/null +++ b/testdata/status/testdata/TestStatus-run_gen-foo_3.golden @@ -0,0 +1 @@ +task: [gen-foo] touch foo.txt diff --git a/testdata/var_inheritance/v3/entrypoint-global-dotenv/testdata/TestVarInheritance-entrypoint-global-dotenv.golden b/testdata/var_inheritance/v3/entrypoint-global-dotenv/testdata/TestVarInheritance-entrypoint-global-dotenv.golden new file mode 100644 index 00000000..efe7d9e8 --- /dev/null +++ b/testdata/var_inheritance/v3/entrypoint-global-dotenv/testdata/TestVarInheritance-entrypoint-global-dotenv.golden @@ -0,0 +1,2 @@ +entrypoint-global-dotenv +entrypoint-global-dotenv diff --git a/testdata/var_inheritance/v3/entrypoint-global-vars/testdata/TestVarInheritance-entrypoint-global-vars.golden b/testdata/var_inheritance/v3/entrypoint-global-vars/testdata/TestVarInheritance-entrypoint-global-vars.golden new file mode 100644 index 00000000..e6cf1ca5 --- /dev/null +++ b/testdata/var_inheritance/v3/entrypoint-global-vars/testdata/TestVarInheritance-entrypoint-global-vars.golden @@ -0,0 +1,2 @@ +entrypoint-global-vars +entrypoint-global-vars diff --git a/testdata/var_inheritance/v3/entrypoint-task-call-dotenv/testdata/TestVarInheritance-entrypoint-task-call-dotenv.golden b/testdata/var_inheritance/v3/entrypoint-task-call-dotenv/testdata/TestVarInheritance-entrypoint-task-call-dotenv.golden new file mode 100644 index 00000000..85fc33e2 --- /dev/null +++ b/testdata/var_inheritance/v3/entrypoint-task-call-dotenv/testdata/TestVarInheritance-entrypoint-task-call-dotenv.golden @@ -0,0 +1,2 @@ +entrypoint-task-call-vars +entrypoint-task-call-dotenv diff --git a/testdata/var_inheritance/v3/entrypoint-task-call-task-vars/testdata/TestVarInheritance-entrypoint-task-call-task-vars.golden b/testdata/var_inheritance/v3/entrypoint-task-call-task-vars/testdata/TestVarInheritance-entrypoint-task-call-task-vars.golden new file mode 100644 index 00000000..845b5734 --- /dev/null +++ b/testdata/var_inheritance/v3/entrypoint-task-call-task-vars/testdata/TestVarInheritance-entrypoint-task-call-task-vars.golden @@ -0,0 +1,2 @@ +entrypoint-task-call-task-vars +entrypoint-task-call-task-vars diff --git a/testdata/var_inheritance/v3/entrypoint-task-call-vars/testdata/TestVarInheritance-entrypoint-task-call-vars.golden b/testdata/var_inheritance/v3/entrypoint-task-call-vars/testdata/TestVarInheritance-entrypoint-task-call-vars.golden new file mode 100644 index 00000000..63e192c7 --- /dev/null +++ b/testdata/var_inheritance/v3/entrypoint-task-call-vars/testdata/TestVarInheritance-entrypoint-task-call-vars.golden @@ -0,0 +1,2 @@ +entrypoint-task-call-vars +entrypoint-global-vars diff --git a/testdata/var_inheritance/v3/entrypoint-task-dotenv/testdata/TestVarInheritance-entrypoint-task-dotenv.golden b/testdata/var_inheritance/v3/entrypoint-task-dotenv/testdata/TestVarInheritance-entrypoint-task-dotenv.golden new file mode 100644 index 00000000..366838fc --- /dev/null +++ b/testdata/var_inheritance/v3/entrypoint-task-dotenv/testdata/TestVarInheritance-entrypoint-task-dotenv.golden @@ -0,0 +1,2 @@ +entrypoint-global-vars +entrypoint-task-dotenv diff --git a/testdata/var_inheritance/v3/entrypoint-task-vars/testdata/TestVarInheritance-entrypoint-task-vars.golden b/testdata/var_inheritance/v3/entrypoint-task-vars/testdata/TestVarInheritance-entrypoint-task-vars.golden new file mode 100644 index 00000000..f53e9497 --- /dev/null +++ b/testdata/var_inheritance/v3/entrypoint-task-vars/testdata/TestVarInheritance-entrypoint-task-vars.golden @@ -0,0 +1,2 @@ +entrypoint-task-vars +entrypoint-task-vars diff --git a/testdata/var_inheritance/v3/included-global-vars/testdata/TestVarInheritance-included-global-vars.golden b/testdata/var_inheritance/v3/included-global-vars/testdata/TestVarInheritance-included-global-vars.golden new file mode 100644 index 00000000..0a4be2e9 --- /dev/null +++ b/testdata/var_inheritance/v3/included-global-vars/testdata/TestVarInheritance-included-global-vars.golden @@ -0,0 +1,2 @@ +included-global-vars +included-global-vars diff --git a/testdata/var_inheritance/v3/included-task-call-dotenv/testdata/TestVarInheritance-included-task-call-dotenv.golden b/testdata/var_inheritance/v3/included-task-call-dotenv/testdata/TestVarInheritance-included-task-call-dotenv.golden new file mode 100644 index 00000000..d7cc5d1b --- /dev/null +++ b/testdata/var_inheritance/v3/included-task-call-dotenv/testdata/TestVarInheritance-included-task-call-dotenv.golden @@ -0,0 +1,2 @@ +included-task-call-vars +included-global-vars diff --git a/testdata/var_inheritance/v3/included-task-call-task-vars/testdata/TestVarInheritance-included-task-call-task-vars.golden b/testdata/var_inheritance/v3/included-task-call-task-vars/testdata/TestVarInheritance-included-task-call-task-vars.golden new file mode 100644 index 00000000..96bbe160 --- /dev/null +++ b/testdata/var_inheritance/v3/included-task-call-task-vars/testdata/TestVarInheritance-included-task-call-task-vars.golden @@ -0,0 +1,2 @@ +included-task-call-task-vars +included-task-call-task-vars diff --git a/testdata/var_inheritance/v3/included-task-call-vars/testdata/TestVarInheritance-included-task-call-vars.golden b/testdata/var_inheritance/v3/included-task-call-vars/testdata/TestVarInheritance-included-task-call-vars.golden new file mode 100644 index 00000000..d7cc5d1b --- /dev/null +++ b/testdata/var_inheritance/v3/included-task-call-vars/testdata/TestVarInheritance-included-task-call-vars.golden @@ -0,0 +1,2 @@ +included-task-call-vars +included-global-vars diff --git a/testdata/var_inheritance/v3/included-task-dotenv/testdata/TestVarInheritance-included-task-dotenv.golden b/testdata/var_inheritance/v3/included-task-dotenv/testdata/TestVarInheritance-included-task-dotenv.golden new file mode 100644 index 00000000..9295cee4 --- /dev/null +++ b/testdata/var_inheritance/v3/included-task-dotenv/testdata/TestVarInheritance-included-task-dotenv.golden @@ -0,0 +1,2 @@ +included-global-vars +included-task-dotenv diff --git a/testdata/var_inheritance/v3/included-task-vars/testdata/TestVarInheritance-included-task-vars.golden b/testdata/var_inheritance/v3/included-task-vars/testdata/TestVarInheritance-included-task-vars.golden new file mode 100644 index 00000000..37e2bd0d --- /dev/null +++ b/testdata/var_inheritance/v3/included-task-vars/testdata/TestVarInheritance-included-task-vars.golden @@ -0,0 +1,2 @@ +included-task-vars +included-task-vars diff --git a/testdata/var_inheritance/v3/shell/testdata/TestVarInheritance-shell.golden b/testdata/var_inheritance/v3/shell/testdata/TestVarInheritance-shell.golden new file mode 100644 index 00000000..412a368b --- /dev/null +++ b/testdata/var_inheritance/v3/shell/testdata/TestVarInheritance-shell.golden @@ -0,0 +1,2 @@ +shell +shell diff --git a/testdata/var_references/testdata/TestReference-reference_in_command.golden b/testdata/var_references/testdata/TestReference-reference_in_command.golden new file mode 100644 index 00000000..d00491fd --- /dev/null +++ b/testdata/var_references/testdata/TestReference-reference_in_command.golden @@ -0,0 +1 @@ +1 diff --git a/testdata/var_references/testdata/TestReference-reference_in_dependency.golden b/testdata/var_references/testdata/TestReference-reference_in_dependency.golden new file mode 100644 index 00000000..d00491fd --- /dev/null +++ b/testdata/var_references/testdata/TestReference-reference_in_dependency.golden @@ -0,0 +1 @@ +1 diff --git a/testdata/var_references/testdata/TestReference-reference_using_templating_resolver.golden b/testdata/var_references/testdata/TestReference-reference_using_templating_resolver.golden new file mode 100644 index 00000000..d00491fd --- /dev/null +++ b/testdata/var_references/testdata/TestReference-reference_using_templating_resolver.golden @@ -0,0 +1 @@ +1 diff --git a/testdata/var_references/testdata/TestReference-reference_using_templating_resolver_and_dynamic_var.golden b/testdata/var_references/testdata/TestReference-reference_using_templating_resolver_and_dynamic_var.golden new file mode 100644 index 00000000..10268557 --- /dev/null +++ b/testdata/var_references/testdata/TestReference-reference_using_templating_resolver_and_dynamic_var.golden @@ -0,0 +1 @@ +Alice has 3 children called Bob, Charlie, and Diane diff --git a/testdata/vars/Taskfile.yml b/testdata/vars/Taskfile.yml index 187c48bd..621a7afb 100644 --- a/testdata/vars/Taskfile.yml +++ b/testdata/vars/Taskfile.yml @@ -19,7 +19,7 @@ tasks: - task: with-call - task: from-dot-env - missing-var: echo '{{.NON_EXISTING_VAR}}' > missing-var.txt + missing-var: echo '{{.NON_EXISTING_VAR}}' var-order: vars: @@ -27,7 +27,7 @@ tasks: VAR_E: '{{.VAR_D}}E' VAR_F: '{{.VAR_E}}F' cmds: - - echo '{{.VAR_F}}' > var-order.txt + - echo '{{.VAR_F}}' dependent-sh: vars: @@ -35,7 +35,7 @@ tasks: VAR_5: {sh: 'echo "{{.VAR_4}}5"'} VAR_6: {sh: 'echo "{{.VAR_5}}6"'} cmds: - - echo '{{.VAR_6}}' > dependent-sh.txt + - echo '{{.VAR_6}}' with-call: - task: called-task @@ -46,6 +46,6 @@ tasks: vars: MESSAGE: Hi, {{.ABC123}}! cmds: - - echo "{{.MESSAGE}}" > with-call.txt + - echo "{{.MESSAGE}}" - from-dot-env: echo '{{.DOT_ENV_VAR}}' > from-dot-env.txt + from-dot-env: echo '{{.DOT_ENV_VAR}}' diff --git a/testdata/vars/testdata/TestVars.golden b/testdata/vars/testdata/TestVars.golden new file mode 100644 index 00000000..c6a02ab8 --- /dev/null +++ b/testdata/vars/testdata/TestVars.golden @@ -0,0 +1,5 @@ + +ABCDEF +123456 +Hi, ABC123! +From .env file