From b1167a3b9702b18e7e9254ea27df6b9e773d88e8 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Mon, 9 Sep 2024 23:48:07 +0200 Subject: [PATCH] add initial site resource --- docs/resources/site.md | 25 ++++ internal/provider/provider.go | 1 + internal/provider/site_resource.go | 182 ++++++++++++++++++++++++ internal/provider/site_resource_test.go | 39 +++++ 4 files changed, 247 insertions(+) create mode 100644 docs/resources/site.md create mode 100644 internal/provider/site_resource.go create mode 100644 internal/provider/site_resource_test.go diff --git a/docs/resources/site.md b/docs/resources/site.md new file mode 100644 index 0000000..1c92e30 --- /dev/null +++ b/docs/resources/site.md @@ -0,0 +1,25 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "netlify_site Resource - netlify" +subcategory: "" +description: |- + Netlify site. Read more https://docs.netlify.com/git/overview/ +--- + +# netlify_site (Resource) + +Netlify site. [Read more](https://docs.netlify.com/git/overview/) + + + + +## Schema + +### Required + +- `name` (String) +- `team_slug` (String) + +### Read-Only + +- `id` (String) The ID of this resource. diff --git a/internal/provider/provider.go b/internal/provider/provider.go index ca48cda..1eb12bb 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -212,6 +212,7 @@ func (p *NetlifyProvider) Resources(ctx context.Context) []func() resource.Resou NewFirewallTrafficRulesResource(true), NewFirewallTrafficRulesResource(false), NewLogDrainResource, + NewSiteResource, NewSiteBuildSettingsResource, NewSiteCollaborationSettingsResource, NewSiteDomainSettingsResource, diff --git a/internal/provider/site_resource.go b/internal/provider/site_resource.go new file mode 100644 index 0000000..41dc5d1 --- /dev/null +++ b/internal/provider/site_resource.go @@ -0,0 +1,182 @@ +package provider + +import ( + "context" + "fmt" + + "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/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/netlify/terraform-provider-netlify/internal/netlifyapi" +) + +var ( + _ resource.Resource = &siteResource{} + _ resource.ResourceWithConfigure = &siteResource{} + _ resource.ResourceWithImportState = &siteResource{} +) + +func NewSiteResource() resource.Resource { + return &siteResource{} +} + +type siteResource struct { + data NetlifyProviderData +} + +type siteResourceModel struct { + ID types.String `tfsdk:"id"` + TeamSlug types.String `tfsdk:"team_slug"` + Name types.String `tfsdk:"name"` +} + +func (r *siteResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_site" +} + +func (r *siteResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + + data, ok := req.ProviderData.(NetlifyProviderData) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected Resource Configure Type", + fmt.Sprintf("Expected NetlifyProviderData, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + return + } + + r.data = data +} + +func (r *siteResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Netlify site", + MarkdownDescription: "Netlify site. [Read more](https://docs.netlify.com/git/overview/)", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "team_slug": schema.StringAttribute{ + Required: true, + }, + "name": schema.StringAttribute{ + Required: true, + }, + }, + } +} + +func (r *siteResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var state siteResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + ns := netlifyapi.Site{ + Name: state.Name.ValueString(), + } + site, _, err := r.data.client.SitesAPI. + CreateSite(ctx). + Site(ns). + Execute() + if err != nil { + resp.Diagnostics.AddError( + "Error creating site", + fmt.Sprintf("Could not create site: %q", err.Error()), + ) + return + } + + state.ID = types.StringValue(site.Id) + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *siteResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state siteResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + site, _, err := r.data.client.SitesAPI.GetSite(ctx, state.ID.ValueString()).Execute() + if err != nil { + resp.Diagnostics.AddError( + "Error reading site", + fmt.Sprintf( + "Could not read site %q: %q", + state.ID.ValueString(), + err.Error(), + ), + ) + return + } + + state.Name = types.StringValue(site.Name) + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *siteResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var state siteResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + site, _, err := r.data.client.SitesAPI. + UpdateSite(ctx, state.ID.ValueString()). + PartialSite(netlifyapi.PartialSite{ + Name: state.Name.ValueStringPointer(), + }). + Execute() + if err != nil { + resp.Diagnostics.AddError( + "Error updating site", + fmt.Sprintf("Could not update site %q: %q", state.ID.ValueString(), err.Error()), + ) + return + } + state.Name = types.StringValue(site.Name) + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } +} + +func (r *siteResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state siteResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + _, err := r.data.client.SitesAPI.DeleteSite(ctx, state.ID.ValueString()).Execute() + if err != nil { + resp.Diagnostics.AddError( + "Error deleting site", + fmt.Sprintf( + "Could not delete site %q: %q", + state.ID.ValueString(), + err.Error(), + ), + ) + return + } +} + +func (r *siteResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), req.ID)...) +} diff --git a/internal/provider/site_resource_test.go b/internal/provider/site_resource_test.go new file mode 100644 index 0000000..55e40b3 --- /dev/null +++ b/internal/provider/site_resource_test.go @@ -0,0 +1,39 @@ +package provider + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" +) + +func TestAccSite(t *testing.T) { + accTest(t, []resource.TestStep{ + { + Config: `resource "netlify_site" "example" { + name = "test-netlify-terraform-provider" + team_slug = "jenslanghammer" +}`, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("netlify_site.example", "id"), + // resource.TestCheckResourceAttr("netlify_site.example", "custom_domain", "test-netlify-terraform-provider.netlify.app"), + ), + }, + }, testAccSiteDestroy) +} + +func testAccSiteDestroy(s *terraform.State) error { + for _, m := range s.Modules { + if v, ok := m.Resources["netlify_site.example"]; ok { + key, _, err := testAccProvider.client.SitesAPI.GetSite(context.Background(), v.Primary.Attributes["id"]).Execute() + if err != nil { + //lint:ignore nilerr we expect an error to know it was not found + return nil + } + return fmt.Errorf("Site still exists: %s", key.Id) + } + } + return fmt.Errorf("not found in testAccSiteDestroy check destroy") +}