diff --git a/cli/.gitignore b/cli/.gitignore index bf77320b1a0ff..f2929414b9bc2 100644 --- a/cli/.gitignore +++ b/cli/.gitignore @@ -12,3 +12,4 @@ /scripts/turbo-* /.cram_env testbed +integration_tests/**/*.t.err diff --git a/cli/integration_tests/single_package/run.t b/cli/integration_tests/single_package/run.t index 644556a279ab0..d496e69abbbda 100644 --- a/cli/integration_tests/single_package/run.t +++ b/cli/integration_tests/single_package/run.t @@ -5,6 +5,7 @@ Setup Check $ ${TURBO} run build --single-package \xe2\x80\xa2 Running build (esc) + INFO \xe2\x80\xa2 Remote caching disabled (esc) build: cache miss, executing e491d0044f4b9b90 build: build: > build @@ -18,6 +19,7 @@ Check Run a second time, verify caching works because there is a config $ ${TURBO} run build --single-package \xe2\x80\xa2 Running build (esc) + INFO \xe2\x80\xa2 Remote caching disabled (esc) build: cache hit, replaying output e491d0044f4b9b90 build: build: > build @@ -27,4 +29,4 @@ Run a second time, verify caching works because there is a config 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/single_package_deps/run.t b/cli/integration_tests/single_package_deps/run.t index 461b49ca54f8e..a1cf1fd7f5a0b 100644 --- a/cli/integration_tests/single_package_deps/run.t +++ b/cli/integration_tests/single_package_deps/run.t @@ -5,6 +5,7 @@ Setup Check $ ${TURBO} run test --single-package \xe2\x80\xa2 Running test (esc) + INFO \xe2\x80\xa2 Remote caching disabled (esc) build: cache miss, executing 6218abb18f5176f5 build: build: > build @@ -23,6 +24,7 @@ Check Run a second time, verify caching works because there is a config $ ${TURBO} run test --single-package \xe2\x80\xa2 Running test (esc) + INFO \xe2\x80\xa2 Remote caching disabled (esc) build: cache hit, replaying output 6218abb18f5176f5 build: build: > build @@ -37,4 +39,4 @@ Run a second time, verify caching works because there is a config Tasks: 2 successful, 2 total Cached: 2 cached, 2 total Time:\s*[\.0-9]+m?s >>> FULL TURBO (re) - + \ No newline at end of file diff --git a/cli/integration_tests/single_package_no_config/run.t b/cli/integration_tests/single_package_no_config/run.t index 1d12cc404996f..b0abe5a03e547 100644 --- a/cli/integration_tests/single_package_no_config/run.t +++ b/cli/integration_tests/single_package_no_config/run.t @@ -5,6 +5,7 @@ Setup Check $ ${TURBO} run build --single-package \xe2\x80\xa2 Running build (esc) + INFO \xe2\x80\xa2 Remote caching disabled (esc) build: cache bypass, force executing c207d64157b1635a build: build: > build @@ -19,6 +20,7 @@ Check Run a second time, verify no caching because there is no config $ ${TURBO} run build --single-package \xe2\x80\xa2 Running build (esc) + INFO \xe2\x80\xa2 Remote caching disabled (esc) build: cache bypass, force executing c207d64157b1635a build: build: > build @@ -29,4 +31,4 @@ Run a second time, verify no caching because there is no config Tasks: 1 successful, 1 total Cached: 0 cached, 1 total Time:\s*[\.0-9]+m?s (re) - + \ No newline at end of file diff --git a/cli/internal/cmdutil/cmdutil.go b/cli/internal/cmdutil/cmdutil.go index 1027633dd75d6..bc01c6ae94dcc 100644 --- a/cli/internal/cmdutil/cmdutil.go +++ b/cli/internal/cmdutil/cmdutil.go @@ -147,8 +147,12 @@ func NewHelper(turboVersion string) *Helper { // GetCmdBase returns a CmdBase instance configured with values from this helper. // It additionally returns a mechanism to set an error, so func (h *Helper) GetCmdBase(flags *pflag.FlagSet) (*CmdBase, error) { + // terminal is for color/no-color output terminal := h.getUI(flags) + + // logger is configured with verbosity level using --verbosity flag from end users logger, err := h.getLogger() + if err != nil { return nil, err } @@ -186,6 +190,7 @@ func (h *Helper) GetCmdBase(flags *pflag.FlagSet) (*CmdBase, error) { h.TurboVersion, h.clientOpts, ) + return &CmdBase{ UI: terminal, Logger: logger, @@ -216,3 +221,20 @@ func (b *CmdBase) LogError(format string, args ...interface{}) { b.Logger.Error("error", err) b.UI.Error(fmt.Sprintf("%s%s", ui.ERROR_PREFIX, color.RedString(" %v", err))) } + +// LogWarning logs an error and outputs it to the UI. +func (b *CmdBase) LogWarning(prefix string, err error) { + b.Logger.Warn(prefix, "warning", err) + + if prefix != "" { + prefix = " " + prefix + ": " + } + + b.UI.Error(fmt.Sprintf("%s%s%s", ui.WARNING_PREFIX, prefix, color.YellowString(" %v", err))) +} + +// LogInfo logs an message and outputs it to the UI. +func (b *CmdBase) LogInfo(msg string) { + b.Logger.Info(msg) + b.UI.Info(fmt.Sprintf("%s%s", ui.InfoPrefix, color.WhiteString(" %v", msg))) +} diff --git a/cli/internal/run/run.go b/cli/internal/run/run.go index d4e40cb3b7005..c2caba7475d70 100644 --- a/cli/internal/run/run.go +++ b/cli/internal/run/run.go @@ -93,6 +93,7 @@ Arguments passed after '--' will be passed through to the named tasks. func GetCmd(helper *cmdutil.Helper, signalWatcher *signals.Watcher) *cobra.Command { var opts *Opts var flags *pflag.FlagSet + cmd := &cobra.Command{ Use: "run [...] [] -- ", Short: "Run tasks across projects in your monorepo", @@ -119,6 +120,7 @@ func GetCmd(helper *cmdutil.Helper, signalWatcher *signals.Watcher) *cobra.Comma return nil }, } + flags = cmd.Flags() opts = optsFromFlags(flags) return cmd @@ -200,7 +202,7 @@ func (r *run) run(ctx gocontext.Context, targets []string) error { } else if !r.opts.runOpts.noDaemon { turbodClient, err := daemon.GetClient(ctx, r.base.RepoRoot, r.base.Logger, r.base.TurboVersion, daemon.ClientOpts{}) if err != nil { - r.logWarning("", errors.Wrap(err, "failed to contact turbod. Continuing in standalone mode")) + r.base.LogWarning("", errors.Wrap(err, "failed to contact turbod. Continuing in standalone mode")) } else { defer func() { _ = turbodClient.Close() }() r.base.Logger.Debug("running in daemon mode") @@ -221,7 +223,7 @@ func (r *run) run(ctx gocontext.Context, targets []string) error { scmInstance, err := scm.FromInRepo(r.base.RepoRoot.ToStringDuringMigration()) if err != nil { if errors.Is(err, scm.ErrFallback) { - r.logWarning("", err) + r.base.LogWarning("", err) } else { return errors.Wrap(err, "failed to create SCM") } @@ -699,17 +701,6 @@ func getDefaultOptions() *Opts { } } -// logError logs an error and outputs it to the UI. -func (r *run) logWarning(prefix string, err error) { - r.base.Logger.Warn(prefix, "warning", err) - - if prefix != "" { - prefix = " " + prefix + ": " - } - - r.base.UI.Error(fmt.Sprintf("%s%s%s", ui.WARNING_PREFIX, prefix, color.YellowString(" %v", err))) -} - func (r *run) initAnalyticsClient(ctx gocontext.Context) analytics.Client { apiClient := r.base.APIClient var analyticsSink analytics.Sink @@ -727,12 +718,13 @@ func (r *run) initCache(ctx gocontext.Context, rs *runSpec, analyticsClient anal apiClient := r.base.APIClient // Theoretically this is overkill, but bias towards not spamming the console once := &sync.Once{} + return cache.New(rs.Opts.cacheOpts, r.base.RepoRoot, apiClient, analyticsClient, func(_cache cache.Cache, err error) { // Currently the HTTP Cache is the only one that can be disabled. // With a cache system refactor, we might consider giving names to the caches so // we can accurately report them here. once.Do(func() { - r.logWarning("Remote Caching is unavailable", err) + r.base.LogWarning("Remote Caching is unavailable", err) }) }) } @@ -741,10 +733,17 @@ func (r *run) executeTasks(ctx gocontext.Context, g *completeGraph, rs *runSpec, analyticsClient := r.initAnalyticsClient(ctx) defer analyticsClient.CloseWithTimeout(50 * time.Millisecond) + useHTTPCache := !rs.Opts.cacheOpts.SkipRemote + if useHTTPCache { + r.base.LogInfo("• Remote caching enabled") + } else { + r.base.LogInfo("• Remote caching disabled") + } + turboCache, err := r.initCache(ctx, rs, analyticsClient) if err != nil { if errors.Is(err, cache.ErrNoCachesEnabled) { - r.logWarning("No caches are enabled. You can try \"turbo login\", \"turbo link\", or ensuring you are not passing --remote-only to enable caching", nil) + r.base.LogWarning("No caches are enabled. You can try \"turbo login\", \"turbo link\", or ensuring you are not passing --remote-only to enable caching", nil) } else { return errors.Wrap(err, "failed to set up caching") } @@ -856,7 +855,7 @@ func (r *run) executeDryRun(ctx gocontext.Context, engine *core.Scheduler, g *co if err != nil { if errors.Is(err, cache.ErrNoCachesEnabled) { - r.logWarning("No caches are enabled. You can try \"turbo login\", \"turbo link\", or ensuring you are not passing --remote-only to enable caching", nil) + r.base.LogWarning("No caches are enabled. You can try \"turbo login\", \"turbo link\", or ensuring you are not passing --remote-only to enable caching", nil) } else { return nil, errors.Wrap(err, "failed to set up caching") } diff --git a/cli/internal/ui/ui.go b/cli/internal/ui/ui.go index 642a41e49c7d9..8538754a7a5ab 100644 --- a/cli/internal/ui/ui.go +++ b/cli/internal/ui/ui.go @@ -25,6 +25,9 @@ var bold = color.New(color.Bold) var ERROR_PREFIX = color.New(color.Bold, color.FgRed, color.ReverseVideo).Sprint(" ERROR ") var WARNING_PREFIX = color.New(color.Bold, color.FgYellow, color.ReverseVideo).Sprint(" WARNING ") +// InfoPrefix is a colored string for warning level log messages +var InfoPrefix = color.New(color.Bold, color.FgWhite, color.ReverseVideo).Sprint(" INFO ") + var ansiRegex = regexp.MustCompile(ansiEscapeStr) // Dim prints out dimmed text