diff --git a/cli/integration_tests/basic_monorepo/output_logs.t b/cli/integration_tests/basic_monorepo/output_logs.t new file mode 100644 index 0000000000000..528cc384d5e86 --- /dev/null +++ b/cli/integration_tests/basic_monorepo/output_logs.t @@ -0,0 +1,137 @@ +Setup + $ . ${TESTDIR}/../setup.sh + $ . ${TESTDIR}/setup.sh $(pwd) + +Output-logs full + $ ${TURBO} run build --output-logs=full --filter=util --force + \xe2\x80\xa2 Packages in scope: util (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + util:build: cache bypass, force executing 6dec18f9f767112f + util:build: + util:build: \x3e build (esc) + util:build: \x3e echo 'building' (esc) + util:build: + util:build: building + + Tasks: 1 successful, 1 total + Cached: 0 cached, 1 total + Time:\s*[\.0-9]+m?s (re) + +Output-logs none + $ ${TURBO} run build --output-logs=none --filter=util --force + \xe2\x80\xa2 Packages in scope: util (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + + Tasks: 1 successful, 1 total + Cached: 0 cached, 1 total + Time:\s*[\.0-9]+m?s (re) + +Output-logs hash-only + $ ${TURBO} run build --output-logs=hash-only --filter=util --force + \xe2\x80\xa2 Packages in scope: util (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + util:build: cache bypass, force executing 6dec18f9f767112f + + Tasks: 1 successful, 1 total + Cached: 0 cached, 1 total + Time:\s*[\.0-9]+m?s (re) + +Output-logs new-only + $ ${TURBO} run build --output-logs=new-only --filter=util --force + \xe2\x80\xa2 Packages in scope: util (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + util:build: cache bypass, force executing 6dec18f9f767112f + util:build: + util:build: \x3e build (esc) + util:build: \x3e echo 'building' (esc) + util:build: + util:build: building + + Tasks: 1 successful, 1 total + Cached: 0 cached, 1 total + Time:\s*[\.0-9]+m?s (re) + +Output-logs new-only no force + $ ${TURBO} run build --output-logs=new-only --filter=util + \xe2\x80\xa2 Packages in scope: util (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + util:build: cache hit, suppressing output 6dec18f9f767112f + + Tasks: 1 successful, 1 total + Cached: 1 cached, 1 total + Time:\s*[\.0-9]+m?s >>> FULL TURBO (re) + +Output-logs error-only + $ ${TURBO} run build --output-logs=errors-only --filter=util --force + \xe2\x80\xa2 Packages in scope: util (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + + Tasks: 1 successful, 1 total + Cached: 0 cached, 1 total + Time:\s*[\.0-9]+m?s (re) + +Output-logs stdout-full + $ ${TURBO} run build --output-logs=stdout-full --filter=util --force + \xe2\x80\xa2 Packages in scope: util (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + util:build: cache bypass, force executing 6dec18f9f767112f + + \x3e build (esc) + \x3e echo 'building' (esc) + + building + + Tasks: 1 successful, 1 total + Cached: 0 cached, 1 total + Time:\s*[\.0-9]+m?s (re) + +Output-logs stdout-new-only + $ ${TURBO} run build --output-logs=stdout-new-only --filter=util --force + \xe2\x80\xa2 Packages in scope: util (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + util:build: cache bypass, force executing 6dec18f9f767112f + + \x3e build (esc) + \x3e echo 'building' (esc) + + building + + Tasks: 1 successful, 1 total + Cached: 0 cached, 1 total + Time:\s*[\.0-9]+m?s (re) + +Output-logs stdout-full no force + $ ${TURBO} run build --output-logs=stdout-full --filter=util + \xe2\x80\xa2 Packages in scope: util (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + util:build: cache hit, replaying output 6dec18f9f767112f + + \x3e build (esc) + \x3e echo 'building' (esc) + + building + + Tasks: 1 successful, 1 total + Cached: 1 cached, 1 total + Time:\s*[\.0-9]+m?s >>> FULL TURBO (re) + +Output-logs stdout-new-only no force + $ ${TURBO} run build --output-logs=stdout-new-only --filter=util + \xe2\x80\xa2 Packages in scope: util (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + util:build: cache hit, suppressing output 6dec18f9f767112f + + Tasks: 1 successful, 1 total + Cached: 1 cached, 1 total + Time:\s*[\.0-9]+m?s >>> FULL TURBO (re) + \ No newline at end of file diff --git a/cli/integration_tests/no_args.t b/cli/integration_tests/no_args.t index 35311a3c22ff9..d05f6379ecce8 100644 --- a/cli/integration_tests/no_args.t +++ b/cli/integration_tests/no_args.t @@ -51,7 +51,7 @@ Make sure exit code is 2 when no args are passed --no-cache Avoid saving task results to the cache. Useful for development/watch tasks --no-daemon Run without using turbo's daemon process --no-deps Exclude dependent task consumers from execution - --output-logs Set type of process output logging. Use "full" to show all output. Use "hash-only" to show only turbo-computed task hashes. Use "new-only" to show only new output with only hashes for cached tasks. Use "none" to hide process output. (default full) [possible values: full, none, hash-only, new-only, errors-only] + --output-logs Set type of process output logging. Use "full" to show all output. Use "hash-only" to show only turbo-computed task hashes. Use "new-only" to show only new output with only hashes for cached tasks. Use "none" to hide process output. (default full) [possible values: full, none, hash-only, new-only, errors-only, stdout-full, stdout-new-only] --parallel Execute all tasks in parallel --profile File to write turbo's performance profile output into. You can load the file up in chrome://tracing to see which parts of your build were slow --remote-only Ignore the local filesystem cache for all tasks. Only allow reading and caching artifacts using the remote cache diff --git a/cli/integration_tests/turbo_help.t b/cli/integration_tests/turbo_help.t index 194b2603179ee..fb05f48206406 100644 --- a/cli/integration_tests/turbo_help.t +++ b/cli/integration_tests/turbo_help.t @@ -51,7 +51,7 @@ Test help flag --no-cache Avoid saving task results to the cache. Useful for development/watch tasks --no-daemon Run without using turbo's daemon process --no-deps Exclude dependent task consumers from execution - --output-logs Set type of process output logging. Use "full" to show all output. Use "hash-only" to show only turbo-computed task hashes. Use "new-only" to show only new output with only hashes for cached tasks. Use "none" to hide process output. (default full) [possible values: full, none, hash-only, new-only, errors-only] + --output-logs Set type of process output logging. Use "full" to show all output. Use "hash-only" to show only turbo-computed task hashes. Use "new-only" to show only new output with only hashes for cached tasks. Use "none" to hide process output. (default full) [possible values: full, none, hash-only, new-only, errors-only, stdout-full, stdout-new-only] --parallel Execute all tasks in parallel --profile File to write turbo's performance profile output into. You can load the file up in chrome://tracing to see which parts of your build were slow --remote-only Ignore the local filesystem cache for all tasks. Only allow reading and caching artifacts using the remote cache @@ -112,7 +112,7 @@ Test help flag --no-cache Avoid saving task results to the cache. Useful for development/watch tasks --no-daemon Run without using turbo's daemon process --no-deps Exclude dependent task consumers from execution - --output-logs Set type of process output logging. Use "full" to show all output. Use "hash-only" to show only turbo-computed task hashes. Use "new-only" to show only new output with only hashes for cached tasks. Use "none" to hide process output. (default full) [possible values: full, none, hash-only, new-only, errors-only] + --output-logs Set type of process output logging. Use "full" to show all output. Use "hash-only" to show only turbo-computed task hashes. Use "new-only" to show only new output with only hashes for cached tasks. Use "none" to hide process output. (default full) [possible values: full, none, hash-only, new-only, errors-only, stdout-full, stdout-new-only] --parallel Execute all tasks in parallel --profile File to write turbo's performance profile output into. You can load the file up in chrome://tracing to see which parts of your build were slow --remote-only Ignore the local filesystem cache for all tasks. Only allow reading and caching artifacts using the remote cache diff --git a/cli/internal/logstreamer/logstreamer.go b/cli/internal/logstreamer/logstreamer.go index 4379c2597d6ea..cbd9c840b2f24 100644 --- a/cli/internal/logstreamer/logstreamer.go +++ b/cli/internal/logstreamer/logstreamer.go @@ -27,9 +27,12 @@ type Logstreamer struct { colorOkay string colorFail string colorReset string + + // If true, output is not altered, and written straight to stdout + stdout bool } -func NewLogstreamer(logger *log.Logger, prefix string, record bool) *Logstreamer { +func NewLogstreamer(logger *log.Logger, prefix string, record bool, stdout bool) *Logstreamer { streamer := &Logstreamer{ Logger: logger, buf: bytes.NewBuffer([]byte("")), @@ -39,6 +42,7 @@ func NewLogstreamer(logger *log.Logger, prefix string, record bool) *Logstreamer colorOkay: "", colorFail: "", colorReset: "", + stdout: stdout, } if strings.HasPrefix(os.Getenv("TERM"), "xterm") { @@ -121,35 +125,48 @@ func (l *Logstreamer) out(str string) { l.persist = l.persist + str } - if l.prefix == "stdout" { - str = l.colorOkay + l.prefix + l.colorReset + " " + str - } else if l.prefix == "stderr" { - str = l.colorFail + l.prefix + l.colorReset + " " + str + if !l.stdout { + if l.prefix == "stdout" { + str = l.colorOkay + l.prefix + l.colorReset + " " + str + } else if l.prefix == "stderr" { + str = l.colorFail + l.prefix + l.colorReset + " " + str + } } l.Logger.Print(str) } -// PrettyStdoutWriter wraps an ioWriter so it can add string +// StdoutWriter wraps an ioWriter so it can add string // prefixes to every message it writes to stdout. -type PrettyStdoutWriter struct { +type StdoutWriter struct { w io.Writer Prefix string + // If true, output is not altered, and written straight to stdout + Stdout bool } -var _ io.Writer = (*PrettyStdoutWriter)(nil) +var _ io.Writer = (*StdoutWriter)(nil) -// NewPrettyStdoutWriter returns an instance of PrettyStdoutWriter -func NewPrettyStdoutWriter(prefix string) *PrettyStdoutWriter { - return &PrettyStdoutWriter{ +// NewPrettyStdoutWriter returns an instance of StdoutWriter in pretty mode +func NewPrettyStdoutWriter(prefix string) *StdoutWriter { + return &StdoutWriter{ w: os.Stdout, Prefix: prefix, + Stdout: false, } } -func (psw *PrettyStdoutWriter) Write(p []byte) (int, error) { - str := psw.Prefix + string(p) - n, err := psw.w.Write([]byte(str)) +func (psw *StdoutWriter) Write(p []byte) (int, error) { + var data []byte + + if !psw.Stdout { + str := psw.Prefix + string(p) + data = []byte(str) + } else { + data = p + } + + n, err := psw.w.Write(data) if err != nil { return n, err @@ -157,3 +174,12 @@ func (psw *PrettyStdoutWriter) Write(p []byte) (int, error) { return len(p), nil } + +// NewStdoutWriter returns an instance of StdoutWriter in stdout mode +func NewStdoutWriter() *StdoutWriter { + return &StdoutWriter{ + w: os.Stdout, + Prefix: "", + Stdout: true, + } +} diff --git a/cli/internal/logstreamer/logstreamer_test.go b/cli/internal/logstreamer/logstreamer_test.go index 94d8a8283716c..62d2003560fc1 100644 --- a/cli/internal/logstreamer/logstreamer_test.go +++ b/cli/internal/logstreamer/logstreamer_test.go @@ -19,11 +19,11 @@ func TestLogstreamerOk(t *testing.T) { logger := log.New(os.Stdout, "--> ", log.Ldate|log.Ltime) // Setup a streamer that we'll pipe cmd.Stdout to - logStreamerOut := NewLogstreamer(logger, "stdout", false) + logStreamerOut := NewLogstreamer(logger, "stdout", false, false) defer logStreamerOut.Close() // Setup a streamer that we'll pipe cmd.Stderr to. // We want to record/buffer anything that's written to this (3rd argument true) - logStreamerErr := NewLogstreamer(logger, "stderr", true) + logStreamerErr := NewLogstreamer(logger, "stderr", true, false) defer logStreamerErr.Close() // Execute something that succeeds @@ -57,11 +57,11 @@ func TestLogstreamerErr(t *testing.T) { logger := log.New(os.Stdout, "--> ", log.Ldate|log.Ltime) // Setup a streamer that we'll pipe cmd.Stdout to - logStreamerOut := NewLogstreamer(logger, "stdout", false) + logStreamerOut := NewLogstreamer(logger, "stdout", false, false) defer logStreamerOut.Close() // Setup a streamer that we'll pipe cmd.Stderr to. // We want to record/buffer anything that's written to this (3rd argument true) - logStreamerErr := NewLogstreamer(logger, "stderr", true) + logStreamerErr := NewLogstreamer(logger, "stderr", true, false) defer logStreamerErr.Close() // Execute something that succeeds @@ -99,7 +99,7 @@ func TestLogstreamerFlush(t *testing.T) { byteWriter := bufio.NewWriter(&buffer) logger := log.New(byteWriter, "", 0) - logStreamerOut := NewLogstreamer(logger, "", false) + logStreamerOut := NewLogstreamer(logger, "", false, false) defer logStreamerOut.Close() logStreamerOut.Write([]byte(text)) diff --git a/cli/internal/run/real_run.go b/cli/internal/run/real_run.go index d379d2fe258a2..051b3158600c2 100644 --- a/cli/internal/run/real_run.go +++ b/cli/internal/run/real_run.go @@ -28,6 +28,7 @@ import ( "github.com/vercel/turbo/cli/internal/taskhash" "github.com/vercel/turbo/cli/internal/turbopath" "github.com/vercel/turbo/cli/internal/ui" + "github.com/vercel/turbo/cli/internal/util" ) // RealRun executes a set of tasks @@ -157,6 +158,9 @@ func (ec *execContext) exec(ctx gocontext.Context, packageTask *nodes.PackageTas progressLogger := ec.logger.Named("") progressLogger.Debug("start") + // TODO(rafaeltab) this doesn't work + isStdout := ec.rs.Opts.runcacheOpts.TaskOutputModeOverride != nil && (*ec.rs.Opts.runcacheOpts.TaskOutputModeOverride == util.StdoutFullTaskOutput || *ec.rs.Opts.runcacheOpts.TaskOutputModeOverride == util.StdoutNewTaskOutput) + // Setup tracer tracer := ec.runState.Run(packageTask.TaskID) @@ -211,7 +215,7 @@ func (ec *execContext) exec(ctx gocontext.Context, packageTask *nodes.PackageTas // Setup stdout/stderr // If we are not caching anything, then we don't need to write logs to disk // be careful about this conditional given the default of cache = true - writer, err := taskCache.OutputWriter(prettyPrefix) + writer, err := taskCache.OutputWriter(prettyPrefix, isStdout) if err != nil { tracer(TargetBuildFailed, err) ec.logError(progressLogger, prettyPrefix, err) @@ -223,9 +227,9 @@ func (ec *execContext) exec(ctx gocontext.Context, packageTask *nodes.PackageTas // Create a logger logger := log.New(writer, "", 0) // Setup a streamer that we'll pipe cmd.Stdout to - logStreamerOut := logstreamer.NewLogstreamer(logger, prettyPrefix, false) + logStreamerOut := logstreamer.NewLogstreamer(logger, prettyPrefix, false, isStdout) // Setup a streamer that we'll pipe cmd.Stderr to. - logStreamerErr := logstreamer.NewLogstreamer(logger, prettyPrefix, false) + logStreamerErr := logstreamer.NewLogstreamer(logger, prettyPrefix, false, isStdout) cmd.Stderr = logStreamerErr cmd.Stdout = logStreamerOut // Flush/Reset any error we recorded @@ -274,7 +278,7 @@ func (ec *execContext) exec(ctx gocontext.Context, packageTask *nodes.PackageTas } // If there was an error, flush the buffered output - taskCache.OnError(prefixedUI, progressLogger) + taskCache.OnError(prefixedUI, progressLogger, isStdout) return err } diff --git a/cli/internal/runcache/runcache.go b/cli/internal/runcache/runcache.go index 8f56dd8defe39..e762c39c5b399 100644 --- a/cli/internal/runcache/runcache.go +++ b/cli/internal/runcache/runcache.go @@ -24,7 +24,7 @@ import ( ) // LogReplayer is a function that is responsible for replaying the contents of a given log file -type LogReplayer = func(logger hclog.Logger, output *cli.PrefixedUi, logFile turbopath.AbsoluteSystemPath) +type LogReplayer = func(logger hclog.Logger, output *cli.PrefixedUi, logFile turbopath.AbsoluteSystemPath, stdout bool) // Opts holds the configurable options for a RunCache instance type Opts struct { @@ -149,12 +149,18 @@ func (tc TaskCache) RestoreOutputs(ctx context.Context, prefixedUI *cli.Prefixed // When only showing new task output, cached output should only show the computed hash case util.NewTaskOutput: fallthrough + case util.StdoutNewTaskOutput: + fallthrough case util.HashTaskOutput: prefixedUI.Info(fmt.Sprintf("cache hit, suppressing output %s", ui.Dim(tc.hash))) case util.FullTaskOutput: progressLogger.Debug("log file", "path", tc.LogFileName) prefixedUI.Info(fmt.Sprintf("cache hit, replaying output %s", ui.Dim(tc.hash))) - tc.ReplayLogFile(prefixedUI, progressLogger) + tc.ReplayLogFile(prefixedUI, progressLogger, false) + case util.StdoutFullTaskOutput: + progressLogger.Debug("log file", "path", tc.LogFileName) + prefixedUI.Info(fmt.Sprintf("cache hit, replaying output %s", ui.Dim(tc.hash))) + tc.ReplayLogFile(prefixedUI, progressLogger, true) case util.ErrorTaskOutput: // The task succeeded, so we don't output anything in this case default: @@ -165,17 +171,17 @@ func (tc TaskCache) RestoreOutputs(ctx context.Context, prefixedUI *cli.Prefixed } // ReplayLogFile writes out the stored logfile to the terminal -func (tc TaskCache) ReplayLogFile(prefixedUI *cli.PrefixedUi, progressLogger hclog.Logger) { +func (tc TaskCache) ReplayLogFile(prefixedUI *cli.PrefixedUi, progressLogger hclog.Logger, stdout bool) { if tc.LogFileName.FileExists() { - tc.rc.logReplayer(progressLogger, prefixedUI, tc.LogFileName) + tc.rc.logReplayer(progressLogger, prefixedUI, tc.LogFileName, stdout) } } // OnError replays the logfile if --output-mode=errors-only. // This is called if the task exited with an non-zero error code. -func (tc TaskCache) OnError(terminal *cli.PrefixedUi, logger hclog.Logger) { +func (tc TaskCache) OnError(terminal *cli.PrefixedUi, logger hclog.Logger, stdout bool) { if tc.taskOutputMode == util.ErrorTaskOutput { - tc.ReplayLogFile(terminal, logger) + tc.ReplayLogFile(terminal, logger, stdout) } } @@ -201,9 +207,14 @@ func (fwc *fileWriterCloser) Close() error { // OutputWriter creates a sink suitable for handling the output of the command associated // with this task. -func (tc TaskCache) OutputWriter(prefix string) (io.WriteCloser, error) { +func (tc TaskCache) OutputWriter(prefix string, stdout bool) (io.WriteCloser, error) { // an os.Stdout wrapper that will add prefixes before printing to stdout - stdoutWriter := logstreamer.NewPrettyStdoutWriter(prefix) + var stdoutWriter *logstreamer.StdoutWriter + if stdout { + stdoutWriter = logstreamer.NewStdoutWriter() + } else { + stdoutWriter = logstreamer.NewPrettyStdoutWriter(prefix) + } if tc.cachingDisabled || tc.rc.writesDisabled { return nopWriteCloser{stdoutWriter}, nil @@ -307,7 +318,7 @@ func (rc *RunCache) TaskCache(pt *nodes.PackageTask, hash string) TaskCache { } // defaultLogReplayer will try to replay logs back to the given Ui instance -func defaultLogReplayer(logger hclog.Logger, output *cli.PrefixedUi, logFileName turbopath.AbsoluteSystemPath) { +func defaultLogReplayer(logger hclog.Logger, output *cli.PrefixedUi, logFileName turbopath.AbsoluteSystemPath, stdout bool) { logger.Debug("start replaying logs") f, err := logFileName.Open() if err != nil { @@ -321,7 +332,10 @@ func defaultLogReplayer(logger hclog.Logger, output *cli.PrefixedUi, logFileName // cli.PrefixedUi won't prefix empty strings (it'll just print them as empty strings). // So if we have a blank string, we'll just output the string here, instead of passing // it onto the PrefixedUi. - if str == "" { + if stdout { + // Don't prefix the output if stdout mode is on + output.Ui.Output(str) + } else if str == "" { // Just output the prefix if the current line is a blank string // Note: output.OutputPrefix is also a colored prefix already output.Ui.Output(output.OutputPrefix) diff --git a/cli/internal/util/task_output_mode.go b/cli/internal/util/task_output_mode.go index bcc2abf6abc16..94dbc3d7b2852 100644 --- a/cli/internal/util/task_output_mode.go +++ b/cli/internal/util/task_output_mode.go @@ -19,14 +19,20 @@ const ( NewTaskOutput // ErrorTaskOutput will show task output for failures only; no cache miss/hit messages are emitted ErrorTaskOutput + // StdoutFullTaskOutput will show all task output to stdout without prefix + StdoutFullTaskOutput + // StdoutNewTaskOutput will show all new task output to stdout without prefix + StdoutNewTaskOutput ) const ( - fullTaskOutputString = "full" - noTaskOutputString = "none" - hashTaskOutputString = "hash-only" - newTaskOutputString = "new-only" - errorTaskOutputString = "errors-only" + fullTaskOutputString = "full" + noTaskOutputString = "none" + hashTaskOutputString = "hash-only" + newTaskOutputString = "new-only" + errorTaskOutputString = "errors-only" + stdoutFullTaskOutputString = "stdout-full" + stdoutNewTaskOutputString = "stdout-new-only" ) // TaskOutputModeStrings is an array containing the string representations for task output modes @@ -36,6 +42,8 @@ var TaskOutputModeStrings = []string{ hashTaskOutputString, newTaskOutputString, errorTaskOutputString, + stdoutFullTaskOutputString, + stdoutNewTaskOutputString, } // FromTaskOutputModeString converts a task output mode's string representation into the enum value @@ -51,6 +59,10 @@ func FromTaskOutputModeString(value string) (TaskOutputMode, error) { return NewTaskOutput, nil case errorTaskOutputString: return ErrorTaskOutput, nil + case stdoutFullTaskOutputString: + return StdoutFullTaskOutput, nil + case stdoutNewTaskOutputString: + return StdoutNewTaskOutput, nil } return FullTaskOutput, fmt.Errorf("invalid task output mode: %v", value) @@ -69,6 +81,10 @@ func ToTaskOutputModeString(value TaskOutputMode) (string, error) { return newTaskOutputString, nil case ErrorTaskOutput: return errorTaskOutputString, nil + case StdoutFullTaskOutput: + return stdoutFullTaskOutputString, nil + case StdoutNewTaskOutput: + return stdoutNewTaskOutputString, nil } return "", fmt.Errorf("invalid task output mode: %v", value) diff --git a/crates/turborepo-lib/src/cli.rs b/crates/turborepo-lib/src/cli.rs index d343c87ea7e3f..2d8eb0e7d1ee3 100644 --- a/crates/turborepo-lib/src/cli.rs +++ b/crates/turborepo-lib/src/cli.rs @@ -27,6 +27,10 @@ pub enum OutputLogsMode { NewOnly, #[serde(rename = "errors-only")] ErrorsOnly, + #[serde(rename = "stdout-full")] + StdoutFull, + #[serde(rename = "stdout-new-only")] + StdoutNewOnly, } impl Default for OutputLogsMode {