diff --git a/docs/data-sources/all_projects.md b/docs/data-sources/all_projects.md
index 421e5cea4..bafccfd38 100644
--- a/docs/data-sources/all_projects.md
+++ b/docs/data-sources/all_projects.md
@@ -28,6 +28,7 @@ data "sentry_projects" "default" {
### Read-Only
+- `project_slugs` (Set of String) The slugs of the projects.
- `projects` (Attributes Set) The list of projects. (see [below for nested schema](#nestedatt--projects))
@@ -40,16 +41,5 @@ Read-Only:
- `features` (Set of String) The features of this project.
- `id` (String) The ID of this project.
- `name` (String) The name of this project.
-- `organization` (Attributes) The organization associated with this project. (see [below for nested schema](#nestedatt--projects--organization))
- `platform` (String) The platform of this project.
- `slug` (String) The slug of this project.
-- `status` (String) The status of this project.
-
-
-### Nested Schema for `projects.organization`
-
-Read-Only:
-
-- `id` (String) The ID of this organization.
-- `name` (String) The name of this organization.
-- `slug` (String) The slug of this organization.
diff --git a/docs/resources/all_projects_spike_protection.md b/docs/resources/all_projects_spike_protection.md
new file mode 100644
index 000000000..6a9a99cf1
--- /dev/null
+++ b/docs/resources/all_projects_spike_protection.md
@@ -0,0 +1,65 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "sentry_all_projects_spike_protection Resource - terraform-provider-sentry"
+subcategory: ""
+description: |-
+ Enable spike protection for all projects in an organization.
+---
+
+# sentry_all_projects_spike_protection (Resource)
+
+Enable spike protection for all projects in an organization.
+
+## Example Usage
+
+```terraform
+# Enable spike protection for several projects in a Sentry organization.
+resource "sentry_project" "web-app" {
+ organization = "my-organization"
+
+ teams = ["my-first-team"]
+ name = "web-app"
+ slug = "web-app"
+
+ platform = "go"
+}
+
+resource "sentry_project" "mobile-app" {
+ organization = "my-organization"
+
+ teams = ["my-second-team"]
+ name = "mobile-app"
+ slug = "mobile-app"
+
+ platform = "android"
+}
+
+resource "sentry_all_projects_spike_protection" "main" {
+ organization = "my-organization"
+ projects = [
+ sentry_project.web-app.id,
+ sentry_project.mobile-app.id,
+ ]
+ enabled = true
+}
+
+# Use the `sentry_all_projects` data source to get all projects in a Sentry organization and enable spike protection for all of them.
+data "sentry_all_projects" "all" {
+ organization = "my-organization"
+}
+
+resource "sentry_all_projects_spike_protection" "main" {
+ organization = data.sentry_all_projects.all.organization
+ projects = data.sentry_all_projects.all.project_slugs
+ enabled = true
+}
+```
+
+
+## Schema
+
+### Required
+
+- `enabled` (Boolean) Toggle the browser-extensions, localhost, filtered-transaction, or web-crawlers filter on or off for all projects.
+- `organization` (String) The slug of the organization the resource belongs to.
+- `projects` (Set of String) The slugs of the projects to enable or disable spike protection for.
diff --git a/docs/resources/project_spike_protection.md b/docs/resources/project_spike_protection.md
index 7d87f79d7..63644c83d 100644
--- a/docs/resources/project_spike_protection.md
+++ b/docs/resources/project_spike_protection.md
@@ -37,7 +37,7 @@ resource "sentry_project_spike_protection" "default" {
- `enabled` (Boolean) Toggle the browser-extensions, localhost, filtered-transaction, or web-crawlers filter on or off.
- `organization` (String) The slug of the organization the project belongs to.
-- `project` (String) The slug of the project to create the filter for.
+- `project` (String) The slug of the project to enable or disable spike protection for.
### Read-Only
diff --git a/examples/resources/sentry_all_projects_spike_protection/resource.tf b/examples/resources/sentry_all_projects_spike_protection/resource.tf
new file mode 100644
index 000000000..241957c0a
--- /dev/null
+++ b/examples/resources/sentry_all_projects_spike_protection/resource.tf
@@ -0,0 +1,40 @@
+# Enable spike protection for several projects in a Sentry organization.
+resource "sentry_project" "web-app" {
+ organization = "my-organization"
+
+ teams = ["my-first-team"]
+ name = "web-app"
+ slug = "web-app"
+
+ platform = "go"
+}
+
+resource "sentry_project" "mobile-app" {
+ organization = "my-organization"
+
+ teams = ["my-second-team"]
+ name = "mobile-app"
+ slug = "mobile-app"
+
+ platform = "android"
+}
+
+resource "sentry_all_projects_spike_protection" "main" {
+ organization = "my-organization"
+ projects = [
+ sentry_project.web-app.id,
+ sentry_project.mobile-app.id,
+ ]
+ enabled = true
+}
+
+# Use the `sentry_all_projects` data source to get all projects in a Sentry organization and enable spike protection for all of them.
+data "sentry_all_projects" "all" {
+ organization = "my-organization"
+}
+
+resource "sentry_all_projects_spike_protection" "main" {
+ organization = data.sentry_all_projects.all.organization
+ projects = data.sentry_all_projects.all.project_slugs
+ enabled = true
+}
diff --git a/internal/provider/data_source_all_projects.go b/internal/provider/data_source_all_projects.go
index ac098d17a..3103e5578 100644
--- a/internal/provider/data_source_all_projects.go
+++ b/internal/provider/data_source_all_projects.go
@@ -23,15 +23,13 @@ type AllProjectsDataSource struct {
}
type AllProjectsDataSourceProjectModel struct {
- Id types.String `tfsdk:"id"`
- Slug types.String `tfsdk:"slug"`
- Name types.String `tfsdk:"name"`
- Platform types.String `tfsdk:"platform"`
- DateCreated types.String `tfsdk:"date_created"`
- Features types.Set `tfsdk:"features"`
- Color types.String `tfsdk:"color"`
- Status types.String `tfsdk:"status"`
- Organization OrganizationModel `tfsdk:"organization"`
+ Id types.String `tfsdk:"id"`
+ Slug types.String `tfsdk:"slug"`
+ Name types.String `tfsdk:"name"`
+ Platform types.String `tfsdk:"platform"`
+ DateCreated types.String `tfsdk:"date_created"`
+ Features types.Set `tfsdk:"features"`
+ Color types.String `tfsdk:"color"`
}
func (m *AllProjectsDataSourceProjectModel) Fill(project sentry.Project) error {
@@ -48,23 +46,25 @@ func (m *AllProjectsDataSourceProjectModel) Fill(project sentry.Project) error {
m.Features = types.SetValueMust(types.StringType, featureElements)
m.Color = types.StringValue(project.Color)
- m.Status = types.StringValue(project.Status)
- m.Organization = OrganizationModel{}
- if err := m.Organization.Fill(project.Organization); err != nil {
- return err
- }
return nil
}
type AllProjectsDataSourceModel struct {
Organization types.String `tfsdk:"organization"`
+ ProjectSlugs types.Set `tfsdk:"project_slugs"`
Projects []AllProjectsDataSourceProjectModel `tfsdk:"projects"`
}
func (m *AllProjectsDataSourceModel) Fill(organization string, projects []sentry.Project) error {
m.Organization = types.StringValue(organization)
+ projectSlugElements := []attr.Value{}
+ for _, project := range projects {
+ projectSlugElements = append(projectSlugElements, types.StringValue(project.Slug))
+ }
+ m.ProjectSlugs = types.SetValueMust(types.StringType, projectSlugElements)
+
for _, project := range projects {
p := AllProjectsDataSourceProjectModel{}
if err := p.Fill(project); err != nil {
@@ -89,8 +89,14 @@ func (d *AllProjectsDataSource) Schema(ctx context.Context, req datasource.Schem
MarkdownDescription: "The slug of the organization the resource belongs to.",
Required: true,
},
+ "project_slugs": schema.SetAttribute{
+ MarkdownDescription: "The slugs of the projects.",
+ Computed: true,
+ ElementType: types.StringType,
+ },
"projects": schema.SetNestedAttribute{
MarkdownDescription: "The list of projects.",
+ Computed: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
@@ -122,31 +128,8 @@ func (d *AllProjectsDataSource) Schema(ctx context.Context, req datasource.Schem
MarkdownDescription: "The color of this project.",
Computed: true,
},
- "status": schema.StringAttribute{
- MarkdownDescription: "The status of this project.",
- Computed: true,
- },
- "organization": schema.SingleNestedAttribute{
- MarkdownDescription: "The organization associated with this project.",
- Computed: true,
- Attributes: map[string]schema.Attribute{
- "id": schema.StringAttribute{
- MarkdownDescription: "The ID of this organization.",
- Computed: true,
- },
- "slug": schema.StringAttribute{
- MarkdownDescription: "The slug of this organization.",
- Computed: true,
- },
- "name": schema.StringAttribute{
- MarkdownDescription: "The name of this organization.",
- Computed: true,
- },
- },
- },
},
},
- Computed: true,
},
},
}
@@ -161,10 +144,10 @@ func (d *AllProjectsDataSource) Read(ctx context.Context, req datasource.ReadReq
}
var allProjects []sentry.Project
- params := &sentry.ListProjectsParams{}
+ params := &sentry.ListOrganizationProjectsParams{}
for {
- projects, apiResp, err := d.client.Projects.List(ctx, params)
+ projects, apiResp, err := d.client.OrganizationProjects.List(ctx, data.Organization.ValueString(), params)
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Read error: %s", err))
return
diff --git a/internal/provider/data_source_all_projects_test.go b/internal/provider/data_source_all_projects_test.go
index aca59ccb7..0be82da85 100644
--- a/internal/provider/data_source_all_projects_test.go
+++ b/internal/provider/data_source_all_projects_test.go
@@ -12,32 +12,30 @@ import (
)
func TestAccAllProjectsDataSource(t *testing.T) {
- dn := "data.sentry_all_projects.test"
- team := acctest.RandomWithPrefix("tf-team")
- project := acctest.RandomWithPrefix("tf-project")
+ teamName := acctest.RandomWithPrefix("tf-team")
+ projectName := acctest.RandomWithPrefix("tf-project")
+ rn := "data.sentry_all_projects.test"
resource.Test(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
- Config: testAccAllProjectsDataSourceConfig(team, project),
+ Config: testAccAllProjectsDataSourceConfig(teamName, projectName),
ConfigStateChecks: []statecheck.StateCheck{
- statecheck.ExpectKnownValue(dn, tfjsonpath.New("projects"), knownvalue.ListPartial(map[int]knownvalue.Check{
- 0: knownvalue.ObjectExact(map[string]knownvalue.Check{
+ statecheck.ExpectKnownValue(rn, tfjsonpath.New("organization"), knownvalue.StringExact(acctest.TestOrganization)),
+ statecheck.ExpectKnownValue(rn, tfjsonpath.New("project_slugs"), knownvalue.SetPartial([]knownvalue.Check{
+ knownvalue.StringExact(projectName),
+ })),
+ statecheck.ExpectKnownValue(rn, tfjsonpath.New("projects"), knownvalue.SetPartial([]knownvalue.Check{
+ knownvalue.ObjectExact(map[string]knownvalue.Check{
"id": knownvalue.NotNull(),
- "slug": knownvalue.NotNull(),
- "name": knownvalue.NotNull(),
- "platform": knownvalue.NotNull(),
+ "slug": knownvalue.StringExact(projectName),
+ "name": knownvalue.StringExact(projectName),
+ "platform": knownvalue.StringExact("go"),
"date_created": knownvalue.NotNull(),
"features": knownvalue.NotNull(),
"color": knownvalue.NotNull(),
- "status": knownvalue.NotNull(),
- "organization": knownvalue.ObjectExact(map[string]knownvalue.Check{
- "id": knownvalue.NotNull(),
- "slug": knownvalue.NotNull(),
- "name": knownvalue.NotNull(),
- }),
}),
})),
},
@@ -63,6 +61,8 @@ resource "sentry_project" "test" {
data "sentry_all_projects" "test" {
organization = data.sentry_organization.test.slug
+
+ depends_on = [sentry_project.test]
}
`, teamName, projectName)
}
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
index 2c7c43651..77d65ea44 100644
--- a/internal/provider/provider.go
+++ b/internal/provider/provider.go
@@ -94,6 +94,7 @@ func (p *SentryProvider) Configure(ctx context.Context, req provider.ConfigureRe
func (p *SentryProvider) Resources(ctx context.Context) []func() resource.Resource {
return []func() resource.Resource{
+ NewAllProjectsSpikeProtectionResource,
NewClientKeyResource,
NewIssueAlertResource,
NewNotificationActionResource,
diff --git a/internal/provider/resource_all_projects_spike_protection.go b/internal/provider/resource_all_projects_spike_protection.go
new file mode 100644
index 000000000..be57818c9
--- /dev/null
+++ b/internal/provider/resource_all_projects_spike_protection.go
@@ -0,0 +1,281 @@
+package provider
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator"
+ "github.com/hashicorp/terraform-plugin-framework/attr"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/schema/validator"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ "github.com/jianyuan/go-sentry/v2/sentry"
+)
+
+var _ resource.Resource = &AllProjectsSpikeProtectionResource{}
+var _ resource.ResourceWithConfigure = &AllProjectsSpikeProtectionResource{}
+
+func NewAllProjectsSpikeProtectionResource() resource.Resource {
+ return &AllProjectsSpikeProtectionResource{}
+}
+
+type AllProjectsSpikeProtectionResource struct {
+ baseResource
+}
+
+type AllProjectsSpikeProtectionResourceModel struct {
+ Organization types.String `tfsdk:"organization"`
+ Enabled types.Bool `tfsdk:"enabled"`
+ Projects types.Set `tfsdk:"projects"`
+}
+
+func (m *AllProjectsSpikeProtectionResourceModel) Fill(organization string, enabled bool, projects []sentry.Project) error {
+ m.Organization = types.StringValue(organization)
+ m.Enabled = types.BoolValue(enabled)
+
+ projectElements := []attr.Value{}
+ for _, project := range projects {
+ projectElements = append(projectElements, types.StringValue(project.Slug))
+ }
+ m.Projects = types.SetValueMust(types.StringType, projectElements)
+
+ return nil
+}
+
+func (r *AllProjectsSpikeProtectionResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+ resp.TypeName = req.ProviderTypeName + "_all_projects_spike_protection"
+}
+
+func (r *AllProjectsSpikeProtectionResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+ resp.Schema = schema.Schema{
+ MarkdownDescription: "Enable spike protection for all projects in an organization.",
+
+ Attributes: map[string]schema.Attribute{
+ "organization": schema.StringAttribute{
+ MarkdownDescription: "The slug of the organization the resource belongs to.",
+ Required: true,
+ },
+ "projects": schema.SetAttribute{
+ MarkdownDescription: "The slugs of the projects to enable or disable spike protection for.",
+ Required: true,
+ ElementType: types.StringType,
+ Validators: []validator.Set{
+ setvalidator.SizeAtLeast(1),
+ },
+ },
+ "enabled": schema.BoolAttribute{
+ MarkdownDescription: "Toggle the browser-extensions, localhost, filtered-transaction, or web-crawlers filter on or off for all projects.",
+ Required: true,
+ },
+ },
+ }
+}
+
+func (r *AllProjectsSpikeProtectionResource) readProjects(ctx context.Context, organization string, enabled bool, projectSlugs []string) ([]sentry.Project, error) {
+ var allProjects []sentry.Project
+ params := &sentry.ListOrganizationProjectsParams{
+ Options: "quotas:spike-protection-disabled",
+ }
+
+ for {
+ projects, apiResp, err := r.client.OrganizationProjects.List(ctx, organization, params)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, project := range projects {
+ for _, projectSlug := range projectSlugs {
+ if projectSlug == project.Slug {
+ if projectDisabled, ok := project.Options["quotas:spike-protection-disabled"].(bool); ok && projectDisabled != enabled {
+ allProjects = append(allProjects, *project)
+ }
+
+ break
+ }
+ }
+ }
+
+ if apiResp.Cursor == "" {
+ break
+ }
+ params.Cursor = apiResp.Cursor
+ }
+
+ return allProjects, nil
+}
+
+func (r *AllProjectsSpikeProtectionResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+ var data AllProjectsSpikeProtectionResourceModel
+
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ projects := []string{}
+ if !data.Projects.IsNull() {
+ resp.Diagnostics.Append(data.Projects.ElementsAs(ctx, &projects, false)...)
+ }
+
+ if data.Enabled.ValueBool() {
+ _, err := r.client.SpikeProtections.Enable(
+ ctx,
+ data.Organization.ValueString(),
+ &sentry.SpikeProtectionParams{
+ Projects: projects,
+ },
+ )
+ if err != nil {
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Error enabling spike protection: %s", err.Error()))
+ return
+ }
+ } else {
+ _, err := r.client.SpikeProtections.Disable(
+ ctx,
+ data.Organization.ValueString(),
+ &sentry.SpikeProtectionParams{
+ Projects: projects,
+ },
+ )
+ if err != nil {
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Error disabling spike protection: %s", err.Error()))
+ return
+ }
+ }
+
+ allProjects, err := r.readProjects(ctx, data.Organization.ValueString(), data.Enabled.ValueBool(), projects)
+ if err != nil {
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Read error: %s", err))
+ return
+ }
+
+ if err := data.Fill(data.Organization.ValueString(), data.Enabled.ValueBool(), allProjects); err != nil {
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Fill error: %s", err.Error()))
+ return
+ }
+
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *AllProjectsSpikeProtectionResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+ var data AllProjectsSpikeProtectionResourceModel
+
+ resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ projects := []string{}
+ if !data.Projects.IsNull() {
+ resp.Diagnostics.Append(data.Projects.ElementsAs(ctx, &projects, false)...)
+ }
+
+ allProjects, err := r.readProjects(ctx, data.Organization.ValueString(), data.Enabled.ValueBool(), projects)
+ if err != nil {
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Read error: %s", err))
+ return
+ }
+
+ if err := data.Fill(data.Organization.ValueString(), data.Enabled.ValueBool(), allProjects); err != nil {
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Fill error: %s", err.Error()))
+ return
+ }
+
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *AllProjectsSpikeProtectionResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+ var data AllProjectsSpikeProtectionResourceModel
+
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ projects := []string{}
+ if !data.Projects.IsNull() {
+ resp.Diagnostics.Append(data.Projects.ElementsAs(ctx, &projects, false)...)
+ }
+
+ if data.Enabled.ValueBool() {
+ _, err := r.client.SpikeProtections.Enable(
+ ctx,
+ data.Organization.ValueString(),
+ &sentry.SpikeProtectionParams{
+ Projects: projects,
+ },
+ )
+ if err != nil {
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Error enabling spike protection: %s", err.Error()))
+ return
+ }
+ } else {
+ _, err := r.client.SpikeProtections.Disable(
+ ctx,
+ data.Organization.ValueString(),
+ &sentry.SpikeProtectionParams{
+ Projects: projects,
+ },
+ )
+ if err != nil {
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Error disabling spike protection: %s", err.Error()))
+ return
+ }
+ }
+
+ allProjects, err := r.readProjects(ctx, data.Organization.ValueString(), data.Enabled.ValueBool(), projects)
+ if err != nil {
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Read error: %s", err))
+ return
+ }
+
+ if err := data.Fill(data.Organization.ValueString(), data.Enabled.ValueBool(), allProjects); err != nil {
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Fill error: %s", err.Error()))
+ return
+ }
+
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *AllProjectsSpikeProtectionResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+ var data AllProjectsSpikeProtectionResourceModel
+
+ resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ projects := []string{}
+ if !data.Projects.IsNull() {
+ resp.Diagnostics.Append(data.Projects.ElementsAs(ctx, &projects, false)...)
+ }
+
+ if data.Enabled.ValueBool() {
+ // We need to disable the spike protection if it was enabled.
+ _, err := r.client.SpikeProtections.Disable(
+ ctx,
+ data.Organization.ValueString(),
+ &sentry.SpikeProtectionParams{
+ Projects: projects,
+ },
+ )
+ if err != nil {
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Error disabling spike protection: %s", err.Error()))
+ return
+ }
+ } else {
+ // We need to enable the spike protection if it was disabled.
+ _, err := r.client.SpikeProtections.Enable(
+ ctx,
+ data.Organization.ValueString(),
+ &sentry.SpikeProtectionParams{
+ Projects: projects,
+ },
+ )
+ if err != nil {
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Error enabling spike protection: %s", err.Error()))
+ return
+ }
+ }
+}
diff --git a/internal/provider/resource_all_projects_spike_protection_test.go b/internal/provider/resource_all_projects_spike_protection_test.go
new file mode 100644
index 000000000..b588548d1
--- /dev/null
+++ b/internal/provider/resource_all_projects_spike_protection_test.go
@@ -0,0 +1,85 @@
+package provider
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/knownvalue"
+ "github.com/hashicorp/terraform-plugin-testing/statecheck"
+ "github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
+ "github.com/jianyuan/terraform-provider-sentry/internal/acctest"
+)
+
+func TestAccAllProjectsSpikeProtectionResource(t *testing.T) {
+ teamName := acctest.RandomWithPrefix("tf-team")
+ project1Name := acctest.RandomWithPrefix("tf-project")
+ project2Name := acctest.RandomWithPrefix("tf-project")
+ rn := "sentry_all_projects_spike_protection.test"
+
+ checks := []statecheck.StateCheck{
+ statecheck.ExpectKnownValue(rn, tfjsonpath.New("organization"), knownvalue.StringExact(acctest.TestOrganization)),
+ }
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { acctest.PreCheck(t) },
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccProjectResourceConfig(teamName, project1Name) + `
+ resource "sentry_all_projects_spike_protection" "test" {
+ organization = sentry_team.test.organization
+ projects = [sentry_project.test.id]
+ enabled = true
+ }
+ `,
+ ConfigStateChecks: append(
+ checks,
+ statecheck.ExpectKnownValue(rn, tfjsonpath.New("enabled"), knownvalue.Bool(true)),
+ statecheck.ExpectKnownValue(rn, tfjsonpath.New("projects"), knownvalue.SetExact([]knownvalue.Check{
+ knownvalue.StringExact(project1Name),
+ })),
+ ),
+ },
+ {
+ Config: testAccProjectResourceConfig(teamName, project1Name) + `
+ resource "sentry_all_projects_spike_protection" "test" {
+ organization = sentry_team.test.organization
+ projects = [sentry_project.test.id]
+ enabled = false
+ }
+ `,
+ ConfigStateChecks: append(
+ checks,
+ statecheck.ExpectKnownValue(rn, tfjsonpath.New("enabled"), knownvalue.Bool(false)),
+ statecheck.ExpectKnownValue(rn, tfjsonpath.New("projects"), knownvalue.SetExact([]knownvalue.Check{
+ knownvalue.StringExact(project1Name),
+ })),
+ ),
+ },
+ {
+ Config: testAccProjectResourceConfig(teamName, project1Name) + fmt.Sprintf(`
+ resource "sentry_project" "test2" {
+ organization = sentry_team.test.organization
+ teams = [sentry_team.test.id]
+ name = "%[1]s"
+ }
+
+ resource "sentry_all_projects_spike_protection" "test" {
+ organization = sentry_team.test.organization
+ projects = [sentry_project.test.id, sentry_project.test2.id]
+ enabled = false
+ }
+ `, project2Name),
+ ConfigStateChecks: append(
+ checks,
+ statecheck.ExpectKnownValue(rn, tfjsonpath.New("enabled"), knownvalue.Bool(false)),
+ statecheck.ExpectKnownValue(rn, tfjsonpath.New("projects"), knownvalue.SetExact([]knownvalue.Check{
+ knownvalue.StringExact(project1Name),
+ knownvalue.StringExact(project2Name),
+ })),
+ ),
+ },
+ },
+ })
+}
diff --git a/internal/provider/resource_project_spike_protection.go b/internal/provider/resource_project_spike_protection.go
index 6d908cd8b..67af13475 100644
--- a/internal/provider/resource_project_spike_protection.go
+++ b/internal/provider/resource_project_spike_protection.go
@@ -54,23 +54,23 @@ func (r *ProjectSpikeProtectionResource) Schema(ctx context.Context, req resourc
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
- Description: "The ID of this resource.",
- Computed: true,
+ MarkdownDescription: "The ID of this resource.",
+ Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"organization": schema.StringAttribute{
- Description: "The slug of the organization the project belongs to.",
- Required: true,
+ MarkdownDescription: "The slug of the organization the project belongs to.",
+ Required: true,
},
"project": schema.StringAttribute{
- Description: "The slug of the project to create the filter for.",
- Required: true,
+ MarkdownDescription: "The slug of the project to enable or disable spike protection for.",
+ Required: true,
},
"enabled": schema.BoolAttribute{
- Description: "Toggle the browser-extensions, localhost, filtered-transaction, or web-crawlers filter on or off.",
- Required: true,
+ MarkdownDescription: "Toggle the browser-extensions, localhost, filtered-transaction, or web-crawlers filter on or off.",
+ Required: true,
},
},
}
diff --git a/internal/provider/resource_project_spike_protection_test.go b/internal/provider/resource_project_spike_protection_test.go
index cddbda4fe..c2967ee5a 100644
--- a/internal/provider/resource_project_spike_protection_test.go
+++ b/internal/provider/resource_project_spike_protection_test.go
@@ -5,33 +5,36 @@ import (
"testing"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/knownvalue"
+ "github.com/hashicorp/terraform-plugin-testing/statecheck"
+ "github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
"github.com/jianyuan/terraform-provider-sentry/internal/acctest"
)
func TestAccProjectSpikeProtectionResource(t *testing.T) {
rn := "sentry_project_spike_protection.test"
- team := acctest.RandomWithPrefix("tf-team")
- project := acctest.RandomWithPrefix("tf-project")
+ teamName := acctest.RandomWithPrefix("tf-team")
+ projectName := acctest.RandomWithPrefix("tf-project")
resource.Test(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
- Config: testAccProjectSpikeProtectionResourceConfig(team, project, true),
- Check: resource.ComposeTestCheckFunc(
- resource.TestCheckResourceAttr(rn, "organization", acctest.TestOrganization),
- resource.TestCheckResourceAttr(rn, "project", project),
- resource.TestCheckResourceAttr(rn, "enabled", "true"),
- ),
+ Config: testAccProjectSpikeProtectionResourceConfig(teamName, projectName, true),
+ ConfigStateChecks: []statecheck.StateCheck{
+ statecheck.ExpectKnownValue(rn, tfjsonpath.New("organization"), knownvalue.StringExact(acctest.TestOrganization)),
+ statecheck.ExpectKnownValue(rn, tfjsonpath.New("project"), knownvalue.StringExact(projectName)),
+ statecheck.ExpectKnownValue(rn, tfjsonpath.New("enabled"), knownvalue.Bool(true)),
+ },
},
{
- Config: testAccProjectSpikeProtectionResourceConfig(team, project, false),
- Check: resource.ComposeTestCheckFunc(
- resource.TestCheckResourceAttr(rn, "organization", acctest.TestOrganization),
- resource.TestCheckResourceAttr(rn, "project", project),
- resource.TestCheckResourceAttr(rn, "enabled", "false"),
- ),
+ Config: testAccProjectSpikeProtectionResourceConfig(teamName, projectName, false),
+ ConfigStateChecks: []statecheck.StateCheck{
+ statecheck.ExpectKnownValue(rn, tfjsonpath.New("organization"), knownvalue.StringExact(acctest.TestOrganization)),
+ statecheck.ExpectKnownValue(rn, tfjsonpath.New("project"), knownvalue.StringExact(projectName)),
+ statecheck.ExpectKnownValue(rn, tfjsonpath.New("enabled"), knownvalue.Bool(false)),
+ },
},
{
ResourceName: rn,
@@ -42,7 +45,7 @@ func TestAccProjectSpikeProtectionResource(t *testing.T) {
})
}
-func testAccProjectSpikeProtectionResourceConfig(teamName string, projectName string, enabled bool) string {
+func testAccProjectSpikeProtectionResourceConfig(teamName, projectName string, enabled bool) string {
return testAccOrganizationDataSourceConfig + fmt.Sprintf(`
resource "sentry_team" "test" {
organization = data.sentry_organization.test.id