Skip to content

Commit f7114fe

Browse files
CLOUDP-230402: Implemented project tagging (#2666)
1 parent 06a9115 commit f7114fe

File tree

5 files changed

+79
-1
lines changed

5 files changed

+79
-1
lines changed

docs/atlascli/command/atlas-projects-create.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ Options
7575
- string
7676
- false
7777
- Unique 24-digit string that identifies the Atlas user to be granted the Project Owner role on the specified project. If unspecified, this value defaults to the user ID of the oldest Organization Owner.
78+
* - --tag
79+
- stringToString
80+
- false
81+
- List that contains key-value pairs between 1 to 255 characters in length for tagging and categorizing the project. This value defaults to [].
7882
* - --withoutDefaultAlertSettings
7983
-
8084
- false

internal/cli/atlas/projects/create.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ package projects
1717
import (
1818
"context"
1919
"fmt"
20+
"sort"
2021

2122
"github.com/mongodb/mongodb-atlas-cli/internal/cli"
2223
"github.com/mongodb/mongodb-atlas-cli/internal/cli/require"
2324
"github.com/mongodb/mongodb-atlas-cli/internal/config"
2425
"github.com/mongodb/mongodb-atlas-cli/internal/flag"
26+
"github.com/mongodb/mongodb-atlas-cli/internal/pointer"
2527
store "github.com/mongodb/mongodb-atlas-cli/internal/store/atlas"
2628
"github.com/mongodb/mongodb-atlas-cli/internal/usage"
2729
"github.com/spf13/cobra"
@@ -37,6 +39,7 @@ type CreateOpts struct {
3739
projectOwnerID string
3840
regionUsageRestrictions bool
3941
withoutDefaultAlertSettings bool
42+
tag map[string]string
4043
store store.ProjectCreator
4144
}
4245

@@ -57,12 +60,42 @@ func (opts *CreateOpts) Run() error {
5760
return opts.Print(r)
5861
}
5962

63+
func (opts *CreateOpts) newCreateProjectGroupTags() *[]atlasv2.ResourceTag {
64+
if len(opts.tag) == 0 {
65+
return nil
66+
}
67+
68+
tags := make([]atlasv2.ResourceTag, 0)
69+
70+
keys := make([]string, 0)
71+
for k := range opts.tag {
72+
keys = append(keys, k)
73+
}
74+
sort.Strings(keys)
75+
76+
for _, key := range keys {
77+
value := opts.tag[key]
78+
if key == "" || value == "" {
79+
continue
80+
}
81+
82+
resourceTag := *atlasv2.NewResourceTag()
83+
resourceTag.Key = pointer.Get(key)
84+
resourceTag.Value = pointer.Get(value)
85+
86+
tags = append(tags, resourceTag)
87+
}
88+
89+
return &tags
90+
}
91+
6092
func (opts *CreateOpts) newCreateProjectGroup() *atlasv2.Group {
6193
return &atlasv2.Group{
6294
Name: opts.name,
6395
OrgId: opts.ConfigOrgID(),
6496
WithDefaultAlertsSettings: opts.defaultAlertSettings(),
6597
RegionUsageRestrictions: opts.newRegionUsageRestrictions(),
98+
Tags: opts.newCreateProjectGroupTags(),
6699
}
67100
}
68101

@@ -123,6 +156,7 @@ func CreateBuilder() *cobra.Command {
123156
cmd.Flags().StringVar(&opts.projectOwnerID, flag.OwnerID, "", usage.ProjectOwnerID)
124157
cmd.Flags().BoolVar(&opts.regionUsageRestrictions, flag.GovCloudRegionsOnly, false, usage.GovCloudRegionsOnly)
125158
cmd.Flags().BoolVar(&opts.withoutDefaultAlertSettings, flag.WithoutDefaultAlertSettings, false, usage.WithoutDefaultAlertSettings)
159+
cmd.Flags().StringToStringVar(&opts.tag, flag.Tag, nil, usage.ProjectTag)
126160
cmd.Flags().StringVarP(&opts.Output, flag.Output, flag.OutputShort, "", usage.FormatOut)
127161
_ = cmd.RegisterFlagCompletionFunc(flag.Output, opts.AutoCompleteOutputFlag())
128162

internal/cli/atlas/projects/create_test.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/golang/mock/gomock"
2323
"github.com/mongodb/mongodb-atlas-cli/internal/flag"
2424
mocks "github.com/mongodb/mongodb-atlas-cli/internal/mocks/atlas"
25+
"github.com/mongodb/mongodb-atlas-cli/internal/pointer"
2526
"github.com/mongodb/mongodb-atlas-cli/internal/test"
2627
atlasv2 "go.mongodb.org/atlas-sdk/v20231115007/admin"
2728
)
@@ -31,11 +32,20 @@ func TestCreate_Run(t *testing.T) {
3132
mockStore := mocks.NewMockProjectCreator(ctrl)
3233

3334
opts := CreateOpts{}
34-
expected := &atlasv2.Group{}
35+
expected := &atlasv2.Group{
36+
Tags: &[]atlasv2.ResourceTag{
37+
{Key: pointer.Get("environment"), Value: pointer.Get("unit-testing")},
38+
{Key: pointer.Get("production"), Value: pointer.Get("false")},
39+
},
40+
}
3541

3642
createOpts := &CreateOpts{
3743
store: mockStore,
3844
name: "ProjectBar",
45+
tag: map[string]string{
46+
"environment": "unit-testing",
47+
"production": "false",
48+
},
3949
}
4050
createOpts.OrgID = "5a0a1e7e0f2912c554080adc"
4151
params := &atlasv2.CreateProjectApiParams{

internal/usage/usage.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ dbName and collection are required only for built-in roles.`
450450
CompletedAfter = "Date filter for when the backup snapshots were completed. You must use the YYYY-MM-DD format."
451451
Tag = "List that contains key-value pairs between 1 to 255 characters in length for tagging and categorizing the cluster."
452452
DeploymentTag = "List that contains key-value pairs between 1 to 255 characters in length for tagging and categorizing the deployment."
453+
ProjectTag = "List that contains key-value pairs between 1 to 255 characters in length for tagging and categorizing the project."
453454
ServerlessTag = "List that contains key-value pairs between 1 to 255 characters in length for tagging and categorizing the serverless instance."
454455
UpdateWarning = " Passing this flag replaces preexisting data."
455456
EnableWatch = "Flag that indicates whether to watch the command until it completes its execution or the watch times out. To set the time that the watch times out, use the --watchTimeout option."

test/e2e/iam/atlas_projects_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ func TestAtlasProjects(t *testing.T) {
4747
projectsEntity,
4848
"create",
4949
projectName,
50+
"--tag", "env=e2e",
51+
"--tag", "prod=false",
5052
"-o=json")
5153
cmd.Env = os.Environ()
5254
resp, err := cmd.CombinedOutput()
@@ -84,6 +86,33 @@ func TestAtlasProjects(t *testing.T) {
8486
require.NoError(t, err, string(resp))
8587
})
8688

89+
t.Run("Tags", func(t *testing.T) {
90+
cmd := exec.Command(cliPath,
91+
projectsEntity,
92+
"describe",
93+
projectID,
94+
"-o=json")
95+
cmd.Env = os.Environ()
96+
resp, err := cmd.CombinedOutput()
97+
require.NoError(t, err, string(resp))
98+
var project admin.Group
99+
if err := json.Unmarshal(resp, &project); err != nil {
100+
t.Fatalf("unexpected error: %v", err)
101+
}
102+
103+
require.Len(t, project.GetTags(), 2)
104+
105+
expectedTags := map[string]string{"env": "e2e", "prod": "false"}
106+
for _, tag := range project.GetTags() {
107+
expectedValue, ok := expectedTags[tag.GetKey()]
108+
if !ok {
109+
t.Errorf("unexpected tag key %s in tags: %v, expected tags: %v\n", tag.GetKey(), project.Tags, expectedTags)
110+
}
111+
112+
require.Equal(t, expectedValue, tag.GetValue())
113+
}
114+
})
115+
87116
t.Run("Users", func(t *testing.T) {
88117
cmd := exec.Command(cliPath,
89118
projectsEntity,

0 commit comments

Comments
 (0)