Skip to content

Commit 52bb9eb

Browse files
authored
fix(67): Add Tags resource (#122)
* Add Tags resource * Add tags support to feature resource * Add docs * update changelog * bump plugin-docs
1 parent e88dd5a commit 52bb9eb

File tree

14 files changed

+568
-115
lines changed

14 files changed

+568
-115
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
## 0.7.0
2+
FEATURES:
3+
* Add resource `flagsmith_tag`
4+
* Update resource `flagsmith_feature` to add support for tags
5+
6+
BUG FIXES
7+
fix https://github.com/Flagsmith/terraform-provider-flagsmith/issues/67
8+
9+
## 0.6.0
10+
NOTES:
11+
* This Go module(and related dependencies) has been updated to GO 1.20 as per the Go Support policy
12+
113
## 0.5.1
214
BUG FIXES
315
fix https://github.com/Flagsmith/terraform-provider-flagsmith/issues/81

docs/resources/feature.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ resource "flagsmith_feature" "new_standard_feature" {
4343
- `initial_value` (String) Determines the initial value of the feature.
4444
- `is_archived` (Boolean) Can be used to archive/unarchive a feature. If unspecified, it will default to false
4545
- `owners` (Set of Number) List of user IDs representing the owners of the feature.
46+
- `tags` (Set of Number) List of tag IDs representing the tags attached to the feature.
4647
- `type` (String) Type of the feature, can be STANDARD, or MULTIVARIATE. if unspecified, it will default to STANDARD
4748

4849
### Read-Only

docs/resources/tag.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "flagsmith_tag Resource - terraform-provider-flagsmith"
4+
subcategory: ""
5+
description: |-
6+
Flagsmith Tag
7+
---
8+
9+
# flagsmith_tag (Resource)
10+
11+
Flagsmith Tag
12+
13+
14+
15+
<!-- schema generated by tfplugindocs -->
16+
## Schema
17+
18+
### Required
19+
20+
- `project_uuid` (String) UUID of project the tag belongs to
21+
- `tag_colour` (String) Hexadecimal value of the tag color
22+
- `tag_name` (String) Name of the tag
23+
24+
### Optional
25+
26+
- `description` (String) Description of the feature
27+
28+
### Read-Only
29+
30+
- `id` (Number) ID of the tag
31+
- `project_id` (Number) ID of the project
32+
- `uuid` (String) UUID of the tag

flagsmith/models.go

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ type FeatureResourceData struct {
222222
DefaultEnabled types.Bool `tfsdk:"default_enabled"`
223223
IsArchived types.Bool `tfsdk:"is_archived"`
224224
Owners *[]types.Int64 `tfsdk:"owners"`
225+
Tags *[]types.Int64 `tfsdk:"tags"`
225226
ProjectID types.Int64 `tfsdk:"project_id"`
226227
ProjectUUID types.String `tfsdk:"project_uuid"`
227228
}
@@ -241,6 +242,7 @@ func (f *FeatureResourceData) ToClientFeature() *flagsmithapi.Feature {
241242
DefaultEnabled: f.DefaultEnabled.ValueBool(),
242243
IsArchived: f.IsArchived.ValueBool(),
243244
ProjectUUID: f.ProjectUUID.ValueString(),
245+
Tags: []int64{},
244246
Owners: &[]int64{},
245247
}
246248
if !f.ID.IsNull() && !f.ID.IsUnknown() {
@@ -259,7 +261,12 @@ func (f *FeatureResourceData) ToClientFeature() *flagsmithapi.Feature {
259261
for _, owner := range *f.Owners {
260262
ownerID := owner.ValueInt64()
261263
*feature.Owners = append(*feature.Owners, ownerID)
262-
264+
}
265+
}
266+
if f.Tags != nil {
267+
for _, tag := range *f.Tags {
268+
tagID := tag.ValueInt64()
269+
feature.Tags = append(feature.Tags, tagID)
263270
}
264271
}
265272
return &feature
@@ -292,6 +299,12 @@ func MakeFeatureResourceDataFromClientFeature(clientFeature *flagsmithapi.Featur
292299
*resourceData.Owners = append(*resourceData.Owners, types.Int64Value(owner))
293300
}
294301
}
302+
if clientFeature.Tags != nil && len(clientFeature.Tags) > 0 {
303+
resourceData.Tags = &[]types.Int64{}
304+
for _, tag := range clientFeature.Tags {
305+
*resourceData.Tags = append(*resourceData.Tags, types.Int64Value(tag))
306+
}
307+
}
295308
return resourceData
296309
}
297310

@@ -439,3 +452,51 @@ func MakeSegmentResourceDataFromClientSegment(clientSegment *flagsmithapi.Segmen
439452
}
440453
return resourceData
441454
}
455+
456+
type TagResourceData struct {
457+
ID types.Int64 `tfsdk:"id"`
458+
UUID types.String `tfsdk:"uuid"`
459+
Name types.String `tfsdk:"tag_name"`
460+
Description types.String `tfsdk:"description"`
461+
ProjectID types.Int64 `tfsdk:"project_id"`
462+
ProjectUUID types.String `tfsdk:"project_uuid"`
463+
Colour types.String `tfsdk:"tag_colour"`
464+
}
465+
466+
func (t *TagResourceData) ToClientTag() *flagsmithapi.Tag {
467+
tag := flagsmithapi.Tag{
468+
UUID: t.UUID.ValueString(),
469+
Name: t.Name.ValueString(),
470+
ProjectUUID: t.ProjectUUID.ValueString(),
471+
Colour: t.Colour.ValueString(),
472+
}
473+
if t.Description.ValueString() != "" {
474+
value := t.Description.ValueString()
475+
tag.Description = &value
476+
}
477+
if !t.ID.IsNull() && !t.ID.IsUnknown() {
478+
tagID := t.ID.ValueInt64()
479+
tag.ID = &tagID
480+
}
481+
if !t.ProjectID.IsNull() && !t.ProjectID.IsUnknown() {
482+
projectID := t.ProjectID.ValueInt64()
483+
tag.ProjectID = &projectID
484+
}
485+
return &tag
486+
}
487+
488+
func MakeTagResourceDataFromClientTag(clientTag *flagsmithapi.Tag) TagResourceData {
489+
resourceData := TagResourceData{
490+
ID: types.Int64Value(*clientTag.ID),
491+
UUID: types.StringValue(clientTag.UUID),
492+
Name: types.StringValue(clientTag.Name),
493+
ProjectID: types.Int64Value(*clientTag.ProjectID),
494+
ProjectUUID: types.StringValue(clientTag.ProjectUUID),
495+
Colour: types.StringValue(clientTag.Colour),
496+
}
497+
if clientTag.Description != nil {
498+
resourceData.Description = types.StringValue(*clientTag.Description)
499+
}
500+
501+
return resourceData
502+
}

flagsmith/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ func (p *fsProvider) Resources(ctx context.Context) []func() resource.Resource {
7979
newFeatureStateResource,
8080
newSegmentResource,
8181
newMultivariateResource,
82+
newTagResource,
8283
}
8384

8485
}

flagsmith/provider_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ import (
55
"github.com/Flagsmith/terraform-provider-flagsmith/flagsmith"
66
"github.com/hashicorp/terraform-plugin-framework/providerserver"
77
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
8+
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
810
"os"
911
"strconv"
1012
"testing"
13+
"fmt"
1114
)
1215

1316
// Create provider factories - to be used by resource tests
@@ -68,3 +71,16 @@ func testClient() *flagsmithapi.Client {
6871

6972
return tc
7073
}
74+
func getAttributefromState(s *terraform.State, resourceName , attribute string) (string, error) {
75+
rs, ok := s.RootModule().Resources[resourceName]
76+
if !ok {
77+
return "", fmt.Errorf("not found: %s", resourceName)
78+
}
79+
80+
uuid := rs.Primary.Attributes[attribute]
81+
82+
if uuid == "" {
83+
return "", fmt.Errorf("no uuid is set")
84+
}
85+
return uuid, nil
86+
}

flagsmith/resource_feature.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,11 @@ func (t *featureResource) Schema(ctx context.Context, req resource.SchemaRequest
115115
ElementType: types.Int64Type,
116116
MarkdownDescription: "List of user IDs representing the owners of the feature.",
117117
},
118+
"tags": schema.SetAttribute{
119+
Optional: true,
120+
ElementType: types.Int64Type,
121+
MarkdownDescription: "List of tag IDs representing the tags attached to the feature.",
122+
},
118123
"project_uuid": schema.StringAttribute{
119124
MarkdownDescription: "UUID of project the feature belongs to",
120125
Required: true,

flagsmith/resource_feature_state_test.go

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import (
77
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
88

99
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
10+
"regexp"
1011
"strconv"
1112
"testing"
12-
"regexp"
1313
)
1414

1515
func TestAccEnvironmentFeatureStateResource(t *testing.T) {
@@ -19,15 +19,13 @@ func TestAccEnvironmentFeatureStateResource(t *testing.T) {
1919
Steps: []resource.TestStep{
2020
// Test feature State value validator
2121
{
22-
Config: testAccInvalidFeatureStateValueConfig(),
22+
Config: testAccInvalidFeatureStateValueConfig(),
2323
ExpectError: regexp.MustCompile(`Exactly one of these attributes must be configured:\n\[feature_state_value.string_value,feature_state_value.integer_value,feature_state_value.boolean_value\]`),
24-
2524
},
2625
// Test feature State string value validator
2726
{
28-
Config: testAccEnvironmentFeatureStateResourceConfig(" some_value ", true),
27+
Config: testAccEnvironmentFeatureStateResourceConfig(" some_value ", true),
2928
ExpectError: regexp.MustCompile(`Attribute feature_state_value.string_value Leading and trailing whitespace is\n.*not allowed`),
30-
3129
},
3230

3331
// Create and Read testing
@@ -134,7 +132,7 @@ func TestAccSegmentFeatureStateResource(t *testing.T) {
134132

135133
func getFeatureStateImportID(n string) resource.ImportStateIdFunc {
136134
return func(s *terraform.State) (string, error) {
137-
uuid, err := getUUIDfromState(s, n)
135+
uuid, err := getAttributefromState(s, n, "uuid")
138136
if err != nil {
139137
return "", err
140138
}
@@ -144,7 +142,7 @@ func getFeatureStateImportID(n string) resource.ImportStateIdFunc {
144142
}
145143

146144
func testAccCheckSegmentFeatureStateDestroy(s *terraform.State) error {
147-
uuid, err := getUUIDfromState(s, "flagsmith_feature_state.dummy_environment_feature_x_segment_override")
145+
uuid, err := getAttributefromState(s, "flagsmith_feature_state.dummy_environment_feature_x_segment_override", "uuid")
148146
if err != nil {
149147
return err
150148
}
@@ -237,5 +235,5 @@ resource "flagsmith_feature_state" "dummy_environment_feature_x" {
237235
}
238236
}
239237
240-
`, environmentKey(), featureID())
238+
`, environmentKey(), featureID())
241239
}

flagsmith/resource_feature_test.go

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ func TestAccFeatureResource(t *testing.T) {
3636
resource.TestCheckResourceAttr("flagsmith_feature.test_feature", "owners.0", fmt.Sprintf("%d", firstUserID)),
3737
resource.TestCheckResourceAttr("flagsmith_feature.test_feature", "owners.1", fmt.Sprintf("%d", secondUserID)),
3838

39+
resource.TestCheckResourceAttrSet("flagsmith_feature.test_feature", "tags.0"),
40+
3941
resource.TestCheckResourceAttrSet("flagsmith_feature.test_feature", "id"),
4042
resource.TestCheckResourceAttrSet("flagsmith_feature.test_feature", "uuid"),
4143
resource.TestCheckResourceAttrSet("flagsmith_feature.test_feature", "project_id"),
@@ -56,6 +58,8 @@ func TestAccFeatureResource(t *testing.T) {
5658
resource.TestCheckResourceAttr("flagsmith_feature.test_feature", "owners.0", fmt.Sprintf("%d", firstUserID)),
5759
resource.TestCheckResourceAttr("flagsmith_feature.test_feature", "owners.1", fmt.Sprintf("%d", secondUserID)),
5860

61+
resource.TestCheckResourceAttrSet("flagsmith_feature.test_feature", "tags.0"),
62+
5963
resource.TestCheckResourceAttrSet("flagsmith_feature.test_feature", "id"),
6064
resource.TestCheckResourceAttrSet("flagsmith_feature.test_feature", "uuid"),
6165
resource.TestCheckResourceAttrSet("flagsmith_feature.test_feature", "project_id"),
@@ -70,6 +74,8 @@ func TestAccFeatureResource(t *testing.T) {
7074
resource.TestCheckResourceAttr("flagsmith_feature.test_feature", "description", "feature description updated"),
7175
resource.TestCheckResourceAttr("flagsmith_feature.test_feature", "project_uuid", projectUUID()),
7276

77+
resource.TestCheckResourceAttrSet("flagsmith_feature.test_feature", "tags.0"),
78+
7379
resource.TestCheckResourceAttr("flagsmith_feature.test_feature", "owners.0", fmt.Sprintf("%d", firstUserID)),
7480
resource.TestCheckResourceAttr("flagsmith_feature.test_feature", "owners.1", fmt.Sprintf("%d", thirdUserID)),
7581
),
@@ -136,14 +142,15 @@ func TestAccFeatureResourceOwners(t *testing.T) {
136142
},
137143
})
138144
}
145+
139146
func getFeatureImportID(n string) resource.ImportStateIdFunc {
140147
return func(s *terraform.State) (string, error) {
141-
return getUUIDfromState(s, n)
148+
return getAttributefromState(s, n, "uuid")
142149
}
143150
}
144151

145152
func testAccCheckFeatureResourceDestroy(s *terraform.State) error {
146-
uuid, err := getUUIDfromState(s, "flagsmith_feature.test_feature")
153+
uuid, err := getAttributefromState(s, "flagsmith_feature.test_feature", "uuid")
147154
if err != nil {
148155
return err
149156
}
@@ -156,33 +163,25 @@ func testAccCheckFeatureResourceDestroy(s *terraform.State) error {
156163

157164
}
158165

159-
func getUUIDfromState(s *terraform.State, resourceName string) (string, error) {
160-
rs, ok := s.RootModule().Resources[resourceName]
161-
if !ok {
162-
return "", fmt.Errorf("not found: %s", resourceName)
163-
}
164-
165-
uuid := rs.Primary.Attributes["uuid"]
166-
167-
if uuid == "" {
168-
return "", fmt.Errorf("no uuid is set")
169-
}
170-
return uuid, nil
171-
}
172-
173166
func testAccFeatureResourceConfig(featureName, description string, owners []int) string {
174167
return fmt.Sprintf(`
175168
provider "flagsmith" {
176169
177170
}
171+
resource "flagsmith_tag" "test_tag" {
172+
tag_name = "feature_acc_test_tag"
173+
tag_colour = "#000000"
174+
project_uuid = "%s"
175+
}
178176
179177
resource "flagsmith_feature" "test_feature" {
180178
feature_name = "%s"
181179
description = "%s"
182180
project_uuid = "%s"
183181
type = "STANDARD"
184182
owners = %s
183+
tags = [flagsmith_tag.test_tag.id]
185184
}
186185
187-
`, featureName, description, projectUUID(), strings.Join(strings.Fields(fmt.Sprint(owners)), ","))
186+
`, projectUUID(), featureName, description, projectUUID(), strings.Join(strings.Fields(fmt.Sprint(owners)), ","))
188187
}

0 commit comments

Comments
 (0)