From 36ea80af197fb98f1d66a24a4ef203ff58825c7c Mon Sep 17 00:00:00 2001 From: u110 Date: Wed, 22 Jan 2025 13:23:38 +0900 Subject: [PATCH 01/11] resource_group --- .../resources/trocco_resource_group/import.sh | 1 + .../trocco_resource_group/resource.tf | 15 ++ internal/client/datamart_definition.go | 8 - internal/client/resource_group.go | 132 ++++++++++ .../model/resource_group/resource_group.go | 17 ++ internal/provider/provider.go | 1 + internal/provider/resource_group_resource.go | 249 ++++++++++++++++++ .../validator/unique_team_validator.go | 46 ++++ 8 files changed, 461 insertions(+), 8 deletions(-) create mode 100644 examples/resources/trocco_resource_group/import.sh create mode 100644 examples/resources/trocco_resource_group/resource.tf create mode 100644 internal/client/resource_group.go create mode 100644 internal/provider/model/resource_group/resource_group.go create mode 100644 internal/provider/resource_group_resource.go create mode 100644 internal/provider/validator/unique_team_validator.go diff --git a/examples/resources/trocco_resource_group/import.sh b/examples/resources/trocco_resource_group/import.sh new file mode 100644 index 00000000..683e944f --- /dev/null +++ b/examples/resources/trocco_resource_group/import.sh @@ -0,0 +1 @@ +terraform import trocco_resource.import_resource_group diff --git a/examples/resources/trocco_resource_group/resource.tf b/examples/resources/trocco_resource_group/resource.tf new file mode 100644 index 00000000..1c92789d --- /dev/null +++ b/examples/resources/trocco_resource_group/resource.tf @@ -0,0 +1,15 @@ +resource "trocco_resource_group" "example" { + name = "resource group name" + description = "description" + teams = [ + { + team_id = 1 + role = "administrator" + }, + { + team_id = 2 + role = "operator" + } + ] +} + diff --git a/internal/client/datamart_definition.go b/internal/client/datamart_definition.go index d91bea91..4394576f 100644 --- a/internal/client/datamart_definition.go +++ b/internal/client/datamart_definition.go @@ -102,14 +102,6 @@ type DatamartBigqueryOption struct { Location *string `json:"location"` } -type ResourceGroup struct { - ID int64 `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` -} - type CustomVariableSetting struct { Name string `json:"name"` Type string `json:"type"` diff --git a/internal/client/resource_group.go b/internal/client/resource_group.go new file mode 100644 index 00000000..1ba3711a --- /dev/null +++ b/internal/client/resource_group.go @@ -0,0 +1,132 @@ +package client + +import ( + "fmt" + "net/http" + "net/url" +) + +const resourceGroupBasePath = "/api/resource_groups" + +type ResourceGroup struct { + ID int64 `json:"id"` + Name string `json:"name"` + Description *string `json:"description"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` +} + +type ResourceGroupWithTeams struct { + ID int64 `json:"id"` + Name string `json:"name"` + Description *string `json:"description"` + Teams []ResourceGroupPermission `json:"teams"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` +} + +type ResourceGroupPermission struct { + TeamID int64 `json:"team_id"` + Role string `json:"role"` +} + +// List of ResourceGroups + +type ListResouceGroupInput struct { + limit *int + cursor *string +} + +func (input *ListResouceGroupInput) SetLimit(limit int) { + input.limit = &limit +} + +func (input *ListResouceGroupInput) SetCursor(cursor string) { + input.cursor = &cursor +} + +type ListResouceGroupOutput struct { + Items []ResourceGroupWithTeams `json:"items"` + NextCursor *string `json:"next_cursor"` +} + +const MaxListResourceGroupsLimit = 100 + +func (client *TroccoClient) ListResourceGroups(input *ListResouceGroupInput) (*ListResouceGroupOutput, error) { + params := url.Values{} + if input != nil && input.limit != nil { + if *input.limit < 1 || *input.limit > MaxListResourceGroupsLimit { + return nil, fmt.Errorf("limit must be between 1 and %d", MaxListResourceGroupsLimit) + } + params.Add("limit", fmt.Sprintf("%d", *input.limit)) + } + if input != nil && input.cursor != nil { + params.Add("cursor", *input.cursor) + } + path := fmt.Sprintf(resourceGroupBasePath+"?%s", params.Encode()) + output := new(ListResouceGroupOutput) + err := client.do(http.MethodGet, path, nil, output) + if err != nil { + return nil, err + } + return output, nil +} + +// Get a Team + +func (client *TroccoClient) GetResourceGroup(id int64) (*ResourceGroupWithTeams, error) { + path := fmt.Sprintf("%s/%d", resourceGroupBasePath, id) + output := new(ResourceGroupWithTeams) + err := client.do(http.MethodGet, path, nil, output) + if err != nil { + return nil, err + } + return output, nil +} + +// Create + +type CreateResourceGroupInput struct { + Name string `json:"name"` + Description *string `json:"description,omitempty"` + Teams []TeamRoleInput `json:"teams"` +} + +type TeamRoleInput struct { + TeamID int64 `json:"team_id"` + Role string `json:"role"` +} + +func (client *TroccoClient) CreateResourceGroup(input *CreateResourceGroupInput) (*ResourceGroupWithTeams, error) { + output := new(ResourceGroupWithTeams) + err := client.do(http.MethodPost, resourceGroupBasePath, input, output) + if err != nil { + return nil, err + } + return output, nil +} + +// Update + +type UpdateResourceGroupInput struct { + Name string `json:"name"` + Description *string `json:"description,omitempty"` + Teams []TeamRoleInput `json:"teams"` +} + +func (client *TroccoClient) UpdateResourceGroup(id int64, input *UpdateResourceGroupInput) (*ResourceGroupWithTeams, error) { + path := fmt.Sprintf("%s/%d", resourceGroupBasePath, id) + output := new(ResourceGroupWithTeams) + err := client.do(http.MethodPatch, path, input, output) + if err != nil { + return nil, err + } + return output, nil +} + +// Delete + +func (client *TroccoClient) DeleteResourceGroup(id int64) error { + path := fmt.Sprintf("%s/%d", resourceGroupBasePath, id) + return client.do(http.MethodDelete, path, nil, nil) +} diff --git a/internal/provider/model/resource_group/resource_group.go b/internal/provider/model/resource_group/resource_group.go new file mode 100644 index 00000000..1b772803 --- /dev/null +++ b/internal/provider/model/resource_group/resource_group.go @@ -0,0 +1,17 @@ +package resource_group + +import ( + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type ResourceGroupResourceModel struct { + ID types.Int64 `tfsdk:"id"` + Name types.String `tfsdk:"name"` + Description types.String `tfsdk:"description"` + Teams []TeamRoleResourceModel `tfsdk:"teams"` +} + +type TeamRoleResourceModel struct { + TeamID types.Int64 `tfsdk:"team_id"` + Role types.String `tfsdk:"role"` +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index a8d274ae..b8b44753 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -135,6 +135,7 @@ func (p *TroccoProvider) Resources(ctx context.Context) []func() resource.Resour NewPipelineDefinitionResource, NewJobDefinitionResource, NewTeamResource, + NewResourceGroupResource, } } diff --git a/internal/provider/resource_group_resource.go b/internal/provider/resource_group_resource.go new file mode 100644 index 00000000..b297d88d --- /dev/null +++ b/internal/provider/resource_group_resource.go @@ -0,0 +1,249 @@ +package provider + +import ( + "context" + "fmt" + "strconv" + "terraform-provider-trocco/internal/client" + model "terraform-provider-trocco/internal/provider/model/resource_group" + troccoValidator "terraform-provider-trocco/internal/provider/validator" + + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var ( + _ resource.Resource = &resourceGroupResource{} + _ resource.ResourceWithConfigure = &resourceGroupResource{} + _ resource.ResourceWithImportState = &resourceGroupResource{} +) + +func NewResourceGroupResource() resource.Resource { + return &resourceGroupResource{} +} + +type resourceGroupResource struct { + client *client.TroccoClient +} + +func (r *resourceGroupResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_resource_group" +} + +func (r *resourceGroupResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*client.TroccoClient) + if !ok { + resp.Diagnostics.AddError( + "Unexpected Resource Configure Type", + fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + return + } + + r.client = client +} + +func (r *resourceGroupResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + MarkdownDescription: "Provides a TROCCO resource_group resource.", + Attributes: map[string]schema.Attribute{ + "id": schema.Int64Attribute{ + Computed: true, + PlanModifiers: []planmodifier.Int64{ + int64planmodifier.UseStateForUnknown(), + }, + MarkdownDescription: "The ID of the resource group.", + }, + "name": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The name of the resource group.", + }, + "description": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The description of the resource group.", + }, + "teams": schema.SetNestedAttribute{ + Required: true, + MarkdownDescription: "The team roles of the resource group.", + Validators: []validator.Set{ + troccoValidator.UniqueTeamValidator{}, + }, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "team_id": schema.Int64Attribute{ + Required: true, + MarkdownDescription: "The team ID of the role.", + }, + "role": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.OneOf("administrator", "editor", "operator", "viewer"), + }, + MarkdownDescription: "The role of the team. Valid values are `administrator`, `editor`, `operator`, `viewer`.", + }, + }, + }, + }, + }, + } +} + +func (r *resourceGroupResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan model.ResourceGroupResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + input := client.CreateResourceGroupInput{ + Name: plan.Name.ValueString(), + Description: plan.Description.ValueStringPointer(), + Teams: []client.TeamRoleInput{}, + } + for _, m := range plan.Teams { + input.Teams = append(input.Teams, client.TeamRoleInput{ + TeamID: m.TeamID.ValueInt64(), + Role: m.Role.ValueString(), + }) + + } + + resourceGroup, err := r.client.CreateResourceGroup(&input) + if err != nil { + resp.Diagnostics.AddError( + "Creating resource group", + fmt.Sprintf("Unable to create resource group, got error: %s", err), + ) + return + } + + newState := model.ResourceGroupResourceModel{ + ID: types.Int64Value(resourceGroup.ID), + Name: types.StringValue(resourceGroup.Name), + Description: types.StringPointerValue(resourceGroup.Description), + Teams: []model.TeamRoleResourceModel{}, + } + for _, m := range resourceGroup.Teams { + newState.Teams = append(newState.Teams, model.TeamRoleResourceModel{ + TeamID: types.Int64Value(m.TeamID), + Role: types.StringValue(m.Role), + }) + } + + resp.Diagnostics.Append(resp.State.Set(ctx, newState)...) +} + +func (r *resourceGroupResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state model.ResourceGroupResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + resourceGroup, err := r.client.GetResourceGroup(state.ID.ValueInt64()) + if err != nil { + resp.Diagnostics.AddError( + "Reading resource group", + fmt.Sprintf("Unable to read resource group, got error: %s", err), + ) + return + } + + newState := model.ResourceGroupResourceModel{ + ID: types.Int64Value(resourceGroup.ID), + Name: types.StringValue(resourceGroup.Name), + Description: types.StringPointerValue(resourceGroup.Description), + Teams: []model.TeamRoleResourceModel{}, + } + for _, m := range resourceGroup.Teams { + newState.Teams = append(newState.Teams, model.TeamRoleResourceModel{ + TeamID: types.Int64Value(m.TeamID), + Role: types.StringValue(m.Role), + }) + } + + resp.Diagnostics.Append(resp.State.Set(ctx, newState)...) +} +func (r *resourceGroupResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan, state model.ResourceGroupResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + input := client.UpdateResourceGroupInput{ + Name: *plan.Name.ValueStringPointer(), + Description: plan.Description.ValueStringPointer(), + Teams: []client.TeamRoleInput{}, + } + for _, m := range plan.Teams { + input.Teams = append(input.Teams, client.TeamRoleInput{ + TeamID: m.TeamID.ValueInt64(), + Role: m.Role.ValueString(), + }) + } + + resourceGroup, err := r.client.UpdateResourceGroup(state.ID.ValueInt64(), &input) + if err != nil { + resp.Diagnostics.AddError( + "Updating team", + fmt.Sprintf("Unable to update team, got error: %s", err), + ) + return + } + + newState := model.ResourceGroupResourceModel{ + ID: types.Int64Value(resourceGroup.ID), + Name: types.StringValue(resourceGroup.Name), + Description: types.StringPointerValue(resourceGroup.Description), + Teams: []model.TeamRoleResourceModel{}, + } + for _, m := range resourceGroup.Teams { + newState.Teams = append(newState.Teams, model.TeamRoleResourceModel{ + TeamID: types.Int64Value(m.TeamID), + Role: types.StringValue(m.Role), + }) + } + + resp.Diagnostics.Append(resp.State.Set(ctx, newState)...) +} +func (r *resourceGroupResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state model.ResourceGroupResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + err := r.client.DeleteResourceGroup(state.ID.ValueInt64()) + if err != nil { + resp.Diagnostics.AddError( + "Deleting resource group", + fmt.Sprintf("Unable to delete resource group, got error: %s", err), + ) + return + } +} + +func (r *resourceGroupResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + id, err := strconv.ParseInt(req.ID, 10, 64) + if err != nil { + resp.Diagnostics.AddError( + "Importing resource group", + fmt.Sprintf("Unable to parse id, got error: %s", err), + ) + return + } + + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), id)...) +} diff --git a/internal/provider/validator/unique_team_validator.go b/internal/provider/validator/unique_team_validator.go new file mode 100644 index 00000000..2337d96b --- /dev/null +++ b/internal/provider/validator/unique_team_validator.go @@ -0,0 +1,46 @@ +package validator + +import ( + "context" + "fmt" + + model "terraform-provider-trocco/internal/provider/model/resource_group" + + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +type UniqueTeamValidator struct{} + +func (v UniqueTeamValidator) Description(ctx context.Context) string { + return "Ensures that team IDs are unique within the set." +} + +func (v UniqueTeamValidator) MarkdownDescription(ctx context.Context) string { + return v.Description(ctx) +} + +func (v UniqueTeamValidator) ValidateSet(ctx context.Context, request validator.SetRequest, response *validator.SetResponse) { + var teamIDs []model.TeamRoleResourceModel + diags := request.ConfigValue.ElementsAs(ctx, &teamIDs, false) + if diags.HasError() { + response.Diagnostics.Append(diags...) + return + } + + for i, teamID := range teamIDs { + for j, otherTeamID := range teamIDs { + if i == j { + continue + } + + if teamID.TeamID == otherTeamID.TeamID { + response.Diagnostics.AddAttributeError( + request.Path, + "Duplicate Team ID", + fmt.Sprintf("Team ID %q is duplicated in the list.", teamID.TeamID), + ) + return + } + } + } +} From 46f715d3f92b07280a267fe1ce87d21d0e0703cb Mon Sep 17 00:00:00 2001 From: u110 Date: Thu, 23 Jan 2025 10:50:23 +0900 Subject: [PATCH 02/11] rename --- internal/provider/validator/unique_team_validator.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/provider/validator/unique_team_validator.go b/internal/provider/validator/unique_team_validator.go index 2337d96b..8e328f38 100644 --- a/internal/provider/validator/unique_team_validator.go +++ b/internal/provider/validator/unique_team_validator.go @@ -27,17 +27,17 @@ func (v UniqueTeamValidator) ValidateSet(ctx context.Context, request validator. return } - for i, teamID := range teamIDs { - for j, otherTeamID := range teamIDs { + for i, teamI := range teamIDs { + for j, teamJ := range teamIDs { if i == j { continue } - if teamID.TeamID == otherTeamID.TeamID { + if teamI.TeamID == teamJ.TeamID { response.Diagnostics.AddAttributeError( request.Path, "Duplicate Team ID", - fmt.Sprintf("Team ID %q is duplicated in the list.", teamID.TeamID), + fmt.Sprintf("Team ID %q is duplicated in the list.", teamI.TeamID), ) return } From 1391a6ef241ffafdd58cb30be9f65ef10f2dbe8a Mon Sep 17 00:00:00 2001 From: u110 Date: Thu, 23 Jan 2025 10:52:02 +0900 Subject: [PATCH 03/11] add docs using go generate --- docs/resources/resource_group.md | 62 ++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 docs/resources/resource_group.md diff --git a/docs/resources/resource_group.md b/docs/resources/resource_group.md new file mode 100644 index 00000000..e1b84a14 --- /dev/null +++ b/docs/resources/resource_group.md @@ -0,0 +1,62 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "trocco_resource_group Resource - trocco" +subcategory: "" +description: |- + Provides a TROCCO resource_group resource. +--- + +# trocco_resource_group (Resource) + +Provides a TROCCO resource_group resource. + +## Example Usage + +```terraform +resource "trocco_resource_group" "example" { + name = "resource group name" + description = "description" + teams = [ + { + team_id = 1 + role = "administrator" + }, + { + team_id = 2 + role = "operator" + } + ] +} +``` + + +## Schema + +### Required + +- `name` (String) The name of the resource group. +- `teams` (Attributes Set) The team roles of the resource group. (see [below for nested schema](#nestedatt--teams)) + +### Optional + +- `description` (String) The description of the resource group. + +### Read-Only + +- `id` (Number) The ID of the resource group. + + +### Nested Schema for `teams` + +Required: + +- `role` (String) The role of the team. Valid values are `administrator`, `editor`, `operator`, `viewer`. +- `team_id` (Number) The team ID of the role. + +## Import + +Import is supported using the following syntax: + +```shell +terraform import trocco_resource.import_resource_group +``` From 891a33d26eb8115358a9a34451d51eb487b7563e Mon Sep 17 00:00:00 2001 From: u110 Date: Fri, 24 Jan 2025 12:09:11 +0900 Subject: [PATCH 04/11] fix --- internal/client/resource_group.go | 4 ++-- internal/provider/resource_group_resource.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/client/resource_group.go b/internal/client/resource_group.go index 1ba3711a..a31be42a 100644 --- a/internal/client/resource_group.go +++ b/internal/client/resource_group.go @@ -87,7 +87,7 @@ func (client *TroccoClient) GetResourceGroup(id int64) (*ResourceGroupWithTeams, // Create type CreateResourceGroupInput struct { - Name string `json:"name"` + Name *string `json:"name"` Description *string `json:"description,omitempty"` Teams []TeamRoleInput `json:"teams"` } @@ -109,7 +109,7 @@ func (client *TroccoClient) CreateResourceGroup(input *CreateResourceGroupInput) // Update type UpdateResourceGroupInput struct { - Name string `json:"name"` + Name *string `json:"name"` Description *string `json:"description,omitempty"` Teams []TeamRoleInput `json:"teams"` } diff --git a/internal/provider/resource_group_resource.go b/internal/provider/resource_group_resource.go index b297d88d..92a42524 100644 --- a/internal/provider/resource_group_resource.go +++ b/internal/provider/resource_group_resource.go @@ -106,7 +106,7 @@ func (r *resourceGroupResource) Create(ctx context.Context, req resource.CreateR } input := client.CreateResourceGroupInput{ - Name: plan.Name.ValueString(), + Name: plan.Name.ValueStringPointer(), Description: plan.Description.ValueStringPointer(), Teams: []client.TeamRoleInput{}, } @@ -183,7 +183,7 @@ func (r *resourceGroupResource) Update(ctx context.Context, req resource.UpdateR } input := client.UpdateResourceGroupInput{ - Name: *plan.Name.ValueStringPointer(), + Name: plan.Name.ValueStringPointer(), Description: plan.Description.ValueStringPointer(), Teams: []client.TeamRoleInput{}, } From 426d740437ddd7adb095db186fb4a00a2d7f54c8 Mon Sep 17 00:00:00 2001 From: u110 Date: Fri, 24 Jan 2025 12:09:27 +0900 Subject: [PATCH 05/11] add tests --- internal/client/resource_group_test.go | 278 ++++++++++++++++++ .../provider/resource_group_resource_test.go | 118 ++++++++ 2 files changed, 396 insertions(+) create mode 100644 internal/client/resource_group_test.go create mode 100644 internal/provider/resource_group_resource_test.go diff --git a/internal/client/resource_group_test.go b/internal/client/resource_group_test.go new file mode 100644 index 00000000..6726a5b8 --- /dev/null +++ b/internal/client/resource_group_test.go @@ -0,0 +1,278 @@ +package client + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/samber/lo" + "github.com/stretchr/testify/assert" +) + +// List Teams + +func TestListResourceGroup(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, "/api/resource_groups", r.URL.Path) + assert.Equal(t, http.MethodGet, r.Method) + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + resp := ` + { + "items": [ + { + "id": 1, + "name": "ResourceGroup 1", + "description": "ResourceGroup 1 description", + "created_at": "2023-10-16T18:24:51.806+09:00", + "updated_at": "2023-10-16T18:24:51.806+09:00" + }, + { + "id": 2, + "name": "ResourceGroup 2", + "description": "ResourceGroup 2 description", + "created_at": "2023-10-16T18:24:51.806+09:00", + "updated_at": "2023-10-16T18:24:51.806+09:00" + } + ] + } + ` + _, err := w.Write([]byte(resp)) + assert.NoError(t, err) + })) + defer server.Close() + + output, err := NewDevTroccoClient("1234567890", server.URL).ListResourceGroups(nil) + + assert.NoError(t, err) + assert.Len(t, output.Items, 2) + assert.Equal(t, int64(1), output.Items[0].ID) + assert.Equal(t, "ResourceGroup 1", output.Items[0].Name) + assert.Equal(t, "ResourceGroup 1 description", *output.Items[0].Description) + assert.Equal(t, "2023-10-16T18:24:51.806+09:00", output.Items[0].CreatedAt) + assert.Equal(t, "2023-10-16T18:24:51.806+09:00", output.Items[0].UpdatedAt) + assert.Equal(t, int64(2), output.Items[1].ID) + assert.Equal(t, "ResourceGroup 2", output.Items[1].Name) + assert.Equal(t, "ResourceGroup 2 description", *output.Items[1].Description) + assert.Equal(t, "2023-10-16T18:24:51.806+09:00", output.Items[1].CreatedAt) + assert.Equal(t, "2023-10-16T18:24:51.806+09:00", output.Items[1].UpdatedAt) +} + +func TestListResourceGroupsLimitAndCursor(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, "1", r.URL.Query().Get("limit")) + assert.Equal(t, "test_prev_cursor", r.URL.Query().Get("cursor")) + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + resp := ` + { + "items": [ + { + "id": 1, + "name": "ResourceGroup 1", + "description": "ResourceGroup 1 description", + "created_at": "2023-10-16T18:24:51.806+09:00", + "updated_at": "2023-10-16T18:24:51.806+09:00" + } + ], + "next_cursor": "test_next_cursor" + } + ` + _, err := w.Write([]byte(resp)) + assert.NoError(t, err) + })) + defer server.Close() + + input := &ListResouceGroupInput{} + input.SetLimit(1) + input.SetCursor("test_prev_cursor") + + output, err := NewDevTroccoClient("1234567890", server.URL).ListResourceGroups(input) + + assert.NoError(t, err) + assert.Len(t, output.Items, 1) + assert.Equal(t, int64(1), output.Items[0].ID) + assert.Equal(t, "ResourceGroup 1", output.Items[0].Name) + assert.Equal(t, "ResourceGroup 1 description", *output.Items[0].Description) + assert.Equal(t, "2023-10-16T18:24:51.806+09:00", output.Items[0].CreatedAt) + assert.Equal(t, "2023-10-16T18:24:51.806+09:00", output.Items[0].UpdatedAt) + assert.Equal(t, "test_next_cursor", *output.NextCursor) +} + +// Get Team + +func TestGetResouceGroup(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, "/api/resource_groups/1", r.URL.Path) + assert.Equal(t, http.MethodGet, r.Method) + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + resp := ` + { + "id": 1, + "name": "ResourceGroup 1", + "description": "ResourceGroup 1 description", + "created_at": "2023-10-16T18:24:51.806+09:00", + "updated_at": "2023-10-16T18:24:51.806+09:00", + "teams": [ + { + "team_id": 1, + "role": "administrator" + }, + { + "team_id": 2, + "role": "operator" + } + ] + } + ` + _, err := w.Write([]byte(resp)) + assert.NoError(t, err) + })) + defer server.Close() + + output, err := NewDevTroccoClient("1234567890", server.URL).GetResourceGroup(1) + + assert.NoError(t, err) + assert.Equal(t, int64(1), output.ID) + assert.Equal(t, "ResourceGroup 1", output.Name) + assert.Equal(t, "ResourceGroup 1 description", *output.Description) + assert.Equal(t, "2023-10-16T18:24:51.806+09:00", output.CreatedAt) + assert.Equal(t, "2023-10-16T18:24:51.806+09:00", output.UpdatedAt) + assert.Len(t, output.Teams, 2) + assert.Equal(t, int64(1), output.Teams[0].TeamID) + assert.Equal(t, "administrator", output.Teams[0].Role) + assert.Equal(t, int64(2), output.Teams[1].TeamID) + assert.Equal(t, "operator", output.Teams[1].Role) +} + +// Create Team + +func TestCreateResourceGroup(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, "/api/resource_groups", r.URL.Path) + assert.Equal(t, http.MethodPost, r.Method) + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + + resp := ` + { + "id": 1, + "name": "ResourceGroup", + "description": "description", + "created_at": "2023-10-16T18:24:51.806+09:00", + "updated_at": "2023-10-16T18:24:51.806+09:00", + "teams": [ + { + "team_id": 1, + "role": "administrator" + } + ] + } + ` + _, err := w.Write([]byte(resp)) + assert.NoError(t, err) + })) + defer server.Close() + + input := &CreateResourceGroupInput{ + Name: lo.ToPtr("ResourceGroup"), + Description: lo.ToPtr("description"), + Teams: []TeamRoleInput{ + {TeamID: 1, Role: "administrator"}, + }, + } + + output, err := NewDevTroccoClient("1234567890", server.URL).CreateResourceGroup(input) + + assert.NoError(t, err) + assert.Equal(t, int64(1), output.ID) + assert.Equal(t, "ResourceGroup", output.Name) + assert.Equal(t, "description", *output.Description) + assert.Equal(t, "2023-10-16T18:24:51.806+09:00", output.CreatedAt) + assert.Equal(t, "2023-10-16T18:24:51.806+09:00", output.UpdatedAt) + assert.Len(t, output.Teams, 1) + assert.Equal(t, int64(1), output.Teams[0].TeamID) + assert.Equal(t, "administrator", output.Teams[0].Role) +} + +// Update Team + +func TestUpdateResourceGroup(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, "/api/resource_groups/1", r.URL.Path) + assert.Equal(t, http.MethodPatch, r.Method) + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + resp := ` + { + "id": 1, + "name": "ResourceGroup", + "description": "description", + "created_at": "2023-10-16T18:24:51.806+09:00", + "updated_at": "2023-10-16T18:24:51.806+09:00", + "teams": [ + { + "team_id": 1, + "role": "administrator" + }, + { + "team_id": 2, + "role": "operator" + } + ] + } + ` + _, err := w.Write([]byte(resp)) + assert.NoError(t, err) + })) + defer server.Close() + + input := &UpdateResourceGroupInput{ + Name: lo.ToPtr("ResourceGroup"), + Description: lo.ToPtr("description"), + Teams: []TeamRoleInput{ + {TeamID: 1, Role: "administrator"}, + {TeamID: 2, Role: "operator"}, + }, + } + + output, err := NewDevTroccoClient("1234567890", server.URL).UpdateResourceGroup(1, input) + + assert.NoError(t, err) + assert.Equal(t, int64(1), output.ID) + assert.Equal(t, "ResourceGroup", output.Name) + assert.Equal(t, "description", *output.Description) + assert.Equal(t, "2023-10-16T18:24:51.806+09:00", output.CreatedAt) + assert.Equal(t, "2023-10-16T18:24:51.806+09:00", output.UpdatedAt) + assert.Len(t, output.Teams, 2) + assert.Equal(t, int64(1), output.Teams[0].TeamID) + assert.Equal(t, "administrator", output.Teams[0].Role) + assert.Equal(t, int64(2), output.Teams[1].TeamID) + assert.Equal(t, "operator", output.Teams[1].Role) +} + +// Delete Team + +func TestDeleteResourceGroup(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, "/api/resource_groups/1", r.URL.Path) + assert.Equal(t, http.MethodDelete, r.Method) + + w.WriteHeader(http.StatusNoContent) + })) + defer server.Close() + + err := NewDevTroccoClient("1234567890", server.URL).DeleteResourceGroup(1) + + assert.NoError(t, err) +} diff --git a/internal/provider/resource_group_resource_test.go b/internal/provider/resource_group_resource_test.go new file mode 100644 index 00000000..b67d4dc0 --- /dev/null +++ b/internal/provider/resource_group_resource_test.go @@ -0,0 +1,118 @@ +package provider + +import ( + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccResourceGroupResource(t *testing.T) { + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Create and Read testing + { + Config: providerConfig + ` + resource "trocco_resource_group" "test" { + name = "test" + description = "test" + teams = [ + { + team_id = 1 + role = "operator" + } + ] + } + `, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("trocco_resource_group.test", "name", "test"), + resource.TestCheckResourceAttr("trocco_resource_group.test", "description", "test"), + resource.TestCheckResourceAttr("trocco_resource_group.test", "teams.#", "1"), + resource.TestCheckResourceAttr("trocco_resource_group.test", "teams.0.team_id", "1"), + resource.TestCheckResourceAttr("trocco_resource_group.test", "teams.0.role", "operator"), + ), + }, + // ImportState testing + { + ResourceName: "trocco_resource_group.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"id"}, + }, + // Update testing + { + Config: providerConfig + ` + resource "trocco_resource_group" "test" { + name = "updated" + description = "updated" + teams = [ + { + team_id = 1 + role = "administrator" + }, + { + team_id = 2 + role = "operator" + } + ] + } + `, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("trocco_resource_group.test", "name", "updated"), + resource.TestCheckResourceAttr("trocco_resource_group.test", "description", "updated"), + resource.TestCheckResourceAttr("trocco_resource_group.test", "teams.#", "2"), + resource.TestCheckResourceAttr("trocco_resource_group.test", "teams.0.team_id", "1"), + resource.TestCheckResourceAttr("trocco_resource_group.test", "teams.0.role", "administrator"), + resource.TestCheckResourceAttr("trocco_resource_group.test", "teams.1.team_id", "2"), + resource.TestCheckResourceAttr("trocco_resource_group.test", "teams.1.role", "operator"), + ), + }, + }, + }) +} + +func TestAccResourceGroupNoTeams(t *testing.T) { + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: providerConfig + ` + resource "trocco_resource_group" "test" { + name = "test" + description = "test" + teams = [] + } + `, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("trocco_resource_group.test", "name", "test"), + resource.TestCheckResourceAttr("trocco_resource_group.test", "description", "test"), + resource.TestCheckResourceAttr("trocco_resource_group.test", "teams.#", "0"), + ), + }, + }, + }) +} + +func TestAccResourceGroupDuplicateRoles(t *testing.T) { + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: providerConfig + ` + resource "trocco_resource_group" "test" { + name = "test" + description = "test" + teams = [ + { team_id = 1, role = "administrator" }, + { team_id = 1, role = "operator" }, + ] + } + `, + ExpectError: regexp.MustCompile(`Team ID "1" is duplicated in the list.`), + }, + }, + }) + +} + From d97185700ecdb87f0be43eafe14bb15fec42154a Mon Sep 17 00:00:00 2001 From: u110 Date: Fri, 24 Jan 2025 13:18:47 +0900 Subject: [PATCH 06/11] golangci-lint --- internal/client/resource_group.go | 32 +++++++++---------- .../model/resource_group/resource_group.go | 6 ++-- internal/provider/resource_group_resource.go | 10 +++--- .../provider/resource_group_resource_test.go | 1 - 4 files changed, 24 insertions(+), 25 deletions(-) diff --git a/internal/client/resource_group.go b/internal/client/resource_group.go index a31be42a..8fd6d5f4 100644 --- a/internal/client/resource_group.go +++ b/internal/client/resource_group.go @@ -9,22 +9,22 @@ import ( const resourceGroupBasePath = "/api/resource_groups" type ResourceGroup struct { - ID int64 `json:"id"` - Name string `json:"name"` - Description *string `json:"description"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` -} - -type ResourceGroupWithTeams struct { ID int64 `json:"id"` Name string `json:"name"` Description *string `json:"description"` - Teams []ResourceGroupPermission `json:"teams"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } +type ResourceGroupWithTeams struct { + ID int64 `json:"id"` + Name string `json:"name"` + Description *string `json:"description"` + Teams []ResourceGroupPermission `json:"teams"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` +} + type ResourceGroupPermission struct { TeamID int64 `json:"team_id"` Role string `json:"role"` @@ -47,7 +47,7 @@ func (input *ListResouceGroupInput) SetCursor(cursor string) { type ListResouceGroupOutput struct { Items []ResourceGroupWithTeams `json:"items"` - NextCursor *string `json:"next_cursor"` + NextCursor *string `json:"next_cursor"` } const MaxListResourceGroupsLimit = 100 @@ -87,9 +87,9 @@ func (client *TroccoClient) GetResourceGroup(id int64) (*ResourceGroupWithTeams, // Create type CreateResourceGroupInput struct { - Name *string `json:"name"` - Description *string `json:"description,omitempty"` - Teams []TeamRoleInput `json:"teams"` + Name *string `json:"name"` + Description *string `json:"description,omitempty"` + Teams []TeamRoleInput `json:"teams"` } type TeamRoleInput struct { @@ -109,9 +109,9 @@ func (client *TroccoClient) CreateResourceGroup(input *CreateResourceGroupInput) // Update type UpdateResourceGroupInput struct { - Name *string `json:"name"` - Description *string `json:"description,omitempty"` - Teams []TeamRoleInput `json:"teams"` + Name *string `json:"name"` + Description *string `json:"description,omitempty"` + Teams []TeamRoleInput `json:"teams"` } func (client *TroccoClient) UpdateResourceGroup(id int64, input *UpdateResourceGroupInput) (*ResourceGroupWithTeams, error) { diff --git a/internal/provider/model/resource_group/resource_group.go b/internal/provider/model/resource_group/resource_group.go index 1b772803..d0ea6a6b 100644 --- a/internal/provider/model/resource_group/resource_group.go +++ b/internal/provider/model/resource_group/resource_group.go @@ -5,9 +5,9 @@ import ( ) type ResourceGroupResourceModel struct { - ID types.Int64 `tfsdk:"id"` - Name types.String `tfsdk:"name"` - Description types.String `tfsdk:"description"` + ID types.Int64 `tfsdk:"id"` + Name types.String `tfsdk:"name"` + Description types.String `tfsdk:"description"` Teams []TeamRoleResourceModel `tfsdk:"teams"` } diff --git a/internal/provider/resource_group_resource.go b/internal/provider/resource_group_resource.go index 92a42524..0e8cdd16 100644 --- a/internal/provider/resource_group_resource.go +++ b/internal/provider/resource_group_resource.go @@ -108,7 +108,7 @@ func (r *resourceGroupResource) Create(ctx context.Context, req resource.CreateR input := client.CreateResourceGroupInput{ Name: plan.Name.ValueStringPointer(), Description: plan.Description.ValueStringPointer(), - Teams: []client.TeamRoleInput{}, + Teams: []client.TeamRoleInput{}, } for _, m := range plan.Teams { input.Teams = append(input.Teams, client.TeamRoleInput{ @@ -131,7 +131,7 @@ func (r *resourceGroupResource) Create(ctx context.Context, req resource.CreateR ID: types.Int64Value(resourceGroup.ID), Name: types.StringValue(resourceGroup.Name), Description: types.StringPointerValue(resourceGroup.Description), - Teams: []model.TeamRoleResourceModel{}, + Teams: []model.TeamRoleResourceModel{}, } for _, m := range resourceGroup.Teams { newState.Teams = append(newState.Teams, model.TeamRoleResourceModel{ @@ -163,7 +163,7 @@ func (r *resourceGroupResource) Read(ctx context.Context, req resource.ReadReque ID: types.Int64Value(resourceGroup.ID), Name: types.StringValue(resourceGroup.Name), Description: types.StringPointerValue(resourceGroup.Description), - Teams: []model.TeamRoleResourceModel{}, + Teams: []model.TeamRoleResourceModel{}, } for _, m := range resourceGroup.Teams { newState.Teams = append(newState.Teams, model.TeamRoleResourceModel{ @@ -185,7 +185,7 @@ func (r *resourceGroupResource) Update(ctx context.Context, req resource.UpdateR input := client.UpdateResourceGroupInput{ Name: plan.Name.ValueStringPointer(), Description: plan.Description.ValueStringPointer(), - Teams: []client.TeamRoleInput{}, + Teams: []client.TeamRoleInput{}, } for _, m := range plan.Teams { input.Teams = append(input.Teams, client.TeamRoleInput{ @@ -207,7 +207,7 @@ func (r *resourceGroupResource) Update(ctx context.Context, req resource.UpdateR ID: types.Int64Value(resourceGroup.ID), Name: types.StringValue(resourceGroup.Name), Description: types.StringPointerValue(resourceGroup.Description), - Teams: []model.TeamRoleResourceModel{}, + Teams: []model.TeamRoleResourceModel{}, } for _, m := range resourceGroup.Teams { newState.Teams = append(newState.Teams, model.TeamRoleResourceModel{ diff --git a/internal/provider/resource_group_resource_test.go b/internal/provider/resource_group_resource_test.go index b67d4dc0..3f9dfce8 100644 --- a/internal/provider/resource_group_resource_test.go +++ b/internal/provider/resource_group_resource_test.go @@ -115,4 +115,3 @@ func TestAccResourceGroupDuplicateRoles(t *testing.T) { }) } - From 5d45b480c3e4551b2ee6aec041ad776f9e1ee6b6 Mon Sep 17 00:00:00 2001 From: Yuu Ito Date: Wed, 29 Jan 2025 10:40:19 +0900 Subject: [PATCH 07/11] Update internal/client/resource_group.go --- internal/client/resource_group.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/client/resource_group.go b/internal/client/resource_group.go index 8fd6d5f4..69535698 100644 --- a/internal/client/resource_group.go +++ b/internal/client/resource_group.go @@ -11,7 +11,7 @@ const resourceGroupBasePath = "/api/resource_groups" type ResourceGroup struct { ID int64 `json:"id"` Name string `json:"name"` - Description *string `json:"description"` + Description string `json:"description"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } From c522c3c9c2b77c64b373884dfe451001a67b64f5 Mon Sep 17 00:00:00 2001 From: u110 Date: Wed, 29 Jan 2025 10:57:33 +0900 Subject: [PATCH 08/11] fix typo --- internal/client/resource_group.go | 12 ++++++------ internal/client/resource_group_test.go | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/client/resource_group.go b/internal/client/resource_group.go index 69535698..2e11d2ff 100644 --- a/internal/client/resource_group.go +++ b/internal/client/resource_group.go @@ -32,27 +32,27 @@ type ResourceGroupPermission struct { // List of ResourceGroups -type ListResouceGroupInput struct { +type ListResourceGroupInput struct { limit *int cursor *string } -func (input *ListResouceGroupInput) SetLimit(limit int) { +func (input *ListResourceGroupInput) SetLimit(limit int) { input.limit = &limit } -func (input *ListResouceGroupInput) SetCursor(cursor string) { +func (input *ListResourceGroupInput) SetCursor(cursor string) { input.cursor = &cursor } -type ListResouceGroupOutput struct { +type ListResourceGroupOutput struct { Items []ResourceGroupWithTeams `json:"items"` NextCursor *string `json:"next_cursor"` } const MaxListResourceGroupsLimit = 100 -func (client *TroccoClient) ListResourceGroups(input *ListResouceGroupInput) (*ListResouceGroupOutput, error) { +func (client *TroccoClient) ListResourceGroups(input *ListResourceGroupInput) (*ListResourceGroupOutput, error) { params := url.Values{} if input != nil && input.limit != nil { if *input.limit < 1 || *input.limit > MaxListResourceGroupsLimit { @@ -64,7 +64,7 @@ func (client *TroccoClient) ListResourceGroups(input *ListResouceGroupInput) (*L params.Add("cursor", *input.cursor) } path := fmt.Sprintf(resourceGroupBasePath+"?%s", params.Encode()) - output := new(ListResouceGroupOutput) + output := new(ListResourceGroupOutput) err := client.do(http.MethodGet, path, nil, output) if err != nil { return nil, err diff --git a/internal/client/resource_group_test.go b/internal/client/resource_group_test.go index 6726a5b8..fdbac1df 100644 --- a/internal/client/resource_group_test.go +++ b/internal/client/resource_group_test.go @@ -87,7 +87,7 @@ func TestListResourceGroupsLimitAndCursor(t *testing.T) { })) defer server.Close() - input := &ListResouceGroupInput{} + input := &ListResourceGroupInput{} input.SetLimit(1) input.SetCursor("test_prev_cursor") @@ -105,7 +105,7 @@ func TestListResourceGroupsLimitAndCursor(t *testing.T) { // Get Team -func TestGetResouceGroup(t *testing.T) { +func TestGetResourceGroup(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "/api/resource_groups/1", r.URL.Path) assert.Equal(t, http.MethodGet, r.Method) From 10b4dfd7b3b790dc23d0f425b318db62e08d24b5 Mon Sep 17 00:00:00 2001 From: u110 Date: Wed, 29 Jan 2025 11:10:09 +0900 Subject: [PATCH 09/11] undo move struct definition --- internal/client/datamart_definition.go | 8 ++++++++ internal/client/resource_group.go | 8 -------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/client/datamart_definition.go b/internal/client/datamart_definition.go index 4394576f..d91bea91 100644 --- a/internal/client/datamart_definition.go +++ b/internal/client/datamart_definition.go @@ -102,6 +102,14 @@ type DatamartBigqueryOption struct { Location *string `json:"location"` } +type ResourceGroup struct { + ID int64 `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` +} + type CustomVariableSetting struct { Name string `json:"name"` Type string `json:"type"` diff --git a/internal/client/resource_group.go b/internal/client/resource_group.go index 2e11d2ff..599ceed7 100644 --- a/internal/client/resource_group.go +++ b/internal/client/resource_group.go @@ -8,14 +8,6 @@ import ( const resourceGroupBasePath = "/api/resource_groups" -type ResourceGroup struct { - ID int64 `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` -} - type ResourceGroupWithTeams struct { ID int64 `json:"id"` Name string `json:"name"` From 2b58ea9d7b1576b73fb24bbd11a24f176608beed Mon Sep 17 00:00:00 2001 From: u110 Date: Wed, 29 Jan 2025 11:17:37 +0900 Subject: [PATCH 10/11] use stringdefault --- internal/provider/resource_group_resource.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/provider/resource_group_resource.go b/internal/provider/resource_group_resource.go index 0e8cdd16..7ec25a88 100644 --- a/internal/provider/resource_group_resource.go +++ b/internal/provider/resource_group_resource.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -70,7 +71,9 @@ func (r *resourceGroupResource) Schema(ctx context.Context, req resource.SchemaR }, "description": schema.StringAttribute{ Optional: true, + Computed: true, MarkdownDescription: "The description of the resource group.", + Default: stringdefault.StaticString(""), }, "teams": schema.SetNestedAttribute{ Required: true, From 0660f6d06d6041f8f52cecee065f24f5adfc8a14 Mon Sep 17 00:00:00 2001 From: u110 Date: Wed, 29 Jan 2025 11:29:44 +0900 Subject: [PATCH 11/11] add length validator & misc --- internal/client/resource_group.go | 2 +- internal/client/resource_group_test.go | 2 +- internal/provider/resource_group_resource.go | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/internal/client/resource_group.go b/internal/client/resource_group.go index 599ceed7..a61827b7 100644 --- a/internal/client/resource_group.go +++ b/internal/client/resource_group.go @@ -79,7 +79,7 @@ func (client *TroccoClient) GetResourceGroup(id int64) (*ResourceGroupWithTeams, // Create type CreateResourceGroupInput struct { - Name *string `json:"name"` + Name string `json:"name"` Description *string `json:"description,omitempty"` Teams []TeamRoleInput `json:"teams"` } diff --git a/internal/client/resource_group_test.go b/internal/client/resource_group_test.go index fdbac1df..85ffca0f 100644 --- a/internal/client/resource_group_test.go +++ b/internal/client/resource_group_test.go @@ -183,7 +183,7 @@ func TestCreateResourceGroup(t *testing.T) { defer server.Close() input := &CreateResourceGroupInput{ - Name: lo.ToPtr("ResourceGroup"), + Name: "ResourceGroup", Description: lo.ToPtr("description"), Teams: []TeamRoleInput{ {TeamID: 1, Role: "administrator"}, diff --git a/internal/provider/resource_group_resource.go b/internal/provider/resource_group_resource.go index 7ec25a88..da58c889 100644 --- a/internal/provider/resource_group_resource.go +++ b/internal/provider/resource_group_resource.go @@ -68,6 +68,10 @@ func (r *resourceGroupResource) Schema(ctx context.Context, req resource.SchemaR "name": schema.StringAttribute{ Required: true, MarkdownDescription: "The name of the resource group.", + Validators: []validator.String{ + stringvalidator.UTF8LengthAtLeast(1), + stringvalidator.UTF8LengthAtMost(255), + }, }, "description": schema.StringAttribute{ Optional: true, @@ -109,7 +113,7 @@ func (r *resourceGroupResource) Create(ctx context.Context, req resource.CreateR } input := client.CreateResourceGroupInput{ - Name: plan.Name.ValueStringPointer(), + Name: plan.Name.ValueString(), Description: plan.Description.ValueStringPointer(), Teams: []client.TeamRoleInput{}, }