From 4d80395177dc0bb871f14437830a8674b467f913 Mon Sep 17 00:00:00 2001 From: Ramon Snir Date: Sun, 25 Aug 2024 14:13:15 -0400 Subject: [PATCH] netlify_deploy_key --- docs/resources/deploy_key.md | 35 ++++ .../resources/netlify_deploy_key/import.sh | 2 + .../resources/netlify_deploy_key/resource.tf | 1 + internal/provider/deploy_key_resource.go | 158 ++++++++++++++++++ internal/provider/deploy_key_resource_test.go | 43 +++++ internal/provider/dns_record_resource_test.go | 16 +- internal/provider/provider.go | 1 + 7 files changed, 255 insertions(+), 1 deletion(-) create mode 100644 docs/resources/deploy_key.md create mode 100644 examples/resources/netlify_deploy_key/import.sh create mode 100644 examples/resources/netlify_deploy_key/resource.tf create mode 100644 internal/provider/deploy_key_resource.go create mode 100644 internal/provider/deploy_key_resource_test.go diff --git a/docs/resources/deploy_key.md b/docs/resources/deploy_key.md new file mode 100644 index 0000000..3422059 --- /dev/null +++ b/docs/resources/deploy_key.md @@ -0,0 +1,35 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "netlify_deploy_key Resource - netlify" +subcategory: "" +description: |- + Deploy key for Git repositories. Avoid creating this resource directly if possible. Read more https://docs.netlify.com/git/repo-permissions-linking/#deploy-keys +--- + +# netlify_deploy_key (Resource) + +Deploy key for Git repositories. Avoid creating this resource directly if possible. [Read more](https://docs.netlify.com/git/repo-permissions-linking/#deploy-keys) + +## Example Usage + +```terraform +resource "netlify_deploy_key" "common" {} +``` + + +## Schema + +### Read-Only + +- `id` (String) The ID of this resource. +- `last_updated` (String) +- `public_key` (String) + +## Import + +Import is supported using the following syntax: + +```shell +# Import a deploy key by its ID +terraform import netlify_deploy_key.common 6600abcdef1234567890abcd +``` diff --git a/examples/resources/netlify_deploy_key/import.sh b/examples/resources/netlify_deploy_key/import.sh new file mode 100644 index 0000000..00fe902 --- /dev/null +++ b/examples/resources/netlify_deploy_key/import.sh @@ -0,0 +1,2 @@ +# Import a deploy key by its ID +terraform import netlify_deploy_key.common 6600abcdef1234567890abcd diff --git a/examples/resources/netlify_deploy_key/resource.tf b/examples/resources/netlify_deploy_key/resource.tf new file mode 100644 index 0000000..53c87d9 --- /dev/null +++ b/examples/resources/netlify_deploy_key/resource.tf @@ -0,0 +1 @@ +resource "netlify_deploy_key" "common" {} diff --git a/internal/provider/deploy_key_resource.go b/internal/provider/deploy_key_resource.go new file mode 100644 index 0000000..6900ff8 --- /dev/null +++ b/internal/provider/deploy_key_resource.go @@ -0,0 +1,158 @@ +package provider + +import ( + "context" + "fmt" + "time" + + "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" +) + +var ( + _ resource.Resource = &deployKeyResource{} + _ resource.ResourceWithConfigure = &deployKeyResource{} + _ resource.ResourceWithImportState = &deployKeyResource{} +) + +func NewDeployKeyResource() resource.Resource { + return &deployKeyResource{} +} + +type deployKeyResource struct { + data NetlifyProviderData +} + +type deployKeyResourceModel struct { + ID types.String `tfsdk:"id"` + LastUpdated types.String `tfsdk:"last_updated"` + PublicKey types.String `tfsdk:"public_key"` +} + +func (r *deployKeyResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_deploy_key" +} + +func (r *deployKeyResource) 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 *deployKeyResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Deploy key for Git repositories. Avoid creating this resource directly if possible.", + MarkdownDescription: "Deploy key for Git repositories. Avoid creating this resource directly if possible. [Read more](https://docs.netlify.com/git/repo-permissions-linking/#deploy-keys)", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "last_updated": schema.StringAttribute{ + Computed: true, + }, + "public_key": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + }, + } +} + +func (r *deployKeyResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan deployKeyResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + key, _, err := r.data.client.DeployKeysAPI.CreateDeployKey(ctx).Execute() + if err != nil { + resp.Diagnostics.AddError( + "Error creating Netlify deploy key", + fmt.Sprintf("Could not create Netlify deploy key: %q", err.Error()), + ) + return + } + + plan.ID = types.StringValue(key.Id) + plan.LastUpdated = types.StringValue(time.Now().Format(time.RFC3339)) + plan.PublicKey = types.StringValue(key.PublicKey) + + resp.Diagnostics.Append(resp.State.Set(ctx, plan)...) + if resp.Diagnostics.HasError() { + return + } +} + +func (r *deployKeyResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state deployKeyResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + key, _, err := r.data.client.DeployKeysAPI.GetDeployKey(ctx, state.ID.ValueString()).Execute() + if err != nil { + resp.Diagnostics.AddError( + "Error reading Netlify deploy key", + fmt.Sprintf("Could not read Netlify deploy key %q: %q", state.ID.ValueString(), err.Error()), + ) + return + } + + state.PublicKey = types.StringValue(key.PublicKey) + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } +} + +func (r *deployKeyResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + resp.Diagnostics.AddError( + "Update not supported for Netlify deploy keys", + "Update is not supported for Netlify deploy keys at this time.", + ) +} + +func (r *deployKeyResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state deployKeyResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + _, err := r.data.client.DeployKeysAPI.DeleteDeployKey(ctx, state.ID.ValueString()).Execute() + if err != nil { + resp.Diagnostics.AddError( + "Error deleting Netlify deploy key", + fmt.Sprintf("Could not delete Netlify deploy key %q: %q", state.ID.ValueString(), err.Error()), + ) + return + } +} + +func (r *deployKeyResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} diff --git a/internal/provider/deploy_key_resource_test.go b/internal/provider/deploy_key_resource_test.go new file mode 100644 index 0000000..d38ca7d --- /dev/null +++ b/internal/provider/deploy_key_resource_test.go @@ -0,0 +1,43 @@ +package provider + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" +) + +func TestAccDeployKey(t *testing.T) { + accTest(t, []resource.TestStep{ + { + Config: `resource "netlify_deploy_key" "example" {}`, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet("netlify_deploy_key.example", "id"), + resource.TestCheckResourceAttrSet("netlify_deploy_key.example", "last_updated"), + resource.TestCheckResourceAttrSet("netlify_deploy_key.example", "public_key"), + ), + }, + { + ResourceName: "netlify_deploy_key.example", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"last_updated"}, + }, + }, testAccDeployKeyDestroy) +} + +func testAccDeployKeyDestroy(s *terraform.State) error { + for _, m := range s.Modules { + if v, ok := m.Resources["netlify_deploy_key.example"]; ok { + key, _, err := testAccProvider.client.DeployKeysAPI.GetDeployKey(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("Deploy key still exists: %s", key.Id) + } + } + return fmt.Errorf("not found in testAccDeployKeyDestroy check destroy") +} diff --git a/internal/provider/dns_record_resource_test.go b/internal/provider/dns_record_resource_test.go index 7c61710..93256cb 100644 --- a/internal/provider/dns_record_resource_test.go +++ b/internal/provider/dns_record_resource_test.go @@ -27,6 +27,20 @@ func TestAccDnsRecordA(t *testing.T) { resource.TestCheckResourceAttr("netlify_dns_record.example", "value", "10.0.0.0"), ), }, + { + ResourceName: "netlify_dns_record.example", + ImportState: true, + ImportStateIdFunc: func(s *terraform.State) (string, error) { + for _, m := range s.Modules { + if v, ok := m.Resources["netlify_dns_record.example"]; ok { + return fmt.Sprintf("%s:%s", v.Primary.Attributes["zone_id"], v.Primary.Attributes["id"]), nil + } + } + return "", fmt.Errorf("not found in TestAccDnsRecordA import test step") + }, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"last_updated"}, + }, { Config: fmt.Sprintf(`resource "netlify_dns_record" "example" { type = "A" @@ -34,7 +48,7 @@ func TestAccDnsRecordA(t *testing.T) { hostname = "testacc.examplepetstore.com" value = "10.0.0.1" }`, zoneId), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("netlify_dns_record.example", "type", "A"), resource.TestCheckResourceAttr("netlify_dns_record.example", "zone_id", zoneId), resource.TestCheckResourceAttr("netlify_dns_record.example", "hostname", "testacc.examplepetstore.com"), diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 92f90b3..6ef526c 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -205,6 +205,7 @@ func (p *NetlifyProvider) Configure(ctx context.Context, req provider.ConfigureR func (p *NetlifyProvider) Resources(ctx context.Context) []func() resource.Resource { return []func() resource.Resource{ + NewDeployKeyResource, NewDnsRecordResource, NewDnsZoneResource, NewEnvironmentVariableResource,