diff --git a/cli/cliui/cliui.go b/cli/cliui/cliui.go index 9b2189e96bbde..5373fbae25333 100644 --- a/cli/cliui/cliui.go +++ b/cli/cliui/cliui.go @@ -22,6 +22,7 @@ type Styles struct { DateTimeStamp, Error, Field, + Hyperlink, Keyword, Placeholder, Prompt, @@ -149,6 +150,10 @@ func init() { pretty.Wrap("> ", ""), pretty.FgColor(brightBlue), }, + Hyperlink: pretty.Style{ + pretty.FgColor(magenta), + pretty.Underline(), + }, Keyword: pretty.Style{ pretty.FgColor(green), }, diff --git a/cli/login.go b/cli/login.go index a6cf7fc04ce22..484de69fdf1b5 100644 --- a/cli/login.go +++ b/cli/login.go @@ -416,6 +416,9 @@ func isWSL() (bool, error) { // openURL opens the provided URL via user's default browser func openURL(inv *serpent.Invocation, urlToOpen string) error { + if !isTTYOut(inv) { + return xerrors.New("skipping browser open in non-interactive mode") + } noOpen, err := inv.ParsedFlags().GetBool(varNoOpen) if err != nil { panic(err) diff --git a/cli/root.go b/cli/root.go index 085c5e1d7f149..2b6cc2c19c8ec 100644 --- a/cli/root.go +++ b/cli/root.go @@ -695,14 +695,7 @@ func namedWorkspace(ctx context.Context, client *codersdk.Client, identifier str func initAppearance(client *codersdk.Client, outConfig *codersdk.AppearanceConfig) serpent.MiddlewareFunc { return func(next serpent.HandlerFunc) serpent.HandlerFunc { return func(inv *serpent.Invocation) error { - var err error - cfg, err := client.Appearance(inv.Context()) - if err != nil { - var sdkErr *codersdk.Error - if !(xerrors.As(err, &sdkErr) && sdkErr.StatusCode() == http.StatusNotFound) { - return err - } - } + cfg, _ := client.Appearance(inv.Context()) if cfg.DocsURL == "" { cfg.DocsURL = codersdk.DefaultDocsURL() } diff --git a/cli/server.go b/cli/server.go index 17d078a1549c9..561c1bac16375 100644 --- a/cli/server.go +++ b/cli/server.go @@ -32,6 +32,7 @@ import ( "sync/atomic" "time" + "github.com/charmbracelet/lipgloss" "github.com/coreos/go-oidc/v3/oidc" "github.com/coreos/go-systemd/daemon" embeddedpostgres "github.com/fergusstrange/embedded-postgres" @@ -483,8 +484,15 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. ) } - // A newline is added before for visibility in terminal output. - cliui.Infof(inv.Stdout, "\nView the Web UI: %s", vals.AccessURL.String()) + accessURL := vals.AccessURL.String() + cliui.Infof(inv.Stdout, lipgloss.NewStyle(). + Border(lipgloss.DoubleBorder()). + Align(lipgloss.Center). + Padding(0, 3). + BorderForeground(lipgloss.Color("12")). + Render(fmt.Sprintf("View the Web UI:\n%s", + pretty.Sprint(cliui.DefaultStyles.Hyperlink, accessURL)))) + _ = openURL(inv, accessURL) // Used for zero-trust instance identity with Google Cloud. googleTokenValidator, err := idtoken.NewValidator(ctx, option.WithoutAuthentication()) @@ -1438,6 +1446,7 @@ func newProvisionerDaemon( // Omit any duplicates provisionerTypes = slice.Unique(provisionerTypes) + provisionerLogger := logger.Named(fmt.Sprintf("provisionerd-%s", name)) // Populate the connector with the supported types. connector := provisionerd.LocalProvisioners{} @@ -1494,7 +1503,7 @@ func newProvisionerDaemon( err := terraform.Serve(ctx, &terraform.ServeOptions{ ServeOptions: &provisionersdk.ServeOptions{ Listener: terraformServer, - Logger: logger.Named("terraform"), + Logger: provisionerLogger, WorkDirectory: workDir, }, CachePath: tfDir, @@ -1519,7 +1528,7 @@ func newProvisionerDaemon( // in provisionerdserver.go to learn more! return coderAPI.CreateInMemoryProvisionerDaemon(dialCtx, name, provisionerTypes) }, &provisionerd.Options{ - Logger: logger.Named(fmt.Sprintf("provisionerd-%s", name)), + Logger: provisionerLogger, UpdateInterval: time.Second, ForceCancelInterval: cfg.Provisioner.ForceCancelInterval.Value(), Connector: connector, diff --git a/cli/server_test.go b/cli/server_test.go index 80f26bf232d33..ad6a98038c7bb 100644 --- a/cli/server_test.go +++ b/cli/server_test.go @@ -221,7 +221,8 @@ func TestServer(t *testing.T) { _ = waitAccessURL(t, cfg) pty.ExpectMatch("this may cause unexpected problems when creating workspaces") - pty.ExpectMatch("View the Web UI: http://localhost:3000/") + pty.ExpectMatch("View the Web UI:") + pty.ExpectMatch("http://localhost:3000/") }) // Validate that an https scheme is prepended to a remote access URL @@ -244,7 +245,8 @@ func TestServer(t *testing.T) { _ = waitAccessURL(t, cfg) pty.ExpectMatch("this may cause unexpected problems when creating workspaces") - pty.ExpectMatch("View the Web UI: https://foobarbaz.mydomain") + pty.ExpectMatch("View the Web UI:") + pty.ExpectMatch("https://foobarbaz.mydomain") }) t.Run("NoWarningWithRemoteAccessURL", func(t *testing.T) { @@ -262,7 +264,8 @@ func TestServer(t *testing.T) { // Just wait for startup _ = waitAccessURL(t, cfg) - pty.ExpectMatch("View the Web UI: https://google.com") + pty.ExpectMatch("View the Web UI:") + pty.ExpectMatch("https://google.com") }) t.Run("NoSchemeAccessURL", func(t *testing.T) { diff --git a/coderd/coderd.go b/coderd/coderd.go index 2cb2388fa77a0..83a780474825b 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -1505,7 +1505,7 @@ func (api *API) CreateInMemoryTaggedProvisionerDaemon(dialCtx context.Context, n } mux := drpcmux.New() - api.Logger.Info(dialCtx, "starting in-memory provisioner daemon", slog.F("name", name)) + api.Logger.Debug(dialCtx, "starting in-memory provisioner daemon", slog.F("name", name)) logger := api.Logger.Named(fmt.Sprintf("inmem-provisionerd-%s", name)) srv, err := provisionerdserver.NewServer( api.ctx, // use the same ctx as the API diff --git a/coderd/database/pubsub/pubsub.go b/coderd/database/pubsub/pubsub.go index 79be4bd602032..fa4dc8b90b1d0 100644 --- a/coderd/database/pubsub/pubsub.go +++ b/coderd/database/pubsub/pubsub.go @@ -413,7 +413,7 @@ func (d logDialer) DialContext(ctx context.Context, network, address string) (ne logger := d.logger.With(slog.F("network", network), slog.F("address", address), slog.F("timeout_ms", timeoutMS)) - logger.Info(ctx, "pubsub dialing postgres") + logger.Debug(ctx, "pubsub dialing postgres") start := time.Now() conn, err := d.d.DialContext(ctx, network, address) if err != nil { @@ -421,7 +421,7 @@ func (d logDialer) DialContext(ctx context.Context, network, address string) (ne return nil, err } elapsed := time.Since(start) - logger.Info(ctx, "pubsub postgres TCP connection established", slog.F("elapsed_ms", elapsed.Milliseconds())) + logger.Debug(ctx, "pubsub postgres TCP connection established", slog.F("elapsed_ms", elapsed.Milliseconds())) return conn, nil } @@ -466,7 +466,7 @@ func (p *PGPubsub) startListener(ctx context.Context, connectURL string) error { Listener: pq.NewConnectorListener(connector, connectURL, time.Second, time.Minute, func(t pq.ListenerEventType, err error) { switch t { case pq.ListenerEventConnected: - p.logger.Info(ctx, "pubsub connected to postgres") + p.logger.Debug(ctx, "pubsub connected to postgres") p.connected.Set(1.0) case pq.ListenerEventDisconnected: p.logger.Error(ctx, "pubsub disconnected from postgres", slog.Error(err)) @@ -618,7 +618,7 @@ func New(startCtx context.Context, logger slog.Logger, db *sql.DB, connectURL st return nil, err } go p.listen() - logger.Info(startCtx, "pubsub has started") + logger.Debug(startCtx, "pubsub has started") return p, nil } diff --git a/enterprise/cli/proxyserver.go b/enterprise/cli/proxyserver.go index 9c528dd42add7..686055039b77e 100644 --- a/enterprise/cli/proxyserver.go +++ b/enterprise/cli/proxyserver.go @@ -14,6 +14,7 @@ import ( rpprof "runtime/pprof" "time" + "github.com/charmbracelet/lipgloss" "github.com/coreos/go-systemd/daemon" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/collectors" @@ -29,6 +30,7 @@ import ( "github.com/coder/coder/v2/coderd/workspaceapps/appurl" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/enterprise/wsproxy" + "github.com/coder/pretty" "github.com/coder/serpent" ) @@ -202,8 +204,14 @@ func (r *RootCmd) proxyServer() *serpent.Command { headerTransport.Transport = httpClient.Transport httpClient.Transport = headerTransport - // A newline is added before for visibility in terminal output. - cliui.Infof(inv.Stdout, "\nView the Web UI: %s", cfg.AccessURL.String()) + accessURL := cfg.AccessURL.String() + cliui.Infof(inv.Stdout, lipgloss.NewStyle(). + Border(lipgloss.DoubleBorder()). + Align(lipgloss.Center). + Padding(0, 3). + BorderForeground(lipgloss.Color("12")). + Render(fmt.Sprintf("View the Web UI:\n%s", + pretty.Sprint(cliui.DefaultStyles.Hyperlink, accessURL)))) var appHostnameRegex *regexp.Regexp appHostname := cfg.WildcardAccessURL.String() diff --git a/tailnet/configmaps.go b/tailnet/configmaps.go index fb00fc2a396e1..326186017be4f 100644 --- a/tailnet/configmaps.go +++ b/tailnet/configmaps.go @@ -147,14 +147,14 @@ func (c *configMaps) configLoop() { if c.derpMapDirty { derpMap := c.derpMapLocked() actions = append(actions, func() { - c.logger.Info(context.Background(), "updating engine DERP map", slog.F("derp_map", (*derpMapStringer)(derpMap))) + c.logger.Debug(context.Background(), "updating engine DERP map", slog.F("derp_map", (*derpMapStringer)(derpMap))) c.engine.SetDERPMap(derpMap) }) } if c.netmapDirty { nm := c.netMapLocked() actions = append(actions, func() { - c.logger.Info(context.Background(), "updating engine network map", slog.F("network_map", nm)) + c.logger.Debug(context.Background(), "updating engine network map", slog.F("network_map", nm)) c.engine.SetNetworkMap(nm) c.reconfig(nm) }) @@ -162,7 +162,7 @@ func (c *configMaps) configLoop() { if c.filterDirty { f := c.filterLocked() actions = append(actions, func() { - c.logger.Info(context.Background(), "updating engine filter", slog.F("filter", f)) + c.logger.Debug(context.Background(), "updating engine filter", slog.F("filter", f)) c.engine.SetFilter(f) }) }