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

Commit9b1173e

Browse files
committed
Add table output to envs ls
1 parentb957f37 commit9b1173e

File tree

8 files changed

+125
-25
lines changed

8 files changed

+125
-25
lines changed

‎ci/integration/integration_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func TestCoderCLI(t *testing.T) {
4949
headlessLogin(ctx,t,c)
5050

5151
c.Run(ctx,"coder envs").Assert(t,
52-
tcli.Success(),
52+
tcli.Error(),
5353
)
5454

5555
c.Run(ctx,"coder envs ls").Assert(t,

‎cmd/coder/envs.go

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
package main
22

33
import (
4-
"fmt"
4+
"encoding/json"
5+
"os"
56

7+
"cdr.dev/coder-cli/internal/x/xtabwriter"
68
"github.com/urfave/cli"
9+
10+
"go.coder.com/flog"
711
)
812

913
funcmakeEnvsCommand() cli.Command {
14+
varoutputFmtstring
1015
return cli.Command{
1116
Name:"envs",
1217
Usage:"Interact with Coder environments",
1318
Description:"Perform operations on the Coder environments owned by the active user.",
19+
Action:exitHelp,
1420
Subcommands: []cli.Command{
1521
{
1622
Name:"ls",
@@ -21,11 +27,27 @@ func makeEnvsCommand() cli.Command {
2127
entClient:=requireAuth()
2228
envs:=getEnvs(entClient)
2329

24-
for_,env:=rangeenvs {
25-
fmt.Println(env.Name)
30+
switchoutputFmt {
31+
case"human":
32+
err:=xtabwriter.WriteTable(len(envs),func(iint)interface{} {
33+
returnenvs[i]
34+
})
35+
requireSuccess(err,"failed to write table: %v",err)
36+
case"json":
37+
err:=json.NewEncoder(os.Stdout).Encode(envs)
38+
requireSuccess(err,"failed to write json: %v",err)
39+
default:
40+
flog.Fatal("unknown --output value %q",outputFmt)
2641
}
2742
},
28-
Flags:nil,
43+
Flags: []cli.Flag{
44+
cli.StringFlag{
45+
Name:"output",
46+
Usage:"json | human",
47+
Value:"human",
48+
Destination:&outputFmt,
49+
},
50+
},
2951
},
3052
},
3153
}

‎cmd/coder/main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ func main() {
4040
flog.Fatal("command %q not found",s)
4141
}
4242
app.Email="support@coder.com"
43+
app.Action=exitHelp
4344

4445
app.Commands= []cli.Command{
4546
makeLoginCmd(),
@@ -64,3 +65,7 @@ func requireSuccess(err error, msg string, args ...interface{}) {
6465
flog.Fatal(msg,args...)
6566
}
6667
}
68+
69+
funcexitHelp(c*cli.Context) {
70+
cli.ShowCommandHelpAndExit(c,c.Command.FullName(),1)
71+
}

‎cmd/coder/secrets.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ func makeSecretsCmd() cli.Command {
1919
Name:"secrets",
2020
Usage:"Interact with Coder Secrets",
2121
Description:"Interact with secrets objects owned by the active user.",
22+
Action:exitHelp,
2223
Subcommands: []cli.Command{
2324
{
2425
Name:"ls",
@@ -30,7 +31,7 @@ func makeSecretsCmd() cli.Command {
3031
Name:"rm",
3132
Usage:"Remove one or more secrets by name",
3233
ArgsUsage:"[...secret_name]",
33-
Action:removeSecret,
34+
Action:removeSecrets,
3435
},
3536
{
3637
Name:"view",
@@ -171,7 +172,7 @@ func viewSecret(c *cli.Context) {
171172
requireSuccess(err,"failed to write: %v",err)
172173
}
173174

174-
funcremoveSecret(c*cli.Context) {
175+
funcremoveSecrets(c*cli.Context) {
175176
var (
176177
client=requireAuth()
177178
names=append([]string{c.Args().First()},c.Args().Tail()...)

‎cmd/coder/users.go

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package main
22

33
import (
44
"encoding/json"
5-
"fmt"
65
"os"
76

87
"cdr.dev/coder-cli/internal/x/xtabwriter"
@@ -14,8 +13,9 @@ import (
1413
funcmakeUsersCmd() cli.Command {
1514
varoutputstring
1615
return cli.Command{
17-
Name:"users",
18-
Usage:"Interact with Coder user accounts",
16+
Name:"users",
17+
Usage:"Interact with Coder user accounts",
18+
Action:exitHelp,
1919
Subcommands: []cli.Command{
2020
{
2121
Name:"ls",
@@ -24,7 +24,7 @@ func makeUsersCmd() cli.Command {
2424
Flags: []cli.Flag{
2525
cli.StringFlag{
2626
Name:"output",
27-
Usage:"(json | human)",
27+
Usage:"json | human",
2828
Value:"human",
2929
Destination:&output,
3030
},
@@ -43,17 +43,10 @@ func listUsers(outputFmt *string) func(c *cli.Context) {
4343

4444
switch*outputFmt {
4545
case"human":
46-
w:=xtabwriter.NewWriter()
47-
iflen(users)>0 {
48-
_,err=fmt.Fprintln(w,xtabwriter.StructFieldNames(users[0]))
49-
requireSuccess(err,"failed to write: %v",err)
50-
}
51-
for_,u:=rangeusers {
52-
_,err=fmt.Fprintln(w,xtabwriter.StructValues(u))
53-
requireSuccess(err,"failed to write: %v",err)
54-
}
55-
err=w.Flush()
56-
requireSuccess(err,"failed to flush writer: %v",err)
46+
err:=xtabwriter.WriteTable(len(users),func(iint)interface{} {
47+
returnusers[i]
48+
})
49+
requireSuccess(err,"failed to write table: %v",err)
5750
case"json":
5851
err=json.NewEncoder(os.Stdout).Encode(users)
5952
requireSuccess(err,"failed to encode users to json: %v",err)

‎internal/entclient/env.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,33 @@ import (
44
"context"
55
"time"
66

7+
"cdr.dev/coder-cli/internal/x/xjson"
78
"nhooyr.io/websocket"
89
)
910

1011
// Environment describes a Coder environment
1112
typeEnvironmentstruct {
12-
Namestring`json:"name"`
13-
IDstring`json:"id"`
13+
IDstring`json:"id" tab:"-"`
14+
Namestring`json:"name"`
15+
ImageIDstring`json:"image_id" tab:"-"`
16+
ImageTagstring`json:"image_tag"`
17+
OrganizationIDstring`json:"organization_id" tab:"-"`
18+
UserIDstring`json:"user_id" tab:"-"`
19+
LastBuiltAt time.Time`json:"last_built_at" tab:"-"`
20+
CPUCoresfloat32`json:"cpu_cores"`
21+
MemoryGBint`json:"memory_gb"`
22+
DiskGBint`json:"disk_gb"`
23+
GPUsint`json:"gpus"`
24+
Updatingbool`json:"updating"`
25+
RebuildMessages []struct {
26+
Textstring`json:"text"`
27+
Requiredbool`json:"required"`
28+
}`json:"rebuild_messages" tab:"-"`
29+
CreatedAt time.Time`json:"created_at" tab:"-"`
30+
UpdatedAt time.Time`json:"updated_at" tab:"-"`
31+
LastOpenedAt time.Time`json:"last_opened_at" tab:"-"`
32+
LastConnectionAt time.Time`json:"last_connection_at" tab:"-"`
33+
AutoOffThreshold xjson.Duration`json:"auto_off_threshold" tab:"-"`
1434
}
1535

1636
// Envs gets the list of environments owned by the authenticated user

‎internal/x/xjson/duration.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package xjson
2+
3+
import (
4+
"encoding/json"
5+
"strconv"
6+
"time"
7+
)
8+
9+
// Duration is a time.Duration that marshals to millisecond precision.
10+
// Most javascript applications expect durations to be in milliseconds.
11+
typeDuration time.Duration
12+
13+
// MarshalJSON marshals the duration to millisecond precision.
14+
func (dDuration)MarshalJSON() ([]byte,error) {
15+
du:=time.Duration(d)
16+
returnjson.Marshal(du.Milliseconds())
17+
}
18+
19+
// UnmarshalJSON unmarshals a millisecond-precision integer to
20+
// a time.Duration.
21+
func (d*Duration)UnmarshalJSON(b []byte)error {
22+
i,err:=strconv.ParseInt(string(b),10,64)
23+
iferr!=nil {
24+
returnerr
25+
}
26+
27+
*d=Duration(time.Duration(i)*time.Millisecond)
28+
returnnil
29+
}
30+
31+
func (dDuration)String()string {
32+
returntime.Duration(d).String()
33+
}

‎internal/x/xtabwriter/tabwriter.go

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func StructValues(data interface{}) string {
2525
ifshouldHideField(v.Type().Field(i)) {
2626
continue
2727
}
28-
s.WriteString(fmt.Sprintf("%s\t",v.Field(i).Interface()))
28+
s.WriteString(fmt.Sprintf("%v\t",v.Field(i).Interface()))
2929
}
3030
returns.String()
3131
}
@@ -46,6 +46,32 @@ func StructFieldNames(data interface{}) string {
4646
returns.String()
4747
}
4848

49+
// WriteTable writes the given list elements to stdout in a human readable
50+
// tabular format. Headers abide by the `tab` struct tag.
51+
//
52+
// `tab:"-"` omits the field and no tag defaults to the Go identifier.
53+
funcWriteTable(lengthint,eachfunc(iint)interface{})error {
54+
iflength<1 {
55+
returnnil
56+
}
57+
w:=NewWriter()
58+
deferw.Flush()
59+
forix:=0;ix<length;ix++ {
60+
item:=each(ix)
61+
ifix==0 {
62+
_,err:=fmt.Fprintln(w,StructFieldNames(item))
63+
iferr!=nil {
64+
returnerr
65+
}
66+
}
67+
_,err:=fmt.Fprintln(w,StructValues(item))
68+
iferr!=nil {
69+
returnerr
70+
}
71+
}
72+
returnnil
73+
}
74+
4975
funcshouldHideField(f reflect.StructField)bool {
5076
returnf.Tag.Get(structFieldTagKey)=="-"
5177
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp