• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mongodb / mongodb-atlas-cli / 16670272475

01 Aug 2025 08:27AM UTC coverage: 57.953% (-7.1%) from 65.017%
16670272475

Pull #4071

github

fmenezes
lint
Pull Request #4071: chore: remove unit tag from tests

23613 of 40745 relevant lines covered (57.95%)

2.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.62
/internal/cli/root/builder.go
1
// Copyright 2022 MongoDB Inc
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
package root
16

17
import (
18
        "errors"
19
        "fmt"
20
        "io"
21
        "os"
22
        "runtime"
23
        "strings"
24
        "syscall"
25
        "time"
26

27
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli"
28
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/accesslists"
29
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/accesslogs"
30
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/alerts"
31
        apiCmd "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/api"
32
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/auditing"
33
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/auth"
34
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/backup"
35
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/cloudproviders"
36
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/clusters"
37
        cliconfig "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/config"
38
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/customdbroles"
39
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/customdns"
40
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/datafederation"
41
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/datalake"
42
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/datalakepipelines"
43
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/dbusers"
44
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/deployments"
45
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/events"
46
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/federatedauthentication"
47
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/integrations"
48
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/livemigrations"
49
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/logs"
50
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/maintenance"
51
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/metrics"
52
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/networking"
53
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/organizations"
54
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/performanceadvisor"
55
        pluginCmd "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/plugin"
56
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/privateendpoints"
57
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/processes"
58
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/projects"
59
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/security"
60
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/serverless"
61
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/setup"
62
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/streams"
63
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/teams"
64
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/users"
65
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/config"
66
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/flag"
67
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/homebrew"
68
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/latestrelease"
69
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/log"
70
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/plugin"
71
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/prerun"
72
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/sighandle"
73
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/telemetry"
74
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/terminal"
75
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/usage"
76
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/validate"
77
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/version"
78
        "github.com/spf13/afero"
79
        "github.com/spf13/cobra"
80
)
81

82
const atlas = "atlas"
83

84
type Notifier struct {
85
        currentVersion string
86
        finder         latestrelease.VersionFinder
87
        filesystem     afero.Fs
88
        writer         io.Writer
89
}
90

91
type AuthRequirements int64
92

93
const (
94
        // NoAuth command does not require authentication.
95
        NoAuth AuthRequirements = 0
96
        // RequiredAuth command requires authentication.
97
        RequiredAuth AuthRequirements = 1
98
        // OptionalAuth command can work with or without authentication,
99
        // and if access token is found, try to refresh it.
100
        OptionalAuth AuthRequirements = 2
101
)
102

103
func handleSignal() {
1✔
104
        sighandle.Notify(func(sig os.Signal) {
1✔
105
                telemetry.FinishTrackingCommand(telemetry.TrackOptions{
×
106
                        Err:    errors.New(sig.String()),
×
107
                        Signal: sig.String(),
×
108
                })
×
109
                os.Exit(1)
×
110
        }, os.Interrupt, syscall.SIGTERM)
×
111
}
112

113
// Builder conditionally adds children commands as needed.
114
func Builder() *cobra.Command {
1✔
115
        var (
1✔
116
                profile    string
1✔
117
                debugLevel bool
1✔
118
        )
1✔
119
        opts := &cli.RefresherOpts{}
1✔
120
        rootCmd := &cobra.Command{
1✔
121
                Version: version.Version,
1✔
122
                Use:     atlas,
1✔
123
                Short:   "CLI tool to manage MongoDB Atlas.",
1✔
124
                Long: `The Atlas CLI is a command line interface built specifically for MongoDB Atlas. You can manage your Atlas database deployments and Atlas Search from the terminal with short, intuitive commands.
1✔
125
                
1✔
126
Use the --help flag with any command for more info on that command.`,
1✔
127
                Example: `  # Display the help menu for the config command:
1✔
128
  atlas config --help
1✔
129
`,
1✔
130
                SilenceUsage: true,
1✔
131
                Annotations: map[string]string{
1✔
132
                        "toc": "true",
1✔
133
                },
1✔
134
                PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
2✔
135
                        log.SetWriter(cmd.ErrOrStderr())
1✔
136
                        if debugLevel {
1✔
137
                                log.SetLevel(log.DebugLevel)
×
138
                        }
×
139

140
                        if err := cli.InitProfile(profile); err != nil {
2✔
141
                                return err
1✔
142
                        }
1✔
143

144
                        telemetry.StartTrackingCommand(cmd, args)
1✔
145

1✔
146
                        handleSignal()
1✔
147

1✔
148
                        if shouldSetService(cmd) {
2✔
149
                                config.SetService(config.CloudService)
1✔
150
                        }
1✔
151

152
                        authReq := shouldCheckCredentials(cmd)
1✔
153
                        if authReq == NoAuth {
2✔
154
                                return nil
1✔
155
                        }
1✔
156

157
                        if err := prerun.ExecuteE(
1✔
158
                                opts.InitFlow(config.Default()),
1✔
159
                                func() error {
2✔
160
                                        err := opts.RefreshAccessToken(cmd.Context())
1✔
161
                                        if err != nil && authReq == RequiredAuth {
1✔
162
                                                return err
×
163
                                        }
×
164
                                        return nil
1✔
165
                                },
166
                        ); err != nil {
×
167
                                return err
×
168
                        }
×
169

170
                        if authReq == RequiredAuth {
2✔
171
                                return validate.Credentials()
1✔
172
                        }
1✔
173

174
                        return nil
1✔
175
                },
176
                // PersistentPostRun only runs if the command is successful
177
                PersistentPostRun: func(cmd *cobra.Command, _ []string) {
1✔
178
                        // we don't run the release alert feature on the completion command
1✔
179
                        if strings.HasPrefix(cmd.CommandPath(), fmt.Sprintf("%s %s", atlas, "completion")) {
2✔
180
                                return
1✔
181
                        }
1✔
182

183
                        w := cmd.ErrOrStderr()
1✔
184
                        fs := afero.NewOsFs()
1✔
185
                        f, _ := latestrelease.NewVersionFinder(fs, version.NewReleaseVersionDescriber())
1✔
186

1✔
187
                        notifier := &Notifier{
1✔
188
                                currentVersion: latestrelease.VersionFromTag(version.Version),
1✔
189
                                finder:         f,
1✔
190
                                filesystem:     fs,
1✔
191
                                writer:         w,
1✔
192
                        }
1✔
193

1✔
194
                        if check, isHb := notifier.shouldCheck(); check {
2✔
195
                                _ = notifier.notifyIfApplicable(isHb)
1✔
196
                        }
1✔
197
                        telemetry.FinishTrackingCommand(telemetry.TrackOptions{})
1✔
198
                },
199
        }
200
        rootCmd.SetVersionTemplate(formattedVersion())
1✔
201
        rootCmd.SetHelpTemplate(cli.HelpTemplate)
1✔
202

1✔
203
        // hidden shortcuts
1✔
204
        loginCmd := auth.LoginBuilder()
1✔
205
        loginCmd.Hidden = true
1✔
206
        logoutCmd := auth.LogoutBuilder()
1✔
207
        logoutCmd.Hidden = true
1✔
208
        whoCmd := auth.WhoAmIBuilder()
1✔
209
        whoCmd.Hidden = true
1✔
210
        registerCmd := auth.RegisterBuilder()
1✔
211
        registerCmd.Hidden = true
1✔
212

1✔
213
        rootCmd.AddCommand(
1✔
214
                cliconfig.Builder(),
1✔
215
                auth.Builder(),
1✔
216
                setup.Builder(),
1✔
217
                projects.Builder(),
1✔
218
                organizations.Builder(),
1✔
219
                users.Builder(),
1✔
220
                teams.Builder(),
1✔
221
                clusters.Builder(),
1✔
222
                dbusers.Builder(),
1✔
223
                customdbroles.Builder(),
1✔
224
                accesslists.Builder(),
1✔
225
                datalake.Builder(),
1✔
226
                datalakepipelines.Builder(),
1✔
227
                alerts.Builder(),
1✔
228
                backup.Builder(),
1✔
229
                events.Builder(),
1✔
230
                metrics.Builder(),
1✔
231
                performanceadvisor.Builder(),
1✔
232
                logs.Builder(),
1✔
233
                processes.Builder(),
1✔
234
                privateendpoints.Builder(),
1✔
235
                networking.Builder(),
1✔
236
                security.Builder(),
1✔
237
                integrations.Builder(),
1✔
238
                maintenance.Builder(),
1✔
239
                customdns.Builder(),
1✔
240
                cloudproviders.Builder(),
1✔
241
                serverless.Builder(),
1✔
242
                streams.Builder(),
1✔
243
                livemigrations.Builder(),
1✔
244
                accesslogs.Builder(),
1✔
245
                loginCmd,
1✔
246
                logoutCmd,
1✔
247
                whoCmd,
1✔
248
                registerCmd,
1✔
249
                datafederation.Builder(),
1✔
250
                auditing.Builder(),
1✔
251
                deployments.Builder(),
1✔
252
                federatedauthentication.Builder(),
1✔
253
                apiCmd.Builder(),
1✔
254
        )
1✔
255

1✔
256
        pluginCmd.RegisterCommands(rootCmd)
1✔
257

1✔
258
        rootCmd.PersistentFlags().StringVarP(&profile, flag.Profile, flag.ProfileShort, "", usage.ProfileAtlasCLI)
1✔
259
        rootCmd.PersistentFlags().BoolVarP(&debugLevel, flag.Debug, flag.DebugShort, false, usage.Debug)
1✔
260
        _ = rootCmd.PersistentFlags().MarkHidden(flag.Debug)
1✔
261

1✔
262
        _ = rootCmd.RegisterFlagCompletionFunc(flag.Profile, func(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
1✔
263
                return config.List(), cobra.ShellCompDirectiveDefault
×
264
        })
×
265
        return rootCmd
1✔
266
}
267

268
const verTemplate = `atlascli version: %s
269
git version: %s
270
Go version: %s
271
   os: %s
272
   arch: %s
273
   compiler: %s
274
`
275

276
func shouldSetService(cmd *cobra.Command) bool {
1✔
277
        if config.Service() != "" {
2✔
278
                return false
1✔
279
        }
1✔
280

281
        if strings.HasPrefix(cmd.CommandPath(), fmt.Sprintf("%s %s", atlas, "config")) { // user wants to set credentials
2✔
282
                return false
1✔
283
        }
1✔
284

285
        if strings.HasPrefix(cmd.CommandPath(), fmt.Sprintf("%s %s", atlas, "completion")) {
1✔
286
                return false
×
287
        }
×
288

289
        return true
1✔
290
}
291

292
func shouldCheckCredentials(cmd *cobra.Command) AuthRequirements {
1✔
293
        searchByName := []string{
1✔
294
                "__complete",
1✔
295
                "help",
1✔
296
        }
1✔
297
        for _, n := range searchByName {
2✔
298
                if cmd.Name() == n {
2✔
299
                        return NoAuth
1✔
300
                }
1✔
301
        }
302
        customRequirements := map[string]AuthRequirements{
1✔
303
                fmt.Sprintf("%s %s", atlas, "completion"):  NoAuth,       // completion commands do not require credentials
1✔
304
                fmt.Sprintf("%s %s", atlas, "config"):      NoAuth,       // user wants to set credentials
1✔
305
                fmt.Sprintf("%s %s", atlas, "auth"):        NoAuth,       // user wants to set credentials
1✔
306
                fmt.Sprintf("%s %s", atlas, "register"):    NoAuth,       // user wants to set credentials
1✔
307
                fmt.Sprintf("%s %s", atlas, "login"):       NoAuth,       // user wants to set credentials
1✔
308
                fmt.Sprintf("%s %s", atlas, "logout"):      NoAuth,       // user wants to set credentials
1✔
309
                fmt.Sprintf("%s %s", atlas, "whoami"):      NoAuth,       // user wants to set credentials
1✔
310
                fmt.Sprintf("%s %s", atlas, "setup"):       NoAuth,       // user wants to set credentials
1✔
311
                fmt.Sprintf("%s %s", atlas, "register"):    NoAuth,       // user wants to set credentials
1✔
312
                fmt.Sprintf("%s %s", atlas, "plugin"):      NoAuth,       // plugin functionality requires no authentication
1✔
313
                fmt.Sprintf("%s %s", atlas, "quickstart"):  NoAuth,       // command supports login
1✔
314
                fmt.Sprintf("%s %s", atlas, "deployments"): OptionalAuth, // command supports local and Atlas
1✔
315
        }
1✔
316
        for p, r := range customRequirements {
2✔
317
                if strings.HasPrefix(cmd.CommandPath(), p) {
2✔
318
                        return r
1✔
319
                }
1✔
320
        }
321

322
        if plugin.IsPluginCmd(cmd) || pluginCmd.IsFirstClassPluginCmd(cmd) {
2✔
323
                return OptionalAuth
1✔
324
        }
1✔
325

326
        return RequiredAuth
1✔
327
}
328

329
func formattedVersion() string {
1✔
330
        return fmt.Sprintf(verTemplate,
1✔
331
                version.Version,
1✔
332
                version.GitCommit,
1✔
333
                runtime.Version(),
1✔
334
                runtime.GOOS,
1✔
335
                runtime.GOARCH,
1✔
336
                runtime.Compiler)
1✔
337
}
1✔
338

339
func (n *Notifier) shouldCheck() (shouldCheck, isHb bool) {
1✔
340
        shouldCheck = !config.SkipUpdateCheck() && terminal.IsTerminal(n.writer)
1✔
341
        isHb = false
1✔
342

1✔
343
        if !shouldCheck {
2✔
344
                return shouldCheck, isHb
1✔
345
        }
1✔
346

347
        c, _ := homebrew.NewChecker(n.filesystem)
1✔
348
        isHb = c.IsHomebrew()
1✔
349

1✔
350
        return shouldCheck, isHb
1✔
351
}
352

353
func (n *Notifier) notifyIfApplicable(isHb bool) error {
1✔
354
        release, err := n.finder.Find()
1✔
355
        if err != nil || release == nil {
2✔
356
                return err
1✔
357
        }
1✔
358

359
        // homebrew is an external dependency we give them 24h to have the cli available there
360
        if isHb && !isAtLeast24HoursPast(release.PublishedAt) {
×
361
                return nil
×
362
        }
×
363

364
        var upgradeInstructions string
×
365
        if isHb {
×
366
                upgradeInstructions = `To upgrade, run "brew update && brew upgrade mongodb-atlas-cli"`
×
367
        } else {
×
368
                upgradeInstructions = "To upgrade, see: https://dochub.mongodb.org/core/install-atlas-cli"
×
369
        }
×
370
        _, err = fmt.Fprintf(n.writer, `
×
371
A new version of atlascli is available %q!
×
372
%s
×
373

×
374
To disable this alert, run "atlas config set skip_update_check true"
×
375
`, release.Version, upgradeInstructions)
×
376
        return err
×
377
}
378

379
func isAtLeast24HoursPast(t time.Time) bool {
×
380
        return !t.IsZero() && time.Since(t) >= time.Hour*24
×
381
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc