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

Commitf5df548

Browse files
authored
feat: tokens (#4380)
1 parentfe7c9f8 commitf5df548

21 files changed

+685
-260
lines changed

‎cli/cliui/table.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,10 @@ func DisplayTable(out any, sort string, filterColumns []string) (string, error)
153153
// Special type formatting.
154154
switchval:=v.(type) {
155155
case time.Time:
156-
v=val.Format(time.Stamp)
156+
v=val.Format(time.RFC3339)
157157
case*time.Time:
158158
ifval!=nil {
159-
v=val.Format(time.Stamp)
159+
v=val.Format(time.RFC3339)
160160
}
161161
case fmt.Stringer:
162162
ifval!=nil {

‎cli/cliui/table_test.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,10 @@ func Test_DisplayTable(t *testing.T) {
131131
t.Parallel()
132132

133133
expected:=`
134-
NAME AGE ROLES SUB 1 NAME SUB 1 AGE SUB 2 NAME SUB 2 AGE SUB 3 INNER NAME SUB 3 INNER AGE SUB 4 TIME TIME PTR
135-
foo 10 [a b c] foo1 11 foo2 12 foo3 13 {foo4 14 }Aug 2 15:49:10 Aug 2 15:49:10
136-
bar 20 [a] bar1 21 <nil> <nil> bar3 23 {bar4 24 }Aug 2 15:49:10 <nil>
137-
baz 30 [] baz1 31 <nil> <nil> baz3 33 {baz4 34 }Aug 2 15:49:10 <nil>
134+
NAME AGE ROLES SUB 1 NAME SUB 1 AGE SUB 2 NAME SUB 2 AGE SUB 3 INNER NAME SUB 3 INNER AGE SUB 4 TIMETIME PTR
135+
foo 10 [a b c] foo1 11 foo2 12 foo3 13 {foo4 14 }2022-08-02T15:49:10Z 2022-08-02T15:49:10Z
136+
bar 20 [a] bar1 21 <nil> <nil> bar3 23 {bar4 24 }2022-08-02T15:49:10Z <nil>
137+
baz 30 [] baz1 31 <nil> <nil> baz3 33 {baz4 34 }2022-08-02T15:49:10Z <nil>
138138
`
139139

140140
// Test with non-pointer values.
@@ -158,10 +158,10 @@ baz 30 [] baz1 31 <nil> <nil> baz3
158158
t.Parallel()
159159

160160
expected:=`
161-
NAME AGE ROLES SUB 1 NAME SUB 1 AGE SUB 2 NAME SUB 2 AGE SUB 3 INNER NAME SUB 3 INNER AGE SUB 4 TIME TIME PTR
162-
bar 20 [a] bar1 21 <nil> <nil> bar3 23 {bar4 24 }Aug 2 15:49:10 <nil>
163-
baz 30 [] baz1 31 <nil> <nil> baz3 33 {baz4 34 }Aug 2 15:49:10 <nil>
164-
foo 10 [a b c] foo1 11 foo2 12 foo3 13 {foo4 14 }Aug 2 15:49:10 Aug 2 15:49:10
161+
NAME AGE ROLES SUB 1 NAME SUB 1 AGE SUB 2 NAME SUB 2 AGE SUB 3 INNER NAME SUB 3 INNER AGE SUB 4 TIMETIME PTR
162+
bar 20 [a] bar1 21 <nil> <nil> bar3 23 {bar4 24 }2022-08-02T15:49:10Z <nil>
163+
baz 30 [] baz1 31 <nil> <nil> baz3 33 {baz4 34 }2022-08-02T15:49:10Z <nil>
164+
foo 10 [a b c] foo1 11 foo2 12 foo3 13 {foo4 14 }2022-08-02T15:49:10Z 2022-08-02T15:49:10Z
165165
`
166166

167167
out,err:=cliui.DisplayTable(in,"name",nil)
@@ -175,9 +175,9 @@ foo 10 [a b c] foo1 11 foo2 12 foo3
175175

176176
expected:=`
177177
NAME SUB 1 NAME SUB 3 INNER NAME TIME
178-
foo foo1 foo3Aug 2 15:49:10
179-
bar bar1 bar3Aug 2 15:49:10
180-
baz baz1 baz3Aug 2 15:49:10
178+
foo foo1 foo32022-08-02T15:49:10Z
179+
bar bar1 bar32022-08-02T15:49:10Z
180+
baz baz1 baz32022-08-02T15:49:10Z
181181
`
182182

183183
out,err:=cliui.DisplayTable(in,"", []string{"name","sub_1_name","sub_3 inner name","time"})

‎cli/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ func Core() []*cobra.Command {
9393
users(),
9494
versionCmd(),
9595
workspaceAgent(),
96+
tokens(),
9697
}
9798
}
9899

‎cli/tokens.go

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
"time"
7+
8+
"github.com/spf13/cobra"
9+
"golang.org/x/xerrors"
10+
11+
"github.com/coder/coder/cli/cliui"
12+
"github.com/coder/coder/codersdk"
13+
)
14+
15+
functokens()*cobra.Command {
16+
cmd:=&cobra.Command{
17+
Use:"tokens",
18+
Short:"Manage personal access tokens",
19+
Long:"Tokens are used to authenticate automated clients to Coder.",
20+
Aliases: []string{"token"},
21+
Example:formatExamples(
22+
example{
23+
Description:"Create a token for automation",
24+
Command:"coder tokens create",
25+
},
26+
example{
27+
Description:"List your tokens",
28+
Command:"coder tokens ls",
29+
},
30+
example{
31+
Description:"Remove a token by ID",
32+
Command:"coder tokens rm WuoWs4ZsMX",
33+
},
34+
),
35+
}
36+
cmd.AddCommand(
37+
createToken(),
38+
listTokens(),
39+
removeToken(),
40+
)
41+
42+
returncmd
43+
}
44+
45+
funccreateToken()*cobra.Command {
46+
cmd:=&cobra.Command{
47+
Use:"create",
48+
Short:"Create a tokens",
49+
RunE:func(cmd*cobra.Command,args []string)error {
50+
client,err:=CreateClient(cmd)
51+
iferr!=nil {
52+
returnxerrors.Errorf("create codersdk client: %w",err)
53+
}
54+
55+
res,err:=client.CreateToken(cmd.Context(),codersdk.Me)
56+
iferr!=nil {
57+
returnxerrors.Errorf("create tokens: %w",err)
58+
}
59+
60+
cmd.Println(cliui.Styles.Wrap.Render(
61+
"Here is your token. 🪄",
62+
))
63+
cmd.Println()
64+
cmd.Println(cliui.Styles.Code.Render(strings.TrimSpace(res.Key)))
65+
cmd.Println()
66+
cmd.Println(cliui.Styles.Wrap.Render(
67+
fmt.Sprintf("You can use this token by setting the --%s CLI flag, the %s environment variable, or the %q HTTP header.",varToken,envSessionToken,codersdk.SessionTokenKey),
68+
))
69+
70+
returnnil
71+
},
72+
}
73+
74+
returncmd
75+
}
76+
77+
typetokenRowstruct {
78+
IDstring`table:"ID"`
79+
LastUsed time.Time`table:"Last Used"`
80+
ExpiresAt time.Time`table:"Expires At"`
81+
CreatedAt time.Time`table:"Created At"`
82+
}
83+
84+
funclistTokens()*cobra.Command {
85+
cmd:=&cobra.Command{
86+
Use:"list",
87+
Aliases: []string{"ls"},
88+
Short:"List tokens",
89+
RunE:func(cmd*cobra.Command,args []string)error {
90+
client,err:=CreateClient(cmd)
91+
iferr!=nil {
92+
returnxerrors.Errorf("create codersdk client: %w",err)
93+
}
94+
95+
keys,err:=client.GetTokens(cmd.Context(),codersdk.Me)
96+
iferr!=nil {
97+
returnxerrors.Errorf("create tokens: %w",err)
98+
}
99+
100+
iflen(keys)==0 {
101+
cmd.Println(cliui.Styles.Wrap.Render(
102+
"No tokens found.",
103+
))
104+
}
105+
106+
varrows []tokenRow
107+
for_,key:=rangekeys {
108+
rows=append(rows,tokenRow{
109+
ID:key.ID,
110+
LastUsed:key.LastUsed,
111+
ExpiresAt:key.ExpiresAt,
112+
CreatedAt:key.CreatedAt,
113+
})
114+
}
115+
116+
out,err:=cliui.DisplayTable(rows,"",nil)
117+
iferr!=nil {
118+
returnerr
119+
}
120+
121+
_,err=fmt.Fprintln(cmd.OutOrStdout(),out)
122+
returnerr
123+
},
124+
}
125+
126+
returncmd
127+
}
128+
129+
funcremoveToken()*cobra.Command {
130+
cmd:=&cobra.Command{
131+
Use:"remove [id]",
132+
Aliases: []string{"rm"},
133+
Short:"Delete a token",
134+
Args:cobra.ExactArgs(1),
135+
RunE:func(cmd*cobra.Command,args []string)error {
136+
client,err:=CreateClient(cmd)
137+
iferr!=nil {
138+
returnxerrors.Errorf("create codersdk client: %w",err)
139+
}
140+
141+
err=client.DeleteAPIKey(cmd.Context(),codersdk.Me,args[0])
142+
iferr!=nil {
143+
returnxerrors.Errorf("delete api key: %w",err)
144+
}
145+
146+
cmd.Println(cliui.Styles.Wrap.Render(
147+
"Token has been deleted.",
148+
))
149+
150+
returnnil
151+
},
152+
}
153+
154+
returncmd
155+
}

‎cli/tokens_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package cli_test
2+
3+
import (
4+
"bytes"
5+
"regexp"
6+
"testing"
7+
8+
"github.com/stretchr/testify/require"
9+
10+
"github.com/coder/coder/cli/clitest"
11+
"github.com/coder/coder/coderd/coderdtest"
12+
)
13+
14+
funcTestTokens(t*testing.T) {
15+
t.Parallel()
16+
client:=coderdtest.New(t,nil)
17+
_=coderdtest.CreateFirstUser(t,client)
18+
19+
// helpful empty response
20+
cmd,root:=clitest.New(t,"tokens","ls")
21+
clitest.SetupConfig(t,client,root)
22+
buf:=new(bytes.Buffer)
23+
cmd.SetOut(buf)
24+
err:=cmd.Execute()
25+
require.NoError(t,err)
26+
res:=buf.String()
27+
require.Contains(t,res,"tokens found")
28+
29+
cmd,root=clitest.New(t,"tokens","create")
30+
clitest.SetupConfig(t,client,root)
31+
buf=new(bytes.Buffer)
32+
cmd.SetOut(buf)
33+
err=cmd.Execute()
34+
require.NoError(t,err)
35+
res=buf.String()
36+
require.NotEmpty(t,res)
37+
// find API key in format "XXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXX"
38+
r:=regexp.MustCompile("[a-zA-Z0-9]{10}-[a-zA-Z0-9]{22}")
39+
require.Regexp(t,r,res)
40+
key:=r.FindString(res)
41+
id:=key[:10]
42+
43+
cmd,root=clitest.New(t,"tokens","ls")
44+
clitest.SetupConfig(t,client,root)
45+
buf=new(bytes.Buffer)
46+
cmd.SetOut(buf)
47+
err=cmd.Execute()
48+
require.NoError(t,err)
49+
res=buf.String()
50+
require.NotEmpty(t,res)
51+
require.Contains(t,res,"ID")
52+
require.Contains(t,res,"EXPIRES AT")
53+
require.Contains(t,res,"CREATED AT")
54+
require.Contains(t,res,"LAST USED")
55+
require.Contains(t,res,id)
56+
57+
cmd,root=clitest.New(t,"tokens","rm",id)
58+
clitest.SetupConfig(t,client,root)
59+
buf=new(bytes.Buffer)
60+
cmd.SetOut(buf)
61+
err=cmd.Execute()
62+
require.NoError(t,err)
63+
res=buf.String()
64+
require.NotEmpty(t,res)
65+
require.Contains(t,res,"deleted")
66+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp