Skip to content

Commit 9737e97

Browse files
cli: prompt for organization on login (#19107)
* cli: prompt for organization on login If the user is a member of more than one organization, let them choose one upon login, interactively. * Avoid double negation in `if` * Remove 'em pesky whitespaces Thanks Chris! * Loading indicator * Move the block to the correct location 🙄 * Bump version
1 parent 1d3b862 commit 9737e97

File tree

4 files changed

+69
-16
lines changed

4 files changed

+69
-16
lines changed

components/local-app/cmd/login.go

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"github.com/gitpod-io/local-app/pkg/auth"
2020
"github.com/gitpod-io/local-app/pkg/config"
2121
"github.com/gitpod-io/local-app/pkg/prettyprint"
22+
"github.com/manifoldco/promptui"
2223
"github.com/spf13/cobra"
2324
)
2425

@@ -27,6 +28,7 @@ var loginOpts struct {
2728
Host string
2829
ContextName string
2930
OrganizationID string
31+
NonInteractive bool
3032
}
3133

3234
// loginCmd represents the login command
@@ -51,15 +53,19 @@ var loginCmd = &cobra.Command{
5153
token = os.Getenv("GITPOD_TOKEN")
5254
}
5355
if token == "" {
54-
var err error
55-
token, err = auth.Login(context.Background(), auth.LoginOpts{
56-
GitpodURL: loginOpts.Host,
57-
AuthTimeout: 5 * time.Minute,
58-
// Request CLI scopes (extended compared to the local companion app)
59-
ExtendScopes: true,
60-
})
61-
if err != nil {
62-
return err
56+
if loginOpts.NonInteractive {
57+
return fmt.Errorf("no token provided")
58+
} else {
59+
var err error
60+
token, err = auth.Login(context.Background(), auth.LoginOpts{
61+
GitpodURL: loginOpts.Host,
62+
AuthTimeout: 5 * time.Minute,
63+
// Request CLI scopes (extended compared to the local companion app)
64+
ExtendScopes: true,
65+
})
66+
if err != nil {
67+
return err
68+
}
6369
}
6470
}
6571

@@ -91,6 +97,9 @@ var loginCmd = &cobra.Command{
9197
if err != nil {
9298
return fmt.Errorf("cannot connect to Gitpod with this context: %w", err)
9399
}
100+
if !loginOpts.NonInteractive {
101+
fmt.Println("loading your organizations...")
102+
}
94103
orgsList, err := clnt.Teams.ListTeams(cmd.Context(), connect.NewRequest(&v1.ListTeamsRequest{}))
95104
if err != nil {
96105
var (
@@ -117,15 +126,47 @@ var loginCmd = &cobra.Command{
117126
}
118127
}
119128

129+
orgs := orgsList.Msg.GetTeams()
130+
fmt.Print("\033[A\033[K")
131+
132+
resolutions := []string{
133+
"pass an organization ID using --organization-id",
134+
}
135+
120136
var orgID string
121-
switch len(orgsList.Msg.GetTeams()) {
137+
switch len(orgs) {
122138
case 0:
123-
return fmt.Errorf("no organizations found. Please pass an organization ID using --organization-id")
139+
return prettyprint.AddResolution(fmt.Errorf("no organizations found"), resolutions...)
124140
case 1:
125-
orgID = orgsList.Msg.GetTeams()[0].Id
141+
orgID = orgs[0].Id
126142
default:
127-
orgID = orgsList.Msg.GetTeams()[0].Id
128-
slog.Info("found more than one organization and choose the first one", "org", orgID)
143+
if loginOpts.NonInteractive {
144+
resolutions = append(resolutions,
145+
"omit --non-interactive and select an organization interactively",
146+
)
147+
return prettyprint.AddResolution(fmt.Errorf("found more than one organization"), resolutions...)
148+
}
149+
150+
var orgNames []string
151+
for _, org := range orgs {
152+
orgNames = append(orgNames, org.Name)
153+
}
154+
155+
prompt := promptui.Select{
156+
Label: "What organization would you like to use?",
157+
Items: orgNames,
158+
Templates: &promptui.SelectTemplates{
159+
Selected: "Selected organization {{ . }}",
160+
},
161+
}
162+
selectedIndex, selectedValue, err := prompt.Run()
163+
if selectedValue == "" {
164+
return fmt.Errorf("no organization selected")
165+
}
166+
if err != nil {
167+
return err
168+
}
169+
orgID = orgs[selectedIndex].Id
129170
}
130171
cfg.Contexts[contextName].OrganizationID = orgID
131172
}
@@ -144,7 +185,7 @@ var loginCmd = &cobra.Command{
144185
return err
145186
}
146187

147-
slog.Info("Login succesfull")
188+
slog.Info("login successful")
148189
fmt.Println()
149190
return WriteTabular(who, formatOpts{}, prettyprint.WriterFormatNarrow)
150191
},
@@ -161,4 +202,5 @@ func init() {
161202
loginCmd.Flags().StringVar(&loginOpts.Token, "token", "", "The token to use for authentication (defaults to $GITPOD_TOKEN)")
162203
loginCmd.Flags().StringVarP(&loginOpts.ContextName, "context-name", "n", "default", "The name of the context to create")
163204
loginCmd.Flags().StringVar(&loginOpts.OrganizationID, "org", "", "The organization ID to use for the context")
205+
loginCmd.Flags().BoolVar(&loginOpts.NonInteractive, "non-interactive", false, "Disable opening the browser and prompt to select an organization")
164206
}

components/local-app/go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ require (
3232
github.com/gookit/color v1.5.4
3333
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf
3434
github.com/lmittmann/tint v1.0.3
35+
github.com/manifoldco/promptui v0.9.0
3536
github.com/mattn/go-isatty v0.0.17
3637
github.com/sagikazarmark/slog-shim v0.1.0
3738
github.com/spf13/cobra v1.7.0
@@ -45,6 +46,7 @@ require (
4546
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
4647
github.com/acomagu/bufpipe v1.0.4 // indirect
4748
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
49+
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
4850
github.com/cloudflare/circl v1.3.3 // indirect
4951
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
5052
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect

components/local-app/go.sum

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/local-app/version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.1.1
1+
0.1.2

0 commit comments

Comments
 (0)