Skip to content

Commit c0be26d

Browse files
Onboarding improvements - merge to master (#1301)
* CLOUDP-120254: Address advocate experience feedback (#1281) * CLOUDP-124560: Add login to quickstart (#1284) * CLOUDP-118914: Clean up after tests that set config (#1285) * CLOUDP-118914: Save selected values and ask setup in a loop (#1297) * license header Co-authored-by: Bianca <[email protected]> Co-authored-by: Bianca <[email protected]>
1 parent f335d42 commit c0be26d

File tree

16 files changed

+512
-69
lines changed

16 files changed

+512
-69
lines changed

internal/cli/atlas/quickstart/access_list_setup.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020

2121
"github.com/AlecAivazis/survey/v2"
2222
"github.com/mongodb/mongodb-atlas-cli/internal/cli"
23+
"github.com/mongodb/mongodb-atlas-cli/internal/flag"
2324
"github.com/mongodb/mongodb-atlas-cli/internal/store"
2425
"github.com/mongodb/mongodb-atlas-cli/internal/telemetry"
2526
atlas "go.mongodb.org/atlas/mongodbatlas"
@@ -35,27 +36,30 @@ func (opts *Opts) createAccessList() error {
3536
}
3637

3738
func (opts *Opts) askAccessListOptions() error {
38-
if len(opts.IPAddresses) > 0 {
39+
if !opts.shouldAskForValue(flag.AccessListIP) {
3940
return nil
4041
}
42+
message := ""
4143

44+
if len(opts.IPAddresses) == 0 {
45+
publicIP := store.IPAddress()
46+
if publicIP != "" {
47+
message = fmt.Sprintf(" [Press Enter to use your public IP address '%s']", publicIP)
48+
}
49+
opts.IPAddresses = append(opts.IPAddresses, publicIP)
50+
}
4251
fmt.Print(`
4352
[Set up your database network access details]
4453
`)
45-
message := ""
46-
publicIP := store.IPAddress()
47-
if publicIP != "" {
48-
message = fmt.Sprintf(" [Press Enter to use your public IP address '%s']", publicIP)
49-
}
5054
err := telemetry.TrackAskOne(
51-
newAccessListQuestion(publicIP, message),
55+
newAccessListQuestion(strings.Join(opts.IPAddresses, ", "), message),
5256
&opts.IPAddressesResponse,
5357
survey.WithValidator(survey.Required),
5458
)
5559

5660
if err == nil && opts.IPAddressesResponse != "" {
5761
ips := strings.Split(opts.IPAddressesResponse, ",")
58-
opts.IPAddresses = append(opts.IPAddresses, ips...)
62+
opts.IPAddresses = ips
5963
}
6064
return err
6165
}

internal/cli/atlas/quickstart/cluster_setup.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121

2222
"github.com/AlecAivazis/survey/v2"
2323
"github.com/mongodb/mongodb-atlas-cli/internal/cli"
24+
"github.com/mongodb/mongodb-atlas-cli/internal/flag"
2425
"github.com/mongodb/mongodb-atlas-cli/internal/search"
2526
"github.com/mongodb/mongodb-atlas-cli/internal/telemetry"
2627
"github.com/mongodb/mongodb-atlas-cli/internal/usage"
@@ -40,16 +41,18 @@ func (opts *Opts) createCluster() error {
4041
func (opts *Opts) askClusterOptions() error {
4142
var qs []*survey.Question
4243

43-
if opts.ClusterName == "" {
44-
opts.ClusterName = opts.defaultName
44+
if opts.shouldAskForValue(flag.ClusterName) {
45+
if opts.ClusterName == "" {
46+
opts.ClusterName = opts.defaultName
47+
}
4548
qs = append(qs, newClusterNameQuestion(opts.ClusterName))
4649
}
4750

48-
if opts.Provider == "" {
51+
if opts.shouldAskForValue(flag.Provider) {
4952
qs = append(qs, newClusterProviderQuestion())
5053
}
5154

52-
if opts.Provider == "" || opts.ClusterName == "" || opts.Region == "" {
55+
if opts.shouldAskForValue(flag.ClusterName) || opts.shouldAskForValue(flag.Provider) || opts.shouldAskForValue(flag.Region) {
5356
fmt.Print(`
5457
[Set up your Atlas cluster]
5558
`)
@@ -60,7 +63,7 @@ func (opts *Opts) askClusterOptions() error {
6063
}
6164

6265
// We need the provider to ask for the region
63-
if opts.Region == "" {
66+
if opts.shouldAskForValue(flag.Region) {
6467
return opts.askClusterRegion()
6568
}
6669
return nil

internal/cli/atlas/quickstart/confirm_cluster_setup.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import (
2525
const loadSampleDataMsg = `
2626
Load sample data: Yes`
2727

28+
var ErrUserAborted = errors.New("user-aborted. Not creating cluster")
29+
2830
func (opts *Opts) askConfirmConfigQuestion() error {
2931
if opts.Confirm {
3032
return nil
@@ -68,7 +70,7 @@ Allow connections from (IP Address): %s
6870
}
6971

7072
if !opts.Confirm {
71-
return errors.New("user-aborted. Not creating cluster")
73+
return ErrUserAborted
7274
}
7375
return nil
7476
}

internal/cli/atlas/quickstart/dbuser_setup.go

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ import (
1818
"errors"
1919
"fmt"
2020

21-
"github.com/mongodb/mongodb-atlas-cli/internal/config"
22-
"github.com/mongodb/mongodb-atlas-cli/internal/telemetry"
23-
2421
"github.com/AlecAivazis/survey/v2"
22+
"github.com/mongodb/mongodb-atlas-cli/internal/config"
2523
"github.com/mongodb/mongodb-atlas-cli/internal/convert"
24+
"github.com/mongodb/mongodb-atlas-cli/internal/flag"
2625
"github.com/mongodb/mongodb-atlas-cli/internal/randgen"
26+
"github.com/mongodb/mongodb-atlas-cli/internal/telemetry"
2727
atlas "go.mongodb.org/atlas/mongodbatlas"
2828
)
2929

@@ -40,23 +40,28 @@ func (opts *Opts) askDBUserOptions() error {
4040

4141
if opts.DBUsername == "" {
4242
opts.DBUsername = opts.defaultName
43+
}
4344

45+
if opts.shouldAskForValue(flag.Username) {
4446
qs = append(qs, newDBUsernameQuestion(opts.DBUsername, opts.validateUniqueUsername))
4547
}
4648

47-
if opts.DBUserPassword == "" {
48-
pwd, err := generatePassword()
49-
if err != nil {
50-
return err
49+
if opts.shouldAskForValue(flag.Password) {
50+
if opts.DBUserPassword == "" {
51+
pwd, err := generatePassword()
52+
if err != nil {
53+
return err
54+
}
55+
opts.DBUserPassword = pwd
5156
}
52-
opts.DBUserPassword = pwd
57+
5358
minLength := 10
5459
if config.Service() == config.CloudGovService {
5560
minLength = 12
5661
}
5762
message := fmt.Sprintf(" [Must be >%d characters. Press Enter to use an auto-generated password]", minLength)
5863

59-
qs = append(qs, newDBUserPasswordQuestion(pwd, message))
64+
qs = append(qs, newDBUserPasswordQuestion(opts.DBUserPassword, message))
6065
}
6166

6267
if len(qs) == 0 {

internal/cli/atlas/quickstart/quick_start.go

Lines changed: 94 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727

2828
"github.com/AlecAivazis/survey/v2"
2929
"github.com/mongodb/mongodb-atlas-cli/internal/cli"
30+
"github.com/mongodb/mongodb-atlas-cli/internal/cli/auth"
3031
"github.com/mongodb/mongodb-atlas-cli/internal/config"
3132
"github.com/mongodb/mongodb-atlas-cli/internal/flag"
3233
"github.com/mongodb/mongodb-atlas-cli/internal/log"
@@ -37,6 +38,7 @@ import (
3738
"github.com/mongodb/mongodb-atlas-cli/internal/usage"
3839
"github.com/mongodb/mongodb-atlas-cli/internal/validate"
3940
"github.com/spf13/cobra"
41+
"github.com/spf13/pflag"
4042
atlas "go.mongodb.org/atlas/mongodbatlas"
4143
)
4244

@@ -86,6 +88,8 @@ const (
8688
type Opts struct {
8789
cli.GlobalOpts
8890
cli.WatchOpts
91+
login auth.LoginFlow
92+
loginOpts *auth.LoginOpts
8993
defaultName string
9094
ClusterName string
9195
Tier string
@@ -104,6 +108,9 @@ type Opts struct {
104108
Confirm bool
105109
CurrentIP bool
106110
store store.AtlasClusterQuickStarter
111+
shouldRunLogin bool
112+
flags *pflag.FlagSet
113+
flagSet map[string]struct{}
107114
}
108115

109116
type quickstart struct {
@@ -123,6 +130,17 @@ type Flow interface {
123130
Run() error
124131
}
125132

133+
func NewQuickstartFlow(qsOpts *Opts) Flow {
134+
return qsOpts
135+
}
136+
137+
func NewQuickstartOpts(loginOpts *auth.LoginOpts) *Opts {
138+
return &Opts{
139+
loginOpts: loginOpts,
140+
login: auth.NewLoginFlow(loginOpts),
141+
}
142+
}
143+
126144
func (opts *Opts) initStore(ctx context.Context) func() error {
127145
return func() error {
128146
var err error
@@ -131,13 +149,59 @@ func (opts *Opts) initStore(ctx context.Context) func() error {
131149
}
132150
}
133151

134-
func (opts *Opts) quickstartPreRun() error {
135-
return opts.PreRunE(
136-
opts.ValidateProjectID,
137-
)
152+
func (opts *Opts) quickstartPreRun(ctx context.Context, outWriter io.Writer) error {
153+
opts.shouldRunLogin = false
154+
opts.OutWriter = outWriter
155+
156+
// Get authentication status to define whether login should be run
157+
status, _ := auth.GetStatus(ctx)
158+
if status == auth.LoggedInWithValidToken || status == auth.LoggedInWithAPIKeys {
159+
return opts.PreRunE(
160+
opts.ValidateProjectID,
161+
)
162+
}
163+
164+
// If customer used --force and is not authenticated, check credentials and proceed. Likely to
165+
// throw an error here.
166+
if opts.Confirm {
167+
if err := validate.Credentials(); err != nil {
168+
return err
169+
}
170+
return opts.PreRunE(
171+
opts.ValidateProjectID,
172+
)
173+
}
174+
175+
opts.loginOpts.OutWriter = opts.OutWriter
176+
if err := opts.login.PreRun(); err != nil {
177+
return err
178+
}
179+
180+
opts.shouldRunLogin = true
181+
_, _ = fmt.Fprintf(opts.OutWriter, `This action requires authentication.
182+
`)
183+
return opts.login.Run(ctx)
184+
}
185+
186+
func (opts *Opts) shouldAskForValue(f string) bool {
187+
_, isFlagSet := opts.flagSet[f]
188+
return !isFlagSet
189+
}
190+
191+
func (opts *Opts) trackFlags() {
192+
if opts.flags == nil {
193+
opts.flagSet = make(map[string]struct{})
194+
return
195+
}
196+
197+
opts.flagSet = make(map[string]struct{}, opts.flags.NFlag())
198+
opts.flags.Visit(func(f *pflag.Flag) {
199+
opts.flagSet[f.Name] = struct{}{}
200+
})
138201
}
139202

140203
func (opts *Opts) PreRun(ctx context.Context, outWriter io.Writer) error {
204+
opts.shouldRunLogin = false
141205
opts.setTier()
142206

143207
if opts.CurrentIP && len(opts.IPAddresses) > 0 {
@@ -154,6 +218,7 @@ func (opts *Opts) Run() error {
154218
const base10 = 10
155219
opts.defaultName = "Cluster" + strconv.FormatInt(time.Now().Unix(), base10)[5:]
156220
opts.providerAndRegionToConstant()
221+
opts.trackFlags()
157222

158223
if opts.CurrentIP {
159224
if publicIP := store.IPAddress(); publicIP != "" {
@@ -414,23 +479,31 @@ func (opts *Opts) replaceWithDefaultSettings(values *quickstart) {
414479
}
415480

416481
func (opts *Opts) interactiveSetup() error {
417-
if err := opts.askClusterOptions(); err != nil {
418-
return err
419-
}
482+
for {
483+
if err := opts.askClusterOptions(); err != nil {
484+
return err
485+
}
420486

421-
if err := opts.askSampleDataQuestion(); err != nil {
422-
return err
423-
}
487+
if err := opts.askSampleDataQuestion(); err != nil {
488+
return err
489+
}
424490

425-
if err := opts.askDBUserOptions(); err != nil {
426-
return err
427-
}
491+
if err := opts.askDBUserOptions(); err != nil {
492+
return err
493+
}
428494

429-
if err := opts.askAccessListOptions(); err != nil {
430-
return err
431-
}
495+
if err := opts.askAccessListOptions(); err != nil {
496+
return err
497+
}
432498

433-
return opts.askConfirmConfigQuestion()
499+
if err := opts.askConfirmConfigQuestion(); err != nil && !errors.Is(err, ErrUserAborted) {
500+
return err
501+
}
502+
503+
if opts.Confirm {
504+
return nil
505+
}
506+
}
434507
}
435508

436509
// Builder
@@ -444,7 +517,7 @@ func (opts *Opts) interactiveSetup() error {
444517
// [--skipMongosh skipMongosh]
445518
// [--default]
446519
func Builder() *cobra.Command {
447-
opts := &Opts{}
520+
opts := NewQuickstartOpts(auth.NewLoginOpts())
448521
cmd := &cobra.Command{
449522
Use: "quickstart",
450523
Short: "Create and access an Atlas Cluster.",
@@ -453,12 +526,13 @@ func Builder() *cobra.Command {
453526
$ %[1]s quickstart --force
454527
$ %[1]s quickstart --clusterName Test --provider GCP --username dbuserTest`, cli.ExampleAtlasEntryPoint()),
455528
PreRunE: func(cmd *cobra.Command, args []string) error {
456-
if err := opts.quickstartPreRun(); err != nil {
529+
if err := opts.PreRun(cmd.Context(), cmd.OutOrStdout()); err != nil {
457530
return err
458531
}
459-
return opts.PreRun(cmd.Context(), cmd.OutOrStdout())
532+
return opts.quickstartPreRun(cmd.Context(), cmd.OutOrStdout())
460533
},
461534
RunE: func(cmd *cobra.Command, args []string) error {
535+
opts.flags = cmd.Flags()
462536
return opts.Run()
463537
},
464538
}

0 commit comments

Comments
 (0)