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

Commit8a35925

Browse files
authored
feat: add "Full Name" field to user creation (#13659)
Adds the ability to specify "Full Name" (a.k.a. Name) whencreating users either via CLI or UI.
1 parent87ad560 commit8a35925

33 files changed

+435
-25
lines changed

‎Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,3 +865,7 @@ test-tailnet-integration:
865865
test-clean:
866866
go clean -testcache
867867
.PHONY: test-clean
868+
869+
.PHONY: test-e2e
870+
test-e2e:
871+
cd ./site&& DEBUG=pw:api pnpm playwright:test --forbid-only --workers 1

‎cli/login.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,21 @@ func promptFirstUsername(inv *serpent.Invocation) (string, error) {
5858
returnusername,nil
5959
}
6060

61+
funcpromptFirstName(inv*serpent.Invocation) (string,error) {
62+
name,err:=cliui.Prompt(inv, cliui.PromptOptions{
63+
Text:"(Optional) What "+pretty.Sprint(cliui.DefaultStyles.Field,"name")+" would you like?",
64+
Default:"",
65+
})
66+
iferr!=nil {
67+
iferrors.Is(err,cliui.Canceled) {
68+
return"",nil
69+
}
70+
return"",err
71+
}
72+
73+
returnname,nil
74+
}
75+
6176
funcpromptFirstPassword(inv*serpent.Invocation) (string,error) {
6277
retry:
6378
password,err:=cliui.Prompt(inv, cliui.PromptOptions{
@@ -130,6 +145,7 @@ func (r *RootCmd) login() *serpent.Command {
130145
var (
131146
emailstring
132147
usernamestring
148+
namestring
133149
passwordstring
134150
trialbool
135151
useTokenForSessionbool
@@ -191,6 +207,7 @@ func (r *RootCmd) login() *serpent.Command {
191207

192208
_,_=fmt.Fprintf(inv.Stdout,"Attempting to authenticate with %s URL: '%s'\n",urlSource,serverURL)
193209

210+
// nolint: nestif
194211
if!hasFirstUser {
195212
_,_=fmt.Fprintf(inv.Stdout,Caret+"Your Coder deployment hasn't been set up!\n")
196213

@@ -212,6 +229,10 @@ func (r *RootCmd) login() *serpent.Command {
212229
iferr!=nil {
213230
returnerr
214231
}
232+
name,err=promptFirstName(inv)
233+
iferr!=nil {
234+
returnerr
235+
}
215236
}
216237

217238
ifemail=="" {
@@ -249,6 +270,7 @@ func (r *RootCmd) login() *serpent.Command {
249270
_,err=client.CreateFirstUser(ctx, codersdk.CreateFirstUserRequest{
250271
Email:email,
251272
Username:username,
273+
Name:name,
252274
Password:password,
253275
Trial:trial,
254276
})
@@ -360,6 +382,12 @@ func (r *RootCmd) login() *serpent.Command {
360382
Description:"Specifies a username to use if creating the first user for the deployment.",
361383
Value:serpent.StringOf(&username),
362384
},
385+
{
386+
Flag:"first-user-full-name",
387+
Env:"CODER_FIRST_USER_FULL_NAME",
388+
Description:"Specifies a human-readable name for the first user of the deployment.",
389+
Value:serpent.StringOf(&name),
390+
},
363391
{
364392
Flag:"first-user-password",
365393
Env:"CODER_FIRST_USER_PASSWORD",

‎cli/login_test.go

Lines changed: 133 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/coder/coder/v2/coderd/coderdtest"
2121
"github.com/coder/coder/v2/codersdk"
2222
"github.com/coder/coder/v2/pty/ptytest"
23+
"github.com/coder/coder/v2/testutil"
2324
)
2425

2526
funcTestLogin(t*testing.T) {
@@ -91,10 +92,11 @@ func TestLogin(t *testing.T) {
9192

9293
matches:= []string{
9394
"first user?","yes",
94-
"username","testuser",
95-
"email","user@coder.com",
96-
"password","SomeSecurePassword!",
97-
"password","SomeSecurePassword!",// Confirm.
95+
"username",coderdtest.FirstUserParams.Username,
96+
"name",coderdtest.FirstUserParams.Name,
97+
"email",coderdtest.FirstUserParams.Email,
98+
"password",coderdtest.FirstUserParams.Password,
99+
"password",coderdtest.FirstUserParams.Password,// confirm
98100
"trial","yes",
99101
}
100102
fori:=0;i<len(matches);i+=2 {
@@ -105,6 +107,64 @@ func TestLogin(t *testing.T) {
105107
}
106108
pty.ExpectMatch("Welcome to Coder")
107109
<-doneChan
110+
ctx:=testutil.Context(t,testutil.WaitShort)
111+
resp,err:=client.LoginWithPassword(ctx, codersdk.LoginWithPasswordRequest{
112+
Email:coderdtest.FirstUserParams.Email,
113+
Password:coderdtest.FirstUserParams.Password,
114+
})
115+
require.NoError(t,err)
116+
client.SetSessionToken(resp.SessionToken)
117+
me,err:=client.User(ctx,codersdk.Me)
118+
require.NoError(t,err)
119+
assert.Equal(t,coderdtest.FirstUserParams.Username,me.Username)
120+
assert.Equal(t,coderdtest.FirstUserParams.Name,me.Name)
121+
assert.Equal(t,coderdtest.FirstUserParams.Email,me.Email)
122+
})
123+
124+
t.Run("InitialUserTTYNameOptional",func(t*testing.T) {
125+
t.Parallel()
126+
client:=coderdtest.New(t,nil)
127+
// The --force-tty flag is required on Windows, because the `isatty` library does not
128+
// accurately detect Windows ptys when they are not attached to a process:
129+
// https://github.com/mattn/go-isatty/issues/59
130+
doneChan:=make(chanstruct{})
131+
root,_:=clitest.New(t,"login","--force-tty",client.URL.String())
132+
pty:=ptytest.New(t).Attach(root)
133+
gofunc() {
134+
deferclose(doneChan)
135+
err:=root.Run()
136+
assert.NoError(t,err)
137+
}()
138+
139+
matches:= []string{
140+
"first user?","yes",
141+
"username",coderdtest.FirstUserParams.Username,
142+
"name","",
143+
"email",coderdtest.FirstUserParams.Email,
144+
"password",coderdtest.FirstUserParams.Password,
145+
"password",coderdtest.FirstUserParams.Password,// confirm
146+
"trial","yes",
147+
}
148+
fori:=0;i<len(matches);i+=2 {
149+
match:=matches[i]
150+
value:=matches[i+1]
151+
pty.ExpectMatch(match)
152+
pty.WriteLine(value)
153+
}
154+
pty.ExpectMatch("Welcome to Coder")
155+
<-doneChan
156+
ctx:=testutil.Context(t,testutil.WaitShort)
157+
resp,err:=client.LoginWithPassword(ctx, codersdk.LoginWithPasswordRequest{
158+
Email:coderdtest.FirstUserParams.Email,
159+
Password:coderdtest.FirstUserParams.Password,
160+
})
161+
require.NoError(t,err)
162+
client.SetSessionToken(resp.SessionToken)
163+
me,err:=client.User(ctx,codersdk.Me)
164+
require.NoError(t,err)
165+
assert.Equal(t,coderdtest.FirstUserParams.Username,me.Username)
166+
assert.Equal(t,coderdtest.FirstUserParams.Email,me.Email)
167+
assert.Empty(t,me.Name)
108168
})
109169

110170
t.Run("InitialUserTTYFlag",func(t*testing.T) {
@@ -121,10 +181,11 @@ func TestLogin(t *testing.T) {
121181
pty.ExpectMatch(fmt.Sprintf("Attempting to authenticate with flag URL: '%s'",client.URL.String()))
122182
matches:= []string{
123183
"first user?","yes",
124-
"username","testuser",
125-
"email","user@coder.com",
126-
"password","SomeSecurePassword!",
127-
"password","SomeSecurePassword!",// Confirm.
184+
"username",coderdtest.FirstUserParams.Username,
185+
"name",coderdtest.FirstUserParams.Name,
186+
"email",coderdtest.FirstUserParams.Email,
187+
"password",coderdtest.FirstUserParams.Password,
188+
"password",coderdtest.FirstUserParams.Password,// confirm
128189
"trial","yes",
129190
}
130191
fori:=0;i<len(matches);i+=2 {
@@ -134,20 +195,75 @@ func TestLogin(t *testing.T) {
134195
pty.WriteLine(value)
135196
}
136197
pty.ExpectMatch("Welcome to Coder")
198+
ctx:=testutil.Context(t,testutil.WaitShort)
199+
resp,err:=client.LoginWithPassword(ctx, codersdk.LoginWithPasswordRequest{
200+
Email:coderdtest.FirstUserParams.Email,
201+
Password:coderdtest.FirstUserParams.Password,
202+
})
203+
require.NoError(t,err)
204+
client.SetSessionToken(resp.SessionToken)
205+
me,err:=client.User(ctx,codersdk.Me)
206+
require.NoError(t,err)
207+
assert.Equal(t,coderdtest.FirstUserParams.Username,me.Username)
208+
assert.Equal(t,coderdtest.FirstUserParams.Name,me.Name)
209+
assert.Equal(t,coderdtest.FirstUserParams.Email,me.Email)
137210
})
138211

139212
t.Run("InitialUserFlags",func(t*testing.T) {
140213
t.Parallel()
141214
client:=coderdtest.New(t,nil)
142215
inv,_:=clitest.New(
143216
t,"login",client.URL.String(),
144-
"--first-user-username","testuser","--first-user-email","user@coder.com",
145-
"--first-user-password","SomeSecurePassword!","--first-user-trial",
217+
"--first-user-username",coderdtest.FirstUserParams.Username,
218+
"--first-user-full-name",coderdtest.FirstUserParams.Name,
219+
"--first-user-email",coderdtest.FirstUserParams.Email,
220+
"--first-user-password",coderdtest.FirstUserParams.Password,
221+
"--first-user-trial",
222+
)
223+
pty:=ptytest.New(t).Attach(inv)
224+
w:=clitest.StartWithWaiter(t,inv)
225+
pty.ExpectMatch("Welcome to Coder")
226+
w.RequireSuccess()
227+
ctx:=testutil.Context(t,testutil.WaitShort)
228+
resp,err:=client.LoginWithPassword(ctx, codersdk.LoginWithPasswordRequest{
229+
Email:coderdtest.FirstUserParams.Email,
230+
Password:coderdtest.FirstUserParams.Password,
231+
})
232+
require.NoError(t,err)
233+
client.SetSessionToken(resp.SessionToken)
234+
me,err:=client.User(ctx,codersdk.Me)
235+
require.NoError(t,err)
236+
assert.Equal(t,coderdtest.FirstUserParams.Username,me.Username)
237+
assert.Equal(t,coderdtest.FirstUserParams.Name,me.Name)
238+
assert.Equal(t,coderdtest.FirstUserParams.Email,me.Email)
239+
})
240+
241+
t.Run("InitialUserFlagsNameOptional",func(t*testing.T) {
242+
t.Parallel()
243+
client:=coderdtest.New(t,nil)
244+
inv,_:=clitest.New(
245+
t,"login",client.URL.String(),
246+
"--first-user-username",coderdtest.FirstUserParams.Username,
247+
"--first-user-email",coderdtest.FirstUserParams.Email,
248+
"--first-user-password",coderdtest.FirstUserParams.Password,
249+
"--first-user-trial",
146250
)
147251
pty:=ptytest.New(t).Attach(inv)
148252
w:=clitest.StartWithWaiter(t,inv)
149253
pty.ExpectMatch("Welcome to Coder")
150254
w.RequireSuccess()
255+
ctx:=testutil.Context(t,testutil.WaitShort)
256+
resp,err:=client.LoginWithPassword(ctx, codersdk.LoginWithPasswordRequest{
257+
Email:coderdtest.FirstUserParams.Email,
258+
Password:coderdtest.FirstUserParams.Password,
259+
})
260+
require.NoError(t,err)
261+
client.SetSessionToken(resp.SessionToken)
262+
me,err:=client.User(ctx,codersdk.Me)
263+
require.NoError(t,err)
264+
assert.Equal(t,coderdtest.FirstUserParams.Username,me.Username)
265+
assert.Equal(t,coderdtest.FirstUserParams.Email,me.Email)
266+
assert.Empty(t,me.Name)
151267
})
152268

153269
t.Run("InitialUserTTYConfirmPasswordFailAndReprompt",func(t*testing.T) {
@@ -169,10 +285,11 @@ func TestLogin(t *testing.T) {
169285

170286
matches:= []string{
171287
"first user?","yes",
172-
"username","testuser",
173-
"email","user@coder.com",
174-
"password","MyFirstSecurePassword!",
175-
"password","MyNonMatchingSecurePassword!",// Confirm.
288+
"username",coderdtest.FirstUserParams.Username,
289+
"name",coderdtest.FirstUserParams.Name,
290+
"email",coderdtest.FirstUserParams.Email,
291+
"password",coderdtest.FirstUserParams.Password,
292+
"password","something completely different",
176293
}
177294
fori:=0;i<len(matches);i+=2 {
178295
match:=matches[i]
@@ -185,9 +302,9 @@ func TestLogin(t *testing.T) {
185302
pty.ExpectMatch("Passwords do not match")
186303
pty.ExpectMatch("Enter a "+pretty.Sprint(cliui.DefaultStyles.Field,"password"))
187304

188-
pty.WriteLine("SomeSecurePassword!")
305+
pty.WriteLine(coderdtest.FirstUserParams.Password)
189306
pty.ExpectMatch("Confirm")
190-
pty.WriteLine("SomeSecurePassword!")
307+
pty.WriteLine(coderdtest.FirstUserParams.Password)
191308
pty.ExpectMatch("trial")
192309
pty.WriteLine("yes")
193310
pty.ExpectMatch("Welcome to Coder")

‎cli/server_createadminuser.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ func (r *RootCmd) newCreateAdminUserCommand() *serpent.Command {
8585
// Use the validator tags so we match the API's validation.
8686
req:= codersdk.CreateUserRequest{
8787
Username:"username",
88+
Name:"Admin User",
8889
Email:"email@coder.com",
8990
Password:"ValidPa$$word123!",
9091
OrganizationID:uuid.New(),
@@ -116,6 +117,7 @@ func (r *RootCmd) newCreateAdminUserCommand() *serpent.Command {
116117
returnerr
117118
}
118119
}
120+
119121
ifnewUserEmail=="" {
120122
newUserEmail,err=cliui.Prompt(inv, cliui.PromptOptions{
121123
Text:"Email",
@@ -189,6 +191,7 @@ func (r *RootCmd) newCreateAdminUserCommand() *serpent.Command {
189191
ID:uuid.New(),
190192
Email:newUserEmail,
191193
Username:newUserUsername,
194+
Name:"Admin User",
192195
HashedPassword: []byte(hashedPassword),
193196
CreatedAt:dbtime.Now(),
194197
UpdatedAt:dbtime.Now(),

‎cli/testdata/coder_login_--help.golden

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ OPTIONS:
1010
Specifies an email address to use if creating the first user for the
1111
deployment.
1212

13+
--first-user-full-name string, $CODER_FIRST_USER_FULL_NAME
14+
Specifies a human-readable name for the first user of the deployment.
15+
1316
--first-user-password string, $CODER_FIRST_USER_PASSWORD
1417
Specifies a password to use if creating the first user for the
1518
deployment.

‎cli/testdata/coder_users_create_--help.golden

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ OPTIONS:
77
-e, --email string
88
Specifies an email address for the new user.
99

10+
-n, --full-name string
11+
Specifies an optional human-readable name for the new user.
12+
1013
--login-type string
1114
Optionally specify the login type for the user. Valid values are:
1215
password, none, github, oidc. Using 'none' prevents the user from

‎cli/testdata/coder_users_list_--output_json.golden

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"id": "[first user ID]",
44
"username": "testuser",
55
"avatar_url": "",
6-
"name": "",
6+
"name": "Test User",
77
"email": "testuser@coder.com",
88
"created_at": "[timestamp]",
99
"last_seen_at": "[timestamp]",

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp