From e6ab655d6f960bead3b7da538a284411f1f94294 Mon Sep 17 00:00:00 2001 From: "Plushnikov, Michail" Date: Wed, 3 Jan 2024 15:48:11 +0100 Subject: [PATCH] added resources for saved filter handling --- docs/data-sources/saved_filter.md | 39 +++++ docs/data-sources/saved_filters.md | 57 ++++++ docs/resources/saved_filter.md | 93 ++++++++++ .../spacelift_saved_filter/data-source.tf | 7 + .../spacelift_saved_filters/data-source.tf | 16 ++ .../spacelift_saved_filter/import.sh | 1 + .../spacelift_saved_filter/resource.tf | 54 ++++++ spacelift/data_saved_filter.go | 84 +++++++++ spacelift/data_saved_filter_test.go | 41 +++++ spacelift/data_saved_filters.go | 110 ++++++++++++ spacelift/data_saved_filters_test.go | 39 +++++ spacelift/internal/structs/saved_filter.go | 31 ++++ spacelift/provider.go | 3 + spacelift/resource_saved_filter.go | 163 ++++++++++++++++++ spacelift/resource_saved_filter_test.go | 57 ++++++ 15 files changed, 795 insertions(+) create mode 100644 docs/data-sources/saved_filter.md create mode 100644 docs/data-sources/saved_filters.md create mode 100644 docs/resources/saved_filter.md create mode 100644 examples/data-sources/spacelift_saved_filter/data-source.tf create mode 100644 examples/data-sources/spacelift_saved_filters/data-source.tf create mode 100644 examples/resources/spacelift_saved_filter/import.sh create mode 100644 examples/resources/spacelift_saved_filter/resource.tf create mode 100644 spacelift/data_saved_filter.go create mode 100644 spacelift/data_saved_filter_test.go create mode 100644 spacelift/data_saved_filters.go create mode 100644 spacelift/data_saved_filters_test.go create mode 100644 spacelift/internal/structs/saved_filter.go create mode 100644 spacelift/resource_saved_filter.go create mode 100644 spacelift/resource_saved_filter_test.go diff --git a/docs/data-sources/saved_filter.md b/docs/data-sources/saved_filter.md new file mode 100644 index 00000000..0a13fa4d --- /dev/null +++ b/docs/data-sources/saved_filter.md @@ -0,0 +1,39 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "spacelift_saved_filter Data Source - terraform-provider-spacelift" +subcategory: "" +description: |- + spacelift_saved_filter represents a Spacelift saved filter. +--- + +# spacelift_saved_filter (Data Source) + +`spacelift_saved_filter` represents a Spacelift saved filter. + +## Example Usage + +```terraform +data "spacelift_saved_filter" "filter" { + filter_id = spacelift_saved_filter.filter.id +} + +output "filter_data" { + value = data.spacelift_saved_filter.filter.data +} +``` + + +## Schema + +### Required + +- `filter_id` (String) immutable ID (slug) of the filter + +### Read-Only + +- `created_by` (String) Login of the user who created the saved filter +- `data` (String) Data is the JSON representation of the filter data +- `id` (String) Globally unique ID of the saved filter +- `is_public` (Boolean) Toggle whether the filter is public or not +- `name` (String) Name of the filter +- `type` (String) Type describes the type of the filter. It is used to determine which view the filter is for diff --git a/docs/data-sources/saved_filters.md b/docs/data-sources/saved_filters.md new file mode 100644 index 00000000..d32e0421 --- /dev/null +++ b/docs/data-sources/saved_filters.md @@ -0,0 +1,57 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "spacelift_saved_filters Data Source - terraform-provider-spacelift" +subcategory: "" +description: |- + spacelift_saved_filters can find all saved filters that have certain type or name +--- + +# spacelift_saved_filters (Data Source) + +`spacelift_saved_filters` can find all saved filters that have certain type or name + +## Example Usage + +```terraform +# For all saved filter +data "spacelift_saved_filters" "all" {} + +# Filters with a matching type +data "spacelift_saved_filters" "stack_filters" { + type = "stacks" +} + +# Filters with a matching name +data "spacelift_saved_filters" "my_filters" { + name = "My best filter" +} + +output "filter_ids" { + value = data.spacelift_saved_filters.stack_filters.filters[*].id +} +``` + + +## Schema + +### Optional + +- `filter_name` (String) filter name to look for +- `filter_type` (String) filter type to look for + +### Read-Only + +- `filters` (List of Object) (see [below for nested schema](#nestedatt--filters)) +- `id` (String) The ID of this resource. + + +### Nested Schema for `filters` + +Read-Only: + +- `created_by` (String) +- `data` (String) +- `id` (String) +- `is_public` (Boolean) +- `name` (String) +- `type` (String) diff --git a/docs/resources/saved_filter.md b/docs/resources/saved_filter.md new file mode 100644 index 00000000..c5ec39fe --- /dev/null +++ b/docs/resources/saved_filter.md @@ -0,0 +1,93 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "spacelift_saved_filter Resource - terraform-provider-spacelift" +subcategory: "" +description: |- + spacelift_saved_filter represents a Spacelift filter - a collection of customer-defined criteria that are applied by Spacelift at one of the decision points within the application. +--- + +# spacelift_saved_filter (Resource) + +`spacelift_saved_filter` represents a Spacelift **filter** - a collection of customer-defined criteria that are applied by Spacelift at one of the decision points within the application. + +## Example Usage + +```terraform +resource "spacelift_saved_filter" "my_filter" { + type = "webhooks" + name = "filter for all xyz teams" + is_public = true + data = jsonencode({ + "key" : "activeFilters", + "value" : jsonencode({ + "filters" : [ + [ + "name", + { + "key" : "name", + "filterName" : "name", + "type" : "STRING", + "values" : [ + "team_xyz_*" + ] + } + ] + ], + "sort" : { + "direction" : "ASC", + "option" : "space" + }, + "text" : null, + "order" : [ + { + "name" : "enabled", + "visible" : true + }, + { + "name" : "endpoint", + "visible" : true + }, + { + "name" : "slug", + "visible" : true + }, + { + "name" : "label", + "visible" : true + }, + { + "name" : "name", + "visible" : true + }, + { + "name" : "space", + "visible" : true + } + ] + }) + }) +} +``` + + +## Schema + +### Required + +- `data` (String) Data is the JSON representation of the filter data +- `is_public` (Boolean) Toggle whether the filter is public or not +- `name` (String) Name of the saved filter +- `type` (String) Type describes the type of the filter. It is used to determine which view the filter is for. Possible values are `stacks`, `blueprints`, `contexts`, `webhooks`. + +### Read-Only + +- `created_by` (String) Login of the user who created the saved filter +- `id` (String) Globally unique ID of the saved filter + +## Import + +Import is supported using the following syntax: + +```shell +terraform import spacelift_saved_filter.my_filter $FILTER_ID +``` diff --git a/examples/data-sources/spacelift_saved_filter/data-source.tf b/examples/data-sources/spacelift_saved_filter/data-source.tf new file mode 100644 index 00000000..f1cf0e58 --- /dev/null +++ b/examples/data-sources/spacelift_saved_filter/data-source.tf @@ -0,0 +1,7 @@ +data "spacelift_saved_filter" "filter" { + filter_id = spacelift_saved_filter.filter.id +} + +output "filter_data" { + value = data.spacelift_saved_filter.filter.data +} diff --git a/examples/data-sources/spacelift_saved_filters/data-source.tf b/examples/data-sources/spacelift_saved_filters/data-source.tf new file mode 100644 index 00000000..cc6ee011 --- /dev/null +++ b/examples/data-sources/spacelift_saved_filters/data-source.tf @@ -0,0 +1,16 @@ +# For all saved filter +data "spacelift_saved_filters" "all" {} + +# Filters with a matching type +data "spacelift_saved_filters" "stack_filters" { + type = "stacks" +} + +# Filters with a matching name +data "spacelift_saved_filters" "my_filters" { + name = "My best filter" +} + +output "filter_ids" { + value = data.spacelift_saved_filters.stack_filters.filters[*].id +} diff --git a/examples/resources/spacelift_saved_filter/import.sh b/examples/resources/spacelift_saved_filter/import.sh new file mode 100644 index 00000000..577d102e --- /dev/null +++ b/examples/resources/spacelift_saved_filter/import.sh @@ -0,0 +1 @@ +terraform import spacelift_saved_filter.my_filter $FILTER_ID diff --git a/examples/resources/spacelift_saved_filter/resource.tf b/examples/resources/spacelift_saved_filter/resource.tf new file mode 100644 index 00000000..31a9771e --- /dev/null +++ b/examples/resources/spacelift_saved_filter/resource.tf @@ -0,0 +1,54 @@ +resource "spacelift_saved_filter" "my_filter" { + type = "webhooks" + name = "filter for all xyz teams" + is_public = true + data = jsonencode({ + "key" : "activeFilters", + "value" : jsonencode({ + "filters" : [ + [ + "name", + { + "key" : "name", + "filterName" : "name", + "type" : "STRING", + "values" : [ + "team_xyz_*" + ] + } + ] + ], + "sort" : { + "direction" : "ASC", + "option" : "space" + }, + "text" : null, + "order" : [ + { + "name" : "enabled", + "visible" : true + }, + { + "name" : "endpoint", + "visible" : true + }, + { + "name" : "slug", + "visible" : true + }, + { + "name" : "label", + "visible" : true + }, + { + "name" : "name", + "visible" : true + }, + { + "name" : "space", + "visible" : true + } + ] + }) + }) +} \ No newline at end of file diff --git a/spacelift/data_saved_filter.go b/spacelift/data_saved_filter.go new file mode 100644 index 00000000..73e07752 --- /dev/null +++ b/spacelift/data_saved_filter.go @@ -0,0 +1,84 @@ +package spacelift + +import ( + "context" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/spacelift-io/terraform-provider-spacelift/spacelift/internal" +) + +func dataSavedFilter() *schema.Resource { + return &schema.Resource{ + Description: "" + + "`spacelift_saved_filter` represents a Spacelift saved filter.", + + ReadContext: dataFilterRead, + + Schema: map[string]*schema.Schema{ + "filter_id": { + Type: schema.TypeString, + Description: " immutable ID (slug) of the filter", + Required: true, + }, + "id": { + Type: schema.TypeString, + Description: "Globally unique ID of the saved filter", + Computed: true, + }, + "is_public": { + Type: schema.TypeBool, + Description: "Toggle whether the filter is public or not", + Computed: true, + }, + "created_by": { + Type: schema.TypeString, + Description: "Login of the user who created the saved filter", + Computed: true, + }, + "name": { + Type: schema.TypeString, + Description: "Name of the filter", + Computed: true, + }, + "type": { + Type: schema.TypeString, + Description: "Type describes the type of the filter. It is used to determine which view the filter is for", + Computed: true, + }, + "data": { + Type: schema.TypeString, + Description: "Data is the JSON representation of the filter data", + Computed: true, + }, + }, + } +} + +func dataFilterRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var query struct { + Filter struct { + ID string `graphql:"id"` + IsPublic bool `graphql:"isPublic"` + CreatedBy string `graphql:"createdBy"` + Name string `graphql:"name"` + Type string `graphql:"type"` + Data string `graphql:"data"` + } `graphql:"savedFilter(id: $id)"` + } + + variables := map[string]interface{}{"id": d.Get("filter_id")} + + if err := meta.(*internal.Client).Query(ctx, "savedFilter", &query, variables); err != nil { + return diag.Errorf("could not query for filter: %v", err) + } + + d.SetId(query.Filter.ID) + d.Set("is_public", query.Filter.IsPublic) + d.Set("name", query.Filter.Name) + d.Set("type", query.Filter.Type) + d.Set("created_by", query.Filter.CreatedBy) + d.Set("data", query.Filter.Data) + + return nil +} diff --git a/spacelift/data_saved_filter_test.go b/spacelift/data_saved_filter_test.go new file mode 100644 index 00000000..098dbc38 --- /dev/null +++ b/spacelift/data_saved_filter_test.go @@ -0,0 +1,41 @@ +package spacelift + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + . "github.com/spacelift-io/terraform-provider-spacelift/spacelift/internal/testhelpers" +) + +func TestFilterData(t *testing.T) { + t.Run("creates and updates a filter", func(t *testing.T) { + randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) + + testSteps(t, []resource.TestStep{{ + Config: fmt.Sprintf(` + resource "spacelift_saved_filter" "test" { + name = "My first filter %s" + type = "stacks" + is_public = true + data = jsonencode({ + "key": "activeFilters", + "value": jsonencode({}) + }) + } + data "spacelift_saved_filter" "test" { + filter_id = spacelift_saved_filter.test.id + } + `, randomID), + Check: Resource( + "data.spacelift_saved_filter.test", + Attribute("id", IsNotEmpty()), + Attribute("data", Contains("activeFilters")), + Attribute("type", Equals("stacks")), + Attribute("is_public", Equals("true")), + ), + }}) + }) +} diff --git a/spacelift/data_saved_filters.go b/spacelift/data_saved_filters.go new file mode 100644 index 00000000..af7cdb51 --- /dev/null +++ b/spacelift/data_saved_filters.go @@ -0,0 +1,110 @@ +package spacelift + +import ( + "context" + "fmt" + "github.com/spacelift-io/terraform-provider-spacelift/spacelift/internal/structs" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/spacelift-io/terraform-provider-spacelift/spacelift/internal" +) + +func dataSavedFilters() *schema.Resource { + return &schema.Resource{ + Description: "" + + "`spacelift_saved_filters` can find all saved filters that have certain type or name", + + ReadContext: dataFiltersRead, + + Schema: map[string]*schema.Schema{ + "filter_type": { + Type: schema.TypeString, + Description: "filter type to look for", + Optional: true, + }, + "filter_name": { + Type: schema.TypeString, + Description: "filter name to look for", + Optional: true, + }, + "filters": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Description: "Globally unique ID of the saved filter", + Computed: true, + }, + "is_public": { + Type: schema.TypeBool, + Description: "Toggle whether the filter is public or not", + Computed: true, + }, + "created_by": { + Type: schema.TypeString, + Description: "Login of the user who created the saved filter", + Computed: true, + }, + "name": { + Type: schema.TypeString, + Description: "Name of the filter", + Computed: true, + }, + "type": { + Type: schema.TypeString, + Description: "Type describes the type of the filter. It is used to determine which view the filter is for", + Computed: true, + }, + "data": { + Type: schema.TypeString, + Description: "Data is the JSON representation of the filter data", + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataFiltersRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var query struct { + Filters []structs.SavedFilter `graphql:"savedFilters()"` + } + + typeRaw, typeSpecified := d.GetOk("filter_type") + requestedType := typeRaw.(string) + nameRaw, nameSpecified := d.GetOk("filter_name") + requestedName := nameRaw.(string) + + if err := meta.(*internal.Client).Query(ctx, "savedFilters", &query, nil); err != nil { + return diag.Errorf("could not query for filters: %v", err) + } + + var filters []interface{} + for _, filter := range query.Filters { + if typeSpecified && filter.Type != requestedType { + continue + } + if nameSpecified && filter.Name != requestedName { + continue + } + filters = append(filters, map[string]interface{}{ + "id": filter.ID, + "is_public": filter.IsPublic, + "name": filter.Name, + "type": filter.Type, + "created_by": filter.CreatedBy, + "data": filter.Data, + }) + } + + d.SetId(fmt.Sprintf("filters/%s/%s", requestedType, requestedName)) + d.Set("filters", filters) + + return nil +} diff --git a/spacelift/data_saved_filters_test.go b/spacelift/data_saved_filters_test.go new file mode 100644 index 00000000..344ef44a --- /dev/null +++ b/spacelift/data_saved_filters_test.go @@ -0,0 +1,39 @@ +package spacelift + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + . "github.com/spacelift-io/terraform-provider-spacelift/spacelift/internal/testhelpers" +) + +func TestFiltersData(t *testing.T) { + t.Run("load all saved filters", func(t *testing.T) { + randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) + + datasourceName := "data.spacelift_saved_filters.all" + + testSteps(t, []resource.TestStep{{ + Config: fmt.Sprintf(` + resource "spacelift_saved_filter" "test" { + name = "%s" + type = "stacks" + is_public = true + data = jsonencode({ + "key": "activeFilters", + "value": jsonencode({}) + }) + } + + data "spacelift_saved_filters" "all" { + depends_on = [spacelift_saved_filter.test] + } + `, randomID), + Check: resource.ComposeTestCheckFunc( + Resource(datasourceName, Attribute("id", IsNotEmpty())), + ), + }}) + }) +} diff --git a/spacelift/internal/structs/saved_filter.go b/spacelift/internal/structs/saved_filter.go new file mode 100644 index 00000000..ed34f9a8 --- /dev/null +++ b/spacelift/internal/structs/saved_filter.go @@ -0,0 +1,31 @@ +package structs + +import "github.com/shurcooL/graphql" + +// SavedFilterType represents a saved filter type. +type SavedFilterType string + +// SavedFilter represents SavedFilter data relevant to the provider. +type SavedFilter struct { + ID string `graphql:"id"` + Name string `graphql:"name"` + Data string `graphql:"data"` + Type string `graphql:"type"` + IsPublic bool `graphql:"isPublic"` + CreatedBy string `graphql:"createdBy"` +} + +// SavedFilterInput represents the input required to create a saved filter. +type SavedFilterInput struct { + Name graphql.String `json:"name"` + Data graphql.String `json:"data"` + Type graphql.String `json:"type"` + IsPublic graphql.Boolean `json:"isPublic"` +} + +var SavedFilterTypes = []string{ + "stacks", + "blueprints", + "contexts", + "webhooks", +} diff --git a/spacelift/provider.go b/spacelift/provider.go index ebedbf06..a21b3714 100644 --- a/spacelift/provider.go +++ b/spacelift/provider.go @@ -71,6 +71,8 @@ func Provider(commit, version string) plugin.ProviderFunc { "spacelift_current_space": dataCurrentSpace(), "spacelift_current_stack": dataCurrentStack(), "spacelift_drift_detection": dataDriftDetection(), + "spacelift_saved_filter": dataSavedFilter(), + "spacelift_saved_filters": dataSavedFilters(), "spacelift_environment_variable": dataEnvironmentVariable(), "spacelift_gcp_service_account": dataGCPServiceAccount(), "spacelift_github_enterprise_integration": dataGithubEnterpriseIntegration(), @@ -125,6 +127,7 @@ func Provider(commit, version string) plugin.ProviderFunc { "spacelift_stack_destructor": resourceStackDestructor(), "spacelift_stack_aws_role": resourceStackAWSRole(), // deprecated "spacelift_stack_gcp_service_account": resourceStackGCPServiceAccount(), // deprecated + "spacelift_saved_filter": resourceSavedFilter(), "spacelift_terraform_provider": resourceTerraformProvider(), "spacelift_user": resourceUser(), "spacelift_vcs_agent_pool": resourceVCSAgentPool(), diff --git a/spacelift/resource_saved_filter.go b/spacelift/resource_saved_filter.go new file mode 100644 index 00000000..3de9c950 --- /dev/null +++ b/spacelift/resource_saved_filter.go @@ -0,0 +1,163 @@ +package spacelift + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/spacelift-io/terraform-provider-spacelift/spacelift/internal" + "github.com/spacelift-io/terraform-provider-spacelift/spacelift/internal/structs" + "github.com/spacelift-io/terraform-provider-spacelift/spacelift/internal/validations" +) + +func resourceSavedFilter() *schema.Resource { + return &schema.Resource{ + Description: "" + + "`spacelift_saved_filter` represents a Spacelift **filter** - a collection of " + + "customer-defined criteria that are applied by Spacelift at one of the " + + "decision points within the application.", + + CreateContext: resourceSavedFilterCreate, + ReadContext: resourceSavedFilterRead, + UpdateContext: resourceSavedFilterUpdate, + DeleteContext: resourceSavedFilterDelete, + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: map[string]*schema.Schema{ + "id": { + Description: "Globally unique ID of the saved filter", + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Description: "Name of the saved filter", + Required: true, + ValidateDiagFunc: validations.DisallowEmptyString, + }, + "data": { + Type: schema.TypeString, + Description: "Data is the JSON representation of the filter data", + Required: true, + ValidateDiagFunc: validations.DisallowEmptyString, + }, + "is_public": { + Type: schema.TypeBool, + Description: "Toggle whether the filter is public or not", + Required: true, + }, + "created_by": { + Type: schema.TypeString, + Description: "Login of the user who created the saved filter", + Computed: true, + }, + "type": { + Type: schema.TypeString, + Description: "Type describes the type of the filter. It is used to determine which view the filter is for. " + + "Possible values are `stacks`, `blueprints`, `contexts`, `webhooks`.", + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice( + structs.SavedFilterTypes, + false, // case-sensitive match + ), + }, + }, + } +} + +func resourceSavedFilterCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var mutation struct { + CreateFilter structs.SavedFilter `graphql:"savedFilterCreate(input: $input)"` + } + + variables := map[string]interface{}{ + "input": savedFilterInput(d), + } + + if err := meta.(*internal.Client).Mutate(ctx, "savedFilterCreate", &mutation, variables); err != nil { + return diag.Errorf("could not create saved filter %v: %v", toString(d.Get("name")), internal.FromSpaceliftError(err)) + } + + d.SetId(mutation.CreateFilter.ID) + + return resourceSavedFilterRead(ctx, d, meta) +} + +func savedFilterInput(d *schema.ResourceData) structs.SavedFilterInput { + return structs.SavedFilterInput{ + Name: toString(d.Get("name")), + IsPublic: toBool(d.Get("is_public")), + Data: toString(d.Get("data")), + Type: toString(d.Get("type")), + } +} + +func resourceSavedFilterRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var query struct { + Filter *structs.SavedFilter `graphql:"savedFilter(id: $id)"` + } + + variables := map[string]interface{}{ + "id": toID(d.Id()), + } + if err := meta.(*internal.Client).Query(ctx, "savedFilter", &query, variables); err != nil { + return diag.Errorf("could not query for saved filter: %v", err) + } + + filter := query.Filter + if filter == nil { + d.SetId("") + return nil + } + + d.Set("name", filter.Name) + d.Set("data", filter.Data) + d.Set("type", filter.Type) + d.Set("is_public", filter.IsPublic) + d.Set("created_by", filter.CreatedBy) + return nil +} + +func resourceSavedFilterUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var mutation struct { + UpdateFilter structs.SavedFilter `graphql:"savedFilterUpdate(id: $id, name: $name, data: $data, isPublic: $isPublic)"` + } + + variables := map[string]interface{}{ + "id": toID(d.Id()), + "name": toString(d.Get("name")), + "isPublic": toBool(d.Get("is_public")), + "data": toString(d.Get("data")), + } + + var ret diag.Diagnostics + + if err := meta.(*internal.Client).Mutate(ctx, "savedFilterUpdate", &mutation, variables); err != nil { + ret = diag.Errorf("could not update saved filter: %v", internal.FromSpaceliftError(err)) + } + + return append(ret, resourceSavedFilterRead(ctx, d, meta)...) +} + +func resourceSavedFilterDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var mutation struct { + DeleteFilter *structs.SavedFilter `graphql:"savedFilterDelete(id: $id)"` + } + + variables := map[string]interface{}{ + "id": toID(d.Id()), + } + + if err := meta.(*internal.Client).Mutate(ctx, "SavedFilterDelete", &mutation, variables); err != nil { + return diag.Errorf("could not delete saved filter: %v", internal.FromSpaceliftError(err)) + } + + d.SetId("") + + return nil +} diff --git a/spacelift/resource_saved_filter_test.go b/spacelift/resource_saved_filter_test.go new file mode 100644 index 00000000..c1a4dd3b --- /dev/null +++ b/spacelift/resource_saved_filter_test.go @@ -0,0 +1,57 @@ +package spacelift + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + . "github.com/spacelift-io/terraform-provider-spacelift/spacelift/internal/testhelpers" +) + +func TestSavedFilterResource(t *testing.T) { + const resourceName = "spacelift_saved_filter.test" + + t.Run("creates and updates a filter", func(t *testing.T) { + randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) + + config := func(filterType string) string { + return fmt.Sprintf(` + resource "spacelift_saved_filter" "test" { + name = "My first filter %s" + type = "%s" + is_public = true + data = jsonencode({ + "key": "activeFilters", + "value": jsonencode({}) + }) + } + `, randomID, filterType) + } + + testSteps(t, []resource.TestStep{ + { + Config: config("stacks"), + Check: Resource( + resourceName, + Attribute("id", IsNotEmpty()), + Attribute("data", Contains("activeFilters")), + Attribute("type", Equals("stacks")), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: config("contexts"), + Check: Resource( + resourceName, + Attribute("type", Equals("contexts")), + ), + }, + }) + }) +}