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

mongodb / mongodb-atlas-cli / 26228926989

21 May 2026 01:27PM UTC coverage: 22.63% (-41.6%) from 64.198%
26228926989

push

github

apix-bot[bot]
Update compliance report for v1.55.0

8987 of 39713 relevant lines covered (22.63%)

0.25 hits per line

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

16.95
/internal/cli/plugin/first_class.go
1
// Copyright 2025 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 plugin
16

17
import (
18
        "fmt"
19

20
        "github.com/Masterminds/semver/v3"
21
        "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/plugin"
22
        "github.com/spf13/cobra"
23
)
24

25
const (
26
        FirstClassSourceType = "first-class"
27
        sourceType           = "sourceType"
28

29
        AtlasLocalPluginMinVersion = "0.11.0"
30
)
31

32
// uncomment example plugin to test first class plugin feature.
33
var FirstClassPlugins = []*FirstClassPlugin{
34
        // {
35
        //         Name: "atlas-cli-first-class-plugin-example",
36
        //         Github: &Github{
37
        //                 Owner: "stefan4h",
38
        //                 Name: "atlas-cli-first-class-plugin-example",
39
        //         },
40
        //         Commands: []*Command{
41
        //                 {
42
        //                         Name: "first-class",
43
        //                         Description: "Root command of the Atlas CLI first class plugin example",
44
        //                 },
45
        //         },
46
        // },
47
        {
48
                Name:       "atlas-cli-plugin-kubernetes",
49
                MinVersion: "1.2.4",
50
                Github: &Github{
51
                        Owner: "mongodb",
52
                        Name:  "atlas-cli-plugin-kubernetes",
53
                },
54
                Commands: []*Command{
55
                        {
56
                                Name:        "kubernetes",
57
                                Description: "Manage Kubernetes resources.",
58
                        },
59
                },
60
        },
61
        {
62
                Name:       "atlas-local-plugin",
63
                MinVersion: AtlasLocalPluginMinVersion,
64
                Github: &Github{
65
                        Owner: "mongodb",
66
                        Name:  "atlas-local-cli",
67
                },
68
                Commands: []*Command{
69
                        {
70
                                Name:        "local",
71
                                Description: "Manage MongoDB Atlas local instances",
72
                        },
73
                },
74
        },
75
}
76

77
type Command struct {
78
        Name        string
79
        Description string
80
}
81

82
type Github struct {
83
        Owner string
84
        Name  string
85
}
86

87
type FirstClassPlugin struct {
88
        Name       string
89
        MinVersion string
90
        Github     *Github
91
        Commands   []*Command
92
}
93

94
func IsFirstClassPluginCmd(cmd *cobra.Command) bool {
1✔
95
        if cmdSourceType, ok := cmd.Annotations[sourceType]; ok && cmdSourceType == FirstClassSourceType {
2✔
96
                return true
1✔
97
        }
1✔
98
        return false
1✔
99
}
100

101
func (fcp *FirstClassPlugin) getInstalledPlugin(plugins *plugin.ValidatedPlugins) *plugin.Plugin {
1✔
102
        for _, p := range plugins.GetValidPlugins() {
2✔
103
                if p.Name == fcp.Name {
2✔
104
                        return p
1✔
105
                }
1✔
106
        }
107

108
        return nil
1✔
109
}
110

111
func (fcp *FirstClassPlugin) needsUpdate(installedPlugin *plugin.Plugin) bool {
1✔
112
        if fcp.MinVersion == "" {
2✔
113
                return false
1✔
114
        }
1✔
115

116
        minVersion, err := semver.NewVersion(fcp.MinVersion)
1✔
117
        if err != nil {
2✔
118
                return false
1✔
119
        }
1✔
120

121
        return installedPlugin.Version.LessThan(minVersion)
1✔
122
}
123

124
func (fcp *FirstClassPlugin) installPlugin(cmd *cobra.Command, plugins *plugin.ValidatedPlugins) error {
×
125
        installOpts := &InstallOpts{
×
126
                Opts: Opts{
×
127
                        plugins: plugins,
×
128
                },
×
129
                ghClient: NewAuthenticatedGithubClient(),
×
130
        }
×
131
        installOpts.githubAsset = &GithubAsset{
×
132
                owner: fcp.Github.Owner,
×
133
                name:  fcp.Github.Name,
×
134
        }
×
135
        installOpts.Print("Installing first class plugin " + fcp.Name)
×
136

×
137
        // check if plugin already exists, if not, install it
×
138
        if err := installOpts.checkForDuplicatePlugins(); err != nil {
×
139
                return fmt.Errorf("first class plugin %s is already installed, should not install again", fcp.Name)
×
140
        }
×
141
        if err := installOpts.Run(cmd.Context()); err != nil {
×
142
                return fmt.Errorf("failed to install first class plugin %s: %w", fcp.Name, err)
×
143
        }
×
144

145
        return nil
×
146
}
147

148
func (fcp *FirstClassPlugin) updatePlugin(cmd *cobra.Command, plugins *plugin.ValidatedPlugins, existingPlugin *plugin.Plugin) error {
×
149
        updateOpts := &UpdateOpts{
×
150
                Opts: Opts{
×
151
                        plugins: plugins,
×
152
                },
×
153
                ghClient: NewAuthenticatedGithubClient(),
×
154
        }
×
155

×
156
        githubAsset := &GithubAsset{
×
157
                owner: fcp.Github.Owner,
×
158
                name:  fcp.Github.Name,
×
159
        }
×
160

×
161
        updateOpts.Print(fmt.Sprintf("Updating first class plugin %s to minimum required version %s", fcp.Name, fcp.MinVersion))
×
162

×
163
        if err := updateOpts.updatePlugin(cmd.Context(), githubAsset, existingPlugin); err != nil {
×
164
                return fmt.Errorf("failed to update first class plugin %s: %w", fcp.Name, err)
×
165
        }
×
166

167
        return nil
×
168
}
169

170
func (fcp *FirstClassPlugin) runFirstClassPluginCommand(cmd *cobra.Command, args []string, plugins *plugin.ValidatedPlugins) error {
×
171
        // Check if plugin is already installed
×
172
        installedPlugin := fcp.getInstalledPlugin(plugins)
×
173

×
174
        if installedPlugin == nil {
×
175
                // Plugin not installed, install it
×
176
                if err := fcp.installPlugin(cmd, plugins); err != nil {
×
177
                        return err
×
178
                }
×
179
        } else if fcp.needsUpdate(installedPlugin) {
×
180
                // Plugin installed but below minimum version, update it
×
181
                if err := fcp.updatePlugin(cmd, plugins, installedPlugin); err != nil {
×
182
                        return err
×
183
                }
×
184
        }
185

186
        // find and run installed plugin
187
        installedPlugin, err := plugin.GetPluginWithName(fcp.Name, nil, false)
×
188
        if err != nil {
×
189
                return err
×
190
        }
×
191
        // validate plugin version is compatible
192
        if err := plugin.ValidateVersion(*installedPlugin.Github, installedPlugin.Version); err != nil {
×
193
                return err
×
194
        }
×
195

196
        return installedPlugin.Run(cmd, args)
×
197
}
198

199
func (fcp *FirstClassPlugin) getCommands(plugins *plugin.ValidatedPlugins) []*cobra.Command {
×
200
        commands := make([]*cobra.Command, 0, len(fcp.Commands))
×
201

×
202
        // for every command listed in the first class plugin, create a cobra command that installs the plugin
×
203
        for _, firstClassPluginCommand := range fcp.Commands {
×
204
                cmd := &cobra.Command{
×
205
                        Use:   firstClassPluginCommand.Name,
×
206
                        Short: firstClassPluginCommand.Description,
×
207
                        Annotations: map[string]string{
×
208
                                sourceType: FirstClassSourceType,
×
209
                        },
×
210
                        RunE: func(cmd *cobra.Command, args []string) error {
×
211
                                return fcp.runFirstClassPluginCommand(cmd, args, plugins)
×
212
                        },
×
213
                        DisableFlagParsing: true,
214
                }
215

216
                commands = append(commands, cmd)
×
217
        }
218

219
        return commands
×
220
}
221

222
func getFirstClassPluginCommands(plugins *plugin.ValidatedPlugins) []*cobra.Command {
×
223
        var commands []*cobra.Command
×
224
        // create cobra commands to install/update first class plugins when their commands are run
×
225
        for _, firstClassPlugin := range FirstClassPlugins {
×
226
                installedPlugin := firstClassPlugin.getInstalledPlugin(plugins)
×
227

×
228
                // Skip if plugin is already installed and doesn't need updating
×
229
                if installedPlugin != nil && !firstClassPlugin.needsUpdate(installedPlugin) {
×
230
                        continue
×
231
                }
232

233
                commands = append(commands, firstClassPlugin.getCommands(plugins)...)
×
234
        }
235

236
        return commands
×
237
}
238

239
// getFirstClassPluginsNeedingUpdate returns a set of plugin names that are first-class plugins
240
// which are installed but need updating to meet the minimum version requirement.
241
func getFirstClassPluginsNeedingUpdate(plugins *plugin.ValidatedPlugins) map[string]bool {
×
242
        result := make(map[string]bool)
×
243

×
244
        for _, firstClassPlugin := range FirstClassPlugins {
×
245
                installedPlugin := firstClassPlugin.getInstalledPlugin(plugins)
×
246
                if installedPlugin != nil && firstClassPlugin.needsUpdate(installedPlugin) {
×
247
                        result[installedPlugin.Name] = true
×
248
                }
×
249
        }
250

251
        return result
×
252
}
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