mirror of
https://github.com/coder/coder.git
synced 2025-07-15 22:20:27 +00:00
fix(cli): speed up CLI over SSH (#7885)
By caching the terminal's color profile, we avoid myriad round trips during command execution.
This commit is contained in:
@ -179,7 +179,7 @@ type message struct {
|
|||||||
|
|
||||||
func waitingMessage(agent codersdk.WorkspaceAgent, opts AgentOptions) (m *message) {
|
func waitingMessage(agent codersdk.WorkspaceAgent, opts AgentOptions) (m *message) {
|
||||||
m = &message{
|
m = &message{
|
||||||
Spin: fmt.Sprintf("Waiting for connection from %s...", Styles.Field.Render(agent.Name)),
|
Spin: fmt.Sprintf("Waiting for connection from %s...", DefaultStyles.Field.Render(agent.Name)),
|
||||||
Prompt: "Don't panic, your workspace is booting up!",
|
Prompt: "Don't panic, your workspace is booting up!",
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -192,7 +192,7 @@ func waitingMessage(agent codersdk.WorkspaceAgent, opts AgentOptions) (m *messag
|
|||||||
|
|
||||||
// We don't want to wrap the troubleshooting URL, so we'll handle word
|
// We don't want to wrap the troubleshooting URL, so we'll handle word
|
||||||
// wrapping ourselves (vs using lipgloss).
|
// wrapping ourselves (vs using lipgloss).
|
||||||
w := wordwrap.NewWriter(Styles.Paragraph.GetWidth() - Styles.Paragraph.GetMarginLeft()*2)
|
w := wordwrap.NewWriter(DefaultStyles.Paragraph.GetWidth() - DefaultStyles.Paragraph.GetMarginLeft()*2)
|
||||||
w.Breakpoints = []rune{' ', '\n'}
|
w.Breakpoints = []rune{' ', '\n'}
|
||||||
|
|
||||||
_, _ = fmt.Fprint(w, m.Prompt)
|
_, _ = fmt.Fprint(w, m.Prompt)
|
||||||
@ -208,7 +208,7 @@ func waitingMessage(agent codersdk.WorkspaceAgent, opts AgentOptions) (m *messag
|
|||||||
// We want to prefix the prompt with a caret, but we want text on the
|
// We want to prefix the prompt with a caret, but we want text on the
|
||||||
// following lines to align with the text on the first line (i.e. added
|
// following lines to align with the text on the first line (i.e. added
|
||||||
// spacing).
|
// spacing).
|
||||||
ind := " " + Styles.Prompt.String()
|
ind := " " + DefaultStyles.Prompt.String()
|
||||||
iw := indent.NewWriter(1, func(w io.Writer) {
|
iw := indent.NewWriter(1, func(w io.Writer) {
|
||||||
_, _ = w.Write([]byte(ind))
|
_, _ = w.Write([]byte(ind))
|
||||||
ind = " " // Set indentation to space after initial prompt.
|
ind = " " // Set indentation to space after initial prompt.
|
||||||
@ -223,7 +223,7 @@ func waitingMessage(agent codersdk.WorkspaceAgent, opts AgentOptions) (m *messag
|
|||||||
case codersdk.WorkspaceAgentDisconnected:
|
case codersdk.WorkspaceAgentDisconnected:
|
||||||
m.Prompt = "The workspace agent lost connection!"
|
m.Prompt = "The workspace agent lost connection!"
|
||||||
case codersdk.WorkspaceAgentConnected:
|
case codersdk.WorkspaceAgentConnected:
|
||||||
m.Spin = fmt.Sprintf("Waiting for %s to become ready...", Styles.Field.Render(agent.Name))
|
m.Spin = fmt.Sprintf("Waiting for %s to become ready...", DefaultStyles.Field.Render(agent.Name))
|
||||||
m.Prompt = "Don't panic, your workspace agent has connected and the workspace is getting ready!"
|
m.Prompt = "Don't panic, your workspace agent has connected and the workspace is getting ready!"
|
||||||
if opts.NoWait {
|
if opts.NoWait {
|
||||||
m.Prompt = "Your workspace is still getting ready, it may be in an incomplete state."
|
m.Prompt = "Your workspace is still getting ready, it may be in an incomplete state."
|
||||||
|
@ -1,27 +1,20 @@
|
|||||||
package cliui
|
package cliui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/charmbracelet/charm/ui/common"
|
"github.com/charmbracelet/charm/ui/common"
|
||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
|
"github.com/muesli/termenv"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var Canceled = xerrors.New("canceled")
|
||||||
Canceled = xerrors.New("canceled")
|
|
||||||
|
|
||||||
defaultStyles = common.DefaultStyles()
|
// DefaultStyles compose visual elements of the UI.
|
||||||
)
|
var DefaultStyles Styles
|
||||||
|
|
||||||
// ValidateNotEmpty is a helper function to disallow empty inputs!
|
type Styles struct {
|
||||||
func ValidateNotEmpty(s string) error {
|
|
||||||
if s == "" {
|
|
||||||
return xerrors.New("Must be provided!")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Styles compose visual elements of the UI!
|
|
||||||
var Styles = struct {
|
|
||||||
Bold,
|
Bold,
|
||||||
Checkmark,
|
Checkmark,
|
||||||
Code,
|
Code,
|
||||||
@ -38,23 +31,45 @@ var Styles = struct {
|
|||||||
Logo,
|
Logo,
|
||||||
Warn,
|
Warn,
|
||||||
Wrap lipgloss.Style
|
Wrap lipgloss.Style
|
||||||
}{
|
}
|
||||||
Bold: lipgloss.NewStyle().Bold(true),
|
|
||||||
Checkmark: defaultStyles.Checkmark,
|
func init() {
|
||||||
Code: defaultStyles.Code,
|
lipgloss.SetDefaultRenderer(
|
||||||
Crossmark: defaultStyles.Error.Copy().SetString("✘"),
|
lipgloss.NewRenderer(os.Stdout, termenv.WithColorCache(true)),
|
||||||
DateTimeStamp: defaultStyles.LabelDim,
|
)
|
||||||
Error: defaultStyles.Error,
|
|
||||||
Field: defaultStyles.Code.Copy().Foreground(lipgloss.AdaptiveColor{Light: "#000000", Dark: "#FFFFFF"}),
|
// All Styles are set after we change the DefaultRenderer so that the ColorCache
|
||||||
Keyword: defaultStyles.Keyword,
|
// is in effect, mitigating the severe performance issue seen here:
|
||||||
Paragraph: defaultStyles.Paragraph,
|
// https://github.com/coder/coder/issues/7884.
|
||||||
Placeholder: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#585858", Dark: "#4d46b3"}),
|
|
||||||
Prompt: defaultStyles.Prompt.Copy().Foreground(lipgloss.AdaptiveColor{Light: "#9B9B9B", Dark: "#5C5C5C"}),
|
charmStyles := common.DefaultStyles()
|
||||||
FocusedPrompt: defaultStyles.FocusedPrompt.Copy().Foreground(lipgloss.Color("#651fff")),
|
|
||||||
Fuchsia: defaultStyles.SelectedMenuItem.Copy(),
|
DefaultStyles = Styles{
|
||||||
Logo: defaultStyles.Logo.Copy().SetString("Coder"),
|
Bold: lipgloss.NewStyle().Bold(true),
|
||||||
Warn: lipgloss.NewStyle().Foreground(
|
Checkmark: charmStyles.Checkmark,
|
||||||
lipgloss.AdaptiveColor{Light: "#04B575", Dark: "#ECFD65"},
|
Code: charmStyles.Code,
|
||||||
),
|
Crossmark: charmStyles.Error.Copy().SetString("✘"),
|
||||||
Wrap: lipgloss.NewStyle().Width(80),
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateNotEmpty is a helper function to disallow empty inputs!
|
||||||
|
func ValidateNotEmpty(s string) error {
|
||||||
|
if s == "" {
|
||||||
|
return xerrors.New("Must be provided!")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ func (m cliMessage) String() string {
|
|||||||
// Warn writes a log to the writer provided.
|
// Warn writes a log to the writer provided.
|
||||||
func Warn(wtr io.Writer, header string, lines ...string) {
|
func Warn(wtr io.Writer, header string, lines ...string) {
|
||||||
_, _ = fmt.Fprint(wtr, cliMessage{
|
_, _ = fmt.Fprint(wtr, cliMessage{
|
||||||
Style: Styles.Warn.Copy(),
|
Style: DefaultStyles.Warn.Copy(),
|
||||||
Prefix: "WARN: ",
|
Prefix: "WARN: ",
|
||||||
Header: header,
|
Header: header,
|
||||||
Lines: lines,
|
Lines: lines,
|
||||||
@ -63,7 +63,7 @@ func Infof(wtr io.Writer, fmtStr string, args ...interface{}) {
|
|||||||
// Error writes a log to the writer provided.
|
// Error writes a log to the writer provided.
|
||||||
func Error(wtr io.Writer, header string, lines ...string) {
|
func Error(wtr io.Writer, header string, lines ...string) {
|
||||||
_, _ = fmt.Fprint(wtr, cliMessage{
|
_, _ = fmt.Fprint(wtr, cliMessage{
|
||||||
Style: Styles.Error.Copy(),
|
Style: DefaultStyles.Error.Copy(),
|
||||||
Prefix: "ERROR: ",
|
Prefix: "ERROR: ",
|
||||||
Header: header,
|
Header: header,
|
||||||
Lines: lines,
|
Lines: lines,
|
||||||
|
@ -15,7 +15,7 @@ func RichParameter(inv *clibase.Invocation, templateVersionParameter codersdk.Te
|
|||||||
label = templateVersionParameter.DisplayName
|
label = templateVersionParameter.DisplayName
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, Styles.Bold.Render(label))
|
_, _ = fmt.Fprintln(inv.Stdout, DefaultStyles.Bold.Render(label))
|
||||||
if templateVersionParameter.DescriptionPlaintext != "" {
|
if templateVersionParameter.DescriptionPlaintext != "" {
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, " "+strings.TrimSpace(strings.Join(strings.Split(templateVersionParameter.DescriptionPlaintext, "\n"), "\n "))+"\n")
|
_, _ = fmt.Fprintln(inv.Stdout, " "+strings.TrimSpace(strings.Join(strings.Split(templateVersionParameter.DescriptionPlaintext, "\n"), "\n "))+"\n")
|
||||||
}
|
}
|
||||||
@ -40,7 +40,7 @@ func RichParameter(inv *clibase.Invocation, templateVersionParameter codersdk.Te
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintln(inv.Stdout)
|
_, _ = fmt.Fprintln(inv.Stdout)
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, " "+Styles.Prompt.String()+Styles.Field.Render(strings.Join(values, ", ")))
|
_, _ = fmt.Fprintln(inv.Stdout, " "+DefaultStyles.Prompt.String()+DefaultStyles.Field.Render(strings.Join(values, ", ")))
|
||||||
value = string(v)
|
value = string(v)
|
||||||
}
|
}
|
||||||
} else if len(templateVersionParameter.Options) > 0 {
|
} else if len(templateVersionParameter.Options) > 0 {
|
||||||
@ -54,7 +54,7 @@ func RichParameter(inv *clibase.Invocation, templateVersionParameter codersdk.Te
|
|||||||
})
|
})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
_, _ = fmt.Fprintln(inv.Stdout)
|
_, _ = fmt.Fprintln(inv.Stdout)
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, " "+Styles.Prompt.String()+Styles.Field.Render(richParameterOption.Name))
|
_, _ = fmt.Fprintln(inv.Stdout, " "+DefaultStyles.Prompt.String()+DefaultStyles.Field.Render(richParameterOption.Name))
|
||||||
value = richParameterOption.Value
|
value = richParameterOption.Value
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -65,7 +65,7 @@ func RichParameter(inv *clibase.Invocation, templateVersionParameter codersdk.Te
|
|||||||
text += ":"
|
text += ":"
|
||||||
|
|
||||||
value, err = Prompt(inv, PromptOptions{
|
value, err = Prompt(inv, PromptOptions{
|
||||||
Text: Styles.Bold.Render(text),
|
Text: DefaultStyles.Bold.Render(text),
|
||||||
Validate: func(value string) error {
|
Validate: func(value string) error {
|
||||||
return validateRichPrompt(value, templateVersionParameter)
|
return validateRichPrompt(value, templateVersionParameter)
|
||||||
},
|
},
|
||||||
|
@ -55,21 +55,21 @@ func Prompt(inv *clibase.Invocation, opts PromptOptions) (string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprint(inv.Stdout, Styles.FocusedPrompt.String()+opts.Text+" ")
|
_, _ = fmt.Fprint(inv.Stdout, DefaultStyles.FocusedPrompt.String()+opts.Text+" ")
|
||||||
if opts.IsConfirm {
|
if opts.IsConfirm {
|
||||||
if len(opts.Default) == 0 {
|
if len(opts.Default) == 0 {
|
||||||
opts.Default = ConfirmYes
|
opts.Default = ConfirmYes
|
||||||
}
|
}
|
||||||
renderedYes := Styles.Placeholder.Render(ConfirmYes)
|
renderedYes := DefaultStyles.Placeholder.Render(ConfirmYes)
|
||||||
renderedNo := Styles.Placeholder.Render(ConfirmNo)
|
renderedNo := DefaultStyles.Placeholder.Render(ConfirmNo)
|
||||||
if opts.Default == ConfirmYes {
|
if opts.Default == ConfirmYes {
|
||||||
renderedYes = Styles.Bold.Render(ConfirmYes)
|
renderedYes = DefaultStyles.Bold.Render(ConfirmYes)
|
||||||
} else {
|
} else {
|
||||||
renderedNo = Styles.Bold.Render(ConfirmNo)
|
renderedNo = DefaultStyles.Bold.Render(ConfirmNo)
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprint(inv.Stdout, Styles.Placeholder.Render("("+renderedYes+Styles.Placeholder.Render("/"+renderedNo+Styles.Placeholder.Render(") "))))
|
_, _ = fmt.Fprint(inv.Stdout, DefaultStyles.Placeholder.Render("("+renderedYes+DefaultStyles.Placeholder.Render("/"+renderedNo+DefaultStyles.Placeholder.Render(") "))))
|
||||||
} else if opts.Default != "" {
|
} else if opts.Default != "" {
|
||||||
_, _ = fmt.Fprint(inv.Stdout, Styles.Placeholder.Render("("+opts.Default+") "))
|
_, _ = fmt.Fprint(inv.Stdout, DefaultStyles.Placeholder.Render("("+opts.Default+") "))
|
||||||
}
|
}
|
||||||
interrupt := make(chan os.Signal, 1)
|
interrupt := make(chan os.Signal, 1)
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ func Prompt(inv *clibase.Invocation, opts PromptOptions) (string, error) {
|
|||||||
if opts.Validate != nil {
|
if opts.Validate != nil {
|
||||||
err := opts.Validate(line)
|
err := opts.Validate(line)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, defaultStyles.Error.Render(err.Error()))
|
_, _ = fmt.Fprintln(inv.Stdout, DefaultStyles.Error.Render(err.Error()))
|
||||||
return Prompt(inv, opts)
|
return Prompt(inv, opts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ func ProvisionerJob(ctx context.Context, writer io.Writer, opts ProvisionerJobOp
|
|||||||
)
|
)
|
||||||
|
|
||||||
printStage := func() {
|
printStage := func() {
|
||||||
_, _ = fmt.Fprintf(writer, Styles.Prompt.Render("⧗")+"%s\n", Styles.Field.Render(currentStage))
|
_, _ = fmt.Fprintf(writer, DefaultStyles.Prompt.Render("⧗")+"%s\n", DefaultStyles.Field.Render(currentStage))
|
||||||
}
|
}
|
||||||
|
|
||||||
updateStage := func(stage string, startedAt time.Time) {
|
updateStage := func(stage string, startedAt time.Time) {
|
||||||
@ -80,11 +80,11 @@ func ProvisionerJob(ctx context.Context, writer io.Writer, opts ProvisionerJobOp
|
|||||||
if !didLogBetweenStage {
|
if !didLogBetweenStage {
|
||||||
prefix = "\033[1A\r"
|
prefix = "\033[1A\r"
|
||||||
}
|
}
|
||||||
mark := Styles.Checkmark
|
mark := DefaultStyles.Checkmark
|
||||||
if job.CompletedAt != nil && job.Status != codersdk.ProvisionerJobSucceeded {
|
if job.CompletedAt != nil && job.Status != codersdk.ProvisionerJobSucceeded {
|
||||||
mark = Styles.Crossmark
|
mark = DefaultStyles.Crossmark
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintf(writer, prefix+mark.String()+Styles.Placeholder.Render(" %s [%dms]")+"\n", currentStage, startedAt.Sub(currentStageStartedAt).Milliseconds())
|
_, _ = fmt.Fprintf(writer, prefix+mark.String()+DefaultStyles.Placeholder.Render(" %s [%dms]")+"\n", currentStage, startedAt.Sub(currentStageStartedAt).Milliseconds())
|
||||||
}
|
}
|
||||||
if stage == "" {
|
if stage == "" {
|
||||||
return
|
return
|
||||||
@ -129,7 +129,7 @@ func ProvisionerJob(ctx context.Context, writer io.Writer, opts ProvisionerJobOp
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintf(writer, "\033[2K\r\n"+Styles.FocusedPrompt.String()+Styles.Bold.Render("Gracefully canceling...")+"\n\n")
|
_, _ = fmt.Fprintf(writer, "\033[2K\r\n"+DefaultStyles.FocusedPrompt.String()+DefaultStyles.Bold.Render("Gracefully canceling...")+"\n\n")
|
||||||
err := opts.Cancel()
|
err := opts.Cancel()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errChan <- xerrors.Errorf("cancel: %w", err)
|
errChan <- xerrors.Errorf("cancel: %w", err)
|
||||||
@ -207,11 +207,11 @@ func ProvisionerJob(ctx context.Context, writer io.Writer, opts ProvisionerJobOp
|
|||||||
if !opts.Verbose {
|
if !opts.Verbose {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
output = Styles.Placeholder.Render(log.Output)
|
output = DefaultStyles.Placeholder.Render(log.Output)
|
||||||
case codersdk.LogLevelError:
|
case codersdk.LogLevelError:
|
||||||
output = defaultStyles.Error.Render(log.Output)
|
output = DefaultStyles.Error.Render(log.Output)
|
||||||
case codersdk.LogLevelWarn:
|
case codersdk.LogLevelWarn:
|
||||||
output = Styles.Warn.Render(log.Output)
|
output = DefaultStyles.Warn.Render(log.Output)
|
||||||
case codersdk.LogLevelInfo:
|
case codersdk.LogLevelInfo:
|
||||||
output = log.Output
|
output = log.Output
|
||||||
}
|
}
|
||||||
@ -222,7 +222,7 @@ func ProvisionerJob(ctx context.Context, writer io.Writer, opts ProvisionerJobOp
|
|||||||
jobMutex.Unlock()
|
jobMutex.Unlock()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintf(logOutput, "%s %s\n", Styles.Placeholder.Render(" "), output)
|
_, _ = fmt.Fprintf(logOutput, "%s %s\n", DefaultStyles.Placeholder.Render(" "), output)
|
||||||
if !opts.Silent {
|
if !opts.Silent {
|
||||||
didLogBetweenStage = true
|
didLogBetweenStage = true
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ func WorkspaceResources(writer io.Writer, resources []codersdk.WorkspaceResource
|
|||||||
|
|
||||||
// Display a line for the resource.
|
// Display a line for the resource.
|
||||||
tableWriter.AppendRow(table.Row{
|
tableWriter.AppendRow(table.Row{
|
||||||
Styles.Bold.Render(resourceAddress),
|
DefaultStyles.Bold.Render(resourceAddress),
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
})
|
})
|
||||||
@ -106,7 +106,7 @@ func WorkspaceResources(writer io.Writer, resources []codersdk.WorkspaceResource
|
|||||||
if totalAgents > 1 {
|
if totalAgents > 1 {
|
||||||
sshCommand += "." + agent.Name
|
sshCommand += "." + agent.Name
|
||||||
}
|
}
|
||||||
sshCommand = Styles.Code.Render(sshCommand)
|
sshCommand = DefaultStyles.Code.Render(sshCommand)
|
||||||
row = append(row, sshCommand)
|
row = append(row, sshCommand)
|
||||||
}
|
}
|
||||||
tableWriter.AppendRow(row)
|
tableWriter.AppendRow(row)
|
||||||
@ -121,23 +121,23 @@ func renderAgentStatus(agent codersdk.WorkspaceAgent) string {
|
|||||||
switch agent.Status {
|
switch agent.Status {
|
||||||
case codersdk.WorkspaceAgentConnecting:
|
case codersdk.WorkspaceAgentConnecting:
|
||||||
since := database.Now().Sub(agent.CreatedAt)
|
since := database.Now().Sub(agent.CreatedAt)
|
||||||
return Styles.Warn.Render("⦾ connecting") + " " +
|
return DefaultStyles.Warn.Render("⦾ connecting") + " " +
|
||||||
Styles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]")
|
DefaultStyles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]")
|
||||||
case codersdk.WorkspaceAgentDisconnected:
|
case codersdk.WorkspaceAgentDisconnected:
|
||||||
since := database.Now().Sub(*agent.DisconnectedAt)
|
since := database.Now().Sub(*agent.DisconnectedAt)
|
||||||
return Styles.Error.Render("⦾ disconnected") + " " +
|
return DefaultStyles.Error.Render("⦾ disconnected") + " " +
|
||||||
Styles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]")
|
DefaultStyles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]")
|
||||||
case codersdk.WorkspaceAgentTimeout:
|
case codersdk.WorkspaceAgentTimeout:
|
||||||
since := database.Now().Sub(agent.CreatedAt)
|
since := database.Now().Sub(agent.CreatedAt)
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"%s %s",
|
"%s %s",
|
||||||
Styles.Warn.Render("⦾ timeout"),
|
DefaultStyles.Warn.Render("⦾ timeout"),
|
||||||
Styles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]"),
|
DefaultStyles.Placeholder.Render("["+strconv.Itoa(int(since.Seconds()))+"s]"),
|
||||||
)
|
)
|
||||||
case codersdk.WorkspaceAgentConnected:
|
case codersdk.WorkspaceAgentConnected:
|
||||||
return Styles.Keyword.Render("⦿ connected")
|
return DefaultStyles.Keyword.Render("⦿ connected")
|
||||||
default:
|
default:
|
||||||
return Styles.Warn.Render("○ unknown")
|
return DefaultStyles.Warn.Render("○ unknown")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,11 +146,11 @@ func renderAgentVersion(agentVersion, serverVersion string) string {
|
|||||||
agentVersion = "(unknown)"
|
agentVersion = "(unknown)"
|
||||||
}
|
}
|
||||||
if !semver.IsValid(serverVersion) || !semver.IsValid(agentVersion) {
|
if !semver.IsValid(serverVersion) || !semver.IsValid(agentVersion) {
|
||||||
return Styles.Placeholder.Render(agentVersion)
|
return DefaultStyles.Placeholder.Render(agentVersion)
|
||||||
}
|
}
|
||||||
outdated := semver.Compare(agentVersion, serverVersion) < 0
|
outdated := semver.Compare(agentVersion, serverVersion) < 0
|
||||||
if outdated {
|
if outdated {
|
||||||
return Styles.Warn.Render(agentVersion + " (outdated)")
|
return DefaultStyles.Warn.Render(agentVersion + " (outdated)")
|
||||||
}
|
}
|
||||||
return Styles.Keyword.Render(agentVersion)
|
return DefaultStyles.Keyword.Render(agentVersion)
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ func (r *RootCmd) create() *clibase.Cmd {
|
|||||||
|
|
||||||
var template codersdk.Template
|
var template codersdk.Template
|
||||||
if templateName == "" {
|
if templateName == "" {
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Wrap.Render("Select a template below to preview the provisioned infrastructure:"))
|
_, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Wrap.Render("Select a template below to preview the provisioned infrastructure:"))
|
||||||
|
|
||||||
templates, err := client.TemplatesByOrganization(inv.Context(), organization.ID)
|
templates, err := client.TemplatesByOrganization(inv.Context(), organization.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -81,7 +81,7 @@ func (r *RootCmd) create() *clibase.Cmd {
|
|||||||
templateName := template.Name
|
templateName := template.Name
|
||||||
|
|
||||||
if template.ActiveUserCount > 0 {
|
if template.ActiveUserCount > 0 {
|
||||||
templateName += cliui.Styles.Placeholder.Render(
|
templateName += cliui.DefaultStyles.Placeholder.Render(
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
" (used by %s)",
|
" (used by %s)",
|
||||||
formatActiveDevelopers(template.ActiveUserCount),
|
formatActiveDevelopers(template.ActiveUserCount),
|
||||||
@ -159,7 +159,7 @@ func (r *RootCmd) create() *clibase.Cmd {
|
|||||||
return xerrors.Errorf("watch build: %w", err)
|
return xerrors.Errorf("watch build: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "\nThe %s workspace has been created at %s!\n", cliui.Styles.Keyword.Render(workspace.Name), cliui.Styles.DateTimeStamp.Render(time.Now().Format(time.Stamp)))
|
_, _ = 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)))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -230,7 +230,7 @@ func prepWorkspaceBuild(inv *clibase.Invocation, client *codersdk.Client, args p
|
|||||||
useParamFile := false
|
useParamFile := false
|
||||||
if args.RichParameterFile != "" {
|
if args.RichParameterFile != "" {
|
||||||
useParamFile = true
|
useParamFile = true
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Paragraph.Render("Attempting to read the variables from the rich parameter file.")+"\r\n")
|
_, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Paragraph.Render("Attempting to read the variables from the rich parameter file.")+"\r\n")
|
||||||
parameterMapFromFile, err = createParameterMapFromFile(args.RichParameterFile)
|
parameterMapFromFile, err = createParameterMapFromFile(args.RichParameterFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -241,7 +241,7 @@ func prepWorkspaceBuild(inv *clibase.Invocation, client *codersdk.Client, args p
|
|||||||
PromptRichParamLoop:
|
PromptRichParamLoop:
|
||||||
for _, templateVersionParameter := range templateVersionParameters {
|
for _, templateVersionParameter := range templateVersionParameters {
|
||||||
if !disclaimerPrinted {
|
if !disclaimerPrinted {
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Paragraph.Render("This template has customizable parameters. Values can be changed after create, but may have unintended side effects (like data loss).")+"\r\n")
|
_, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Paragraph.Render("This template has customizable parameters. Values can be changed after create, but may have unintended side effects (like data loss).")+"\r\n")
|
||||||
disclaimerPrinted = true
|
disclaimerPrinted = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,7 +265,7 @@ PromptRichParamLoop:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if exists {
|
if exists {
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Warn.Render(fmt.Sprintf(`Parameter %q is not mutable, so can't be customized after workspace creation.`, templateVersionParameter.Name)))
|
_, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Warn.Render(fmt.Sprintf(`Parameter %q is not mutable, so can't be customized after workspace creation.`, templateVersionParameter.Name)))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ func (r *RootCmd) deleteWorkspace() *clibase.Cmd {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "\nThe %s workspace has been deleted at %s!\n", cliui.Styles.Keyword.Render(workspace.Name), cliui.Styles.DateTimeStamp.Render(time.Now().Format(time.Stamp)))
|
_, _ = fmt.Fprintf(inv.Stdout, "\nThe %s workspace has been deleted at %s!\n", cliui.DefaultStyles.Keyword.Render(workspace.Name), cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp)))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@ func (r *RootCmd) dotfiles() *clibase.Cmd {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// if the repo exists we soft fail the update operation and try to continue
|
// if the repo exists we soft fail the update operation and try to continue
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Error.Render("Failed to update repo, continuing..."))
|
_, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Error.Render("Failed to update repo, continuing..."))
|
||||||
}
|
}
|
||||||
|
|
||||||
// save git repo url so we can detect changes next time
|
// save git repo url so we can detect changes next time
|
||||||
|
@ -90,12 +90,12 @@ func (r *RootCmd) gitssh() *clibase.Cmd {
|
|||||||
exitErr := &exec.ExitError{}
|
exitErr := &exec.ExitError{}
|
||||||
if xerrors.As(err, &exitErr) && exitErr.ExitCode() == 255 {
|
if xerrors.As(err, &exitErr) && exitErr.ExitCode() == 255 {
|
||||||
_, _ = fmt.Fprintln(inv.Stderr,
|
_, _ = fmt.Fprintln(inv.Stderr,
|
||||||
"\n"+cliui.Styles.Wrap.Render("Coder authenticates with "+cliui.Styles.Field.Render("git")+
|
"\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")
|
" using the public key below. All clones with SSH are authenticated automatically 🪄.")+"\n")
|
||||||
_, _ = fmt.Fprintln(inv.Stderr, cliui.Styles.Code.Render(strings.TrimSpace(key.PublicKey))+"\n")
|
_, _ = fmt.Fprintln(inv.Stderr, cliui.DefaultStyles.Code.Render(strings.TrimSpace(key.PublicKey))+"\n")
|
||||||
_, _ = fmt.Fprintln(inv.Stderr, "Add to GitHub and GitLab:")
|
_, _ = fmt.Fprintln(inv.Stderr, "Add to GitHub and GitLab:")
|
||||||
_, _ = fmt.Fprintln(inv.Stderr, cliui.Styles.Prompt.String()+"https://github.com/settings/ssh/new")
|
_, _ = fmt.Fprintln(inv.Stderr, cliui.DefaultStyles.Prompt.String()+"https://github.com/settings/ssh/new")
|
||||||
_, _ = fmt.Fprintln(inv.Stderr, cliui.Styles.Prompt.String()+"https://gitlab.com/-/profile/keys")
|
_, _ = fmt.Fprintln(inv.Stderr, cliui.DefaultStyles.Prompt.String()+"https://gitlab.com/-/profile/keys")
|
||||||
_, _ = fmt.Fprintln(inv.Stderr)
|
_, _ = fmt.Fprintln(inv.Stderr)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ var usageTemplate = template.Must(
|
|||||||
return opt.Flag
|
return opt.Flag
|
||||||
},
|
},
|
||||||
"prettyHeader": func(s string) string {
|
"prettyHeader": func(s string) string {
|
||||||
return cliui.Styles.Bold.Render(s)
|
return cliui.DefaultStyles.Bold.Render(s)
|
||||||
},
|
},
|
||||||
"isEnterprise": func(opt clibase.Option) bool {
|
"isEnterprise": func(opt clibase.Option) bool {
|
||||||
return opt.Annotations.IsSet("enterprise")
|
return opt.Annotations.IsSet("enterprise")
|
||||||
|
@ -98,9 +98,9 @@ func (r *RootCmd) list() *clibase.Cmd {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(res.Workspaces) == 0 {
|
if len(res.Workspaces) == 0 {
|
||||||
_, _ = fmt.Fprintln(inv.Stderr, cliui.Styles.Prompt.String()+"No workspaces found! Create one:")
|
_, _ = fmt.Fprintln(inv.Stderr, cliui.DefaultStyles.Prompt.String()+"No workspaces found! Create one:")
|
||||||
_, _ = fmt.Fprintln(inv.Stderr)
|
_, _ = fmt.Fprintln(inv.Stderr)
|
||||||
_, _ = fmt.Fprintln(inv.Stderr, " "+cliui.Styles.Code.Render("coder create <name>"))
|
_, _ = fmt.Fprintln(inv.Stderr, " "+cliui.DefaultStyles.Code.Render("coder create <name>"))
|
||||||
_, _ = fmt.Fprintln(inv.Stderr)
|
_, _ = fmt.Fprintln(inv.Stderr)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
18
cli/login.go
18
cli/login.go
@ -86,7 +86,7 @@ func (r *RootCmd) login() *clibase.Cmd {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
// Checking versions isn't a fatal error so we print a warning
|
// Checking versions isn't a fatal error so we print a warning
|
||||||
// and proceed.
|
// and proceed.
|
||||||
_, _ = fmt.Fprintln(inv.Stderr, cliui.Styles.Warn.Render(err.Error()))
|
_, _ = fmt.Fprintln(inv.Stderr, cliui.DefaultStyles.Warn.Render(err.Error()))
|
||||||
}
|
}
|
||||||
|
|
||||||
hasInitialUser, err := client.HasFirstUser(inv.Context())
|
hasInitialUser, err := client.HasFirstUser(inv.Context())
|
||||||
@ -116,7 +116,7 @@ func (r *RootCmd) login() *clibase.Cmd {
|
|||||||
return xerrors.Errorf("get current user: %w", err)
|
return xerrors.Errorf("get current user: %w", err)
|
||||||
}
|
}
|
||||||
username, err = cliui.Prompt(inv, cliui.PromptOptions{
|
username, err = cliui.Prompt(inv, cliui.PromptOptions{
|
||||||
Text: "What " + cliui.Styles.Field.Render("username") + " would you like?",
|
Text: "What " + cliui.DefaultStyles.Field.Render("username") + " would you like?",
|
||||||
Default: currentUser.Username,
|
Default: currentUser.Username,
|
||||||
})
|
})
|
||||||
if errors.Is(err, cliui.Canceled) {
|
if errors.Is(err, cliui.Canceled) {
|
||||||
@ -129,7 +129,7 @@ func (r *RootCmd) login() *clibase.Cmd {
|
|||||||
|
|
||||||
if email == "" {
|
if email == "" {
|
||||||
email, err = cliui.Prompt(inv, cliui.PromptOptions{
|
email, err = cliui.Prompt(inv, cliui.PromptOptions{
|
||||||
Text: "What's your " + cliui.Styles.Field.Render("email") + "?",
|
Text: "What's your " + cliui.DefaultStyles.Field.Render("email") + "?",
|
||||||
Validate: func(s string) error {
|
Validate: func(s string) error {
|
||||||
err := validator.New().Var(s, "email")
|
err := validator.New().Var(s, "email")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -148,7 +148,7 @@ func (r *RootCmd) login() *clibase.Cmd {
|
|||||||
|
|
||||||
for !matching {
|
for !matching {
|
||||||
password, err = cliui.Prompt(inv, cliui.PromptOptions{
|
password, err = cliui.Prompt(inv, cliui.PromptOptions{
|
||||||
Text: "Enter a " + cliui.Styles.Field.Render("password") + ":",
|
Text: "Enter a " + cliui.DefaultStyles.Field.Render("password") + ":",
|
||||||
Secret: true,
|
Secret: true,
|
||||||
Validate: func(s string) error {
|
Validate: func(s string) error {
|
||||||
return userpassword.Validate(s)
|
return userpassword.Validate(s)
|
||||||
@ -158,7 +158,7 @@ func (r *RootCmd) login() *clibase.Cmd {
|
|||||||
return xerrors.Errorf("specify password prompt: %w", err)
|
return xerrors.Errorf("specify password prompt: %w", err)
|
||||||
}
|
}
|
||||||
confirm, err := cliui.Prompt(inv, cliui.PromptOptions{
|
confirm, err := cliui.Prompt(inv, cliui.PromptOptions{
|
||||||
Text: "Confirm " + cliui.Styles.Field.Render("password") + ":",
|
Text: "Confirm " + cliui.DefaultStyles.Field.Render("password") + ":",
|
||||||
Secret: true,
|
Secret: true,
|
||||||
Validate: cliui.ValidateNotEmpty,
|
Validate: cliui.ValidateNotEmpty,
|
||||||
})
|
})
|
||||||
@ -168,7 +168,7 @@ func (r *RootCmd) login() *clibase.Cmd {
|
|||||||
|
|
||||||
matching = confirm == password
|
matching = confirm == password
|
||||||
if !matching {
|
if !matching {
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Error.Render("Passwords do not match"))
|
_, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Error.Render("Passwords do not match"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -211,10 +211,10 @@ func (r *RootCmd) login() *clibase.Cmd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(inv.Stdout,
|
_, _ = fmt.Fprintf(inv.Stdout,
|
||||||
cliui.Styles.Paragraph.Render(fmt.Sprintf("Welcome to Coder, %s! You're authenticated.", cliui.Styles.Keyword.Render(username)))+"\n")
|
cliui.DefaultStyles.Paragraph.Render(fmt.Sprintf("Welcome to Coder, %s! You're authenticated.", cliui.DefaultStyles.Keyword.Render(username)))+"\n")
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(inv.Stdout,
|
_, _ = fmt.Fprintf(inv.Stdout,
|
||||||
cliui.Styles.Paragraph.Render("Get started by creating a template: "+cliui.Styles.Code.Render("coder templates init"))+"\n")
|
cliui.DefaultStyles.Paragraph.Render("Get started by creating a template: "+cliui.DefaultStyles.Code.Render("coder templates init"))+"\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,7 +264,7 @@ func (r *RootCmd) login() *clibase.Cmd {
|
|||||||
return xerrors.Errorf("write server url: %w", err)
|
return xerrors.Errorf("write server url: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, Caret+"Welcome to Coder, %s! You're authenticated.\n", cliui.Styles.Keyword.Render(resp.Username))
|
_, _ = fmt.Fprintf(inv.Stdout, Caret+"Welcome to Coder, %s! You're authenticated.\n", cliui.DefaultStyles.Keyword.Render(resp.Username))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ func TestLogin(t *testing.T) {
|
|||||||
|
|
||||||
// Validate that we reprompt for matching passwords.
|
// Validate that we reprompt for matching passwords.
|
||||||
pty.ExpectMatch("Passwords do not match")
|
pty.ExpectMatch("Passwords do not match")
|
||||||
pty.ExpectMatch("Enter a " + cliui.Styles.Field.Render("password"))
|
pty.ExpectMatch("Enter a " + cliui.DefaultStyles.Field.Render("password"))
|
||||||
|
|
||||||
pty.WriteLine("SomeSecurePassword!")
|
pty.WriteLine("SomeSecurePassword!")
|
||||||
pty.ExpectMatch("Confirm")
|
pty.ExpectMatch("Confirm")
|
||||||
|
14
cli/ping.go
14
cli/ping.go
@ -98,14 +98,14 @@ func (r *RootCmd) ping() *clibase.Cmd {
|
|||||||
if p2p {
|
if p2p {
|
||||||
if !didP2p {
|
if !didP2p {
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, "p2p connection established in",
|
_, _ = fmt.Fprintln(inv.Stdout, "p2p connection established in",
|
||||||
cliui.Styles.DateTimeStamp.Render(time.Since(start).Round(time.Millisecond).String()),
|
cliui.DefaultStyles.DateTimeStamp.Render(time.Since(start).Round(time.Millisecond).String()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
didP2p = true
|
didP2p = true
|
||||||
|
|
||||||
via = fmt.Sprintf("%s via %s",
|
via = fmt.Sprintf("%s via %s",
|
||||||
cliui.Styles.Fuchsia.Render("p2p"),
|
cliui.DefaultStyles.Fuchsia.Render("p2p"),
|
||||||
cliui.Styles.Code.Render(pong.Endpoint),
|
cliui.DefaultStyles.Code.Render(pong.Endpoint),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
derpName := "unknown"
|
derpName := "unknown"
|
||||||
@ -114,15 +114,15 @@ func (r *RootCmd) ping() *clibase.Cmd {
|
|||||||
derpName = derpRegion.RegionName
|
derpName = derpRegion.RegionName
|
||||||
}
|
}
|
||||||
via = fmt.Sprintf("%s via %s",
|
via = fmt.Sprintf("%s via %s",
|
||||||
cliui.Styles.Fuchsia.Render("proxied"),
|
cliui.DefaultStyles.Fuchsia.Render("proxied"),
|
||||||
cliui.Styles.Code.Render(fmt.Sprintf("DERP(%s)", derpName)),
|
cliui.DefaultStyles.Code.Render(fmt.Sprintf("DERP(%s)", derpName)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "pong from %s %s in %s\n",
|
_, _ = fmt.Fprintf(inv.Stdout, "pong from %s %s in %s\n",
|
||||||
cliui.Styles.Keyword.Render(workspaceName),
|
cliui.DefaultStyles.Keyword.Render(workspaceName),
|
||||||
via,
|
via,
|
||||||
cliui.Styles.DateTimeStamp.Render(dur.String()),
|
cliui.DefaultStyles.DateTimeStamp.Render(dur.String()),
|
||||||
)
|
)
|
||||||
|
|
||||||
if n == int(pingNum) {
|
if n == int(pingNum) {
|
||||||
|
@ -44,13 +44,13 @@ func (r *RootCmd) publickey() *clibase.Cmd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cliui.Infof(inv.Stdout,
|
cliui.Infof(inv.Stdout,
|
||||||
"This is your public key for using "+cliui.Styles.Field.Render("git")+" in "+
|
"This is your public key for using "+cliui.DefaultStyles.Field.Render("git")+" in "+
|
||||||
"Coder. All clones with SSH will be authenticated automatically 🪄.\n\n",
|
"Coder. All clones with SSH will be authenticated automatically 🪄.\n\n",
|
||||||
)
|
)
|
||||||
cliui.Infof(inv.Stdout, cliui.Styles.Code.Render(strings.TrimSpace(key.PublicKey))+"\n\n")
|
cliui.Infof(inv.Stdout, cliui.DefaultStyles.Code.Render(strings.TrimSpace(key.PublicKey))+"\n\n")
|
||||||
cliui.Infof(inv.Stdout, "Add to GitHub and GitLab:"+"\n")
|
cliui.Infof(inv.Stdout, "Add to GitHub and GitLab:"+"\n")
|
||||||
cliui.Infof(inv.Stdout, cliui.Styles.Prompt.String()+"https://github.com/settings/ssh/new"+"\n")
|
cliui.Infof(inv.Stdout, cliui.DefaultStyles.Prompt.String()+"https://github.com/settings/ssh/new"+"\n")
|
||||||
cliui.Infof(inv.Stdout, cliui.Styles.Prompt.String()+"https://gitlab.com/-/profile/keys"+"\n")
|
cliui.Infof(inv.Stdout, cliui.DefaultStyles.Prompt.String()+"https://gitlab.com/-/profile/keys"+"\n")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
@ -27,7 +27,7 @@ func (r *RootCmd) rename() *clibase.Cmd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "%s\n\n",
|
_, _ = fmt.Fprintf(inv.Stdout, "%s\n\n",
|
||||||
cliui.Styles.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."),
|
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."),
|
||||||
)
|
)
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "See: %s\n\n", "https://coder.com/docs/coder-oss/latest/templates/resource-persistence#%EF%B8%8F-persistence-pitfalls")
|
_, _ = 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{
|
_, err = cliui.Prompt(inv, cliui.PromptOptions{
|
||||||
|
@ -47,7 +47,7 @@ func (*RootCmd) resetPassword() *clibase.Cmd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
password, err := cliui.Prompt(inv, cliui.PromptOptions{
|
password, err := cliui.Prompt(inv, cliui.PromptOptions{
|
||||||
Text: "Enter new " + cliui.Styles.Field.Render("password") + ":",
|
Text: "Enter new " + cliui.DefaultStyles.Field.Render("password") + ":",
|
||||||
Secret: true,
|
Secret: true,
|
||||||
Validate: func(s string) error {
|
Validate: func(s string) error {
|
||||||
return userpassword.Validate(s)
|
return userpassword.Validate(s)
|
||||||
@ -57,7 +57,7 @@ func (*RootCmd) resetPassword() *clibase.Cmd {
|
|||||||
return xerrors.Errorf("password prompt: %w", err)
|
return xerrors.Errorf("password prompt: %w", err)
|
||||||
}
|
}
|
||||||
confirmedPassword, err := cliui.Prompt(inv, cliui.PromptOptions{
|
confirmedPassword, err := cliui.Prompt(inv, cliui.PromptOptions{
|
||||||
Text: "Confirm " + cliui.Styles.Field.Render("password") + ":",
|
Text: "Confirm " + cliui.DefaultStyles.Field.Render("password") + ":",
|
||||||
Secret: true,
|
Secret: true,
|
||||||
Validate: cliui.ValidateNotEmpty,
|
Validate: cliui.ValidateNotEmpty,
|
||||||
})
|
})
|
||||||
@ -81,7 +81,7 @@ func (*RootCmd) resetPassword() *clibase.Cmd {
|
|||||||
return xerrors.Errorf("updating password: %w", err)
|
return xerrors.Errorf("updating password: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "\nPassword has been reset for user %s!\n", cliui.Styles.Keyword.Render(user.Username))
|
_, _ = fmt.Fprintf(inv.Stdout, "\nPassword has been reset for user %s!\n", cliui.DefaultStyles.Keyword.Render(user.Username))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ func (r *RootCmd) restart() *clibase.Cmd {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(out, "\nThe %s workspace has been restarted at %s!\n", cliui.Styles.Keyword.Render(workspace.Name), cliui.Styles.DateTimeStamp.Render(time.Now().Format(time.Stamp)))
|
_, _ = 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)))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
22
cli/root.go
22
cli/root.go
@ -29,6 +29,7 @@ import (
|
|||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
"github.com/gobwas/httphead"
|
"github.com/gobwas/httphead"
|
||||||
"github.com/mattn/go-isatty"
|
"github.com/mattn/go-isatty"
|
||||||
|
"github.com/mitchellh/go-wordwrap"
|
||||||
|
|
||||||
"github.com/coder/coder/buildinfo"
|
"github.com/coder/coder/buildinfo"
|
||||||
"github.com/coder/coder/cli/clibase"
|
"github.com/coder/coder/cli/clibase"
|
||||||
@ -42,7 +43,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Caret = cliui.Styles.Prompt.String()
|
Caret = cliui.DefaultStyles.Prompt.String()
|
||||||
|
|
||||||
// Applied as annotations to workspace commands
|
// Applied as annotations to workspace commands
|
||||||
// so they display in a separated "help" section.
|
// so they display in a separated "help" section.
|
||||||
@ -538,14 +539,14 @@ func (r *RootCmd) InitClient(client *codersdk.Client) clibase.MiddlewareFunc {
|
|||||||
// Just log the error here. We never want to fail a command
|
// Just log the error here. We never want to fail a command
|
||||||
// due to a pre-run.
|
// due to a pre-run.
|
||||||
_, _ = fmt.Fprintf(inv.Stderr,
|
_, _ = fmt.Fprintf(inv.Stderr,
|
||||||
cliui.Styles.Warn.Render("check versions error: %s"), err)
|
cliui.DefaultStyles.Warn.Render("check versions error: %s"), err)
|
||||||
_, _ = fmt.Fprintln(inv.Stderr)
|
_, _ = fmt.Fprintln(inv.Stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = <-warningErr; err != nil {
|
if err = <-warningErr; err != nil {
|
||||||
// Same as above
|
// Same as above
|
||||||
_, _ = fmt.Fprintf(inv.Stderr,
|
_, _ = fmt.Fprintf(inv.Stderr,
|
||||||
cliui.Styles.Warn.Render("check entitlement warnings error: %s"), err)
|
cliui.DefaultStyles.Warn.Render("check entitlement warnings error: %s"), err)
|
||||||
_, _ = fmt.Fprintln(inv.Stderr)
|
_, _ = fmt.Fprintln(inv.Stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -676,17 +677,20 @@ type example struct {
|
|||||||
// formatExamples formats the examples as width wrapped bulletpoint
|
// formatExamples formats the examples as width wrapped bulletpoint
|
||||||
// descriptions with the command underneath.
|
// descriptions with the command underneath.
|
||||||
func formatExamples(examples ...example) string {
|
func formatExamples(examples ...example) string {
|
||||||
wrap := cliui.Styles.Wrap.Copy()
|
|
||||||
wrap.PaddingLeft(4)
|
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
|
|
||||||
|
padStyle := cliui.DefaultStyles.Wrap.Copy().PaddingLeft(4)
|
||||||
for i, e := range examples {
|
for i, e := range examples {
|
||||||
if len(e.Description) > 0 {
|
if len(e.Description) > 0 {
|
||||||
_, _ = sb.WriteString(" - " + wrap.Render(e.Description + ":")[4:] + "\n\n ")
|
wordwrap.WrapString(e.Description, 80)
|
||||||
|
_, _ = sb.WriteString(
|
||||||
|
" - " + padStyle.Render(e.Description + ":")[4:] + "\n\n ",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
// We add 1 space here because `cliui.Styles.Code` adds an extra
|
// We add 1 space here because `cliui.Styles.Code` adds an extra
|
||||||
// space. This makes the code block align at an even 2 or 6
|
// space. This makes the code block align at an even 2 or 6
|
||||||
// spaces for symmetry.
|
// spaces for symmetry.
|
||||||
_, _ = sb.WriteString(" " + cliui.Styles.Code.Render(fmt.Sprintf("$ %s", e.Command)))
|
_, _ = sb.WriteString(" " + cliui.DefaultStyles.Code.Render(fmt.Sprintf("$ %s", e.Command)))
|
||||||
if i < len(examples)-1 {
|
if i < len(examples)-1 {
|
||||||
_, _ = sb.WriteString("\n\n")
|
_, _ = sb.WriteString("\n\n")
|
||||||
}
|
}
|
||||||
@ -724,7 +728,7 @@ func (r *RootCmd) checkVersions(i *clibase.Invocation, client *codersdk.Client)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !buildinfo.VersionsMatch(clientVersion, info.Version) {
|
if !buildinfo.VersionsMatch(clientVersion, info.Version) {
|
||||||
warn := cliui.Styles.Warn.Copy().Align(lipgloss.Left)
|
warn := cliui.DefaultStyles.Warn.Copy().Align(lipgloss.Left)
|
||||||
_, _ = fmt.Fprintf(i.Stderr, warn.Render(fmtWarningText), clientVersion, info.Version, strings.TrimPrefix(info.CanonicalVersion(), "v"))
|
_, _ = fmt.Fprintf(i.Stderr, warn.Render(fmtWarningText), clientVersion, info.Version, strings.TrimPrefix(info.CanonicalVersion(), "v"))
|
||||||
_, _ = fmt.Fprintln(i.Stderr)
|
_, _ = fmt.Fprintln(i.Stderr)
|
||||||
}
|
}
|
||||||
@ -743,7 +747,7 @@ func (r *RootCmd) checkWarnings(i *clibase.Invocation, client *codersdk.Client)
|
|||||||
entitlements, err := client.Entitlements(ctx)
|
entitlements, err := client.Entitlements(ctx)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for _, w := range entitlements.Warnings {
|
for _, w := range entitlements.Warnings {
|
||||||
_, _ = fmt.Fprintln(i.Stderr, cliui.Styles.Warn.Render(w))
|
_, _ = fmt.Fprintln(i.Stderr, cliui.DefaultStyles.Warn.Render(w))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -361,7 +361,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
|||||||
cliui.Warnf(
|
cliui.Warnf(
|
||||||
inv.Stderr,
|
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",
|
"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.Styles.Field.Render(cfg.AccessURL.String()), reason,
|
cliui.DefaultStyles.Field.Render(cfg.AccessURL.String()), reason,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -904,7 +904,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
|||||||
select {
|
select {
|
||||||
case <-notifyCtx.Done():
|
case <-notifyCtx.Done():
|
||||||
exitErr = notifyCtx.Err()
|
exitErr = notifyCtx.Err()
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Bold.Render(
|
_, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Bold.Render(
|
||||||
"Interrupt caught, gracefully exiting. Use ctrl+\\ to force quit",
|
"Interrupt caught, gracefully exiting. Use ctrl+\\ to force quit",
|
||||||
))
|
))
|
||||||
case <-tunnelDone:
|
case <-tunnelDone:
|
||||||
@ -1016,7 +1016,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
|||||||
if pgRawURL {
|
if pgRawURL {
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "%s\n", url)
|
_, _ = fmt.Fprintf(inv.Stdout, "%s\n", url)
|
||||||
} else {
|
} else {
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "%s\n", cliui.Styles.Code.Render(fmt.Sprintf("psql %q", url)))
|
_, _ = fmt.Fprintf(inv.Stdout, "%s\n", cliui.DefaultStyles.Code.Render(fmt.Sprintf("psql %q", url)))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
@ -1046,7 +1046,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
|||||||
if pgRawURL {
|
if pgRawURL {
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "%s\n", url)
|
_, _ = fmt.Fprintf(inv.Stdout, "%s\n", url)
|
||||||
} else {
|
} else {
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "%s\n", cliui.Styles.Code.Render(fmt.Sprintf("psql %q", url)))
|
_, _ = fmt.Fprintf(inv.Stdout, "%s\n", cliui.DefaultStyles.Code.Render(fmt.Sprintf("psql %q", url)))
|
||||||
}
|
}
|
||||||
|
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
@ -1282,7 +1282,7 @@ func PrintLogo(inv *clibase.Invocation) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "%s - Your Self-Hosted Remote Development Platform\n", cliui.Styles.Bold.Render("Coder "+buildinfo.Version()))
|
_, _ = fmt.Fprintf(inv.Stdout, "%s - Your Self-Hosted Remote Development Platform\n", cliui.DefaultStyles.Bold.Render("Coder "+buildinfo.Version()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadCertificates(tlsCertFiles, tlsKeyFiles []string) ([]tls.Certificate, error) {
|
func loadCertificates(tlsCertFiles, tlsKeyFiles []string) ([]tls.Certificate, error) {
|
||||||
|
@ -39,7 +39,7 @@ func (r *RootCmd) start() *clibase.Cmd {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "\nThe %s workspace has been started at %s!\n", cliui.Styles.Keyword.Render(workspace.Name), cliui.Styles.DateTimeStamp.Render(time.Now().Format(time.Stamp)))
|
_, _ = 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)))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ func (r *RootCmd) stop() *clibase.Cmd {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "\nThe %s workspace has been stopped at %s!\n", cliui.Styles.Keyword.Render(workspace.Name), cliui.Styles.DateTimeStamp.Render(time.Now().Format(time.Stamp)))
|
_, _ = 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)))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -133,11 +133,11 @@ func (r *RootCmd) templateCreate() *clibase.Cmd {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, "\n"+cliui.Styles.Wrap.Render(
|
_, _ = fmt.Fprintln(inv.Stdout, "\n"+cliui.DefaultStyles.Wrap.Render(
|
||||||
"The "+cliui.Styles.Keyword.Render(templateName)+" template has been created at "+cliui.Styles.DateTimeStamp.Render(time.Now().Format(time.Stamp))+"! "+
|
"The "+cliui.DefaultStyles.Keyword.Render(templateName)+" template has been created at "+cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))+"! "+
|
||||||
"Developers can provision a workspace with this template using:")+"\n")
|
"Developers can provision a workspace with this template using:")+"\n")
|
||||||
|
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, " "+cliui.Styles.Code.Render(fmt.Sprintf("coder create --template=%q [workspace name]", templateName)))
|
_, _ = fmt.Fprintln(inv.Stdout, " "+cliui.DefaultStyles.Code.Render(fmt.Sprintf("coder create --template=%q [workspace name]", templateName)))
|
||||||
_, _ = fmt.Fprintln(inv.Stdout)
|
_, _ = fmt.Fprintln(inv.Stdout)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -77,7 +77,7 @@ func (r *RootCmd) templateDelete() *clibase.Cmd {
|
|||||||
|
|
||||||
// Confirm deletion of the template.
|
// Confirm deletion of the template.
|
||||||
_, err = cliui.Prompt(inv, cliui.PromptOptions{
|
_, err = cliui.Prompt(inv, cliui.PromptOptions{
|
||||||
Text: fmt.Sprintf("Delete these templates: %s?", cliui.Styles.Code.Render(strings.Join(templateNames, ", "))),
|
Text: fmt.Sprintf("Delete these templates: %s?", cliui.DefaultStyles.Code.Render(strings.Join(templateNames, ", "))),
|
||||||
IsConfirm: true,
|
IsConfirm: true,
|
||||||
Default: cliui.ConfirmNo,
|
Default: cliui.ConfirmNo,
|
||||||
})
|
})
|
||||||
@ -91,7 +91,7 @@ func (r *RootCmd) templateDelete() *clibase.Cmd {
|
|||||||
return xerrors.Errorf("delete template %q: %w", template.Name, err)
|
return xerrors.Errorf("delete template %q: %w", template.Name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, "Deleted template "+cliui.Styles.Code.Render(template.Name)+" at "+cliui.Styles.DateTimeStamp.Render(time.Now().Format(time.Stamp))+"!")
|
_, _ = fmt.Fprintln(inv.Stdout, "Deleted template "+cliui.DefaultStyles.Code.Render(template.Name)+" at "+cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))+"!")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -37,7 +37,7 @@ func TestTemplateDelete(t *testing.T) {
|
|||||||
execDone <- inv.Run()
|
execDone <- inv.Run()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
pty.ExpectMatch(fmt.Sprintf("Delete these templates: %s?", cliui.Styles.Code.Render(template.Name)))
|
pty.ExpectMatch(fmt.Sprintf("Delete these templates: %s?", cliui.DefaultStyles.Code.Render(template.Name)))
|
||||||
pty.WriteLine("yes")
|
pty.WriteLine("yes")
|
||||||
|
|
||||||
require.NoError(t, <-execDone)
|
require.NoError(t, <-execDone)
|
||||||
@ -95,7 +95,7 @@ func TestTemplateDelete(t *testing.T) {
|
|||||||
execDone <- inv.Run()
|
execDone <- inv.Run()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
pty.ExpectMatch(fmt.Sprintf("Delete these templates: %s?", cliui.Styles.Code.Render(strings.Join(templateNames, ", "))))
|
pty.ExpectMatch(fmt.Sprintf("Delete these templates: %s?", cliui.DefaultStyles.Code.Render(strings.Join(templateNames, ", "))))
|
||||||
pty.WriteLine("yes")
|
pty.WriteLine("yes")
|
||||||
|
|
||||||
require.NoError(t, <-execDone)
|
require.NoError(t, <-execDone)
|
||||||
|
@ -90,7 +90,7 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("update template metadata: %w", err)
|
return xerrors.Errorf("update template metadata: %w", err)
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "Updated template metadata at %s!\n", cliui.Styles.DateTimeStamp.Render(time.Now().Format(time.Stamp)))
|
_, _ = fmt.Fprintf(inv.Stdout, "Updated template metadata at %s!\n", cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp)))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -42,15 +42,15 @@ func (*RootCmd) templateInit() *clibase.Cmd {
|
|||||||
for _, example := range exampleList {
|
for _, example := range exampleList {
|
||||||
name := fmt.Sprintf(
|
name := fmt.Sprintf(
|
||||||
"%s\n%s\n%s\n",
|
"%s\n%s\n%s\n",
|
||||||
cliui.Styles.Bold.Render(example.Name),
|
cliui.DefaultStyles.Bold.Render(example.Name),
|
||||||
cliui.Styles.Wrap.Copy().PaddingLeft(6).Render(example.Description),
|
cliui.DefaultStyles.Wrap.Copy().PaddingLeft(6).Render(example.Description),
|
||||||
cliui.Styles.Keyword.Copy().PaddingLeft(6).Render(example.URL),
|
cliui.DefaultStyles.Keyword.Copy().PaddingLeft(6).Render(example.URL),
|
||||||
)
|
)
|
||||||
optsToID[name] = example.ID
|
optsToID[name] = example.ID
|
||||||
}
|
}
|
||||||
opts := maps.Keys(optsToID)
|
opts := maps.Keys(optsToID)
|
||||||
sort.Strings(opts)
|
sort.Strings(opts)
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Wrap.Render(
|
_, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Wrap.Render(
|
||||||
"A template defines infrastructure as code to be provisioned "+
|
"A template defines infrastructure as code to be provisioned "+
|
||||||
"for individual developer workspaces. Select an example to be copied to the active directory:\n"))
|
"for individual developer workspaces. Select an example to be copied to the active directory:\n"))
|
||||||
selected, err := cliui.Select(inv, cliui.SelectOptions{
|
selected, err := cliui.Select(inv, cliui.SelectOptions{
|
||||||
@ -94,7 +94,7 @@ func (*RootCmd) templateInit() *clibase.Cmd {
|
|||||||
} else {
|
} else {
|
||||||
relPath = "./" + relPath
|
relPath = "./" + relPath
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "Extracting %s to %s...\n", cliui.Styles.Field.Render(selectedTemplate.ID), relPath)
|
_, _ = fmt.Fprintf(inv.Stdout, "Extracting %s to %s...\n", cliui.DefaultStyles.Field.Render(selectedTemplate.ID), relPath)
|
||||||
err = os.MkdirAll(directory, 0o700)
|
err = os.MkdirAll(directory, 0o700)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -104,8 +104,8 @@ func (*RootCmd) templateInit() *clibase.Cmd {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, "Create your template by running:")
|
_, _ = fmt.Fprintln(inv.Stdout, "Create your template by running:")
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Paragraph.Render(cliui.Styles.Code.Render("cd "+relPath+" && coder templates create"))+"\n")
|
_, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Paragraph.Render(cliui.DefaultStyles.Code.Render("cd "+relPath+" && coder templates create"))+"\n")
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Wrap.Render("Examples provide a starting point and are expected to be edited! 🎨"))
|
_, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Wrap.Render("Examples provide a starting point and are expected to be edited! 🎨"))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ func (pf *templateUploadFlags) upload(inv *clibase.Invocation, client *codersdk.
|
|||||||
|
|
||||||
spin := spinner.New(spinner.CharSets[5], 100*time.Millisecond)
|
spin := spinner.New(spinner.CharSets[5], 100*time.Millisecond)
|
||||||
spin.Writer = inv.Stdout
|
spin.Writer = inv.Stdout
|
||||||
spin.Suffix = cliui.Styles.Keyword.Render(" Uploading directory...")
|
spin.Suffix = cliui.DefaultStyles.Keyword.Render(" Uploading directory...")
|
||||||
spin.Start()
|
spin.Start()
|
||||||
defer spin.Stop()
|
defer spin.Stop()
|
||||||
|
|
||||||
@ -182,7 +182,7 @@ func (r *RootCmd) templatePush() *clibase.Cmd {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "Updated version at %s!\n", cliui.Styles.DateTimeStamp.Render(time.Now().Format(time.Stamp)))
|
_, _ = fmt.Fprintf(inv.Stdout, "Updated version at %s!\n", cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp)))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ func templatesToRows(templates ...codersdk.Template) []templateTableRow {
|
|||||||
OrganizationID: template.OrganizationID,
|
OrganizationID: template.OrganizationID,
|
||||||
Provisioner: template.Provisioner,
|
Provisioner: template.Provisioner,
|
||||||
ActiveVersionID: template.ActiveVersionID,
|
ActiveVersionID: template.ActiveVersionID,
|
||||||
UsedBy: cliui.Styles.Fuchsia.Render(formatActiveDevelopers(template.ActiveUserCount)),
|
UsedBy: cliui.DefaultStyles.Fuchsia.Render(formatActiveDevelopers(template.ActiveUserCount)),
|
||||||
DefaultTTL: (time.Duration(template.DefaultTTLMillis) * time.Millisecond),
|
DefaultTTL: (time.Duration(template.DefaultTTLMillis) * time.Millisecond),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ func templateVersionsToRows(activeVersionID uuid.UUID, templateVersions ...coder
|
|||||||
for i, templateVersion := range templateVersions {
|
for i, templateVersion := range templateVersions {
|
||||||
activeStatus := ""
|
activeStatus := ""
|
||||||
if templateVersion.ID == activeVersionID {
|
if templateVersion.ID == activeVersionID {
|
||||||
activeStatus = cliui.Styles.Code.Render(cliui.Styles.Keyword.Render("Active"))
|
activeStatus = cliui.DefaultStyles.Code.Render(cliui.DefaultStyles.Keyword.Render("Active"))
|
||||||
}
|
}
|
||||||
|
|
||||||
rows[i] = templateVersionRow{
|
rows[i] = templateVersionRow{
|
||||||
|
@ -71,16 +71,16 @@ func (r *RootCmd) userCreate() *clibase.Cmd {
|
|||||||
}
|
}
|
||||||
_, _ = fmt.Fprintln(inv.Stderr, `A new user has been created!
|
_, _ = fmt.Fprintln(inv.Stderr, `A new user has been created!
|
||||||
Share the instructions below to get them started.
|
Share the instructions below to get them started.
|
||||||
`+cliui.Styles.Placeholder.Render("—————————————————————————————————————————————————")+`
|
`+cliui.DefaultStyles.Placeholder.Render("—————————————————————————————————————————————————")+`
|
||||||
Download the Coder command line for your operating system:
|
Download the Coder command line for your operating system:
|
||||||
https://github.com/coder/coder/releases
|
https://github.com/coder/coder/releases
|
||||||
|
|
||||||
Run `+cliui.Styles.Code.Render("coder login "+client.URL.String())+` to authenticate.
|
Run `+cliui.DefaultStyles.Code.Render("coder login "+client.URL.String())+` to authenticate.
|
||||||
|
|
||||||
Your email is: `+cliui.Styles.Field.Render(email)+`
|
Your email is: `+cliui.DefaultStyles.Field.Render(email)+`
|
||||||
Your password is: `+cliui.Styles.Field.Render(password)+`
|
Your password is: `+cliui.DefaultStyles.Field.Render(password)+`
|
||||||
|
|
||||||
Create a workspace `+cliui.Styles.Code.Render("coder create")+`!`)
|
Create a workspace `+cliui.DefaultStyles.Code.Render("coder create")+`!`)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ func (r *RootCmd) createUserStatusCommand(sdkStatus codersdk.UserStatus) *clibas
|
|||||||
return xerrors.Errorf("%s user: %w", verb, err)
|
return xerrors.Errorf("%s user: %w", verb, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "\nUser %s has been %s!\n", cliui.Styles.Keyword.Render(user.Username), pastVerb)
|
_, _ = fmt.Fprintf(inv.Stdout, "\nUser %s has been %s!\n", cliui.DefaultStyles.Keyword.Render(user.Username), pastVerb)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -35,9 +35,9 @@ func (vi versionInfo) String() string {
|
|||||||
_, _ = str.WriteString("\r\n" + vi.ExternalURL + "\r\n\r\n")
|
_, _ = str.WriteString("\r\n" + vi.ExternalURL + "\r\n\r\n")
|
||||||
|
|
||||||
if vi.Slim {
|
if vi.Slim {
|
||||||
_, _ = str.WriteString(fmt.Sprintf("Slim build of Coder, does not support the %s subcommand.", cliui.Styles.Code.Render("server")))
|
_, _ = str.WriteString(fmt.Sprintf("Slim build of Coder, does not support the %s subcommand.", cliui.DefaultStyles.Code.Render("server")))
|
||||||
} else {
|
} else {
|
||||||
_, _ = str.WriteString(fmt.Sprintf("Full build of Coder, supports the %s subcommand.", cliui.Styles.Code.Render("server")))
|
_, _ = str.WriteString(fmt.Sprintf("Full build of Coder, supports the %s subcommand.", cliui.DefaultStyles.Code.Render("server")))
|
||||||
}
|
}
|
||||||
return str.String()
|
return str.String()
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ func main() {
|
|||||||
Use: "prompt",
|
Use: "prompt",
|
||||||
Handler: func(inv *clibase.Invocation) error {
|
Handler: func(inv *clibase.Invocation) error {
|
||||||
_, err := cliui.Prompt(inv, cliui.PromptOptions{
|
_, err := cliui.Prompt(inv, cliui.PromptOptions{
|
||||||
Text: "What is our " + cliui.Styles.Field.Render("company name") + "?",
|
Text: "What is our " + cliui.DefaultStyles.Field.Render("company name") + "?",
|
||||||
Default: "acme-corp",
|
Default: "acme-corp",
|
||||||
Validate: func(s string) error {
|
Validate: func(s string) error {
|
||||||
if !strings.EqualFold(s, "coder") {
|
if !strings.EqualFold(s, "coder") {
|
||||||
|
@ -114,8 +114,8 @@ func readOrGenerateConfig(customTunnelHost string) (Config, error) {
|
|||||||
|
|
||||||
if cfg.Version == 0 {
|
if cfg.Version == 0 {
|
||||||
_, _ = fmt.Println()
|
_, _ = fmt.Println()
|
||||||
_, _ = fmt.Println(cliui.Styles.Error.Render("You're running a deprecated tunnel version!"))
|
_, _ = fmt.Println(cliui.DefaultStyles.Error.Render("You're running a deprecated tunnel version!"))
|
||||||
_, _ = fmt.Println(cliui.Styles.Error.Render("Upgrading you to the new version now. You will need to rebuild running workspaces."))
|
_, _ = fmt.Println(cliui.DefaultStyles.Error.Render("Upgrading you to the new version now. You will need to rebuild running workspaces."))
|
||||||
_, _ = fmt.Println()
|
_, _ = fmt.Println()
|
||||||
|
|
||||||
cfg, err := GenerateConfig(customTunnelHost)
|
cfg, err := GenerateConfig(customTunnelHost)
|
||||||
@ -172,8 +172,8 @@ func GenerateConfig(customTunnelHost string) (Config, error) {
|
|||||||
|
|
||||||
spin.Stop()
|
spin.Stop()
|
||||||
_, _ = fmt.Printf("Using tunnel in %s with latency %s.\n",
|
_, _ = fmt.Printf("Using tunnel in %s with latency %s.\n",
|
||||||
cliui.Styles.Keyword.Render(locationName),
|
cliui.DefaultStyles.Keyword.Render(locationName),
|
||||||
cliui.Styles.Code.Render(node.AvgLatency.String()),
|
cliui.DefaultStyles.Code.Render(node.AvgLatency.String()),
|
||||||
)
|
)
|
||||||
|
|
||||||
return Config{
|
return Config{
|
||||||
|
@ -37,7 +37,7 @@ func (r *RootCmd) groupCreate() *clibase.Cmd {
|
|||||||
return xerrors.Errorf("create group: %w", err)
|
return xerrors.Errorf("create group: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "Successfully created group %s!\n", cliui.Styles.Keyword.Render(group.Name))
|
_, _ = fmt.Fprintf(inv.Stdout, "Successfully created group %s!\n", cliui.DefaultStyles.Keyword.Render(group.Name))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,6 @@ func TestCreateGroup(t *testing.T) {
|
|||||||
err := inv.Run()
|
err := inv.Run()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
pty.ExpectMatch(fmt.Sprintf("Successfully created group %s!", cliui.Styles.Keyword.Render(groupName)))
|
pty.ExpectMatch(fmt.Sprintf("Successfully created group %s!", cliui.DefaultStyles.Keyword.Render(groupName)))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ func (r *RootCmd) groupDelete() *clibase.Cmd {
|
|||||||
return xerrors.Errorf("delete group: %w", err)
|
return xerrors.Errorf("delete group: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "Successfully deleted group %s!\n", cliui.Styles.Keyword.Render(group.Name))
|
_, _ = fmt.Fprintf(inv.Stdout, "Successfully deleted group %s!\n", cliui.DefaultStyles.Keyword.Render(group.Name))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ func TestGroupDelete(t *testing.T) {
|
|||||||
err = inv.Run()
|
err = inv.Run()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
pty.ExpectMatch(fmt.Sprintf("Successfully deleted group %s", cliui.Styles.Keyword.Render(group.Name)))
|
pty.ExpectMatch(fmt.Sprintf("Successfully deleted group %s", cliui.DefaultStyles.Keyword.Render(group.Name)))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("NoArg", func(t *testing.T) {
|
t.Run("NoArg", func(t *testing.T) {
|
||||||
|
@ -72,7 +72,7 @@ func (r *RootCmd) groupEdit() *clibase.Cmd {
|
|||||||
return xerrors.Errorf("patch group: %w", err)
|
return xerrors.Errorf("patch group: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, "Successfully patched group %s!\n", cliui.Styles.Keyword.Render(group.Name))
|
_, _ = fmt.Fprintf(inv.Stdout, "Successfully patched group %s!\n", cliui.DefaultStyles.Keyword.Render(group.Name))
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ func TestGroupEdit(t *testing.T) {
|
|||||||
err = inv.Run()
|
err = inv.Run()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
pty.ExpectMatch(fmt.Sprintf("Successfully patched group %s", cliui.Styles.Keyword.Render(expectedName)))
|
pty.ExpectMatch(fmt.Sprintf("Successfully patched group %s", cliui.DefaultStyles.Keyword.Render(expectedName)))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("InvalidUserInput", func(t *testing.T) {
|
t.Run("InvalidUserInput", func(t *testing.T) {
|
||||||
|
@ -125,7 +125,7 @@ func (r *RootCmd) provisionerDaemonStart() *clibase.Cmd {
|
|||||||
select {
|
select {
|
||||||
case <-notifyCtx.Done():
|
case <-notifyCtx.Done():
|
||||||
exitErr = notifyCtx.Err()
|
exitErr = notifyCtx.Err()
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Bold.Render(
|
_, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Bold.Render(
|
||||||
"Interrupt caught, gracefully exiting. Use ctrl+\\ to force quit",
|
"Interrupt caught, gracefully exiting. Use ctrl+\\ to force quit",
|
||||||
))
|
))
|
||||||
case exitErr = <-errCh:
|
case exitErr = <-errCh:
|
||||||
|
@ -185,7 +185,7 @@ func (*RootCmd) proxyServer() *clibase.Cmd {
|
|||||||
cliui.Warnf(
|
cliui.Warnf(
|
||||||
inv.Stderr,
|
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",
|
"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.Styles.Field.Render(cfg.AccessURL.String()), reason,
|
cliui.DefaultStyles.Field.Render(cfg.AccessURL.String()), reason,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,7 +297,7 @@ func (*RootCmd) proxyServer() *clibase.Cmd {
|
|||||||
case exitErr = <-errCh:
|
case exitErr = <-errCh:
|
||||||
case <-notifyCtx.Done():
|
case <-notifyCtx.Done():
|
||||||
exitErr = notifyCtx.Err()
|
exitErr = notifyCtx.Err()
|
||||||
_, _ = fmt.Fprintln(inv.Stdout, cliui.Styles.Bold.Render(
|
_, _ = fmt.Fprintln(inv.Stdout, cliui.DefaultStyles.Bold.Render(
|
||||||
"Interrupt caught, gracefully exiting. Use ctrl+\\ to force quit",
|
"Interrupt caught, gracefully exiting. Use ctrl+\\ to force quit",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,5 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var rootCmd entcli.RootCmd
|
var rootCmd entcli.RootCmd
|
||||||
|
|
||||||
rootCmd.RunMain(rootCmd.EnterpriseSubcommands())
|
rootCmd.RunMain(rootCmd.EnterpriseSubcommands())
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user