diff --git a/cmd/task/task.go b/cmd/task/task.go index 335a598b1..1bf65f166 100644 --- a/cmd/task/task.go +++ b/cmd/task/task.go @@ -3,6 +3,7 @@ package main import ( "context" "fmt" + "io" "log" "os" "path/filepath" @@ -87,6 +88,7 @@ func run() error { color bool interval time.Duration global bool + shell bool ) pflag.BoolVar(&versionFlag, "version", false, "Show Task version.") @@ -115,6 +117,7 @@ func run() error { pflag.IntVarP(&concurrency, "concurrency", "C", 0, "Limit number tasks to run concurrently.") pflag.DurationVarP(&interval, "interval", "I", 0, "Interval to watch for changes.") pflag.BoolVarP(&global, "global", "g", false, "Runs global Taskfile, from $HOME/Taskfile.{yml,yaml}.") + pflag.BoolVarP(&shell, "shell", "", false, "Dump raw shell script") pflag.Parse() if versionFlag { @@ -235,6 +238,12 @@ func run() error { return err } + if shell { + e.Shell = true + // disable all other logs except purely shell output + e.Logger.Stdout = io.Discard + } + if e.Taskfile.Version.Compare(taskfile.V3) >= 0 { calls, globals = args.ParseV3(tasksAndVars...) } else { diff --git a/precondition.go b/precondition.go index b79f79617..0b09a748c 100644 --- a/precondition.go +++ b/precondition.go @@ -15,6 +15,11 @@ var ErrPreconditionFailed = errors.New("task: precondition not met") func (e *Executor) areTaskPreconditionsMet(ctx context.Context, t *taskfile.Task) (bool, error) { for _, p := range t.Preconditions { + // log precondition command if shell flag is passed + if e.Shell { + e.Logger.FOutf(e.Stdout, logger.Default, "%s\n", p.Sh) + return true, nil + } err := execext.RunCommand(ctx, &execext.RunCommandOptions{ Command: p.Sh, Dir: t.Dir, diff --git a/task.go b/task.go index f1ebb561e..84461a60f 100644 --- a/task.go +++ b/task.go @@ -46,6 +46,7 @@ type Executor struct { Verbose bool Silent bool Dry bool + Shell bool Summary bool Parallel bool Color bool @@ -278,6 +279,11 @@ func (e *Executor) runCommand(ctx context.Context, t *taskfile.Task, call taskfi return nil } + if e.Shell { + e.Logger.FOutf(e.Stdout, logger.Default, "%s\n", cmd.Cmd) + return nil + } + if e.Verbose || (!cmd.Silent && !t.Silent && !e.Taskfile.Silent && !e.Silent) { e.Logger.Errf(logger.Green, "task: [%s] %s", t.Name(), cmd.Cmd) } diff --git a/task_test.go b/task_test.go index 0def5c0ca..63af37e15 100644 --- a/task_test.go +++ b/task_test.go @@ -1892,3 +1892,27 @@ func TestSplitArgs(t *testing.T) { require.NoError(t, err) assert.Equal(t, "3\n", buff.String()) } + +func TestShell(t *testing.T) { + // reuse testdata/dry since 'shell' flag has similar behavior + const dir = "testdata/dry" + + file := filepathext.SmartJoin(dir, "file.txt") + _ = os.Remove(file) + + var buff bytes.Buffer + + e := task.Executor{ + Dir: dir, + Stdout: &buff, + Stderr: io.Discard, + Shell: true, + } + require.NoError(t, e.Setup()) + require.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "build"})) + + assert.Equal(t, "touch file.txt", strings.TrimSpace(buff.String())) + if _, err := os.Stat(file); err == nil { + t.Errorf("File should not exist %s", file) + } +}