diff --git a/Makefile b/Makefile index 65196d0a4b..943334c780 100644 --- a/Makefile +++ b/Makefile @@ -559,7 +559,7 @@ docs/admin/prometheus.md: scripts/metricsdocgen/main.go scripts/metricsdocgen/me pnpm run format:write:only ./docs/admin/prometheus.md docs/cli.md: scripts/clidocgen/main.go examples/examples.gen.json $(GO_SRC_FILES) - BASE_PATH="." go run ./scripts/clidocgen + CI=true BASE_PATH="." go run ./scripts/clidocgen pnpm run format:write:only ./docs/cli.md ./docs/cli/*.md ./docs/manifest.json docs/admin/audit-logs.md: scripts/auditdocgen/main.go enterprise/audit/table.go coderd/rbac/object_gen.go diff --git a/cli/clitest/golden.go b/cli/clitest/golden.go index 8abaaeb3d1..61dbb5e9f9 100644 --- a/cli/clitest/golden.go +++ b/cli/clitest/golden.go @@ -11,11 +11,11 @@ import ( "strings" "testing" - "github.com/charmbracelet/lipgloss" "github.com/muesli/termenv" "github.com/stretchr/testify/require" "github.com/coder/coder/v2/cli/clibase" + "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/cli/config" "github.com/coder/coder/v2/coderd/coderdtest" "github.com/coder/coder/v2/coderd/database/dbtestutil" @@ -53,13 +53,9 @@ func DefaultCases() []CommandHelpCase { // //nolint:tparallel,paralleltest func TestCommandHelp(t *testing.T, getRoot func(t *testing.T) *clibase.Cmd, cases []CommandHelpCase) { - ogColorProfile := lipgloss.ColorProfile() // ANSI256 escape codes are far easier for humans to parse in a diff, // but TrueColor is probably more popular with modern terminals. - lipgloss.SetColorProfile(termenv.ANSI) - t.Cleanup(func() { - lipgloss.SetColorProfile(ogColorProfile) - }) + cliui.TestColor(t, termenv.ANSI) rootClient, replacements := prepareTestData(t) root := getRoot(t) diff --git a/cli/cliui/cliui.go b/cli/cliui/cliui.go index b59ccd6129..ad8ee442b6 100644 --- a/cli/cliui/cliui.go +++ b/cli/cliui/cliui.go @@ -2,11 +2,13 @@ package cliui import ( "os" + "testing" + "time" - "github.com/charmbracelet/charm/ui/common" - "github.com/charmbracelet/lipgloss" "github.com/muesli/termenv" "golang.org/x/xerrors" + + "github.com/coder/pretty" ) var Canceled = xerrors.New("canceled") @@ -15,55 +17,142 @@ var Canceled = xerrors.New("canceled") var DefaultStyles Styles type Styles struct { - Bold, - Checkmark, Code, - Crossmark, DateTimeStamp, Error, Field, Keyword, - Paragraph, Placeholder, Prompt, FocusedPrompt, Fuchsia, - Logo, Warn, - Wrap lipgloss.Style + Wrap pretty.Style +} + +var color = termenv.NewOutput(os.Stdout).ColorProfile() + +// TestColor sets the color profile to the given profile for the duration of the +// test. +// WARN: Must not be used in parallel tests. +func TestColor(t *testing.T, tprofile termenv.Profile) { + old := color + color = tprofile + t.Cleanup(func() { + color = old + }) +} + +var ( + Green = color.Color("#04B575") + Red = color.Color("#ED567A") + Fuchsia = color.Color("#EE6FF8") + Yellow = color.Color("#ECFD65") + Blue = color.Color("#5000ff") +) + +func isTerm() bool { + return color != termenv.Ascii +} + +// Bold returns a formatter that renders text in bold +// if the terminal supports it. +func Bold(s string) string { + if !isTerm() { + return s + } + return pretty.Sprint(pretty.Bold(), s) +} + +// BoldFmt returns a formatter that renders text in bold +// if the terminal supports it. +func BoldFmt() pretty.Formatter { + if !isTerm() { + return pretty.Style{} + } + return pretty.Bold() +} + +// Timestamp formats a timestamp for display. +func Timestamp(t time.Time) string { + return pretty.Sprint(DefaultStyles.DateTimeStamp, t.Format(time.Stamp)) +} + +// Keyword formats a keyword for display. +func Keyword(s string) string { + return pretty.Sprint(DefaultStyles.Keyword, s) +} + +// Placeholder formats a placeholder for display. +func Placeholder(s string) string { + return pretty.Sprint(DefaultStyles.Placeholder, s) +} + +// Wrap prevents the text from overflowing the terminal. +func Wrap(s string) string { + return pretty.Sprint(DefaultStyles.Wrap, s) +} + +// Code formats code for display. +func Code(s string) string { + return pretty.Sprint(DefaultStyles.Code, s) +} + +// Field formats a field for display. +func Field(s string) string { + return pretty.Sprint(DefaultStyles.Field, s) +} + +func ifTerm(fmt pretty.Formatter) pretty.Formatter { + if !isTerm() { + return pretty.Nop + } + return fmt } func init() { - lipgloss.SetDefaultRenderer( - lipgloss.NewRenderer(os.Stdout, termenv.WithColorCache(true)), - ) - - // All Styles are set after we change the DefaultRenderer so that the ColorCache - // is in effect, mitigating the severe performance issue seen here: - // https://github.com/coder/coder/issues/7884. - - charmStyles := common.DefaultStyles() - + // We do not adapt the color based on whether the terminal is light or dark. + // Doing so would require a round-trip between the program and the terminal + // due to the OSC query and response. DefaultStyles = Styles{ - Bold: lipgloss.NewStyle().Bold(true), - Checkmark: charmStyles.Checkmark, - Code: charmStyles.Code, - Crossmark: charmStyles.Error.Copy().SetString("✘"), - DateTimeStamp: charmStyles.LabelDim, - Error: charmStyles.Error, - Field: charmStyles.Code.Copy().Foreground(lipgloss.AdaptiveColor{Light: "#000000", Dark: "#FFFFFF"}), - Keyword: charmStyles.Keyword, - Paragraph: charmStyles.Paragraph, - Placeholder: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#585858", Dark: "#4d46b3"}), - Prompt: charmStyles.Prompt.Copy().Foreground(lipgloss.AdaptiveColor{Light: "#9B9B9B", Dark: "#5C5C5C"}), - FocusedPrompt: charmStyles.FocusedPrompt.Copy().Foreground(lipgloss.Color("#651fff")), - Fuchsia: charmStyles.SelectedMenuItem.Copy(), - Logo: charmStyles.Logo.Copy().SetString("Coder"), - Warn: lipgloss.NewStyle().Foreground( - lipgloss.AdaptiveColor{Light: "#04B575", Dark: "#ECFD65"}, - ), - Wrap: lipgloss.NewStyle().Width(80), + Code: pretty.Style{ + ifTerm(pretty.XPad(1, 1)), + pretty.FgColor(Red), + pretty.BgColor(color.Color("#2c2c2c")), + }, + DateTimeStamp: pretty.Style{ + pretty.FgColor(color.Color("#7571F9")), + }, + Error: pretty.Style{ + pretty.FgColor(Red), + }, + Field: pretty.Style{ + pretty.XPad(1, 1), + pretty.FgColor(color.Color("#FFFFFF")), + pretty.BgColor(color.Color("#2b2a2a")), + }, + Keyword: pretty.Style{ + pretty.FgColor(Green), + }, + Placeholder: pretty.Style{ + pretty.FgColor(color.Color("#4d46b3")), + }, + Prompt: pretty.Style{ + pretty.FgColor(color.Color("#5C5C5C")), + pretty.Wrap("> ", ""), + }, + Warn: pretty.Style{ + pretty.FgColor(Yellow), + }, + Wrap: pretty.Style{ + pretty.LineWrap(80), + }, } + + DefaultStyles.FocusedPrompt = append( + DefaultStyles.Prompt, + pretty.FgColor(Blue), + ) } // ValidateNotEmpty is a helper function to disallow empty inputs! diff --git a/cli/cliui/log.go b/cli/cliui/log.go index fcc1d9b317..675aed0adc 100644 --- a/cli/cliui/log.go +++ b/cli/cliui/log.go @@ -5,12 +5,12 @@ import ( "io" "strings" - "github.com/charmbracelet/lipgloss" + "github.com/coder/pretty" ) // cliMessage provides a human-readable message for CLI errors and messages. type cliMessage struct { - Style lipgloss.Style + Style pretty.Style Header string Prefix string Lines []string @@ -21,13 +21,13 @@ func (m cliMessage) String() string { var str strings.Builder if m.Prefix != "" { - _, _ = str.WriteString(m.Style.Bold(true).Render(m.Prefix)) + _, _ = str.WriteString(Bold(m.Prefix)) } - _, _ = str.WriteString(m.Style.Bold(false).Render(m.Header)) + pretty.Fprint(&str, m.Style, m.Header) _, _ = str.WriteString("\r\n") for _, line := range m.Lines { - _, _ = fmt.Fprintf(&str, " %s %s\r\n", m.Style.Render("|"), line) + _, _ = fmt.Fprintf(&str, " %s %s\r\n", pretty.Sprint(m.Style, "|"), line) } return str.String() } @@ -35,7 +35,7 @@ func (m cliMessage) String() string { // Warn writes a log to the writer provided. func Warn(wtr io.Writer, header string, lines ...string) { _, _ = fmt.Fprint(wtr, cliMessage{ - Style: DefaultStyles.Warn.Copy(), + Style: DefaultStyles.Warn, Prefix: "WARN: ", Header: header, Lines: lines, @@ -63,7 +63,7 @@ func Infof(wtr io.Writer, fmtStr string, args ...interface{}) { // Error writes a log to the writer provided. func Error(wtr io.Writer, header string, lines ...string) { _, _ = fmt.Fprint(wtr, cliMessage{ - Style: DefaultStyles.Error.Copy(), + Style: DefaultStyles.Error, Prefix: "ERROR: ", Header: header, Lines: lines, diff --git a/cli/cliui/parameter.go b/cli/cliui/parameter.go index a4c8d8e817..3482e285e0 100644 --- a/cli/cliui/parameter.go +++ b/cli/cliui/parameter.go @@ -7,6 +7,7 @@ import ( "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/codersdk" + "github.com/coder/pretty" ) func RichParameter(inv *clibase.Invocation, templateVersionParameter codersdk.TemplateVersionParameter) (string, error) { @@ -16,10 +17,10 @@ func RichParameter(inv *clibase.Invocation, templateVersionParameter codersdk.Te } if templateVersionParameter.Ephemeral { - label += DefaultStyles.Warn.Render(" (build option)") + label += pretty.Sprint(DefaultStyles.Warn, " (build option)") } - _, _ = fmt.Fprintln(inv.Stdout, DefaultStyles.Bold.Render(label)) + _, _ = fmt.Fprintln(inv.Stdout, Bold(label)) if templateVersionParameter.DescriptionPlaintext != "" { _, _ = fmt.Fprintln(inv.Stdout, " "+strings.TrimSpace(strings.Join(strings.Split(templateVersionParameter.DescriptionPlaintext, "\n"), "\n "))+"\n") @@ -45,7 +46,10 @@ func RichParameter(inv *clibase.Invocation, templateVersionParameter codersdk.Te } _, _ = fmt.Fprintln(inv.Stdout) - _, _ = fmt.Fprintln(inv.Stdout, " "+DefaultStyles.Prompt.String()+DefaultStyles.Field.Render(strings.Join(values, ", "))) + pretty.Fprintf( + inv.Stdout, + DefaultStyles.Prompt, "%s\n", strings.Join(values, ", "), + ) value = string(v) } } else if len(templateVersionParameter.Options) > 0 { @@ -59,7 +63,7 @@ func RichParameter(inv *clibase.Invocation, templateVersionParameter codersdk.Te }) if err == nil { _, _ = fmt.Fprintln(inv.Stdout) - _, _ = fmt.Fprintln(inv.Stdout, " "+DefaultStyles.Prompt.String()+DefaultStyles.Field.Render(richParameterOption.Name)) + pretty.Fprintf(inv.Stdout, DefaultStyles.Prompt, "%s\n", richParameterOption.Name) value = richParameterOption.Value } } else { @@ -70,7 +74,7 @@ func RichParameter(inv *clibase.Invocation, templateVersionParameter codersdk.Te text += ":" value, err = Prompt(inv, PromptOptions{ - Text: DefaultStyles.Bold.Render(text), + Text: Bold(text), Validate: func(value string) error { return validateRichPrompt(value, templateVersionParameter) }, diff --git a/cli/cliui/prompt.go b/cli/cliui/prompt.go index ef859814f6..4d7cb6d416 100644 --- a/cli/cliui/prompt.go +++ b/cli/cliui/prompt.go @@ -14,6 +14,7 @@ import ( "golang.org/x/xerrors" "github.com/coder/coder/v2/cli/clibase" + "github.com/coder/pretty" ) // PromptOptions supply a set of options to the prompt. @@ -55,21 +56,24 @@ func Prompt(inv *clibase.Invocation, opts PromptOptions) (string, error) { } } - _, _ = fmt.Fprint(inv.Stdout, DefaultStyles.FocusedPrompt.String()+opts.Text+" ") + pretty.Fprintf(inv.Stdout, DefaultStyles.FocusedPrompt, "") + pretty.Fprintf(inv.Stdout, pretty.Nop, "%s ", opts.Text) if opts.IsConfirm { if len(opts.Default) == 0 { opts.Default = ConfirmYes } - renderedYes := DefaultStyles.Placeholder.Render(ConfirmYes) - renderedNo := DefaultStyles.Placeholder.Render(ConfirmNo) + var ( + renderedYes = pretty.Sprint(DefaultStyles.Placeholder, ConfirmYes) + renderedNo = pretty.Sprint(DefaultStyles.Placeholder, ConfirmNo) + ) if opts.Default == ConfirmYes { - renderedYes = DefaultStyles.Bold.Render(ConfirmYes) + renderedYes = Bold(ConfirmYes) } else { - renderedNo = DefaultStyles.Bold.Render(ConfirmNo) + renderedNo = Bold(ConfirmNo) } - _, _ = fmt.Fprint(inv.Stdout, DefaultStyles.Placeholder.Render("("+renderedYes+DefaultStyles.Placeholder.Render("/"+renderedNo+DefaultStyles.Placeholder.Render(") ")))) + pretty.Fprintf(inv.Stdout, DefaultStyles.Placeholder, "(%s/%s)", renderedYes, renderedNo) } else if opts.Default != "" { - _, _ = fmt.Fprint(inv.Stdout, DefaultStyles.Placeholder.Render("("+opts.Default+") ")) + _, _ = fmt.Fprint(inv.Stdout, pretty.Sprint(DefaultStyles.Placeholder, "("+opts.Default+") ")) } interrupt := make(chan os.Signal, 1) @@ -126,7 +130,7 @@ func Prompt(inv *clibase.Invocation, opts PromptOptions) (string, error) { if opts.Validate != nil { err := opts.Validate(line) if err != nil { - _, _ = fmt.Fprintln(inv.Stdout, DefaultStyles.Error.Render(err.Error())) + _, _ = fmt.Fprintln(inv.Stdout, pretty.Sprint(DefaultStyles.Error, err.Error())) return Prompt(inv, opts) } } diff --git a/cli/cliui/provisionerjob.go b/cli/cliui/provisionerjob.go index b09ac6bc73..aeaea7a34c 100644 --- a/cli/cliui/provisionerjob.go +++ b/cli/cliui/provisionerjob.go @@ -15,6 +15,7 @@ import ( "golang.org/x/xerrors" "github.com/coder/coder/v2/codersdk" + "github.com/coder/pretty" ) func WorkspaceBuild(ctx context.Context, writer io.Writer, client *codersdk.Client, build uuid.UUID) error { @@ -54,7 +55,7 @@ func (err *ProvisionerJobError) Error() string { } // ProvisionerJob renders a provisioner job with interactive cancellation. -func ProvisionerJob(ctx context.Context, writer io.Writer, opts ProvisionerJobOptions) error { +func ProvisionerJob(ctx context.Context, wr io.Writer, opts ProvisionerJobOptions) error { if opts.FetchInterval == 0 { opts.FetchInterval = time.Second } @@ -70,7 +71,7 @@ func ProvisionerJob(ctx context.Context, writer io.Writer, opts ProvisionerJobOp jobMutex sync.Mutex ) - sw := &stageWriter{w: writer, verbose: opts.Verbose, silentLogs: opts.Silent} + sw := &stageWriter{w: wr, verbose: opts.Verbose, silentLogs: opts.Silent} printStage := func() { sw.Start(currentStage) @@ -127,7 +128,11 @@ func ProvisionerJob(ctx context.Context, writer io.Writer, opts ProvisionerJobOp return } } - _, _ = fmt.Fprintf(writer, DefaultStyles.FocusedPrompt.String()+DefaultStyles.Bold.Render("Gracefully canceling...")+"\n\n") + pretty.Fprintf( + wr, + DefaultStyles.FocusedPrompt.With(BoldFmt()), + "Gracefully canceling...\n\n", + ) err := opts.Cancel() if err != nil { errChan <- xerrors.Errorf("cancel: %w", err) @@ -236,7 +241,7 @@ func (s *stageWriter) Log(createdAt time.Time, level codersdk.LogLevel, line str w = &s.logBuf } - render := func(s ...string) string { return strings.Join(s, " ") } + var style pretty.Style var lines []string if !createdAt.IsZero() { @@ -249,14 +254,14 @@ func (s *stageWriter) Log(createdAt time.Time, level codersdk.LogLevel, line str if !s.verbose { return } - render = DefaultStyles.Placeholder.Render + style = DefaultStyles.Placeholder case codersdk.LogLevelError: - render = DefaultStyles.Error.Render + style = DefaultStyles.Error case codersdk.LogLevelWarn: - render = DefaultStyles.Warn.Render + style = DefaultStyles.Warn case codersdk.LogLevelInfo: } - _, _ = fmt.Fprintf(w, "%s\n", render(lines...)) + pretty.Fprintf(w, style, "%s\n", strings.Join(lines, " ")) } func (s *stageWriter) flushLogs() { diff --git a/cli/cliui/resources.go b/cli/cliui/resources.go index a4eb805d88..a9204c968c 100644 --- a/cli/cliui/resources.go +++ b/cli/cliui/resources.go @@ -11,6 +11,7 @@ import ( "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/codersdk" + "github.com/coder/pretty" ) type WorkspaceResourcesOptions struct { @@ -78,7 +79,7 @@ func WorkspaceResources(writer io.Writer, resources []codersdk.WorkspaceResource // Display a line for the resource. tableWriter.AppendRow(table.Row{ - DefaultStyles.Bold.Render(resourceAddress), + Bold(resourceAddress), "", "", "", @@ -107,7 +108,7 @@ func WorkspaceResources(writer io.Writer, resources []codersdk.WorkspaceResource if totalAgents > 1 { sshCommand += "." + agent.Name } - sshCommand = DefaultStyles.Code.Render(sshCommand) + sshCommand = pretty.Sprint(DefaultStyles.Code, sshCommand) row = append(row, sshCommand) } tableWriter.AppendRow(row) @@ -122,31 +123,31 @@ func renderAgentStatus(agent codersdk.WorkspaceAgent) string { switch agent.Status { case codersdk.WorkspaceAgentConnecting: since := dbtime.Now().Sub(agent.CreatedAt) - return DefaultStyles.Warn.Render("⦾ connecting") + " " + - DefaultStyles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]") + return pretty.Sprint(DefaultStyles.Warn, "⦾ connecting") + " " + + pretty.Sprint(DefaultStyles.Placeholder, "["+strconv.Itoa(int(since.Seconds()))+"s]") case codersdk.WorkspaceAgentDisconnected: since := dbtime.Now().Sub(*agent.DisconnectedAt) - return DefaultStyles.Error.Render("⦾ disconnected") + " " + - DefaultStyles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]") + return pretty.Sprint(DefaultStyles.Error, "⦾ disconnected") + " " + + pretty.Sprint(DefaultStyles.Placeholder, "["+strconv.Itoa(int(since.Seconds()))+"s]") case codersdk.WorkspaceAgentTimeout: since := dbtime.Now().Sub(agent.CreatedAt) return fmt.Sprintf( "%s %s", - DefaultStyles.Warn.Render("⦾ timeout"), - DefaultStyles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]"), + pretty.Sprint(DefaultStyles.Warn, "⦾ timeout"), + pretty.Sprint(DefaultStyles.Placeholder, "["+strconv.Itoa(int(since.Seconds()))+"s]"), ) case codersdk.WorkspaceAgentConnected: - return DefaultStyles.Keyword.Render("⦿ connected") + return pretty.Sprint(DefaultStyles.Keyword, "⦿ connected") default: - return DefaultStyles.Warn.Render("○ unknown") + return pretty.Sprint(DefaultStyles.Warn, "○ unknown") } } func renderAgentHealth(agent codersdk.WorkspaceAgent) string { if agent.Health.Healthy { - return DefaultStyles.Keyword.Render("✔ healthy") + return pretty.Sprint(DefaultStyles.Keyword, "✔ healthy") } - return DefaultStyles.Error.Render("✘ " + agent.Health.Reason) + return pretty.Sprint(DefaultStyles.Error, "✘ "+agent.Health.Reason) } func renderAgentVersion(agentVersion, serverVersion string) string { @@ -154,11 +155,11 @@ func renderAgentVersion(agentVersion, serverVersion string) string { agentVersion = "(unknown)" } if !semver.IsValid(serverVersion) || !semver.IsValid(agentVersion) { - return DefaultStyles.Placeholder.Render(agentVersion) + return pretty.Sprint(DefaultStyles.Placeholder, agentVersion) } outdated := semver.Compare(agentVersion, serverVersion) < 0 if outdated { - return DefaultStyles.Warn.Render(agentVersion + " (outdated)") + return pretty.Sprint(DefaultStyles.Warn, agentVersion+" (outdated)") } - return DefaultStyles.Keyword.Render(agentVersion) + return pretty.Sprint(DefaultStyles.Keyword, agentVersion) } diff --git a/cli/create.go b/cli/create.go index 971fbc27aa..d66e89fc48 100644 --- a/cli/create.go +++ b/cli/create.go @@ -10,6 +10,8 @@ import ( "golang.org/x/exp/slices" "golang.org/x/xerrors" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/coderd/util/ptr" @@ -75,7 +77,7 @@ func (r *RootCmd) create() *clibase.Cmd { var template codersdk.Template if templateName == "" { - _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Wrap.Render("Select a template below to preview the provisioned infrastructure:")) + _, _ = fmt.Fprintln(inv.Stdout, pretty.Sprint(cliui.DefaultStyles.Wrap, "Select a template below to preview the provisioned infrastructure:")) templates, err := client.TemplatesByOrganization(inv.Context(), organization.ID) if err != nil { @@ -93,7 +95,7 @@ func (r *RootCmd) create() *clibase.Cmd { templateName := template.Name if template.ActiveUserCount > 0 { - templateName += cliui.DefaultStyles.Placeholder.Render( + templateName += cliui.Placeholder( fmt.Sprintf( " (used by %s)", formatActiveDevelopers(template.ActiveUserCount), @@ -177,7 +179,12 @@ func (r *RootCmd) create() *clibase.Cmd { return xerrors.Errorf("watch build: %w", err) } - _, _ = fmt.Fprintf(inv.Stdout, "\nThe %s workspace has been created at %s!\n", cliui.DefaultStyles.Keyword.Render(workspace.Name), cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))) + _, _ = fmt.Fprintf( + inv.Stdout, + "\nThe %s workspace has been created at %s!\n", + cliui.Keyword(workspace.Name), + cliui.Timestamp(time.Now()), + ) return nil }, } diff --git a/cli/delete.go b/cli/delete.go index 760c0c4e77..a29a821490 100644 --- a/cli/delete.go +++ b/cli/delete.go @@ -54,7 +54,11 @@ func (r *RootCmd) deleteWorkspace() *clibase.Cmd { return err } - _, _ = fmt.Fprintf(inv.Stdout, "\n%s has been deleted at %s!\n", cliui.DefaultStyles.Keyword.Render(workspace.FullName()), cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))) + _, _ = fmt.Fprintf( + inv.Stdout, + "\n%s has been deleted at %s!\n", cliui.Keyword(workspace.FullName()), + cliui.Timestamp(time.Now()), + ) return nil }, } diff --git a/cli/dotfiles.go b/cli/dotfiles.go index 88d57c7089..cf3b1391d5 100644 --- a/cli/dotfiles.go +++ b/cli/dotfiles.go @@ -13,6 +13,8 @@ import ( "golang.org/x/xerrors" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" ) @@ -143,7 +145,7 @@ func (r *RootCmd) dotfiles() *clibase.Cmd { return err } // if the repo exists we soft fail the update operation and try to continue - _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Error.Render("Failed to update repo, continuing...")) + _, _ = fmt.Fprintln(inv.Stdout, pretty.Sprint(cliui.DefaultStyles.Error, "Failed to update repo, continuing...")) } if dotfilesExists && gitbranch != "" { @@ -159,7 +161,7 @@ func (r *RootCmd) dotfiles() *clibase.Cmd { if err != nil { // Do not block on this error, just log it and continue _, _ = fmt.Fprintln(inv.Stdout, - cliui.DefaultStyles.Error.Render(fmt.Sprintf("Failed to use branch %q (%s), continuing...", err.Error(), gitbranch))) + pretty.Sprint(cliui.DefaultStyles.Error, fmt.Sprintf("Failed to use branch %q (%s), continuing...", err.Error(), gitbranch))) } } diff --git a/cli/gitssh.go b/cli/gitssh.go index de5482a8ae..ea461394c3 100644 --- a/cli/gitssh.go +++ b/cli/gitssh.go @@ -16,6 +16,7 @@ import ( "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" + "github.com/coder/pretty" ) func (r *RootCmd) gitssh() *clibase.Cmd { @@ -90,12 +91,15 @@ func (r *RootCmd) gitssh() *clibase.Cmd { exitErr := &exec.ExitError{} if xerrors.As(err, &exitErr) && exitErr.ExitCode() == 255 { _, _ = fmt.Fprintln(inv.Stderr, - "\n"+cliui.DefaultStyles.Wrap.Render("Coder authenticates with "+cliui.DefaultStyles.Field.Render("git")+ - " using the public key below. All clones with SSH are authenticated automatically 🪄.")+"\n") - _, _ = fmt.Fprintln(inv.Stderr, cliui.DefaultStyles.Code.Render(strings.TrimSpace(key.PublicKey))+"\n") + "\n"+pretty.Sprintf( + cliui.DefaultStyles.Wrap, + "Coder authenticates with "+pretty.Sprint(cliui.DefaultStyles.Field, "git")+ + " using the public key below. All clones with SSH are authenticated automatically 🪄.")+"\n", + ) + _, _ = fmt.Fprintln(inv.Stderr, pretty.Sprint(cliui.DefaultStyles.Code, strings.TrimSpace(key.PublicKey))+"\n") _, _ = fmt.Fprintln(inv.Stderr, "Add to GitHub and GitLab:") - _, _ = fmt.Fprintln(inv.Stderr, cliui.DefaultStyles.Prompt.String()+"https://github.com/settings/ssh/new") - _, _ = fmt.Fprintln(inv.Stderr, cliui.DefaultStyles.Prompt.String()+"https://gitlab.com/-/profile/keys") + pretty.Fprintf(inv.Stderr, cliui.DefaultStyles.Prompt, "%s", "https://github.com/settings/ssh/new\n\n") + pretty.Fprintf(inv.Stderr, cliui.DefaultStyles.Prompt, "%s", "https://gitlab.com/-/profile/keys\n\n") _, _ = fmt.Fprintln(inv.Stderr) return err } diff --git a/cli/help.go b/cli/help.go index 3741dbfc28..cd19ecd788 100644 --- a/cli/help.go +++ b/cli/help.go @@ -127,7 +127,7 @@ var usageTemplate = template.Must( return opt.Flag }, "prettyHeader": func(s string) string { - return cliui.DefaultStyles.Bold.Render(s) + return cliui.Bold(s) }, "isEnterprise": func(opt clibase.Option) bool { return opt.Annotations.IsSet("enterprise") diff --git a/cli/list.go b/cli/list.go index e6a1f6fee6..b82d6f3157 100644 --- a/cli/list.go +++ b/cli/list.go @@ -7,6 +7,8 @@ import ( "github.com/google/uuid" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/coderd/schedule/cron" @@ -119,9 +121,9 @@ func (r *RootCmd) list() *clibase.Cmd { return err } if len(res.Workspaces) == 0 { - _, _ = fmt.Fprintln(inv.Stderr, cliui.DefaultStyles.Prompt.String()+"No workspaces found! Create one:") + pretty.Fprintf(inv.Stderr, cliui.DefaultStyles.Prompt, "No workspaces found! Create one:\n") _, _ = fmt.Fprintln(inv.Stderr) - _, _ = fmt.Fprintln(inv.Stderr, " "+cliui.DefaultStyles.Code.Render("coder create ")) + _, _ = fmt.Fprintln(inv.Stderr, " "+pretty.Sprint(cliui.DefaultStyles.Code, "coder create ")) _, _ = fmt.Fprintln(inv.Stderr) return nil } diff --git a/cli/login.go b/cli/login.go index a686037631..73a18a1c40 100644 --- a/cli/login.go +++ b/cli/login.go @@ -16,6 +16,8 @@ import ( "github.com/pkg/browser" "golang.org/x/xerrors" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/coderd/userpassword" @@ -43,7 +45,7 @@ func promptFirstUsername(inv *clibase.Invocation) (string, error) { return "", xerrors.Errorf("get current user: %w", err) } username, err := cliui.Prompt(inv, cliui.PromptOptions{ - Text: "What " + cliui.DefaultStyles.Field.Render("username") + " would you like?", + Text: "What " + pretty.Sprint(cliui.DefaultStyles.Field, "username") + " would you like?", Default: currentUser.Username, }) if errors.Is(err, cliui.Canceled) { @@ -59,7 +61,7 @@ func promptFirstUsername(inv *clibase.Invocation) (string, error) { func promptFirstPassword(inv *clibase.Invocation) (string, error) { retry: password, err := cliui.Prompt(inv, cliui.PromptOptions{ - Text: "Enter a " + cliui.DefaultStyles.Field.Render("password") + ":", + Text: "Enter a " + pretty.Sprint(cliui.DefaultStyles.Field, "password") + ":", Secret: true, Validate: func(s string) error { return userpassword.Validate(s) @@ -69,7 +71,7 @@ retry: return "", xerrors.Errorf("specify password prompt: %w", err) } confirm, err := cliui.Prompt(inv, cliui.PromptOptions{ - Text: "Confirm " + cliui.DefaultStyles.Field.Render("password") + ":", + Text: "Confirm " + pretty.Sprint(cliui.DefaultStyles.Field, "password") + ":", Secret: true, Validate: cliui.ValidateNotEmpty, }) @@ -78,7 +80,7 @@ retry: } if confirm != password { - _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Error.Render("Passwords do not match")) + _, _ = fmt.Fprintln(inv.Stdout, pretty.Sprint(cliui.DefaultStyles.Error, "Passwords do not match")) goto retry } @@ -115,12 +117,8 @@ func (r *RootCmd) loginWithPassword( _, _ = fmt.Fprintf( inv.Stdout, - cliui.DefaultStyles.Paragraph.Render( - fmt.Sprintf( - "Welcome to Coder, %s! You're authenticated.", - cliui.DefaultStyles.Keyword.Render(u.Username), - ), - )+"\n", + "Welcome to Coder, %s! You're authenticated.", + pretty.Sprint(cliui.DefaultStyles.Keyword, u.Username), ) return nil @@ -177,7 +175,7 @@ func (r *RootCmd) login() *clibase.Cmd { if err != nil { // Checking versions isn't a fatal error so we print a warning // and proceed. - _, _ = fmt.Fprintln(inv.Stderr, cliui.DefaultStyles.Warn.Render(err.Error())) + _, _ = fmt.Fprintln(inv.Stderr, pretty.Sprint(cliui.DefaultStyles.Warn, err.Error())) } hasFirstUser, err := client.HasFirstUser(ctx) @@ -209,7 +207,7 @@ func (r *RootCmd) login() *clibase.Cmd { if email == "" { email, err = cliui.Prompt(inv, cliui.PromptOptions{ - Text: "What's your " + cliui.DefaultStyles.Field.Render("email") + "?", + Text: "What's your " + pretty.Sprint(cliui.DefaultStyles.Field, "email") + "?", Validate: func(s string) error { err := validator.New().Var(s, "email") if err != nil { @@ -261,7 +259,9 @@ func (r *RootCmd) login() *clibase.Cmd { _, _ = fmt.Fprintf( inv.Stdout, - cliui.DefaultStyles.Paragraph.Render("Get started by creating a template: "+cliui.DefaultStyles.Code.Render("coder templates init"))+"\n") + "Get started by creating a template: %s\n", + pretty.Sprint(cliui.DefaultStyles.Code, "coder templates init"), + ) return nil } @@ -327,7 +327,7 @@ func (r *RootCmd) login() *clibase.Cmd { return xerrors.Errorf("write server url: %w", err) } - _, _ = fmt.Fprintf(inv.Stdout, Caret+"Welcome to Coder, %s! You're authenticated.\n", cliui.DefaultStyles.Keyword.Render(resp.Username)) + _, _ = fmt.Fprintf(inv.Stdout, Caret+"Welcome to Coder, %s! You're authenticated.\n", pretty.Sprint(cliui.DefaultStyles.Keyword, resp.Username)) return nil }, } diff --git a/cli/login_test.go b/cli/login_test.go index 910f58ea1f..89d4cd87b3 100644 --- a/cli/login_test.go +++ b/cli/login_test.go @@ -8,6 +8,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clitest" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/coderd/coderdtest" @@ -141,7 +143,7 @@ func TestLogin(t *testing.T) { // Validate that we reprompt for matching passwords. pty.ExpectMatch("Passwords do not match") - pty.ExpectMatch("Enter a " + cliui.DefaultStyles.Field.Render("password")) + pty.ExpectMatch("Enter a " + pretty.Sprint(cliui.DefaultStyles.Field, "password")) pty.WriteLine("SomeSecurePassword!") pty.ExpectMatch("Confirm") diff --git a/cli/parameterresolver.go b/cli/parameterresolver.go index 486188d52a..97cf622b75 100644 --- a/cli/parameterresolver.go +++ b/cli/parameterresolver.go @@ -5,6 +5,8 @@ import ( "golang.org/x/xerrors" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/codersdk" @@ -203,7 +205,7 @@ func (pr *ParameterResolver) resolveWithInput(resolved []codersdk.WorkspaceBuild Value: parameterValue, }) } else if action == WorkspaceUpdate && !tvp.Mutable && !firstTimeUse { - _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Warn.Render(fmt.Sprintf("Parameter %q is not mutable, and cannot be customized after workspace creation.", tvp.Name))) + _, _ = fmt.Fprintln(inv.Stdout, pretty.Sprint(cliui.DefaultStyles.Warn, fmt.Sprintf("Parameter %q is not mutable, and cannot be customized after workspace creation.", tvp.Name))) } } return resolved, nil diff --git a/cli/ping.go b/cli/ping.go index a3075a85ad..2df0d57446 100644 --- a/cli/ping.go +++ b/cli/ping.go @@ -10,6 +10,8 @@ import ( "cdr.dev/slog" "cdr.dev/slog/sloggers/sloghuman" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/codersdk" @@ -104,14 +106,14 @@ func (r *RootCmd) ping() *clibase.Cmd { if p2p { if !didP2p { _, _ = fmt.Fprintln(inv.Stdout, "p2p connection established in", - cliui.DefaultStyles.DateTimeStamp.Render(time.Since(start).Round(time.Millisecond).String()), + pretty.Sprint(cliui.DefaultStyles.DateTimeStamp, time.Since(start).Round(time.Millisecond).String()), ) } didP2p = true via = fmt.Sprintf("%s via %s", - cliui.DefaultStyles.Fuchsia.Render("p2p"), - cliui.DefaultStyles.Code.Render(pong.Endpoint), + pretty.Sprint(cliui.DefaultStyles.Fuchsia, "p2p"), + pretty.Sprint(cliui.DefaultStyles.Code, pong.Endpoint), ) } else { derpName := "unknown" @@ -120,15 +122,15 @@ func (r *RootCmd) ping() *clibase.Cmd { derpName = derpRegion.RegionName } via = fmt.Sprintf("%s via %s", - cliui.DefaultStyles.Fuchsia.Render("proxied"), - cliui.DefaultStyles.Code.Render(fmt.Sprintf("DERP(%s)", derpName)), + pretty.Sprint(cliui.DefaultStyles.Fuchsia, "proxied"), + pretty.Sprint(cliui.DefaultStyles.Code, fmt.Sprintf("DERP(%s)", derpName)), ) } _, _ = fmt.Fprintf(inv.Stdout, "pong from %s %s in %s\n", - cliui.DefaultStyles.Keyword.Render(workspaceName), + pretty.Sprint(cliui.DefaultStyles.Keyword, workspaceName), via, - cliui.DefaultStyles.DateTimeStamp.Render(dur.String()), + pretty.Sprint(cliui.DefaultStyles.DateTimeStamp, dur.String()), ) if n == int(pingNum) { diff --git a/cli/publickey.go b/cli/publickey.go index c41c5e2fd4..f6e145377e 100644 --- a/cli/publickey.go +++ b/cli/publickey.go @@ -5,6 +5,8 @@ import ( "golang.org/x/xerrors" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/codersdk" @@ -44,13 +46,13 @@ func (r *RootCmd) publickey() *clibase.Cmd { } cliui.Infof(inv.Stdout, - "This is your public key for using "+cliui.DefaultStyles.Field.Render("git")+" in "+ + "This is your public key for using "+pretty.Sprint(cliui.DefaultStyles.Field, "git")+" in "+ "Coder. All clones with SSH will be authenticated automatically 🪄.", ) - cliui.Infof(inv.Stdout, cliui.DefaultStyles.Code.Render(strings.TrimSpace(key.PublicKey))+"\n") + cliui.Infof(inv.Stdout, pretty.Sprint(cliui.DefaultStyles.Code, strings.TrimSpace(key.PublicKey))+"\n") cliui.Infof(inv.Stdout, "Add to GitHub and GitLab:") - cliui.Infof(inv.Stdout, cliui.DefaultStyles.Prompt.String()+"https://github.com/settings/ssh/new") - cliui.Infof(inv.Stdout, cliui.DefaultStyles.Prompt.String()+"https://gitlab.com/-/profile/keys") + cliui.Infof(inv.Stdout, "> https://github.com/settings/ssh/new") + cliui.Infof(inv.Stdout, "> https://gitlab.com/-/profile/keys") return nil }, diff --git a/cli/rename.go b/cli/rename.go index 94d9fc5517..24a201ab7d 100644 --- a/cli/rename.go +++ b/cli/rename.go @@ -5,6 +5,8 @@ import ( "golang.org/x/xerrors" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/codersdk" @@ -27,7 +29,7 @@ func (r *RootCmd) rename() *clibase.Cmd { } _, _ = fmt.Fprintf(inv.Stdout, "%s\n\n", - cliui.DefaultStyles.Wrap.Render("WARNING: A rename can result in data loss if a resource references the workspace name in the template (e.g volumes). Please backup any data before proceeding."), + pretty.Sprint(cliui.DefaultStyles.Wrap, "WARNING: A rename can result in data loss if a resource references the workspace name in the template (e.g volumes). Please backup any data before proceeding."), ) _, _ = fmt.Fprintf(inv.Stdout, "See: %s\n\n", "https://coder.com/docs/coder-oss/latest/templates/resource-persistence#%EF%B8%8F-persistence-pitfalls") _, err = cliui.Prompt(inv, cliui.PromptOptions{ diff --git a/cli/resetpassword.go b/cli/resetpassword.go index aee1798a51..887aa9575a 100644 --- a/cli/resetpassword.go +++ b/cli/resetpassword.go @@ -8,6 +8,8 @@ import ( "golang.org/x/xerrors" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/coderd/database" @@ -49,7 +51,7 @@ func (*RootCmd) resetPassword() *clibase.Cmd { } password, err := cliui.Prompt(inv, cliui.PromptOptions{ - Text: "Enter new " + cliui.DefaultStyles.Field.Render("password") + ":", + Text: "Enter new " + pretty.Sprint(cliui.DefaultStyles.Field, "password") + ":", Secret: true, Validate: func(s string) error { return userpassword.Validate(s) @@ -59,7 +61,7 @@ func (*RootCmd) resetPassword() *clibase.Cmd { return xerrors.Errorf("password prompt: %w", err) } confirmedPassword, err := cliui.Prompt(inv, cliui.PromptOptions{ - Text: "Confirm " + cliui.DefaultStyles.Field.Render("password") + ":", + Text: "Confirm " + pretty.Sprint(cliui.DefaultStyles.Field, "password") + ":", Secret: true, Validate: cliui.ValidateNotEmpty, }) @@ -83,7 +85,7 @@ func (*RootCmd) resetPassword() *clibase.Cmd { return xerrors.Errorf("updating password: %w", err) } - _, _ = fmt.Fprintf(inv.Stdout, "\nPassword has been reset for user %s!\n", cliui.DefaultStyles.Keyword.Render(user.Username)) + _, _ = fmt.Fprintf(inv.Stdout, "\nPassword has been reset for user %s!\n", pretty.Sprint(cliui.DefaultStyles.Keyword, user.Username)) return nil }, } diff --git a/cli/restart.go b/cli/restart.go index 2f5ca1fff7..a936c30594 100644 --- a/cli/restart.go +++ b/cli/restart.go @@ -6,6 +6,8 @@ import ( "golang.org/x/xerrors" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/codersdk" @@ -92,7 +94,10 @@ func (r *RootCmd) restart() *clibase.Cmd { return err } - _, _ = fmt.Fprintf(out, "\nThe %s workspace has been restarted at %s!\n", cliui.DefaultStyles.Keyword.Render(workspace.Name), cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))) + _, _ = fmt.Fprintf(out, + "\nThe %s workspace has been restarted at %s!\n", + pretty.Sprint(cliui.DefaultStyles.Keyword, workspace.Name), cliui.Timestamp(time.Now()), + ) return nil }, } diff --git a/cli/root.go b/cli/root.go index 53b00e1f6d..2da35c2f98 100644 --- a/cli/root.go +++ b/cli/root.go @@ -30,6 +30,8 @@ import ( "golang.org/x/exp/slices" "golang.org/x/xerrors" + "github.com/coder/pretty" + "cdr.dev/slog" "github.com/coder/coder/v2/buildinfo" "github.com/coder/coder/v2/cli/clibase" @@ -42,7 +44,7 @@ import ( ) var ( - Caret = cliui.DefaultStyles.Prompt.String() + Caret = pretty.Sprint(cliui.DefaultStyles.Prompt, "") // Applied as annotations to workspace commands // so they display in a separated "help" section. @@ -581,15 +583,13 @@ func (r *RootCmd) initClientInternal(client *codersdk.Client, allowTokenMissing if err = <-versionErr; err != nil { // Just log the error here. We never want to fail a command // due to a pre-run. - _, _ = fmt.Fprintf(inv.Stderr, - cliui.DefaultStyles.Warn.Render("check versions error: %s"), err) + pretty.Fprintf(inv.Stderr, cliui.DefaultStyles.Warn, "check versions error: %s", err) _, _ = fmt.Fprintln(inv.Stderr) } if err = <-warningErr; err != nil { // Same as above - _, _ = fmt.Fprintf(inv.Stderr, - cliui.DefaultStyles.Warn.Render("check entitlement warnings error: %s"), err) + pretty.Fprintf(inv.Stderr, cliui.DefaultStyles.Warn, "check entitlement warnings error: %s", err) _, _ = fmt.Fprintln(inv.Stderr) } @@ -753,18 +753,18 @@ type example struct { func formatExamples(examples ...example) string { var sb strings.Builder - padStyle := cliui.DefaultStyles.Wrap.Copy().PaddingLeft(4) + padStyle := cliui.DefaultStyles.Wrap.With(pretty.XPad(4, 0)) for i, e := range examples { if len(e.Description) > 0 { wordwrap.WrapString(e.Description, 80) _, _ = sb.WriteString( - " - " + padStyle.Render(e.Description + ":")[4:] + "\n\n ", + " - " + pretty.Sprint(padStyle, e.Description+":")[4:] + "\n\n ", ) } // We add 1 space here because `cliui.DefaultStyles.Code` adds an extra // space. This makes the code block align at an even 2 or 6 // spaces for symmetry. - _, _ = sb.WriteString(" " + cliui.DefaultStyles.Code.Render(fmt.Sprintf("$ %s", e.Command))) + _, _ = sb.WriteString(" " + pretty.Sprint(cliui.DefaultStyles.Code, fmt.Sprintf("$ %s", e.Command))) if i < len(examples)-1 { _, _ = sb.WriteString("\n\n") } @@ -802,8 +802,8 @@ func (r *RootCmd) checkVersions(i *clibase.Invocation, client *codersdk.Client) } if !buildinfo.VersionsMatch(clientVersion, info.Version) { - warn := cliui.DefaultStyles.Warn.Copy().Align(lipgloss.Left) - _, _ = fmt.Fprintf(i.Stderr, warn.Render(fmtWarningText), clientVersion, info.Version, strings.TrimPrefix(info.CanonicalVersion(), "v")) + warn := cliui.DefaultStyles.Warn + _, _ = fmt.Fprintf(i.Stderr, pretty.Sprint(warn, fmtWarningText), clientVersion, info.Version, strings.TrimPrefix(info.CanonicalVersion(), "v")) _, _ = fmt.Fprintln(i.Stderr) } @@ -821,7 +821,7 @@ func (r *RootCmd) checkWarnings(i *clibase.Invocation, client *codersdk.Client) entitlements, err := client.Entitlements(ctx) if err == nil { for _, w := range entitlements.Warnings { - _, _ = fmt.Fprintln(i.Stderr, cliui.DefaultStyles.Warn.Render(w)) + _, _ = fmt.Fprintln(i.Stderr, pretty.Sprint(cliui.DefaultStyles.Warn, w)) } } return nil @@ -1022,7 +1022,7 @@ func (p *prettyErrorFormatter) printf(style lipgloss.Style, format string, a ... //nolint:unused func SlimUnsupported(w io.Writer, cmd string) { - _, _ = fmt.Fprintf(w, "You are using a 'slim' build of Coder, which does not support the %s subcommand.\n", cliui.DefaultStyles.Code.Render(cmd)) + _, _ = fmt.Fprintf(w, "You are using a 'slim' build of Coder, which does not support the %s subcommand.\n", pretty.Sprint(cliui.DefaultStyles.Code, cmd)) _, _ = fmt.Fprintln(w, "") _, _ = fmt.Fprintln(w, "Please use a build of Coder from GitHub releases:") _, _ = fmt.Fprintln(w, " https://github.com/coder/coder/releases") diff --git a/cli/server.go b/cli/server.go index 63fca59ec3..9526a944f2 100644 --- a/cli/server.go +++ b/cli/server.go @@ -52,6 +52,8 @@ import ( "gopkg.in/yaml.v3" "tailscale.com/tailcfg" + "github.com/coder/pretty" + "cdr.dev/slog" "cdr.dev/slog/sloggers/sloghuman" "cdr.dev/slog/sloggers/slogjson" @@ -512,7 +514,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. cliui.Warnf( inv.Stderr, "The access URL %s %s, this may cause unexpected problems when creating workspaces. Generate a unique *.try.coder.app URL by not specifying an access URL.\n", - cliui.DefaultStyles.Field.Render(vals.AccessURL.String()), reason, + pretty.Sprint(cliui.DefaultStyles.Field, vals.AccessURL.String()), reason, ) } @@ -1026,9 +1028,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. select { case <-notifyCtx.Done(): exitErr = notifyCtx.Err() - _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Bold.Render( - "Interrupt caught, gracefully exiting. Use ctrl+\\ to force quit", - )) + _, _ = io.WriteString(inv.Stdout, cliui.Bold("Interrupt caught, gracefully exiting. Use ctrl+\\ to force quit")) case <-tunnelDone: exitErr = xerrors.New("dev tunnel closed unexpectedly") case exitErr = <-errCh: @@ -1134,7 +1134,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. if pgRawURL { _, _ = fmt.Fprintf(inv.Stdout, "%s\n", url) } else { - _, _ = fmt.Fprintf(inv.Stdout, "%s\n", cliui.DefaultStyles.Code.Render(fmt.Sprintf("psql %q", url))) + _, _ = fmt.Fprintf(inv.Stdout, "%s\n", pretty.Sprint(cliui.DefaultStyles.Code, fmt.Sprintf("psql %q", url))) } return nil }, @@ -1164,7 +1164,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. if pgRawURL { _, _ = fmt.Fprintf(inv.Stdout, "%s\n", url) } else { - _, _ = fmt.Fprintf(inv.Stdout, "%s\n", cliui.DefaultStyles.Code.Render(fmt.Sprintf("psql %q", url))) + _, _ = fmt.Fprintf(inv.Stdout, "%s\n", pretty.Sprint(cliui.DefaultStyles.Code, fmt.Sprintf("psql %q", url))) } <-ctx.Done() @@ -1403,7 +1403,7 @@ func PrintLogo(inv *clibase.Invocation, daemonTitle string) { return } - versionString := cliui.DefaultStyles.Bold.Render(daemonTitle + " " + buildinfo.Version()) + versionString := cliui.Bold(daemonTitle + " " + buildinfo.Version()) _, _ = fmt.Fprintf(inv.Stdout, "%s - Your Self-Hosted Remote Development Platform\n", versionString) } diff --git a/cli/start.go b/cli/start.go index cde5152e14..32f14985c7 100644 --- a/cli/start.go +++ b/cli/start.go @@ -71,7 +71,10 @@ func (r *RootCmd) start() *clibase.Cmd { return err } - _, _ = fmt.Fprintf(inv.Stdout, "\nThe %s workspace has been started at %s!\n", cliui.DefaultStyles.Keyword.Render(workspace.Name), cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))) + _, _ = fmt.Fprintf( + inv.Stdout, "\nThe %s workspace has been started at %s!\n", + cliui.Keyword(workspace.Name), cliui.Timestamp(time.Now()), + ) return nil }, } diff --git a/cli/stop.go b/cli/stop.go index 41265a859f..ea26e426e6 100644 --- a/cli/stop.go +++ b/cli/stop.go @@ -47,7 +47,12 @@ func (r *RootCmd) stop() *clibase.Cmd { return err } - _, _ = fmt.Fprintf(inv.Stdout, "\nThe %s workspace has been stopped at %s!\n", cliui.DefaultStyles.Keyword.Render(workspace.Name), cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))) + _, _ = fmt.Fprintf( + inv.Stdout, + "\nThe %s workspace has been stopped at %s!\n", cliui.Keyword(workspace.Name), + + cliui.Timestamp(time.Now()), + ) return nil }, } diff --git a/cli/templatecreate.go b/cli/templatecreate.go index 5089260c86..2ac9cef963 100644 --- a/cli/templatecreate.go +++ b/cli/templatecreate.go @@ -14,6 +14,8 @@ import ( "github.com/google/uuid" "golang.org/x/xerrors" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/coderd/util/ptr" @@ -144,11 +146,13 @@ func (r *RootCmd) templateCreate() *clibase.Cmd { return err } - _, _ = fmt.Fprintln(inv.Stdout, "\n"+cliui.DefaultStyles.Wrap.Render( - "The "+cliui.DefaultStyles.Keyword.Render(templateName)+" template has been created at "+cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))+"! "+ + _, _ = fmt.Fprintln(inv.Stdout, "\n"+pretty.Sprint(cliui.DefaultStyles.Wrap, + "The "+pretty.Sprint( + cliui.DefaultStyles.Keyword, templateName)+" template has been created at "+ + pretty.Sprint(cliui.DefaultStyles.DateTimeStamp, time.Now().Format(time.Stamp))+"! "+ "Developers can provision a workspace with this template using:")+"\n") - _, _ = fmt.Fprintln(inv.Stdout, " "+cliui.DefaultStyles.Code.Render(fmt.Sprintf("coder create --template=%q [workspace name]", templateName))) + _, _ = fmt.Fprintln(inv.Stdout, " "+pretty.Sprint(cliui.DefaultStyles.Code, fmt.Sprintf("coder create --template=%q [workspace name]", templateName))) _, _ = fmt.Fprintln(inv.Stdout) return nil @@ -331,12 +335,12 @@ func prettyDirectoryPath(dir string) string { if err != nil { return dir } - pretty := dir - if strings.HasPrefix(pretty, homeDir) { - pretty = strings.TrimPrefix(pretty, homeDir) - pretty = "~" + pretty + prettyDir := dir + if strings.HasPrefix(prettyDir, homeDir) { + prettyDir = strings.TrimPrefix(prettyDir, homeDir) + prettyDir = "~" + prettyDir } - return pretty + return prettyDir } func ParseProvisionerTags(rawTags []string) (map[string]string, error) { diff --git a/cli/templatedelete.go b/cli/templatedelete.go index 9380279d6a..6cb4213a93 100644 --- a/cli/templatedelete.go +++ b/cli/templatedelete.go @@ -7,6 +7,8 @@ import ( "golang.org/x/xerrors" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/codersdk" @@ -77,7 +79,7 @@ func (r *RootCmd) templateDelete() *clibase.Cmd { // Confirm deletion of the template. _, err = cliui.Prompt(inv, cliui.PromptOptions{ - Text: fmt.Sprintf("Delete these templates: %s?", cliui.DefaultStyles.Code.Render(strings.Join(templateNames, ", "))), + Text: fmt.Sprintf("Delete these templates: %s?", pretty.Sprint(cliui.DefaultStyles.Code, strings.Join(templateNames, ", "))), IsConfirm: true, Default: cliui.ConfirmNo, }) @@ -91,7 +93,9 @@ func (r *RootCmd) templateDelete() *clibase.Cmd { return xerrors.Errorf("delete template %q: %w", template.Name, err) } - _, _ = fmt.Fprintln(inv.Stdout, "Deleted template "+cliui.DefaultStyles.Code.Render(template.Name)+" at "+cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))+"!") + _, _ = fmt.Fprintln( + inv.Stdout, "Deleted template "+pretty.Sprint(cliui.DefaultStyles.Keyword, template.Name)+" at "+cliui.Timestamp(time.Now()), + ) } return nil diff --git a/cli/templatedelete_test.go b/cli/templatedelete_test.go index 963ece08ab..1e7ecfc61c 100644 --- a/cli/templatedelete_test.go +++ b/cli/templatedelete_test.go @@ -8,6 +8,8 @@ import ( "github.com/stretchr/testify/require" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clitest" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/coderd/coderdtest" @@ -37,7 +39,7 @@ func TestTemplateDelete(t *testing.T) { execDone <- inv.Run() }() - pty.ExpectMatch(fmt.Sprintf("Delete these templates: %s?", cliui.DefaultStyles.Code.Render(template.Name))) + pty.ExpectMatch(fmt.Sprintf("Delete these templates: %s?", pretty.Sprint(cliui.DefaultStyles.Code, template.Name))) pty.WriteLine("yes") require.NoError(t, <-execDone) @@ -95,7 +97,7 @@ func TestTemplateDelete(t *testing.T) { execDone <- inv.Run() }() - pty.ExpectMatch(fmt.Sprintf("Delete these templates: %s?", cliui.DefaultStyles.Code.Render(strings.Join(templateNames, ", ")))) + pty.ExpectMatch(fmt.Sprintf("Delete these templates: %s?", pretty.Sprint(cliui.DefaultStyles.Code, strings.Join(templateNames, ", ")))) pty.WriteLine("yes") require.NoError(t, <-execDone) diff --git a/cli/templateedit.go b/cli/templateedit.go index d44702b664..f64d2c5fc4 100644 --- a/cli/templateedit.go +++ b/cli/templateedit.go @@ -8,6 +8,8 @@ import ( "golang.org/x/xerrors" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/codersdk" @@ -114,7 +116,7 @@ func (r *RootCmd) templateEdit() *clibase.Cmd { if err != nil { return xerrors.Errorf("update template metadata: %w", err) } - _, _ = fmt.Fprintf(inv.Stdout, "Updated template metadata at %s!\n", cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))) + _, _ = fmt.Fprintf(inv.Stdout, "Updated template metadata at %s!\n", pretty.Sprint(cliui.DefaultStyles.DateTimeStamp, time.Now().Format(time.Stamp))) return nil }, } diff --git a/cli/templateinit.go b/cli/templateinit.go index 47addbf05e..a9577733bc 100644 --- a/cli/templateinit.go +++ b/cli/templateinit.go @@ -17,6 +17,7 @@ import ( "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/examples" "github.com/coder/coder/v2/provisionersdk" + "github.com/coder/pretty" ) func (*RootCmd) templateInit() *clibase.Cmd { @@ -42,17 +43,21 @@ func (*RootCmd) templateInit() *clibase.Cmd { for _, example := range exampleList { name := fmt.Sprintf( "%s\n%s\n%s\n", - cliui.DefaultStyles.Bold.Render(example.Name), - cliui.DefaultStyles.Wrap.Copy().PaddingLeft(6).Render(example.Description), - cliui.DefaultStyles.Keyword.Copy().PaddingLeft(6).Render(example.URL), + cliui.Bold(example.Name), + pretty.Sprint(cliui.DefaultStyles.Wrap.With(pretty.XPad(6, 0)), example.Description), + pretty.Sprint(cliui.DefaultStyles.Keyword.With(pretty.XPad(6, 0)), example.URL), ) optsToID[name] = example.ID } opts := maps.Keys(optsToID) sort.Strings(opts) - _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Wrap.Render( - "A template defines infrastructure as code to be provisioned "+ - "for individual developer workspaces. Select an example to be copied to the active directory:\n")) + _, _ = fmt.Fprintln( + inv.Stdout, + pretty.Sprint( + cliui.DefaultStyles.Wrap, + "A template defines infrastructure as code to be provisioned "+ + "for individual developer workspaces. Select an example to be copied to the active directory:\n"), + ) selected, err := cliui.Select(inv, cliui.SelectOptions{ Options: opts, }) @@ -94,7 +99,7 @@ func (*RootCmd) templateInit() *clibase.Cmd { } else { relPath = "./" + relPath } - _, _ = fmt.Fprintf(inv.Stdout, "Extracting %s to %s...\n", cliui.DefaultStyles.Field.Render(selectedTemplate.ID), relPath) + _, _ = fmt.Fprintf(inv.Stdout, "Extracting %s to %s...\n", pretty.Sprint(cliui.DefaultStyles.Field, selectedTemplate.ID), relPath) err = os.MkdirAll(directory, 0o700) if err != nil { return err @@ -104,8 +109,13 @@ func (*RootCmd) templateInit() *clibase.Cmd { return err } _, _ = fmt.Fprintln(inv.Stdout, "Create your template by running:") - _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Paragraph.Render(cliui.DefaultStyles.Code.Render("cd "+relPath+" && coder templates create"))+"\n") - _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Wrap.Render("Examples provide a starting point and are expected to be edited! 🎨")) + _, _ = fmt.Fprintln( + inv.Stdout, + pretty.Sprint( + cliui.DefaultStyles.Code, + "cd "+relPath+" && coder templates create"), + ) + _, _ = fmt.Fprintln(inv.Stdout, pretty.Sprint(cliui.DefaultStyles.Wrap, "\nExamples provide a starting point and are expected to be edited! 🎨")) return nil }, } diff --git a/cli/templatepush.go b/cli/templatepush.go index 66d61375af..ad4403324d 100644 --- a/cli/templatepush.go +++ b/cli/templatepush.go @@ -11,6 +11,8 @@ import ( "github.com/briandowns/spinner" "golang.org/x/xerrors" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/codersdk" @@ -85,7 +87,7 @@ func (pf *templateUploadFlags) upload(inv *clibase.Invocation, client *codersdk. spin := spinner.New(spinner.CharSets[5], 100*time.Millisecond) spin.Writer = inv.Stdout - spin.Suffix = cliui.DefaultStyles.Keyword.Render(" Uploading directory...") + spin.Suffix = pretty.Sprint(cliui.DefaultStyles.Keyword, " Uploading directory...") spin.Start() defer spin.Stop() @@ -110,7 +112,7 @@ func (pf *templateUploadFlags) checkForLockfile(inv *clibase.Invocation) error { if !hasLockfile { cliui.Warn(inv.Stdout, "No .terraform.lock.hcl file found", "When provisioning, Coder will be unable to cache providers without a lockfile and must download them from the internet each time.", - "Create one by running "+cliui.DefaultStyles.Code.Render("terraform init")+" in your template directory.", + "Create one by running "+pretty.Sprint(cliui.DefaultStyles.Code, "terraform init")+" in your template directory.", ) } return nil @@ -246,9 +248,10 @@ func (r *RootCmd) templatePush() *clibase.Cmd { return err } - _, _ = fmt.Fprintln(inv.Stdout, "\n"+cliui.DefaultStyles.Wrap.Render( - "The "+cliui.DefaultStyles.Keyword.Render(name)+" template has been created at "+cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))+"! "+ - "Developers can provision a workspace with this template using:")+"\n") + _, _ = fmt.Fprintln( + inv.Stdout, "\n"+cliui.Wrap( + "The "+cliui.Keyword(name)+" template has been created at "+cliui.Timestamp(time.Now())+"! "+ + "Developers can provision a workspace with this template using:")+"\n") } else if activate { err = client.UpdateActiveTemplateVersion(inv.Context(), template.ID, codersdk.UpdateActiveTemplateVersion{ ID: job.ID, @@ -258,7 +261,7 @@ func (r *RootCmd) templatePush() *clibase.Cmd { } } - _, _ = fmt.Fprintf(inv.Stdout, "Updated version at %s!\n", cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))) + _, _ = fmt.Fprintf(inv.Stdout, "Updated version at %s!\n", pretty.Sprint(cliui.DefaultStyles.DateTimeStamp, time.Now().Format(time.Stamp))) return nil }, } diff --git a/cli/templates.go b/cli/templates.go index 7ded6a7e5e..3d24ec14b5 100644 --- a/cli/templates.go +++ b/cli/templates.go @@ -5,6 +5,8 @@ import ( "github.com/google/uuid" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/codersdk" @@ -75,7 +77,7 @@ func templatesToRows(templates ...codersdk.Template) []templateTableRow { OrganizationID: template.OrganizationID, Provisioner: template.Provisioner, ActiveVersionID: template.ActiveVersionID, - UsedBy: cliui.DefaultStyles.Fuchsia.Render(formatActiveDevelopers(template.ActiveUserCount)), + UsedBy: pretty.Sprint(cliui.DefaultStyles.Fuchsia, formatActiveDevelopers(template.ActiveUserCount)), DefaultTTL: (time.Duration(template.DefaultTTLMillis) * time.Millisecond), } } diff --git a/cli/templateversions.go b/cli/templateversions.go index 622854c4af..299ae98e96 100644 --- a/cli/templateversions.go +++ b/cli/templateversions.go @@ -101,7 +101,7 @@ func templateVersionsToRows(activeVersionID uuid.UUID, templateVersions ...coder for i, templateVersion := range templateVersions { activeStatus := "" if templateVersion.ID == activeVersionID { - activeStatus = cliui.DefaultStyles.Code.Render(cliui.DefaultStyles.Keyword.Render("Active")) + activeStatus = cliui.Keyword("Active") } rows[i] = templateVersionRow{ diff --git a/cli/testdata/coder_--help.golden b/cli/testdata/coder_--help.golden index 6e988a9f56..a0915fc759 100644 --- a/cli/testdata/coder_--help.golden +++ b/cli/testdata/coder_--help.golden @@ -1,13 +1,13 @@ Usage: coder [global-flags] Coder v0.0.0-devel — A tool for provisioning self-hosted development environments with Terraform. - - Start a Coder server: + - Start a Coder server: -  $ coder server  + $ coder server - - Get started by creating a template from an example: + - Get started by creating a template from an example: -  $ coder templates init  + $ coder templates init Subcommands config-ssh Add an SSH Host entry for your workspaces "ssh diff --git a/cli/testdata/coder_config-ssh_--help.golden b/cli/testdata/coder_config-ssh_--help.golden index 8aa547ccb4..2cb7d69f3e 100644 --- a/cli/testdata/coder_config-ssh_--help.golden +++ b/cli/testdata/coder_config-ssh_--help.golden @@ -2,14 +2,14 @@ Usage: coder config-ssh [flags] Add an SSH Host entry for your workspaces "ssh coder.workspace" -- You can use -o (or --ssh-option) so set SSH options to be used for all your - workspaces: +- You can use -o (or --ssh-option) so set SSH options to be used for all your +workspaces: -  $ coder config-ssh -o ForwardAgent=yes  + $ coder config-ssh -o ForwardAgent=yes - - You can use --dry-run (or -n) to see the changes that would be made: + - You can use --dry-run (or -n) to see the changes that would be made: -  $ coder config-ssh --dry-run  + $ coder config-ssh --dry-run Options --coder-binary-path string, $CODER_SSH_CONFIG_BINARY_PATH diff --git a/cli/testdata/coder_create_--help.golden b/cli/testdata/coder_create_--help.golden index 2e080b6e85..005c913529 100644 --- a/cli/testdata/coder_create_--help.golden +++ b/cli/testdata/coder_create_--help.golden @@ -2,9 +2,9 @@ Usage: coder create [flags] [name] Create a workspace -- Create a workspace for another user (if you have permission): +- Create a workspace for another user (if you have permission): -  $ coder create /  + $ coder create / Options --parameter string-array, $CODER_RICH_PARAMETER diff --git a/cli/testdata/coder_dotfiles_--help.golden b/cli/testdata/coder_dotfiles_--help.golden index 0ff91b7dd1..b72d47860b 100644 --- a/cli/testdata/coder_dotfiles_--help.golden +++ b/cli/testdata/coder_dotfiles_--help.golden @@ -2,9 +2,9 @@ Usage: coder dotfiles [flags] Personalize your workspace by applying a canonical dotfiles repository -- Check out and install a dotfiles repository without prompts: +- Check out and install a dotfiles repository without prompts: -  $ coder dotfiles --yes git@github.com:example/dotfiles.git  + $ coder dotfiles --yes git@github.com:example/dotfiles.git Options -b, --branch string diff --git a/cli/testdata/coder_port-forward_--help.golden b/cli/testdata/coder_port-forward_--help.golden index 35c314d400..ff65b059f5 100644 --- a/cli/testdata/coder_port-forward_--help.golden +++ b/cli/testdata/coder_port-forward_--help.golden @@ -5,27 +5,27 @@ forwarding, use "coder ssh -R". Aliases: tunnel -- Port forward a single TCP port from 1234 in the workspace to port 5678 on - your local machine: +- Port forward a single TCP port from 1234 in the workspace to port 5678 on your +local machine: -  $ coder port-forward --tcp 5678:1234  + $ coder port-forward --tcp 5678:1234 - - Port forward a single UDP port from port 9000 to port 9000 on your local - machine: + - Port forward a single UDP port from port 9000 to port 9000 on your local +machine: -  $ coder port-forward --udp 9000  + $ coder port-forward --udp 9000 - - Port forward multiple TCP ports and a UDP port: + - Port forward multiple TCP ports and a UDP port: -  $ coder port-forward --tcp 8080:8080 --tcp 9000:3000 --udp 5353:53  + $ coder port-forward --tcp 8080:8080 --tcp 9000:3000 --udp 5353:53 - - Port forward multiple ports (TCP or UDP) in condensed syntax: + - Port forward multiple ports (TCP or UDP) in condensed syntax: -  $ coder port-forward --tcp 8080,9000:3000,9090-9092,10000-10002:10010-10012  + $ coder port-forward --tcp 8080,9000:3000,9090-9092,10000-10002:10010-10012 - - Port forward specifying the local address to bind to: + - Port forward specifying the local address to bind to: -  $ coder port-forward --tcp 1.2.3.4:8080:8080  + $ coder port-forward --tcp 1.2.3.4:8080:8080 Options -p, --tcp string-array, $CODER_PORT_FORWARD_TCP diff --git a/cli/testdata/coder_schedule_override-stop_--help.golden b/cli/testdata/coder_schedule_override-stop_--help.golden index b0b5ca3050..da5d84210c 100644 --- a/cli/testdata/coder_schedule_override-stop_--help.golden +++ b/cli/testdata/coder_schedule_override-stop_--help.golden @@ -6,7 +6,7 @@ Override the stop time of a currently running workspace instance. * The new stop time must be at least 30 minutes in the future. * The workspace template may restrict the maximum workspace runtime. -  $ coder schedule override-stop my-workspace 90m  + $ coder schedule override-stop my-workspace 90m --- Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_schedule_start_--help.golden b/cli/testdata/coder_schedule_start_--help.golden index 21854d2e39..7420e9a31e 100644 --- a/cli/testdata/coder_schedule_start_--help.golden +++ b/cli/testdata/coder_schedule_start_--help.golden @@ -12,9 +12,9 @@ Schedule format: [day-of-week] [location]. If omitted, we will fall back to either the TZ environment variable or /etc/localtime. You can check your corresponding location by visiting https://ipinfo.io - it shows in the demo widget on the right. - - Set the workspace to start at 9:30am (in Dublin) from Monday to Friday: + - Set the workspace to start at 9:30am (in Dublin) from Monday to Friday: -  $ coder schedule start my-workspace 9:30AM Mon-Fri Europe/Dublin  + $ coder schedule start my-workspace 9:30AM Mon-Fri Europe/Dublin --- Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_schedule_stop_--help.golden b/cli/testdata/coder_schedule_stop_--help.golden index 44cda6c083..73cb9ce2fe 100644 --- a/cli/testdata/coder_schedule_stop_--help.golden +++ b/cli/testdata/coder_schedule_stop_--help.golden @@ -15,7 +15,7 @@ When enabling scheduled stop, enter a duration in one of the following formats: * 2m (2 minutes) * 2 (2 minutes) -  $ coder schedule stop my-workspace 2h30m  + $ coder schedule stop my-workspace 2h30m --- Run `coder --help` for a list of global options. diff --git a/cli/testdata/coder_templates_--help.golden b/cli/testdata/coder_templates_--help.golden index 352695e26f..edd422dd9d 100644 --- a/cli/testdata/coder_templates_--help.golden +++ b/cli/testdata/coder_templates_--help.golden @@ -5,17 +5,17 @@ Manage templates Aliases: template Templates are written in standard Terraform and describe the infrastructure for workspaces - - Create a template for developers to create workspaces: + - Create a template for developers to create workspaces: -  $ coder templates create  + $ coder templates create - - Make changes to your template, and plan the changes: + - Make changes to your template, and plan the changes: -  $ coder templates plan my-template  + $ coder templates plan my-template - Push an update to the template. Your developers can update their workspaces: -  $ coder templates push my-template  + $ coder templates push my-template Subcommands create Create a template from the current directory or as specified by diff --git a/cli/testdata/coder_templates_versions_--help.golden b/cli/testdata/coder_templates_versions_--help.golden index 58636e2ccd..306d6e3869 100644 --- a/cli/testdata/coder_templates_versions_--help.golden +++ b/cli/testdata/coder_templates_versions_--help.golden @@ -4,9 +4,9 @@ Manage different versions of the specified template Aliases: version -- List versions of a specific template: +- List versions of a specific template: -  $ coder templates versions list my-template  + $ coder templates versions list my-template Subcommands list List all the versions of the specified template diff --git a/cli/testdata/coder_tokens_--help.golden b/cli/testdata/coder_tokens_--help.golden index 0ba7c3f1fe..9a98c819c3 100644 --- a/cli/testdata/coder_tokens_--help.golden +++ b/cli/testdata/coder_tokens_--help.golden @@ -5,17 +5,17 @@ Manage personal access tokens Aliases: token Tokens are used to authenticate automated clients to Coder. - - Create a token for automation: + - Create a token for automation: -  $ coder tokens create  + $ coder tokens create - - List your tokens: + - List your tokens: -  $ coder tokens ls  + $ coder tokens ls - - Remove a token by ID: + - Remove a token by ID: -  $ coder tokens rm WuoWs4ZsMX  + $ coder tokens rm WuoWs4ZsMX Subcommands create Create a token diff --git a/cli/testdata/coder_users_activate_--help.golden b/cli/testdata/coder_users_activate_--help.golden index 2d76f72572..f4954ea205 100644 --- a/cli/testdata/coder_users_activate_--help.golden +++ b/cli/testdata/coder_users_activate_--help.golden @@ -5,7 +5,7 @@ platform Aliases: active - $ coder users activate example_user  +$ coder users activate example_user Options -c, --column string-array (default: username,email,created_at,status) diff --git a/cli/testdata/coder_users_show_--help.golden b/cli/testdata/coder_users_show_--help.golden index 2d20c844dd..47cdb3b289 100644 --- a/cli/testdata/coder_users_show_--help.golden +++ b/cli/testdata/coder_users_show_--help.golden @@ -2,7 +2,7 @@ Usage: coder users show [flags] Show a single user. Use 'me' to indicate the currently authenticated user. - $ coder users show me  +$ coder users show me Options -o, --output string (default: table) diff --git a/cli/testdata/coder_users_suspend_--help.golden b/cli/testdata/coder_users_suspend_--help.golden index b5abb4a2c9..7d3d41ea85 100644 --- a/cli/testdata/coder_users_suspend_--help.golden +++ b/cli/testdata/coder_users_suspend_--help.golden @@ -5,7 +5,7 @@ platform Aliases: rm, delete - $ coder users suspend example_user  +$ coder users suspend example_user Options -c, --column string-array (default: username,email,created_at,status) diff --git a/cli/usercreate.go b/cli/usercreate.go index 768e87d826..478cc98e16 100644 --- a/cli/usercreate.go +++ b/cli/usercreate.go @@ -7,6 +7,8 @@ import ( "github.com/go-playground/validator/v10" "golang.org/x/xerrors" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/codersdk" @@ -88,7 +90,7 @@ func (r *RootCmd) userCreate() *clibase.Cmd { authenticationMethod := "" switch codersdk.LoginType(strings.ToLower(string(userLoginType))) { case codersdk.LoginTypePassword: - authenticationMethod = `Your password is: ` + cliui.DefaultStyles.Field.Render(password) + authenticationMethod = `Your password is: ` + pretty.Sprint(cliui.DefaultStyles.Field, password) case codersdk.LoginTypeNone: authenticationMethod = "Login has been disabled for this user. Contact your administrator to authenticate." case codersdk.LoginTypeGithub: @@ -99,16 +101,16 @@ func (r *RootCmd) userCreate() *clibase.Cmd { _, _ = fmt.Fprintln(inv.Stderr, `A new user has been created! Share the instructions below to get them started. -`+cliui.DefaultStyles.Placeholder.Render("—————————————————————————————————————————————————")+` +`+pretty.Sprint(cliui.DefaultStyles.Placeholder, "—————————————————————————————————————————————————")+` Download the Coder command line for your operating system: https://github.com/coder/coder/releases -Run `+cliui.DefaultStyles.Code.Render("coder login "+client.URL.String())+` to authenticate. +Run `+pretty.Sprint(cliui.DefaultStyles.Code, "coder login "+client.URL.String())+` to authenticate. -Your email is: `+cliui.DefaultStyles.Field.Render(email)+` +Your email is: `+pretty.Sprint(cliui.DefaultStyles.Field, email)+` `+authenticationMethod+` -Create a workspace `+cliui.DefaultStyles.Code.Render("coder create")+`!`) +Create a workspace `+pretty.Sprint(cliui.DefaultStyles.Code, "coder create")+`!`) return nil }, } diff --git a/cli/userstatus.go b/cli/userstatus.go index ac3bbaa092..5f516e196b 100644 --- a/cli/userstatus.go +++ b/cli/userstatus.go @@ -6,6 +6,8 @@ import ( "golang.org/x/xerrors" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/codersdk" @@ -89,7 +91,7 @@ func (r *RootCmd) createUserStatusCommand(sdkStatus codersdk.UserStatus) *clibas return xerrors.Errorf("%s user: %w", verb, err) } - _, _ = fmt.Fprintf(inv.Stdout, "\nUser %s has been %s!\n", cliui.DefaultStyles.Keyword.Render(user.Username), pastVerb) + _, _ = fmt.Fprintf(inv.Stdout, "\nUser %s has been %s!\n", pretty.Sprint(cliui.DefaultStyles.Keyword, user.Username), pastVerb) return nil }, } diff --git a/cli/version.go b/cli/version.go index 70cac4f78d..76ae3ffcf6 100644 --- a/cli/version.go +++ b/cli/version.go @@ -5,6 +5,8 @@ import ( "strings" "time" + "github.com/coder/pretty" + "github.com/coder/coder/v2/buildinfo" "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" @@ -39,9 +41,9 @@ func (vi versionInfo) String() string { _, _ = str.WriteString("\r\n" + vi.ExternalURL + "\r\n\r\n") if vi.Slim { - _, _ = str.WriteString(fmt.Sprintf("Slim build of Coder, does not support the %s subcommand.", cliui.DefaultStyles.Code.Render("server"))) + _, _ = str.WriteString(fmt.Sprintf("Slim build of Coder, does not support the %s subcommand.", pretty.Sprint(cliui.DefaultStyles.Code, "server"))) } else { - _, _ = str.WriteString(fmt.Sprintf("Full build of Coder, supports the %s subcommand.", cliui.DefaultStyles.Code.Render("server"))) + _, _ = str.WriteString(fmt.Sprintf("Full build of Coder, supports the %s subcommand.", pretty.Sprint(cliui.DefaultStyles.Code, "server"))) } return str.String() } diff --git a/cli/version_test.go b/cli/version_test.go index 76c4f4392f..5802fff6f1 100644 --- a/cli/version_test.go +++ b/cli/version_test.go @@ -6,28 +6,19 @@ import ( "strings" "testing" - "github.com/charmbracelet/lipgloss" - "github.com/muesli/termenv" "github.com/stretchr/testify/require" "github.com/coder/coder/v2/cli/clitest" "github.com/coder/coder/v2/testutil" ) -// We need to override the global color profile to test escape codes. -// -//nolint:tparallel,paralleltest func TestVersion(t *testing.T) { - ogColorProfile := lipgloss.ColorProfile() - lipgloss.SetColorProfile(termenv.ANSI) - t.Cleanup(func() { - lipgloss.SetColorProfile(ogColorProfile) - }) + t.Parallel() expectedText := `Coder v0.0.0-devel https://github.com/coder/coder -Full build of Coder, supports the  server  subcommand. +Full build of Coder, supports the server subcommand. ` expectedJSON := `{ "version": "v0.0.0-devel", diff --git a/cmd/cliui/main.go b/cmd/cliui/main.go index 749060908f..16137d5733 100644 --- a/cmd/cliui/main.go +++ b/cmd/cliui/main.go @@ -22,16 +22,26 @@ import ( ) func main() { - root := &clibase.Cmd{ + var root *clibase.Cmd + root = &clibase.Cmd{ Use: "cliui", Short: "Used for visually testing UI components for the CLI.", + HelpHandler: func(inv *clibase.Invocation) error { + _, _ = fmt.Fprintln(inv.Stdout, "This command is used for visually testing UI components for the CLI.") + _, _ = fmt.Fprintln(inv.Stdout, "It is not intended to be used by end users.") + _, _ = fmt.Fprintln(inv.Stdout, "Subcommands: ") + for _, child := range root.Children { + _, _ = fmt.Fprintf(inv.Stdout, "- %s\n", child.Use) + } + return nil + }, } root.Children = append(root.Children, &clibase.Cmd{ Use: "prompt", Handler: func(inv *clibase.Invocation) error { _, err := cliui.Prompt(inv, cliui.PromptOptions{ - Text: "What is our " + cliui.DefaultStyles.Field.Render("company name") + "?", + Text: "What is our " + cliui.Field("company name") + "?", Default: "acme-corp", Validate: func(s string) error { if !strings.EqualFold(s, "coder") { diff --git a/coderd/devtunnel/tunnel.go b/coderd/devtunnel/tunnel.go index d61976cef4..89ceace6e4 100644 --- a/coderd/devtunnel/tunnel.go +++ b/coderd/devtunnel/tunnel.go @@ -17,6 +17,7 @@ import ( "cdr.dev/slog" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/cryptorand" + "github.com/coder/pretty" "github.com/coder/wgtunnel/tunnelsdk" ) @@ -114,8 +115,8 @@ func readOrGenerateConfig(customTunnelHost string) (Config, error) { if cfg.Version == 0 { _, _ = fmt.Println() - _, _ = fmt.Println(cliui.DefaultStyles.Error.Render("You're running a deprecated tunnel version!")) - _, _ = fmt.Println(cliui.DefaultStyles.Error.Render("Upgrading you to the new version now. You will need to rebuild running workspaces.")) + pretty.Printf(cliui.DefaultStyles.Error, "You're running a deprecated tunnel version.\n") + pretty.Printf(cliui.DefaultStyles.Error, "Upgrading you to the new version now. You will need to rebuild running workspaces.") _, _ = fmt.Println() cfg, err := GenerateConfig(customTunnelHost) @@ -172,8 +173,8 @@ func GenerateConfig(customTunnelHost string) (Config, error) { spin.Stop() _, _ = fmt.Printf("Using tunnel in %s with latency %s.\n", - cliui.DefaultStyles.Keyword.Render(locationName), - cliui.DefaultStyles.Code.Render(node.AvgLatency.String()), + cliui.Keyword(locationName), + cliui.Code(node.AvgLatency.String()), ) return Config{ diff --git a/docs/cli.md b/docs/cli.md index c9ffdc7c46..a63ccad623 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -14,11 +14,11 @@ coder [global-flags] Coder — A tool for provisioning self-hosted development environments with Terraform. - Start a Coder server: - $ coder server + $ coder server - Get started by creating a template from an example: - $ coder templates init + $ coder templates init ``` ## Subcommands diff --git a/docs/cli/config-ssh.md b/docs/cli/config-ssh.md index 9d5196c824..b46d6bf55b 100644 --- a/docs/cli/config-ssh.md +++ b/docs/cli/config-ssh.md @@ -14,13 +14,13 @@ coder config-ssh [flags] ```console - You can use -o (or --ssh-option) so set SSH options to be used for all your - workspaces: +workspaces: - $ coder config-ssh -o ForwardAgent=yes + $ coder config-ssh -o ForwardAgent=yes - You can use --dry-run (or -n) to see the changes that would be made: - $ coder config-ssh --dry-run + $ coder config-ssh --dry-run ``` ## Options diff --git a/docs/cli/create.md b/docs/cli/create.md index 8c36ea44a3..8cb182528d 100644 --- a/docs/cli/create.md +++ b/docs/cli/create.md @@ -15,7 +15,7 @@ coder create [flags] [name] ```console - Create a workspace for another user (if you have permission): - $ coder create / + $ coder create / ``` ## Options diff --git a/docs/cli/dotfiles.md b/docs/cli/dotfiles.md index 641b292415..59446a8b84 100644 --- a/docs/cli/dotfiles.md +++ b/docs/cli/dotfiles.md @@ -15,7 +15,7 @@ coder dotfiles [flags] ```console - Check out and install a dotfiles repository without prompts: - $ coder dotfiles --yes git@github.com:example/dotfiles.git + $ coder dotfiles --yes git@github.com:example/dotfiles.git ``` ## Options diff --git a/docs/cli/port-forward.md b/docs/cli/port-forward.md index 7919604523..3419269c22 100644 --- a/docs/cli/port-forward.md +++ b/docs/cli/port-forward.md @@ -17,27 +17,27 @@ coder port-forward [flags] ## Description ```console - - Port forward a single TCP port from 1234 in the workspace to port 5678 on - your local machine: + - Port forward a single TCP port from 1234 in the workspace to port 5678 on your +local machine: - $ coder port-forward --tcp 5678:1234 + $ coder port-forward --tcp 5678:1234 - Port forward a single UDP port from port 9000 to port 9000 on your local - machine: +machine: - $ coder port-forward --udp 9000 + $ coder port-forward --udp 9000 - Port forward multiple TCP ports and a UDP port: - $ coder port-forward --tcp 8080:8080 --tcp 9000:3000 --udp 5353:53 + $ coder port-forward --tcp 8080:8080 --tcp 9000:3000 --udp 5353:53 - Port forward multiple ports (TCP or UDP) in condensed syntax: - $ coder port-forward --tcp 8080,9000:3000,9090-9092,10000-10002:10010-10012 + $ coder port-forward --tcp 8080,9000:3000,9090-9092,10000-10002:10010-10012 - Port forward specifying the local address to bind to: - $ coder port-forward --tcp 1.2.3.4:8080:8080 + $ coder port-forward --tcp 1.2.3.4:8080:8080 ``` ## Options diff --git a/docs/cli/schedule_override-stop.md b/docs/cli/schedule_override-stop.md index 2caf7661f1..8c565d734a 100644 --- a/docs/cli/schedule_override-stop.md +++ b/docs/cli/schedule_override-stop.md @@ -18,5 +18,5 @@ coder schedule override-stop * The new stop time must be at least 30 minutes in the future. * The workspace template may restrict the maximum workspace runtime. - $ coder schedule override-stop my-workspace 90m + $ coder schedule override-stop my-workspace 90m ``` diff --git a/docs/cli/schedule_start.md b/docs/cli/schedule_start.md index d967b84487..771bb995e6 100644 --- a/docs/cli/schedule_start.md +++ b/docs/cli/schedule_start.md @@ -25,5 +25,5 @@ Schedule format: [day-of-week] [location]. - Set the workspace to start at 9:30am (in Dublin) from Monday to Friday: - $ coder schedule start my-workspace 9:30AM Mon-Fri Europe/Dublin + $ coder schedule start my-workspace 9:30AM Mon-Fri Europe/Dublin ``` diff --git a/docs/cli/schedule_stop.md b/docs/cli/schedule_stop.md index f00bff4bfb..399bc69cd5 100644 --- a/docs/cli/schedule_stop.md +++ b/docs/cli/schedule_stop.md @@ -26,5 +26,5 @@ When enabling scheduled stop, enter a duration in one of the following formats: * 2m (2 minutes) * 2 (2 minutes) - $ coder schedule stop my-workspace 2h30m + $ coder schedule stop my-workspace 2h30m ``` diff --git a/docs/cli/templates.md b/docs/cli/templates.md index 4426625363..602b4c4fb6 100644 --- a/docs/cli/templates.md +++ b/docs/cli/templates.md @@ -20,15 +20,15 @@ coder templates Templates are written in standard Terraform and describe the infrastructure for workspaces - Create a template for developers to create workspaces: - $ coder templates create + $ coder templates create - Make changes to your template, and plan the changes: - $ coder templates plan my-template + $ coder templates plan my-template - Push an update to the template. Your developers can update their workspaces: - $ coder templates push my-template + $ coder templates push my-template ``` ## Subcommands diff --git a/docs/cli/templates_versions.md b/docs/cli/templates_versions.md index 9114ce1646..5779c22a76 100644 --- a/docs/cli/templates_versions.md +++ b/docs/cli/templates_versions.md @@ -19,7 +19,7 @@ coder templates versions ```console - List versions of a specific template: - $ coder templates versions list my-template + $ coder templates versions list my-template ``` ## Subcommands diff --git a/docs/cli/tokens.md b/docs/cli/tokens.md index a6314c05c9..4e74eb9516 100644 --- a/docs/cli/tokens.md +++ b/docs/cli/tokens.md @@ -20,15 +20,15 @@ coder tokens Tokens are used to authenticate automated clients to Coder. - Create a token for automation: - $ coder tokens create + $ coder tokens create - List your tokens: - $ coder tokens ls + $ coder tokens ls - Remove a token by ID: - $ coder tokens rm WuoWs4ZsMX + $ coder tokens rm WuoWs4ZsMX ``` ## Subcommands diff --git a/docs/cli/users_activate.md b/docs/cli/users_activate.md index 07c001e81d..f5b2d3e8b8 100644 --- a/docs/cli/users_activate.md +++ b/docs/cli/users_activate.md @@ -17,7 +17,7 @@ coder users activate [flags] ## Description ```console - $ coder users activate example_user + $ coder users activate example_user ``` ## Options diff --git a/docs/cli/users_show.md b/docs/cli/users_show.md index 77f9c914c6..dc941a9728 100644 --- a/docs/cli/users_show.md +++ b/docs/cli/users_show.md @@ -13,7 +13,7 @@ coder users show [flags] ## Description ```console - $ coder users show me + $ coder users show me ``` ## Options diff --git a/docs/cli/users_suspend.md b/docs/cli/users_suspend.md index 3c9676b8b4..20c0a3713c 100644 --- a/docs/cli/users_suspend.md +++ b/docs/cli/users_suspend.md @@ -18,7 +18,7 @@ coder users suspend [flags] ## Description ```console - $ coder users suspend example_user + $ coder users suspend example_user ``` ## Options diff --git a/enterprise/cli/groupcreate.go b/enterprise/cli/groupcreate.go index 5f40b79bb4..e5f7bbd8a3 100644 --- a/enterprise/cli/groupcreate.go +++ b/enterprise/cli/groupcreate.go @@ -9,6 +9,7 @@ import ( "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/codersdk" + "github.com/coder/pretty" ) func (r *RootCmd) groupCreate() *clibase.Cmd { @@ -42,7 +43,7 @@ func (r *RootCmd) groupCreate() *clibase.Cmd { return xerrors.Errorf("create group: %w", err) } - _, _ = fmt.Fprintf(inv.Stdout, "Successfully created group %s!\n", cliui.DefaultStyles.Keyword.Render(group.Name)) + _, _ = fmt.Fprintf(inv.Stdout, "Successfully created group %s!\n", pretty.Sprint(cliui.DefaultStyles.Keyword, group.Name)) return nil }, } diff --git a/enterprise/cli/groupcreate_test.go b/enterprise/cli/groupcreate_test.go index 4e9bdfdfb5..783ce12f7c 100644 --- a/enterprise/cli/groupcreate_test.go +++ b/enterprise/cli/groupcreate_test.go @@ -6,6 +6,8 @@ import ( "github.com/stretchr/testify/require" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clitest" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/codersdk" @@ -43,6 +45,6 @@ func TestCreateGroup(t *testing.T) { err := inv.Run() require.NoError(t, err) - pty.ExpectMatch(fmt.Sprintf("Successfully created group %s!", cliui.DefaultStyles.Keyword.Render(groupName))) + pty.ExpectMatch(fmt.Sprintf("Successfully created group %s!", pretty.Sprint(cliui.DefaultStyles.Keyword, groupName))) }) } diff --git a/enterprise/cli/groupdelete.go b/enterprise/cli/groupdelete.go index adada073e3..e7ca01ba36 100644 --- a/enterprise/cli/groupdelete.go +++ b/enterprise/cli/groupdelete.go @@ -9,6 +9,7 @@ import ( "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/codersdk" + "github.com/coder/pretty" ) func (r *RootCmd) groupDelete() *clibase.Cmd { @@ -41,7 +42,7 @@ func (r *RootCmd) groupDelete() *clibase.Cmd { return xerrors.Errorf("delete group: %w", err) } - _, _ = fmt.Fprintf(inv.Stdout, "Successfully deleted group %s!\n", cliui.DefaultStyles.Keyword.Render(group.Name)) + _, _ = fmt.Fprintf(inv.Stdout, "Successfully deleted group %s!\n", pretty.Sprint(cliui.DefaultStyles.Keyword, group.Name)) return nil }, } diff --git a/enterprise/cli/groupdelete_test.go b/enterprise/cli/groupdelete_test.go index c3ff2593e0..21aa6391bd 100644 --- a/enterprise/cli/groupdelete_test.go +++ b/enterprise/cli/groupdelete_test.go @@ -6,6 +6,8 @@ import ( "github.com/stretchr/testify/require" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clitest" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/codersdk" @@ -45,7 +47,7 @@ func TestGroupDelete(t *testing.T) { err = inv.Run() require.NoError(t, err) - pty.ExpectMatch(fmt.Sprintf("Successfully deleted group %s", cliui.DefaultStyles.Keyword.Render(group.Name))) + pty.ExpectMatch(fmt.Sprintf("Successfully deleted group %s", pretty.Sprint(cliui.DefaultStyles.Keyword, group.Name))) }) t.Run("NoArg", func(t *testing.T) { diff --git a/enterprise/cli/groupedit.go b/enterprise/cli/groupedit.go index a1c8db9ab8..8811378bc0 100644 --- a/enterprise/cli/groupedit.go +++ b/enterprise/cli/groupedit.go @@ -7,6 +7,8 @@ import ( "github.com/google/uuid" "golang.org/x/xerrors" + "github.com/coder/pretty" + agpl "github.com/coder/coder/v2/cli" "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" @@ -77,7 +79,7 @@ func (r *RootCmd) groupEdit() *clibase.Cmd { return xerrors.Errorf("patch group: %w", err) } - _, _ = fmt.Fprintf(inv.Stdout, "Successfully patched group %s!\n", cliui.DefaultStyles.Keyword.Render(group.Name)) + _, _ = fmt.Fprintf(inv.Stdout, "Successfully patched group %s!\n", pretty.Sprint(cliui.DefaultStyles.Keyword, group.Name)) return nil }, } diff --git a/enterprise/cli/groupedit_test.go b/enterprise/cli/groupedit_test.go index a6bf396338..a0d192854f 100644 --- a/enterprise/cli/groupedit_test.go +++ b/enterprise/cli/groupedit_test.go @@ -6,6 +6,8 @@ import ( "github.com/stretchr/testify/require" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clitest" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/coderd/coderdtest" @@ -65,7 +67,7 @@ func TestGroupEdit(t *testing.T) { err = inv.Run() require.NoError(t, err) - pty.ExpectMatch(fmt.Sprintf("Successfully patched group %s", cliui.DefaultStyles.Keyword.Render(expectedName))) + pty.ExpectMatch(fmt.Sprintf("Successfully patched group %s", pretty.Sprint(cliui.DefaultStyles.Keyword, expectedName))) }) t.Run("InvalidUserInput", func(t *testing.T) { diff --git a/enterprise/cli/provisionerdaemons.go b/enterprise/cli/provisionerdaemons.go index 124c253595..e63e7cd46c 100644 --- a/enterprise/cli/provisionerdaemons.go +++ b/enterprise/cli/provisionerdaemons.go @@ -147,7 +147,7 @@ func (r *RootCmd) provisionerDaemonStart() *clibase.Cmd { select { case <-notifyCtx.Done(): exitErr = notifyCtx.Err() - _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Bold.Render( + _, _ = fmt.Fprintln(inv.Stdout, cliui.Bold( "Interrupt caught, gracefully exiting. Use ctrl+\\ to force quit", )) case exitErr = <-errCh: diff --git a/enterprise/cli/proxyserver.go b/enterprise/cli/proxyserver.go index e7f4e86507..b3608d1500 100644 --- a/enterprise/cli/proxyserver.go +++ b/enterprise/cli/proxyserver.go @@ -305,7 +305,7 @@ func (*RootCmd) proxyServer() *clibase.Cmd { case exitErr = <-errCh: case <-notifyCtx.Done(): exitErr = notifyCtx.Err() - _, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Bold.Render( + _, _ = fmt.Fprintln(inv.Stdout, cliui.Bold( "Interrupt caught, gracefully exiting. Use ctrl+\\ to force quit", )) } diff --git a/enterprise/cli/testdata/coder_--help.golden b/enterprise/cli/testdata/coder_--help.golden index ae24592079..86a50ec297 100644 --- a/enterprise/cli/testdata/coder_--help.golden +++ b/enterprise/cli/testdata/coder_--help.golden @@ -1,13 +1,13 @@ Usage: coder [global-flags] Coder v0.0.0-devel — A tool for provisioning self-hosted development environments with Terraform. - - Start a Coder server: + - Start a Coder server: -  $ coder server  + $ coder server - - Get started by creating a template from an example: + - Get started by creating a template from an example: -  $ coder templates init  + $ coder templates init Subcommands features List Enterprise features diff --git a/enterprise/cli/workspaceproxy.go b/enterprise/cli/workspaceproxy.go index a0f2004d7a..95f17a251c 100644 --- a/enterprise/cli/workspaceproxy.go +++ b/enterprise/cli/workspaceproxy.go @@ -8,6 +8,8 @@ import ( "github.com/fatih/color" "golang.org/x/xerrors" + "github.com/coder/pretty" + "github.com/coder/coder/v2/cli/clibase" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/codersdk" @@ -206,7 +208,7 @@ func (r *RootCmd) deleteProxy() *clibase.Cmd { // Confirm deletion of the template. _, err = cliui.Prompt(inv, cliui.PromptOptions{ - Text: fmt.Sprintf("Delete this workspace proxy: %s?", cliui.DefaultStyles.Code.Render(wsproxy.DisplayName)), + Text: fmt.Sprintf("Delete this workspace proxy: %s?", pretty.Sprint(cliui.DefaultStyles.Code, wsproxy.DisplayName)), IsConfirm: true, Default: cliui.ConfirmNo, }) @@ -428,14 +430,14 @@ func newUpdateProxyResponseFormatter() *updateProxyResponseFormatter { } return fmt.Sprintf("Workspace Proxy %[1]q updated successfully.\n"+ - cliui.DefaultStyles.Placeholder.Render("—————————————————————————————————————————————————")+"\n"+ + pretty.Sprint(cliui.DefaultStyles.Placeholder, "—————————————————————————————————————————————————")+"\n"+ "Save this authentication token, it will not be shown again.\n"+ "Token: %[2]s\n"+ "\n"+ "Start the proxy by running:\n"+ - cliui.DefaultStyles.Code.Render("CODER_PROXY_SESSION_TOKEN=%[2]s coder wsproxy server --primary-access-url %[3]s --http-address=0.0.0.0:3001")+ + cliui.Code("CODER_PROXY_SESSION_TOKEN=%[2]s coder wsproxy server --primary-access-url %[3]s --http-address=0.0.0.0:3001")+ // This is required to turn off the code style. Otherwise it appears in the code block until the end of the line. - cliui.DefaultStyles.Placeholder.Render(""), + pretty.Sprint(cliui.DefaultStyles.Placeholder, ""), response.Proxy.Name, response.ProxyToken, up.primaryAccessURL), nil }), cliui.JSONFormat(), diff --git a/go.mod b/go.mod index 82c6266b84..0974bae883 100644 --- a/go.mod +++ b/go.mod @@ -79,7 +79,6 @@ require ( github.com/briandowns/spinner v1.18.1 github.com/cakturk/go-netstat v0.0.0-20200220111822-e5b49efee7a5 github.com/cenkalti/backoff/v4 v4.2.1 - github.com/charmbracelet/charm v0.12.4 github.com/charmbracelet/glamour v0.6.0 // In later at least v0.7.1, lipgloss changes its terminal detection // which breaks most of our CLI golden files tests. @@ -245,11 +244,9 @@ require ( github.com/bep/godartsass/v2 v2.0.0 // indirect github.com/bep/golibsass v1.1.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/charmbracelet/bubbles v0.15.0 // indirect - github.com/charmbracelet/bubbletea v0.23.2 // indirect github.com/clbanning/mxj/v2 v2.7.0 // indirect github.com/cloudflare/circl v1.3.3 // indirect - github.com/containerd/console v1.0.3 // indirect + github.com/coder/pretty v0.0.0-20230907185834-1d3e21235f75 github.com/containerd/continuity v0.4.2-0.20230616210509-1e0d26eb2381 // indirect github.com/coreos/go-iptables v0.6.0 // indirect github.com/dlclark/regexp2 v1.10.0 // indirect @@ -321,7 +318,6 @@ require ( github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-localereader v0.0.1 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mdlayher/genetlink v1.3.2 // indirect @@ -336,8 +332,6 @@ require ( github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/term v0.5.0 // indirect - github.com/muesli/ansi v0.0.0-20221106050444-61f0cd9a192a // indirect - github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/reflow v0.3.0 // indirect github.com/niklasfasching/go-org v1.7.0 // indirect github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect diff --git a/go.sum b/go.sum index 92ef6075c4..8f71a9d4ac 100644 --- a/go.sum +++ b/go.sum @@ -124,7 +124,6 @@ github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 h1:7Ip0wMmLHLRJdrloD github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/awalterschulze/gographviz v2.0.3+incompatible h1:9sVEXJBJLwGX7EQVhLm2elIKCm7P2YHFC8v6096G09E= github.com/awalterschulze/gographviz v2.0.3+incompatible/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs= github.com/aws/aws-sdk-go-v2 v1.20.0 h1:INUDpYLt4oiPOJl0XwZDK2OVAVf0Rzo+MGVTv9f+gy8= @@ -154,7 +153,6 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.21.1/go.mod h1:G8SbvL0rFk4WOJroU8tKB github.com/aws/smithy-go v1.14.0 h1:+X90sB94fizKjDmwb4vyl2cTTPXTE5E2G/1mjByb0io= github.com/aws/smithy-go v1.14.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4= -github.com/aymanbagabas/go-osc52 v1.2.1/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= @@ -184,17 +182,8 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/charmbracelet/bubbles v0.15.0 h1:c5vZ3woHV5W2b8YZI1q7v4ZNQaPetfHuoHzx+56Z6TI= -github.com/charmbracelet/bubbles v0.15.0/go.mod h1:Y7gSFbBzlMpUDR/XM9MhZI374Q+1p1kluf1uLl8iK74= -github.com/charmbracelet/bubbletea v0.23.1/go.mod h1:JAfGK/3/pPKHTnAS8JIE2u9f61BjWTQY57RbT25aMXU= -github.com/charmbracelet/bubbletea v0.23.2 h1:vuUJ9HJ7b/COy4I30e8xDVQ+VRDUEFykIjryPfgsdps= -github.com/charmbracelet/bubbletea v0.23.2/go.mod h1:FaP3WUivcTM0xOKNmhciz60M6I+weYLF76mr1JyI7sM= -github.com/charmbracelet/charm v0.12.4 h1:YEB64WxLvdnmmGLiejXlC/e4hAd4a5SY4TqW8bdErv4= -github.com/charmbracelet/charm v0.12.4/go.mod h1:BOvE692iyhnFctYs6Es3gb7xjx/JBgKpR9gxUmqXo3A= github.com/charmbracelet/glamour v0.6.0 h1:wi8fse3Y7nfcabbbDuwolqTqMQPMnVPeZhDM273bISc= github.com/charmbracelet/glamour v0.6.0/go.mod h1:taqWV4swIMMbWALc0m7AfE9JkPSU8om2538k9ITBxOc= -github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= -github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk= github.com/charmbracelet/lipgloss v0.8.0 h1:IS00fk4XAHcf8uZKc3eHeMUTCxUH6NkaTrdyCQk84RU= github.com/charmbracelet/lipgloss v0.8.0/go.mod h1:p4eYUZZJ/0oXTuCQKFF8mqyKCz0ja6y+7DniDDw5KKU= github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= @@ -230,6 +219,8 @@ github.com/coder/go-scim/pkg/v2 v2.0.0-20230221055123-1d63c1222136 h1:0RgB61LcNs github.com/coder/go-scim/pkg/v2 v2.0.0-20230221055123-1d63c1222136/go.mod h1:VkD1P761nykiq75dz+4iFqIQIZka189tx1BQLOp0Skc= github.com/coder/gvisor v0.0.0-20230714132058-be2e4ac102c3 h1:gtuDFa+InmMVUYiurBV+XYu24AeMGv57qlZ23i6rmyE= github.com/coder/gvisor v0.0.0-20230714132058-be2e4ac102c3/go.mod h1:pzr6sy8gDLfVmDAg8OYrlKvGEHw5C3PGTiBXBTCx76Q= +github.com/coder/pretty v0.0.0-20230907185834-1d3e21235f75 h1:cTpm2TCHrJmijom7EUqf5PI3PRQTPz4JDXKWH1XJfpQ= +github.com/coder/pretty v0.0.0-20230907185834-1d3e21235f75/go.mod h1:5UuS2Ts+nTToAMeOjNlnHFkPahrtDkmpydBen/3wgZc= github.com/coder/retry v1.4.0 h1:g0fojHFxcdgM3sBULqgjFDxw1UIvaCqk4ngUDu0EWag= github.com/coder/retry v1.4.0/go.mod h1:blHMk9vs6LkoRT9ZHyuZo360cufXEhrxqvEzeMtRGoY= github.com/coder/ssh v0.0.0-20230621095435-9a7e23486f1c h1:TI7TzdFI0UvQmwgyQhtI1HeyYNRxAQpr8Tw/rjT8VSA= @@ -242,7 +233,6 @@ github.com/coder/wgtunnel v0.1.5 h1:WP3sCj/3iJ34eKvpMQEp1oJHvm24RYh0NHbj1kfUKfs= github.com/coder/wgtunnel v0.1.5/go.mod h1:bokoUrHnUFY4lu9KOeSYiIcHTI2MO1KwqumU4DPDyJI= github.com/coder/wireguard-go v0.0.0-20230807234434-d825b45ccbf5 h1:eDk/42Kj4xN4yfE504LsvcFEo3dWUiCOaBiWJ2uIH2A= github.com/coder/wireguard-go v0.0.0-20230807234434-d825b45ccbf5/go.mod h1:QRIcq2+DbdIC5sKh/gcAZhuqu6WT6L6G8/ALPN5wqYw= -github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/continuity v0.4.2-0.20230616210509-1e0d26eb2381 h1:a5jOuoZHKBi2oH9JsfNqrrPpHhmrYU0NAte3M/EPudw= github.com/containerd/continuity v0.4.2-0.20230616210509-1e0d26eb2381/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= @@ -661,13 +651,9 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= -github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= @@ -717,17 +703,9 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= -github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= -github.com/muesli/ansi v0.0.0-20221106050444-61f0cd9a192a h1:jlDOeO5TU0pYlbc/y6PFguab5IjANI0Knrpg3u/ton4= -github.com/muesli/ansi v0.0.0-20221106050444-61f0cd9a192a/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= -github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= -github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= -github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ= github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= -github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs= github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc= -github.com/muesli/termenv v0.14.0/go.mod h1:kG/pF1E7fh949Xhe156crRUrHNyK221IuGO7Ez60Uc8= github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= @@ -805,7 +783,6 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b h1:gQZ0qzfKHQIybLANtM3mBXNUtOfsCFXeTsnBqCsx1KM= github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= @@ -1171,7 +1148,6 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=