Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Aug 30, 2024. It is now read-only.
/coder-v1-cliPublic archive

Commitb361110

Browse files
committed
Add clog package with CLIMessage and CLIError
- show rich log output for Info and Success logs- preserve rich CLI output for errors when possible
1 parentc9043b7 commitb361110

File tree

16 files changed

+224
-56
lines changed

16 files changed

+224
-56
lines changed

‎cmd/coder/main.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@ import (
99
"os"
1010
"runtime"
1111

12+
"cdr.dev/coder-cli/internal/clog"
1213
"cdr.dev/coder-cli/internal/cmd"
1314
"cdr.dev/coder-cli/internal/x/xterminal"
14-
15-
"go.coder.com/flog"
1615
)
1716

1817
// Using a global for the version so it can be set at build time using ldflags.
@@ -31,7 +30,8 @@ func main() {
3130

3231
stdoutState,err:=xterminal.MakeOutputRaw(os.Stdout.Fd())
3332
iferr!=nil {
34-
flog.Fatal("set output to raw: %s",err)
33+
clog.Log(clog.Fatal(fmt.Sprintf("set output to raw: %s",err)))
34+
os.Exit(1)
3535
}
3636
deferfunc() {
3737
// Best effort. Would result in broken terminal on window but nothing we can do about it.
@@ -42,6 +42,7 @@ func main() {
4242
app.Version=fmt.Sprintf("%s %s %s/%s",version,runtime.Version(),runtime.GOOS,runtime.GOARCH)
4343

4444
iferr:=app.ExecuteContext(ctx);err!=nil {
45-
flog.Fatal("%v",err)
45+
clog.Log(err)
46+
os.Exit(1)
4647
}
4748
}

‎coder-sdk/error.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import (
1212
// ErrNotFound describes an error case in which the requested resource could not be found
1313
varErrNotFound=xerrors.Errorf("resource not found")
1414

15-
//apiError is the expected payload format for our errors.
16-
typeapiErrorstruct {
15+
//APIError is the expected payload format for our errors.
16+
typeAPIErrorstruct {
1717
Errstruct {
1818
Msgstring`json:"msg"`
1919
}`json:"error"`
@@ -30,15 +30,15 @@ func (e *HTTPError) Error() string {
3030
returnfmt.Sprintf("dump response: %+v",err)
3131
}
3232

33-
varmsgapiError
33+
varmsgAPIError
3434
// Try to decode the payload as an error, if it fails or if there is no error message,
3535
// return the response URL with the dump.
3636
iferr:=json.NewDecoder(e.Response.Body).Decode(&msg);err!=nil||msg.Err.Msg=="" {
3737
returnfmt.Sprintf("%s\n%s",e.Response.Request.URL,dump)
3838
}
3939

4040
// If the payload was a in the expected error format with a message, include it.
41-
returnfmt.Sprintf("%s\n%s%s",e.Response.Request.URL,dump,msg.Err.Msg)
41+
returnmsg.Err.Msg
4242
}
4343

4444
funcbodyError(resp*http.Response)error {

‎internal/activity/pusher.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ package activity
22

33
import (
44
"context"
5+
"fmt"
56
"time"
67

78
"golang.org/x/time/rate"
89

910
"cdr.dev/coder-cli/coder-sdk"
10-
11-
"go.coder.com/flog"
11+
"cdr.dev/coder-cli/internal/clog"
1212
)
1313

1414
constpushInterval=time.Minute
@@ -42,6 +42,6 @@ func (p *Pusher) Push(ctx context.Context) {
4242
}
4343

4444
iferr:=p.client.PushActivity(ctx,p.source,p.envID);err!=nil {
45-
flog.Error("push activity: %s",err)
45+
clog.Log(clog.Error(fmt.Sprintf("push activity: %s",err)))
4646
}
4747
}

‎internal/clog/error.go

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package clog
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"os"
7+
"strings"
8+
9+
"github.com/fatih/color"
10+
"golang.org/x/xerrors"
11+
)
12+
13+
// CLIMessage provides a human-readable message for CLI errors and messages.
14+
typeCLIMessagestruct {
15+
Levelstring
16+
Color color.Attribute
17+
Headerstring
18+
Lines []string
19+
}
20+
21+
// CLIError wraps a CLIMessage and allows consumers to treat it as a normal error.
22+
typeCLIErrorstruct {
23+
CLIMessage
24+
error
25+
}
26+
27+
// String formats the CLI message for consumption by a human.
28+
func (mCLIMessage)String()string {
29+
varstr strings.Builder
30+
str.WriteString(fmt.Sprintf("%s: %s\n",
31+
color.New(m.Color).Sprint(m.Level),
32+
color.New(color.Bold).Sprint(m.Header)),
33+
)
34+
for_,line:=rangem.Lines {
35+
str.WriteString(fmt.Sprintf(" %s %s\n",color.New(m.Color).Sprint("|"),line))
36+
}
37+
returnstr.String()
38+
}
39+
40+
// Log logs the given error to stderr, defaulting to "fatal" if the error is not a CLIError.
41+
// If the error is a CLIError, the plain error chain is ignored and the CLIError
42+
// is logged on its own.
43+
funcLog(errerror) {
44+
varcliErrCLIError
45+
if!xerrors.As(err,&cliErr) {
46+
cliErr=Fatal(err.Error())
47+
}
48+
fmt.Fprintln(os.Stderr,cliErr.String())
49+
}
50+
51+
// LogInfo prints the given info message to stderr.
52+
funcLogInfo(headerstring,lines...string) {
53+
fmt.Fprintln(os.Stderr,CLIMessage{
54+
Level:"info",
55+
Color:color.FgBlue,
56+
Header:header,
57+
Lines:lines,
58+
}.String())
59+
}
60+
61+
// LogSuccess prints the given info message to stderr.
62+
funcLogSuccess(headerstring,lines...string) {
63+
fmt.Fprintln(os.Stderr,CLIMessage{
64+
Level:"success",
65+
Color:color.FgGreen,
66+
Header:header,
67+
Lines:lines,
68+
}.String())
69+
}
70+
71+
// Warn creates an error with the level "warning".
72+
funcWarn(headerstring,lines...string)CLIError {
73+
returnCLIError{
74+
CLIMessage:CLIMessage{
75+
Color:color.FgYellow,
76+
Level:"warning",
77+
Header:header,
78+
Lines:lines,
79+
},
80+
error:errors.New(header),
81+
}
82+
}
83+
84+
// Error creates an error with the level "error".
85+
funcError(headerstring,lines...string)CLIError {
86+
returnCLIError{
87+
CLIMessage:CLIMessage{
88+
Color:color.FgRed,
89+
Level:"error",
90+
Header:header,
91+
Lines:lines,
92+
},
93+
error:errors.New(header),
94+
}
95+
}
96+
97+
// Fatal creates an error with the level "fatal".
98+
funcFatal(headerstring,lines...string)CLIError {
99+
returnCLIError{
100+
CLIMessage:CLIMessage{
101+
Color:color.FgRed,
102+
Level:"fatal",
103+
Header:header,
104+
Lines:lines,
105+
},
106+
error:errors.New(header),
107+
}
108+
}
109+
110+
// Bold provides a convenience wrapper around color.New for brevity when logging.
111+
funcBold(astring)string {
112+
returncolor.New(color.Bold).Sprint(a)
113+
}
114+
115+
// Tip formats according to the given format specifier and prepends a bolded "tip: " header.
116+
funcTip(formatstring,a...interface{})string {
117+
returnfmt.Sprintf("%s %s",Bold("tip:"),fmt.Sprintf(format,a...))
118+
}
119+
120+
// Hint formats according to the given format specifier and prepends a bolded "hint: " header.
121+
funcHint(formatstring,a...interface{})string {
122+
returnfmt.Sprintf("%s %s",Bold("hint:"),fmt.Sprintf(format,a...))
123+
}
124+
125+
// Cause formats according to the given format specifier and prepends a bolded "cause: " header.
126+
funcCause(formatstring,a...interface{})string {
127+
returnfmt.Sprintf("%s %s",Bold("cause:"),fmt.Sprintf(format,a...))
128+
}
129+
130+
// BlankLine is an empty string meant to be used in CLIMessage and CLIError construction.
131+
constBlankLine=""

‎internal/cmd/auth.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@ import (
88
"golang.org/x/xerrors"
99

1010
"cdr.dev/coder-cli/coder-sdk"
11+
"cdr.dev/coder-cli/internal/clog"
1112
"cdr.dev/coder-cli/internal/config"
1213
)
1314

14-
varerrNeedLogin=xerrors.New("failed to read session credentials: did you run\"coder login\"?")
15+
varerrNeedLogin=clog.Fatal(
16+
"failed to read session credentials",
17+
clog.Hint(`did you run "coder login [https://coder.domain.com]"?`),
18+
)
1519

1620
funcnewClient() (*coder.Client,error) {
1721
sessionToken,err:=config.Session.Read()

‎internal/cmd/ceapi.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66

77
"cdr.dev/coder-cli/coder-sdk"
8+
"cdr.dev/coder-cli/internal/clog"
89
"golang.org/x/xerrors"
910
)
1011

@@ -73,10 +74,12 @@ func findEnv(ctx context.Context, client *coder.Client, envName, userEmail strin
7374
found=append(found,env.Name)
7475
}
7576

76-
returnnil,notFoundButDidFind{
77-
needle:envName,
78-
haystack:found,
79-
}
77+
returnnil,clog.Fatal(
78+
"failed to find environment",
79+
fmt.Sprintf("environment %q not found in %q",envName,found),
80+
clog.BlankLine,
81+
clog.Tip("run\"coder envs ls\" to view your environments"),
82+
)
8083
}
8184

8285
typenotFoundButDidFindstruct {

‎internal/cmd/envs.go

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@ package cmd
22

33
import (
44
"encoding/json"
5+
"fmt"
56
"os"
7+
"sync/atomic"
68

79
"cdr.dev/coder-cli/coder-sdk"
10+
"cdr.dev/coder-cli/internal/clog"
811
"cdr.dev/coder-cli/internal/x/xtabwriter"
912
"github.com/spf13/cobra"
1013
"golang.org/x/sync/errgroup"
1114
"golang.org/x/xerrors"
12-
13-
"go.coder.com/flog"
1415
)
1516

1617
funcenvsCommand()*cobra.Command {
@@ -37,7 +38,7 @@ func envsCommand() *cobra.Command {
3738
returnerr
3839
}
3940
iflen(envs)<1 {
40-
flog.Info("no environments found")
41+
clog.LogInfo("no environments found")
4142
returnnil
4243
}
4344

@@ -92,26 +93,33 @@ coder envs --user charlie@coder.com ls -o json \
9293
}
9394

9495
varegroup errgroup.Group
96+
varfailsint32
9597
for_,envName:=rangeargs {
9698
envName:=envName
9799
egroup.Go(func()error {
98100
env,err:=findEnv(cmd.Context(),client,envName,*user)
99101
iferr!=nil {
100-
flog.Error("failed to find environment by name\"%s\": %v",envName,err)
101-
returnxerrors.Errorf("find environment by name: %w",err)
102+
atomic.AddInt32(&fails,1)
103+
clog.Log(err)
104+
returnxerrors.Errorf("find env by name: %w",err)
102105
}
103106

104107
iferr=client.StopEnvironment(cmd.Context(),env.ID);err!=nil {
105-
flog.Error("failed to stop environment\"%s\": %v",env.Name,err)
106-
returnxerrors.Errorf("stop environment: %w",err)
108+
atomic.AddInt32(&fails,1)
109+
err=clog.Fatal(fmt.Sprintf("stop environment %q",env.Name),
110+
clog.Cause(err.Error()),clog.BlankLine,
111+
clog.Hint("current environment status is %q",env.LatestStat.ContainerStatus),
112+
)
113+
clog.Log(err)
114+
returnerr
107115
}
108-
flog.Success("Successfully stopped environment %q",envName)
116+
clog.LogSuccess(fmt.Sprintf("successfully stopped environment %q",envName))
109117
returnnil
110118
})
111119
}
112120

113121
iferr=egroup.Wait();err!=nil {
114-
returnxerrors.Errorf("some stop operations failed")
122+
returnclog.Fatal(fmt.Sprintf("%d failure(s) emitted",fails))
115123
}
116124
returnnil
117125
},

‎internal/cmd/login.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@ import (
99
"strings"
1010

1111
"cdr.dev/coder-cli/coder-sdk"
12+
"cdr.dev/coder-cli/internal/clog"
1213
"cdr.dev/coder-cli/internal/config"
1314
"cdr.dev/coder-cli/internal/loginsrv"
1415
"github.com/pkg/browser"
1516
"github.com/spf13/cobra"
1617
"golang.org/x/sync/errgroup"
1718
"golang.org/x/xerrors"
18-
19-
"go.coder.com/flog"
2019
)
2120

2221
funcmakeLoginCmd()*cobra.Command {
@@ -140,7 +139,7 @@ func login(cmd *cobra.Command, envURL *url.URL, urlCfg, sessionCfg config.File)
140139
returnxerrors.Errorf("store config: %w",err)
141140
}
142141

143-
flog.Success("Logged in.")
142+
clog.LogSuccess("logged in")
144143

145144
returnnil
146145
}

‎internal/cmd/logout.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@ package cmd
33
import (
44
"os"
55

6+
"cdr.dev/coder-cli/internal/clog"
67
"cdr.dev/coder-cli/internal/config"
78
"github.com/spf13/cobra"
89
"golang.org/x/xerrors"
9-
10-
"go.coder.com/flog"
1110
)
1211

1312
funcmakeLogoutCmd()*cobra.Command {
@@ -22,11 +21,11 @@ func logout(_ *cobra.Command, _ []string) error {
2221
err:=config.Session.Delete()
2322
iferr!=nil {
2423
ifos.IsNotExist(err) {
25-
flog.Info("no active session")
24+
clog.LogInfo("no active session")
2625
returnnil
2726
}
2827
returnxerrors.Errorf("delete session: %w",err)
2928
}
30-
flog.Success("logged out")
29+
clog.LogSuccess("logged out")
3130
returnnil
3231
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp