mirror of https://github.com/coder/coder.git
Allow `coder login` to log into existing deployment if available. Update help and error messages to indicate that `coder login` is available as a command. Fixes #10925 Fixes #9551
This commit is contained in:
parent
bed61f7d2a
commit
773862a9f5
17
cli/login.go
17
cli/login.go
|
@ -136,16 +136,28 @@ func (r *RootCmd) login() *clibase.Cmd {
|
||||||
useTokenForSession bool
|
useTokenForSession bool
|
||||||
)
|
)
|
||||||
cmd := &clibase.Cmd{
|
cmd := &clibase.Cmd{
|
||||||
Use: "login <url>",
|
Use: "login [<url>]",
|
||||||
Short: "Authenticate with Coder deployment",
|
Short: "Authenticate with Coder deployment",
|
||||||
Middleware: clibase.RequireRangeArgs(0, 1),
|
Middleware: clibase.RequireRangeArgs(0, 1),
|
||||||
Handler: func(inv *clibase.Invocation) error {
|
Handler: func(inv *clibase.Invocation) error {
|
||||||
ctx := inv.Context()
|
ctx := inv.Context()
|
||||||
rawURL := ""
|
rawURL := ""
|
||||||
|
var urlSource string
|
||||||
|
|
||||||
if len(inv.Args) == 0 {
|
if len(inv.Args) == 0 {
|
||||||
rawURL = r.clientURL.String()
|
rawURL = r.clientURL.String()
|
||||||
|
urlSource = "flag"
|
||||||
|
if rawURL != "" && rawURL == inv.Environ.Get(envURL) {
|
||||||
|
urlSource = "environment"
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
rawURL = inv.Args[0]
|
rawURL = inv.Args[0]
|
||||||
|
urlSource = "argument"
|
||||||
|
}
|
||||||
|
|
||||||
|
if url, err := r.createConfig().URL().Read(); rawURL == "" && err == nil {
|
||||||
|
urlSource = "config"
|
||||||
|
rawURL = url
|
||||||
}
|
}
|
||||||
|
|
||||||
if rawURL == "" {
|
if rawURL == "" {
|
||||||
|
@ -187,6 +199,9 @@ func (r *RootCmd) login() *clibase.Cmd {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("Failed to check server %q for first user, is the URL correct and is coder accessible from your browser? Error - has initial user: %w", serverURL.String(), err)
|
return xerrors.Errorf("Failed to check server %q for first user, is the URL correct and is coder accessible from your browser? Error - has initial user: %w", serverURL.String(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, _ = fmt.Fprintf(inv.Stdout, "Attempting to authenticate with %s URL: '%s'\n", urlSource, serverURL)
|
||||||
|
|
||||||
if !hasFirstUser {
|
if !hasFirstUser {
|
||||||
_, _ = fmt.Fprintf(inv.Stdout, Caret+"Your Coder deployment hasn't been set up!\n")
|
_, _ = fmt.Fprintf(inv.Stdout, Caret+"Your Coder deployment hasn't been set up!\n")
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,7 @@ func TestLogin(t *testing.T) {
|
||||||
|
|
||||||
clitest.Start(t, inv)
|
clitest.Start(t, inv)
|
||||||
|
|
||||||
|
pty.ExpectMatch(fmt.Sprintf("Attempting to authenticate with flag URL: '%s'", client.URL.String()))
|
||||||
matches := []string{
|
matches := []string{
|
||||||
"first user?", "yes",
|
"first user?", "yes",
|
||||||
"username", "testuser",
|
"username", "testuser",
|
||||||
|
@ -205,6 +206,7 @@ func TestLogin(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
pty.ExpectMatch(fmt.Sprintf("Attempting to authenticate with argument URL: '%s'", client.URL.String()))
|
||||||
pty.ExpectMatch("Paste your token here:")
|
pty.ExpectMatch("Paste your token here:")
|
||||||
pty.WriteLine(client.SessionToken())
|
pty.WriteLine(client.SessionToken())
|
||||||
if runtime.GOOS != "windows" {
|
if runtime.GOOS != "windows" {
|
||||||
|
@ -215,6 +217,52 @@ func TestLogin(t *testing.T) {
|
||||||
<-doneChan
|
<-doneChan
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("ExistingUserURLSavedInConfig", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
client := coderdtest.New(t, nil)
|
||||||
|
url := client.URL.String()
|
||||||
|
coderdtest.CreateFirstUser(t, client)
|
||||||
|
|
||||||
|
inv, root := clitest.New(t, "login", "--no-open")
|
||||||
|
clitest.SetupConfig(t, client, root)
|
||||||
|
|
||||||
|
doneChan := make(chan struct{})
|
||||||
|
pty := ptytest.New(t).Attach(inv)
|
||||||
|
go func() {
|
||||||
|
defer close(doneChan)
|
||||||
|
err := inv.Run()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}()
|
||||||
|
|
||||||
|
pty.ExpectMatch(fmt.Sprintf("Attempting to authenticate with config URL: '%s'", url))
|
||||||
|
pty.ExpectMatch("Paste your token here:")
|
||||||
|
pty.WriteLine(client.SessionToken())
|
||||||
|
<-doneChan
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ExistingUserURLSavedInEnv", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
client := coderdtest.New(t, nil)
|
||||||
|
url := client.URL.String()
|
||||||
|
coderdtest.CreateFirstUser(t, client)
|
||||||
|
|
||||||
|
inv, _ := clitest.New(t, "login", "--no-open")
|
||||||
|
inv.Environ.Set("CODER_URL", url)
|
||||||
|
|
||||||
|
doneChan := make(chan struct{})
|
||||||
|
pty := ptytest.New(t).Attach(inv)
|
||||||
|
go func() {
|
||||||
|
defer close(doneChan)
|
||||||
|
err := inv.Run()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}()
|
||||||
|
|
||||||
|
pty.ExpectMatch(fmt.Sprintf("Attempting to authenticate with environment URL: '%s'", url))
|
||||||
|
pty.ExpectMatch("Paste your token here:")
|
||||||
|
pty.WriteLine(client.SessionToken())
|
||||||
|
<-doneChan
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("ExistingUserInvalidTokenTTY", func(t *testing.T) {
|
t.Run("ExistingUserInvalidTokenTTY", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
client := coderdtest.New(t, nil)
|
client := coderdtest.New(t, nil)
|
||||||
|
|
|
@ -119,7 +119,7 @@ func TestLogout(t *testing.T) {
|
||||||
go func() {
|
go func() {
|
||||||
defer close(logoutChan)
|
defer close(logoutChan)
|
||||||
err = logout.Run()
|
err = logout.Run()
|
||||||
assert.ErrorContains(t, err, "You are not logged in. Try logging in using 'coder login <url>'.")
|
assert.ErrorContains(t, err, "You are not logged in. Try logging in using 'coder login'.")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
<-logoutChan
|
<-logoutChan
|
||||||
|
|
11
cli/root.go
11
cli/root.go
|
@ -65,7 +65,9 @@ const (
|
||||||
varVerbose = "verbose"
|
varVerbose = "verbose"
|
||||||
varOrganizationSelect = "organization"
|
varOrganizationSelect = "organization"
|
||||||
varDisableDirect = "disable-direct-connections"
|
varDisableDirect = "disable-direct-connections"
|
||||||
notLoggedInMessage = "You are not logged in. Try logging in using 'coder login <url>'."
|
|
||||||
|
notLoggedInMessage = "You are not logged in. Try logging in using 'coder login <url>'."
|
||||||
|
notLoggedInURLSavedMessage = "You are not logged in. Try logging in using 'coder login'."
|
||||||
|
|
||||||
envNoVersionCheck = "CODER_NO_VERSION_WARNING"
|
envNoVersionCheck = "CODER_NO_VERSION_WARNING"
|
||||||
envNoFeatureWarning = "CODER_NO_FEATURE_WARNING"
|
envNoFeatureWarning = "CODER_NO_FEATURE_WARNING"
|
||||||
|
@ -77,7 +79,10 @@ const (
|
||||||
envURL = "CODER_URL"
|
envURL = "CODER_URL"
|
||||||
)
|
)
|
||||||
|
|
||||||
var errUnauthenticated = xerrors.New(notLoggedInMessage)
|
var (
|
||||||
|
errUnauthenticated = xerrors.New(notLoggedInMessage)
|
||||||
|
errUnauthenticatedURLSaved = xerrors.New(notLoggedInURLSavedMessage)
|
||||||
|
)
|
||||||
|
|
||||||
func (r *RootCmd) Core() []*clibase.Cmd {
|
func (r *RootCmd) Core() []*clibase.Cmd {
|
||||||
// Please re-sort this list alphabetically if you change it!
|
// Please re-sort this list alphabetically if you change it!
|
||||||
|
@ -574,7 +579,7 @@ func (r *RootCmd) initClientInternal(client *codersdk.Client, allowTokenMissing
|
||||||
// If the configuration files are absent, the user is logged out
|
// If the configuration files are absent, the user is logged out
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
if !allowTokenMissing {
|
if !allowTokenMissing {
|
||||||
return errUnauthenticated
|
return errUnauthenticatedURLSaved
|
||||||
}
|
}
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
coder v0.0.0-devel
|
coder v0.0.0-devel
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
coder login [flags] <url>
|
coder login [flags] [<url>]
|
||||||
|
|
||||||
Authenticate with Coder deployment
|
Authenticate with Coder deployment
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ Authenticate with Coder deployment
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```console
|
```console
|
||||||
coder login [flags] <url>
|
coder login [flags] [<url>]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
Loading…
Reference in New Issue