From f6c24cd1ddb6af117c69b7ccb9b378658c170041 Mon Sep 17 00:00:00 2001 From: Douglas Parsons Date: Mon, 19 Sep 2022 13:31:43 +0100 Subject: [PATCH] Upgrade to terraform framework v13 - [V12 release notes](https://github.com/hashicorp/terraform-plugin-framework/releases/tag/v0.12.0) - [V13 release notes](https://github.com/hashicorp/terraform-plugin-framework/releases/tag/v0.13.0) --- docs/data-sources/prebuilt_project.md | 2 +- go.mod | 14 ++-- go.sum | 14 ++++ vercel/data_source_alias.go | 49 +++++++---- vercel/data_source_file.go | 47 +++++++---- vercel/data_source_prebuilt_project.go | 51 ++++++++---- vercel/data_source_project.go | 49 +++++++---- vercel/data_source_project_directory.go | 47 +++++++---- vercel/provider.go | 51 +++++++----- vercel/resource_alias.go | 66 ++++++++------- vercel/resource_deployment.go | 74 +++++++++-------- vercel/resource_dns_record.go | 74 +++++++++-------- vercel/resource_project.go | 83 ++++++++++--------- vercel/resource_project_domain.go | 74 +++++++++-------- .../resource_project_environment_variable.go | 74 +++++++++-------- 15 files changed, 460 insertions(+), 309 deletions(-) diff --git a/docs/data-sources/prebuilt_project.md b/docs/data-sources/prebuilt_project.md index d48a8c1b..32e316eb 100644 --- a/docs/data-sources/prebuilt_project.md +++ b/docs/data-sources/prebuilt_project.md @@ -13,7 +13,7 @@ description: |- Provides the output of a project built via `vercel build` and provides metadata for use with a `vercel_deployment` -The [build command](https://vercel.com/docs/cli#commands/build) can be used to build a project locally or in your own CI environment. +The [build command](https://vercel.com/docs/cli#commands/build) can be used to build a project locally or in your own CI environment. Build artifacts are placed into the `.vercel/output` directory according to the [Build Output API](https://vercel.com/docs/build-output-api/v3). This allows a Vercel Deployment to be created without sharing the Project's source code with Vercel. diff --git a/go.mod b/go.mod index 50d04a65..b5ba6c86 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/vercel/terraform-provider-vercel go 1.19 require ( - github.com/hashicorp/terraform-plugin-framework v0.11.1 + github.com/hashicorp/terraform-plugin-framework v0.13.0 github.com/hashicorp/terraform-plugin-go v0.14.0 github.com/hashicorp/terraform-plugin-log v0.7.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.10.1 @@ -17,12 +17,12 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/color v1.13.0 // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/google/go-cmp v0.5.8 // indirect + github.com/google/go-cmp v0.5.9 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-checkpoint v0.5.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect - github.com/hashicorp/go-hclog v1.2.2 // indirect + github.com/hashicorp/go-hclog v1.3.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-plugin v1.4.5 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect @@ -48,11 +48,11 @@ require ( github.com/vmihailenco/tagparser v0.1.2 // indirect github.com/zclconf/go-cty v1.10.0 // indirect golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e // indirect - golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c // indirect - golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 // indirect + golang.org/x/net v0.0.0-20220909164309-bea034e7d591 // indirect + golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect golang.org/x/text v0.3.7 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc // indirect - google.golang.org/grpc v1.48.0 // indirect + google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa // indirect + google.golang.org/grpc v1.49.0 // indirect google.golang.org/protobuf v1.28.1 // indirect ) diff --git a/go.sum b/go.sum index 2d1ce2ca..97fc577c 100644 --- a/go.sum +++ b/go.sum @@ -153,6 +153,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -186,6 +188,8 @@ github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39 github.com/hashicorp/go-hclog v0.16.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v1.2.2 h1:ihRI7YFwcZdiSD7SIenIhHfQH3OuDvWerAUBZbeQS3M= github.com/hashicorp/go-hclog v1.2.2/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-hclog v1.3.0 h1:G0ACM8Z2WilWgPv3Vdzwm3V0BQu/kSmrkVtpe1fy9do= +github.com/hashicorp/go-hclog v1.3.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= @@ -219,6 +223,8 @@ github.com/hashicorp/terraform-json v0.13.0 h1:Li9L+lKD1FO5RVFRM1mMMIBDoUHslOniy github.com/hashicorp/terraform-json v0.13.0/go.mod h1:y5OdLBCT+rxbwnpxZs9kGL7R9ExU76+cpdY8zHwoazk= github.com/hashicorp/terraform-plugin-framework v0.11.1 h1:rq8f+TLDO4tJu+n9mMYlDrcRoIdrg0gTUvV2Jr0Ya24= github.com/hashicorp/terraform-plugin-framework v0.11.1/go.mod h1:GENReHOz6GEt8Jk3UN94vk8BdC6irEHFgN3Z9HPhPUU= +github.com/hashicorp/terraform-plugin-framework v0.13.0 h1:tGnqttzZwU3FKc+HasHr2Yi5L81FcQbdc8zQhbBD9jQ= +github.com/hashicorp/terraform-plugin-framework v0.13.0/go.mod h1:wcZdk4+Uef6Ng+BiBJjGAcIPlIs5bhlEV/TA1k6Xkq8= github.com/hashicorp/terraform-plugin-go v0.5.0/go.mod h1:PAVN26PNGpkkmsvva1qfriae5Arky3xl3NfzKa8XFVM= github.com/hashicorp/terraform-plugin-go v0.14.0 h1:ttnSlS8bz3ZPYbMb84DpcPhY4F5DsQtcAS7cHo8uvP4= github.com/hashicorp/terraform-plugin-go v0.14.0/go.mod h1:2nNCBeRLaenyQEi78xrGrs9hMbulveqG/zDMQSvVJTE= @@ -446,6 +452,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c h1:JVAXQ10yGGVbSyoer5VILysz6YKjdNT2bsvlayjqhes= golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -503,6 +511,8 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 h1:Sx/u41w+OwrInGdEckYmEuU5gHoGSL4QbDz3S9s6j4U= golang.org/x/sys v0.0.0-20220818161305-2296e01440c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc= +golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -615,6 +625,8 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200711021454-869866162049/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc h1:Nf+EdcTLHR8qDNN/KfkQL0u0ssxt9OhbaWCl5C0ucEI= google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa h1:VWkrxnAx2C2hirAP+W5ADU7e/+93Yhk//ioKd2XFyDI= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -632,6 +644,8 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w= google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/vercel/data_source_alias.go b/vercel/data_source_alias.go index abcaea56..95d323b4 100644 --- a/vercel/data_source_alias.go +++ b/vercel/data_source_alias.go @@ -6,16 +6,44 @@ import ( "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/vercel/terraform-provider-vercel/client" ) -type dataSourceAliasType struct{} +func newAliasDataSource() datasource.DataSource { + return &aliasDataSource{} +} + +type aliasDataSource struct { + client *client.Client +} + +func (d *aliasDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_alias" +} + +func (d *aliasDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*client.Client) + if !ok { + resp.Diagnostics.AddError( + "Unexpected Data Source Configure Type", + fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + return + } + + d.client = client +} // GetSchema returns the schema information for an alias data source -func (r dataSourceAliasType) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { +func (r *aliasDataSource) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return tfsdk.Schema{ Description: ` Provides information about an existing Alias resource. @@ -46,21 +74,10 @@ An Alias allows a ` + "`vercel_deployment` to be accessed through a different UR }, nil } -// NewDataSource instantiates a new DataSource of this DataSourceType. -func (r dataSourceAliasType) NewDataSource(ctx context.Context, p provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return dataSourceAlias{ - p: *(p.(*vercelProvider)), - }, nil -} - -type dataSourceAlias struct { - p vercelProvider -} - // Read will read the alias information by requesting it from the Vercel API, and will update terraform // with this information. // It is called by the provider whenever data source values should be read to update state. -func (r dataSourceAlias) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { +func (d *aliasDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { var config Alias diags := req.Config.Get(ctx, &config) resp.Diagnostics.Append(diags...) @@ -68,7 +85,7 @@ func (r dataSourceAlias) Read(ctx context.Context, req datasource.ReadRequest, r return } - out, err := r.p.client.GetAlias(ctx, config.Alias.Value, config.TeamID.Value) + out, err := d.client.GetAlias(ctx, config.Alias.Value, config.TeamID.Value) if err != nil { resp.Diagnostics.AddError( "Error reading alias", diff --git a/vercel/data_source_file.go b/vercel/data_source_file.go index 56445e41..72556e01 100644 --- a/vercel/data_source_file.go +++ b/vercel/data_source_file.go @@ -9,15 +9,43 @@ import ( "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/vercel/terraform-provider-vercel/client" ) -type dataSourceFileType struct{} +func newFileDataSource() datasource.DataSource { + return &fileDataSource{} +} + +type fileDataSource struct { + client *client.Client +} + +func (d *fileDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_file" +} + +func (d *fileDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*client.Client) + if !ok { + resp.Diagnostics.AddError( + "Unexpected Data Source Configure Type", + fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + return + } + + d.client = client +} // GetSchema returns the schema information for a file data source -func (r dataSourceFileType) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { +func (d *fileDataSource) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return tfsdk.Schema{ Description: ` Provides information about a file on disk. @@ -44,17 +72,6 @@ This will read a single file, providing metadata for use with a ` + "`vercel_dep }, nil } -// NewDataSource instantiates a new DataSource of this DataSourceType. -func (r dataSourceFileType) NewDataSource(ctx context.Context, p provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return dataSourceFile{ - p: *(p.(*vercelProvider)), - }, nil -} - -type dataSourceFile struct { - p vercelProvider -} - // FileData represents the information terraform knows about a File data source type FileData struct { Path types.String `tfsdk:"path"` @@ -64,7 +81,7 @@ type FileData struct { // Read will read a file from the filesytem and provide terraform with information about it. // It is called by the provider whenever data source values should be read to update state. -func (r dataSourceFile) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { +func (d *fileDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { var config FileData diags := req.Config.Get(ctx, &config) resp.Diagnostics.Append(diags...) diff --git a/vercel/data_source_prebuilt_project.go b/vercel/data_source_prebuilt_project.go index 04c205c0..7204af5a 100644 --- a/vercel/data_source_prebuilt_project.go +++ b/vercel/data_source_prebuilt_project.go @@ -11,21 +11,49 @@ import ( "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/vercel/terraform-provider-vercel/client" "github.com/vercel/terraform-provider-vercel/file" ) -type dataSourcePrebuiltProjectType struct{} +func newPrebuiltProjectDataSource() datasource.DataSource { + return &prebuiltProjectDataSource{} +} + +type prebuiltProjectDataSource struct { + client *client.Client +} + +func (d *prebuiltProjectDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_prebuilt_project" +} + +func (d *prebuiltProjectDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*client.Client) + if !ok { + resp.Diagnostics.AddError( + "Unexpected Data Source Configure Type", + fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + return + } + + d.client = client +} // GetSchema returns the schema information for a project directory data source -func (r dataSourcePrebuiltProjectType) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { +func (d *prebuiltProjectDataSource) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return tfsdk.Schema{ Description: ` Provides the output of a project built via ` + "`vercel build`" + ` and provides metadata for use with a ` + "`vercel_deployment`" + ` -The [build command](https://vercel.com/docs/cli#commands/build) can be used to build a project locally or in your own CI environment. +The [build command](https://vercel.com/docs/cli#commands/build) can be used to build a project locally or in your own CI environment. Build artifacts are placed into the ` + "`.vercel/output`" + ` directory according to the [Build Output API](https://vercel.com/docs/build-output-api/v3). This allows a Vercel Deployment to be created without sharing the Project's source code with Vercel. @@ -51,17 +79,6 @@ This allows a Vercel Deployment to be created without sharing the Project's sour }, nil } -// NewDataSource instantiates a new DataSource of this DataSourceType. -func (r dataSourcePrebuiltProjectType) NewDataSource(ctx context.Context, p provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return dataSourcePrebuiltProject{ - p: *(p.(*vercelProvider)), - }, nil -} - -type dataSourcePrebuiltProject struct { - p vercelProvider -} - // PrebuiltProjectData represents the information terraform knows about a project directory data source type PrebuiltProjectData struct { Path types.String `tfsdk:"path"` @@ -69,7 +86,7 @@ type PrebuiltProjectData struct { Output map[string]string `tfsdk:"output"` } -func (r dataSourcePrebuiltProject) ValidateConfig(ctx context.Context, req datasource.ValidateConfigRequest, resp *datasource.ValidateConfigResponse) { +func (d *prebuiltProjectDataSource) ValidateConfig(ctx context.Context, req datasource.ValidateConfigRequest, resp *datasource.ValidateConfigResponse) { var config PrebuiltProjectData diags := req.Config.Get(ctx, &config) resp.Diagnostics.Append(diags...) @@ -156,7 +173,7 @@ func validatePrebuiltOutput(diags AddErrorer, path string) { // Read will recursively read files from a .vercel/output directory. Metadata about all these files will then be made // available to terraform. -func (r dataSourcePrebuiltProject) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { +func (d *prebuiltProjectDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { var config PrebuiltProjectData diags := req.Config.Get(ctx, &config) resp.Diagnostics.Append(diags...) diff --git a/vercel/data_source_project.go b/vercel/data_source_project.go index 96cb2d22..6a5cd06b 100644 --- a/vercel/data_source_project.go +++ b/vercel/data_source_project.go @@ -7,16 +7,44 @@ import ( "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/vercel/terraform-provider-vercel/client" ) -type dataSourceProjectType struct{} +func newProjectDataSource() datasource.DataSource { + return &projectDataSource{} +} + +type projectDataSource struct { + client *client.Client +} + +func (d *projectDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_project" +} + +func (d *projectDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*client.Client) + if !ok { + resp.Diagnostics.AddError( + "Unexpected Data Source Configure Type", + fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + return + } + + d.client = client +} // GetSchema returns the schema information for a project data source -func (r dataSourceProjectType) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { +func (d *projectDataSource) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return tfsdk.Schema{ Description: ` Provides information about an existing project within Vercel. @@ -149,21 +177,10 @@ For more detailed information, please see the [Vercel documentation](https://ver }, nil } -// NewDataSource instantiates a new DataSource of this DataSourceType. -func (r dataSourceProjectType) NewDataSource(ctx context.Context, p provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return dataSourceProject{ - p: *(p.(*vercelProvider)), - }, nil -} - -type dataSourceProject struct { - p vercelProvider -} - // Read will read project information by requesting it from the Vercel API, and will update terraform // with this information. // It is called by the provider whenever data source values should be read to update state. -func (r dataSourceProject) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { +func (d *projectDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { var config Project diags := req.Config.Get(ctx, &config) resp.Diagnostics.Append(diags...) @@ -171,7 +188,7 @@ func (r dataSourceProject) Read(ctx context.Context, req datasource.ReadRequest, return } - out, err := r.p.client.GetProject(ctx, config.Name.Value, config.TeamID.Value, true) + out, err := d.client.GetProject(ctx, config.Name.Value, config.TeamID.Value, true) if err != nil { resp.Diagnostics.AddError( "Error reading project", diff --git a/vercel/data_source_project_directory.go b/vercel/data_source_project_directory.go index ccae2409..77d7d216 100644 --- a/vercel/data_source_project_directory.go +++ b/vercel/data_source_project_directory.go @@ -9,16 +9,44 @@ import ( "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/vercel/terraform-provider-vercel/client" "github.com/vercel/terraform-provider-vercel/file" ) -type dataSourceProjectDirectoryType struct{} +func newProjectDirectoryDataSource() datasource.DataSource { + return &projectDirectoryDataSource{} +} + +type projectDirectoryDataSource struct { + client *client.Client +} + +func (d *projectDirectoryDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_project_directory" +} + +func (d *projectDirectoryDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*client.Client) + if !ok { + resp.Diagnostics.AddError( + "Unexpected Data Source Configure Type", + fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + return + } + + d.client = client +} // GetSchema returns the schema information for a project directory data source -func (r dataSourceProjectDirectoryType) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { +func (d projectDirectoryDataSource) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return tfsdk.Schema{ Description: ` Provides information about files within a directory on disk. @@ -48,17 +76,6 @@ This will recursively read files, providing metadata for use with a ` + "`vercel }, nil } -// NewDataSource instantiates a new DataSource of this DataSourceType. -func (r dataSourceProjectDirectoryType) NewDataSource(ctx context.Context, p provider.Provider) (datasource.DataSource, diag.Diagnostics) { - return dataSourceProjectDirectory{ - p: *(p.(*vercelProvider)), - }, nil -} - -type dataSourceProjectDirectory struct { - p vercelProvider -} - // ProjectDirectoryData represents the information terraform knows about a project directory data source type ProjectDirectoryData struct { Path types.String `tfsdk:"path"` @@ -69,7 +86,7 @@ type ProjectDirectoryData struct { // Read will recursively scan a directory looking for any files that do not match a .vercelignore file (if a // .vercelignore is present). Metadata about all these files will then be made available to terraform. // It is called by the provider whenever data source values should be read to update state. -func (r dataSourceProjectDirectory) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { +func (d *projectDirectoryDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { var config ProjectDirectoryData diags := req.Config.Get(ctx, &config) resp.Diagnostics.Append(diags...) diff --git a/vercel/provider.go b/vercel/provider.go index 1c9272f2..3fdd0ae6 100644 --- a/vercel/provider.go +++ b/vercel/provider.go @@ -6,16 +6,17 @@ import ( "os" "regexp" + "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/provider" + "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/vercel/terraform-provider-vercel/client" ) type vercelProvider struct { - configured bool - client *client.Client + client *client.Client } // New instantiates a new instance of a vercel terraform provider. @@ -23,6 +24,10 @@ func New() provider.Provider { return &vercelProvider{} } +func (p *vercelProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) { + resp.TypeName = "vercel" +} + // GetSchema returns the schema information for the provider configuration itself. func (p *vercelProvider) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return tfsdk.Schema{ @@ -48,27 +53,25 @@ Use the navigation to the left to read about the available resources. }, nil } -// GetResources shows the available resources for the vercel provider -func (p *vercelProvider) GetResources(_ context.Context) (map[string]provider.ResourceType, diag.Diagnostics) { - return map[string]provider.ResourceType{ - "vercel_alias": resourceAliasType{}, - "vercel_deployment": resourceDeploymentType{}, - "vercel_dns_record": resourceDNSRecordType{}, - "vercel_project": resourceProjectType{}, - "vercel_project_domain": resourceProjectDomainType{}, - "vercel_project_environment_variable": resourceProjectEnvironmentVariableType{}, - }, nil +func (p *vercelProvider) Resources(_ context.Context) []func() resource.Resource { + return []func() resource.Resource{ + newAliasResource, + newDeploymentResource, + newDNSRecordResource, + newProjectResource, + newProjectDomainResource, + newProjectEnvironmentVariableResource, + } } -// GetDataSources shows the available data sources for the vercel provider -func (p *vercelProvider) GetDataSources(_ context.Context) (map[string]provider.DataSourceType, diag.Diagnostics) { - return map[string]provider.DataSourceType{ - "vercel_alias": dataSourceAliasType{}, - "vercel_file": dataSourceFileType{}, - "vercel_prebuilt_project": dataSourcePrebuiltProjectType{}, - "vercel_project": dataSourceProjectType{}, - "vercel_project_directory": dataSourceProjectDirectoryType{}, - }, nil +func (p *vercelProvider) DataSources(_ context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + newAliasDataSource, + newFileDataSource, + newPrebuiltProjectDataSource, + newProjectDataSource, + newProjectDirectoryDataSource, + } } type providerData struct { @@ -122,7 +125,7 @@ func (p *vercelProvider) Configure(ctx context.Context, req provider.ConfigureRe return } - p.client = client.New(apiToken) + vercelClient := client.New(apiToken) if config.Team.Value != "" { res, err := p.client.GetTeam(ctx, config.Team.Value) if client.NotFound(err) { @@ -141,5 +144,7 @@ func (p *vercelProvider) Configure(ctx context.Context, req provider.ConfigureRe } p.client = p.client.WithTeamID(res.ID) } - p.configured = true + + resp.DataSourceData = vercelClient + resp.ResourceData = vercelClient } diff --git a/vercel/resource_alias.go b/vercel/resource_alias.go index 2c62821c..ace40094 100644 --- a/vercel/resource_alias.go +++ b/vercel/resource_alias.go @@ -5,7 +5,6 @@ import ( "fmt" "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" @@ -13,10 +12,38 @@ import ( "github.com/vercel/terraform-provider-vercel/client" ) -type resourceAliasType struct{} +func newAliasResource() resource.Resource { + return &aliasResource{} +} + +type aliasResource struct { + client *client.Client +} + +func (r *aliasResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_alias" +} + +func (r *aliasResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*client.Client) + 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 +} // GetSchema returns the schema information for an alias resource. -func (r resourceAliasType) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { +func (r *aliasResource) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return tfsdk.Schema{ Description: ` Provides an Alias resource. @@ -50,28 +77,9 @@ An Alias allows a ` + "`vercel_deployment` to be accessed through a different UR }, nil } -// NewResource instantiates a new Resource of this ResourceType. -func (r resourceAliasType) NewResource(_ context.Context, p provider.Provider) (resource.Resource, diag.Diagnostics) { - return resourceAlias{ - p: *(p.(*vercelProvider)), - }, nil -} - -type resourceAlias struct { - p vercelProvider -} - // Create will create an alias within Vercel. // This is called automatically by the provider when a new resource should be created. -func (r resourceAlias) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - if !r.p.configured { - resp.Diagnostics.AddError( - "Provider not configured", - "The provider hasn't been configured before apply. This leads to weird stuff happening, so we'd prefer if you didn't do that. Thanks!", - ) - return - } - +func (r *aliasResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var plan Alias diags := req.Plan.Get(ctx, &plan) resp.Diagnostics.Append(diags...) @@ -79,7 +87,7 @@ func (r resourceAlias) Create(ctx context.Context, req resource.CreateRequest, r return } - out, err := r.p.client.CreateAlias(ctx, client.CreateAliasRequest{ + out, err := r.client.CreateAlias(ctx, client.CreateAliasRequest{ Alias: plan.Alias.Value, }, plan.DeploymentID.Value, plan.TeamID.Value) if err != nil { @@ -106,7 +114,7 @@ func (r resourceAlias) Create(ctx context.Context, req resource.CreateRequest, r // Read will read alias information by requesting it from the Vercel API, and will update terraform // with this information. -func (r resourceAlias) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { +func (r *aliasResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var state Alias diags := req.State.Get(ctx, &state) resp.Diagnostics.Append(diags...) @@ -114,7 +122,7 @@ func (r resourceAlias) Read(ctx context.Context, req resource.ReadRequest, resp return } - out, err := r.p.client.GetAlias(ctx, state.ID.Value, state.TeamID.Value) + out, err := r.client.GetAlias(ctx, state.ID.Value, state.TeamID.Value) if client.NotFound(err) { resp.State.RemoveResource(ctx) return @@ -145,7 +153,7 @@ func (r resourceAlias) Read(ctx context.Context, req resource.ReadRequest, resp } // Update updates the Alias state. -func (r resourceAlias) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { +func (r *aliasResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { var plan Alias diags := req.Plan.Get(ctx, &plan) resp.Diagnostics.Append(diags...) @@ -167,7 +175,7 @@ func (r resourceAlias) Update(ctx context.Context, req resource.UpdateRequest, r } // Delete deletes an Alias. -func (r resourceAlias) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { +func (r *aliasResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { var state Alias diags := req.State.Get(ctx, &state) resp.Diagnostics.Append(diags...) @@ -175,7 +183,7 @@ func (r resourceAlias) Delete(ctx context.Context, req resource.DeleteRequest, r return } - _, err := r.p.client.DeleteAlias(ctx, state.ID.Value, state.TeamID.Value) + _, err := r.client.DeleteAlias(ctx, state.ID.Value, state.TeamID.Value) if client.NotFound(err) { return } diff --git a/vercel/resource_deployment.go b/vercel/resource_deployment.go index 0a2bc93d..71c8dd97 100644 --- a/vercel/resource_deployment.go +++ b/vercel/resource_deployment.go @@ -9,7 +9,6 @@ import ( "strings" "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" @@ -18,10 +17,38 @@ import ( "github.com/vercel/terraform-provider-vercel/file" ) -type resourceDeploymentType struct{} +func newDeploymentResource() resource.Resource { + return &deploymentResource{} +} + +type deploymentResource struct { + client *client.Client +} + +func (r *deploymentResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_deployment" +} + +func (r *deploymentResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*client.Client) + 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 +} // GetSchema returns the schema information for a deployment resource. -func (r resourceDeploymentType) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { +func (r *deploymentResource) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return tfsdk.Schema{ Description: ` Provides a Deployment resource. @@ -158,19 +185,8 @@ terraform to your Deployment. }, nil } -// NewResource instantiates a new Resource of this ResourceType. -func (r resourceDeploymentType) NewResource(_ context.Context, p provider.Provider) (resource.Resource, diag.Diagnostics) { - return resourceDeployment{ - p: *(p.(*vercelProvider)), - }, nil -} - -type resourceDeployment struct { - p vercelProvider -} - // ValidateConfig allows additional validation (specifically cross-field validation) to be added. -func (r resourceDeployment) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { +func (r *deploymentResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { var config Deployment diags := req.Config.Get(ctx, &config) resp.Diagnostics.Append(diags...) @@ -246,15 +262,7 @@ func getPrebuiltBuildsFile(files []client.DeploymentFile) (string, bool) { // Create will create a deployment within Vercel. This is done by first attempting to trigger a deployment, seeing what // files are required, uploading those files, and then attempting to create a deployment again. // This is called automatically by the provider when a new resource should be created. -func (r resourceDeployment) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - if !r.p.configured { - resp.Diagnostics.AddError( - "Provider not configured", - "The provider hasn't been configured before apply. This leads to weird stuff happening, so we'd prefer if you didn't do that. Thanks!", - ) - return - } - +func (r *deploymentResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var plan Deployment diags := req.Plan.Get(ctx, &plan) resp.Diagnostics.Append(diags...) @@ -306,7 +314,7 @@ func (r resourceDeployment) Create(ctx context.Context, req resource.CreateReque Ref: plan.Ref.Value, } - _, err = r.p.client.GetProject(ctx, plan.ProjectID.Value, plan.TeamID.Value, false) + _, err = r.client.GetProject(ctx, plan.ProjectID.Value, plan.TeamID.Value, false) if client.NotFound(err) { resp.Diagnostics.AddError( "Error creating deployment", @@ -315,7 +323,7 @@ func (r resourceDeployment) Create(ctx context.Context, req resource.CreateReque return } - out, err := r.p.client.CreateDeployment(ctx, cdr, plan.TeamID.Value) + out, err := r.client.CreateDeployment(ctx, cdr, plan.TeamID.Value) var mfErr client.MissingFilesError if errors.As(err, &mfErr) { // Then we need to upload the files, and create the deployment again. @@ -334,7 +342,7 @@ func (r resourceDeployment) Create(ctx context.Context, req resource.CreateReque return } - err = r.p.client.CreateFile(ctx, client.CreateFileRequest{ + err = r.client.CreateFile(ctx, client.CreateFileRequest{ Filename: normaliseFilename(f.File, plan.PathPrefix), SHA: f.Sha, Content: string(content), @@ -353,7 +361,7 @@ func (r resourceDeployment) Create(ctx context.Context, req resource.CreateReque } } - out, err = r.p.client.CreateDeployment(ctx, cdr, plan.TeamID.Value) + out, err = r.client.CreateDeployment(ctx, cdr, plan.TeamID.Value) if err != nil { resp.Diagnostics.AddError( "Error creating deployment", @@ -384,7 +392,7 @@ func (r resourceDeployment) Create(ctx context.Context, req resource.CreateReque // Read will read a file from the filesytem and provide terraform with information about it. // It is called by the provider whenever data source values should be read to update state. -func (r resourceDeployment) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { +func (r *deploymentResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var state Deployment diags := req.State.Get(ctx, &state) resp.Diagnostics.Append(diags...) @@ -392,7 +400,7 @@ func (r resourceDeployment) Read(ctx context.Context, req resource.ReadRequest, return } - out, err := r.p.client.GetDeployment(ctx, state.ID.Value, state.TeamID.Value) + out, err := r.client.GetDeployment(ctx, state.ID.Value, state.TeamID.Value) if client.NotFound(err) { resp.State.RemoveResource(ctx) return @@ -425,7 +433,7 @@ func (r resourceDeployment) Read(ctx context.Context, req resource.ReadRequest, // Update updates the deployment state. // Note that only the `delete_on_destroy` field is updatable, and this does not affect Vercel. So it is just a case // of setting terraform state. -func (r resourceDeployment) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { +func (r *deploymentResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { var plan Deployment diags := req.Plan.Get(ctx, &plan) resp.Diagnostics.Append(diags...) @@ -456,7 +464,7 @@ func (r resourceDeployment) Update(ctx context.Context, req resource.UpdateReque // Delete conditionally deletes a Deployment. // Typically, Vercel users do not delete old Deployments so deployments will be deleted only if delete_on_destroy // parameter is set to true. -func (r resourceDeployment) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { +func (r *deploymentResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { var state Deployment diags := req.State.Get(ctx, &state) resp.Diagnostics.Append(diags...) @@ -465,7 +473,7 @@ func (r resourceDeployment) Delete(ctx context.Context, req resource.DeleteReque } if state.DeleteOnDestroy.Value { - dResp, err := r.p.client.DeleteDeployment(ctx, state.ID.Value, state.TeamID.Value) + dResp, err := r.client.DeleteDeployment(ctx, state.ID.Value, state.TeamID.Value) if err != nil { resp.Diagnostics.AddError( "Error deleting deployment", diff --git a/vercel/resource_dns_record.go b/vercel/resource_dns_record.go index 5d06ae4d..1cde12e2 100644 --- a/vercel/resource_dns_record.go +++ b/vercel/resource_dns_record.go @@ -5,7 +5,6 @@ import ( "fmt" "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" @@ -13,9 +12,37 @@ import ( "github.com/vercel/terraform-provider-vercel/client" ) -type resourceDNSRecordType struct{} +func newDNSRecordResource() resource.Resource { + return &dnsRecordResource{} +} + +type dnsRecordResource struct { + client *client.Client +} + +func (r *dnsRecordResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_dns_record" +} + +func (r *dnsRecordResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*client.Client) + 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 resourceDNSRecordType) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { +func (r *dnsRecordResource) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return tfsdk.Schema{ Description: ` Provides a DNS Record resource. @@ -125,19 +152,8 @@ For more detailed information, please see the [Vercel documentation](https://ver }, nil } -// NewResource instantiates a new Resource of this ResourceType. -func (r resourceDNSRecordType) NewResource(_ context.Context, p provider.Provider) (resource.Resource, diag.Diagnostics) { - return resourceDNSRecord{ - p: *(p.(*vercelProvider)), - }, nil -} - -type resourceDNSRecord struct { - p vercelProvider -} - // ValidateConfig validates the Resource configuration. -func (r resourceDNSRecord) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { +func (r *dnsRecordResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { var config DNSRecord diags := req.Config.Get(ctx, &config) resp.Diagnostics.Append(diags...) @@ -190,15 +206,7 @@ func (r resourceDNSRecord) ValidateConfig(ctx context.Context, req resource.Vali // Create will create a DNS record within Vercel by calling the Vercel API. // This is called automatically by the provider when a new resource should be created. -func (r resourceDNSRecord) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - if !r.p.configured { - resp.Diagnostics.AddError( - "Provider not configured", - "The provider hasn't been configured before apply. This leads to weird stuff happening, so we'd prefer if you didn't do that. Thanks!", - ) - return - } - +func (r *dnsRecordResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var plan DNSRecord diags := req.Plan.Get(ctx, &plan) resp.Diagnostics.Append(diags...) @@ -206,7 +214,7 @@ func (r resourceDNSRecord) Create(ctx context.Context, req resource.CreateReques return } - out, err := r.p.client.CreateDNSRecord(ctx, plan.TeamID.Value, plan.toCreateDNSRecordRequest()) + out, err := r.client.CreateDNSRecord(ctx, plan.TeamID.Value, plan.toCreateDNSRecordRequest()) if err != nil { resp.Diagnostics.AddError( "Error creating DNS Record", @@ -238,7 +246,7 @@ func (r resourceDNSRecord) Create(ctx context.Context, req resource.CreateReques // Read will read a DNS record from the vercel API and provide terraform with information about it. // It is called by the provider whenever values should be read to update state. -func (r resourceDNSRecord) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { +func (r *dnsRecordResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var state DNSRecord diags := req.State.Get(ctx, &state) resp.Diagnostics.Append(diags...) @@ -246,7 +254,7 @@ func (r resourceDNSRecord) Read(ctx context.Context, req resource.ReadRequest, r return } - out, err := r.p.client.GetDNSRecord(ctx, state.ID.Value, state.TeamID.Value) + out, err := r.client.GetDNSRecord(ctx, state.ID.Value, state.TeamID.Value) if client.NotFound(err) { resp.State.RemoveResource(ctx) return @@ -285,7 +293,7 @@ func (r resourceDNSRecord) Read(ctx context.Context, req resource.ReadRequest, r } // Update will update a DNS record via the vercel API. -func (r resourceDNSRecord) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { +func (r *dnsRecordResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { var plan DNSRecord diags := req.Plan.Get(ctx, &plan) resp.Diagnostics.Append(diags...) @@ -300,7 +308,7 @@ func (r resourceDNSRecord) Update(ctx context.Context, req resource.UpdateReques return } - out, err := r.p.client.UpdateDNSRecord( + out, err := r.client.UpdateDNSRecord( ctx, plan.TeamID.Value, state.ID.Value, @@ -341,7 +349,7 @@ func (r resourceDNSRecord) Update(ctx context.Context, req resource.UpdateReques } // Delete a DNS record from within terraform. -func (r resourceDNSRecord) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { +func (r *dnsRecordResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { var state DNSRecord diags := req.State.Get(ctx, &state) resp.Diagnostics.Append(diags...) @@ -349,7 +357,7 @@ func (r resourceDNSRecord) Delete(ctx context.Context, req resource.DeleteReques return } - err := r.p.client.DeleteDNSRecord(ctx, state.Domain.Value, state.ID.Value, state.TeamID.Value) + err := r.client.DeleteDNSRecord(ctx, state.Domain.Value, state.ID.Value, state.TeamID.Value) if client.NotFound(err) { // The DNS Record is already gone - do nothing. return @@ -375,7 +383,7 @@ func (r resourceDNSRecord) Delete(ctx context.Context, req resource.DeleteReques } // ImportState takes an identifier and reads all the DNS Record information from the Vercel API. -func (r resourceDNSRecord) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *dnsRecordResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { teamID, recordID, ok := splitID(req.ID) if !ok { resp.Diagnostics.AddError( @@ -384,7 +392,7 @@ func (r resourceDNSRecord) ImportState(ctx context.Context, req resource.ImportS ) } - out, err := r.p.client.GetDNSRecord(ctx, recordID, teamID) + out, err := r.client.GetDNSRecord(ctx, recordID, teamID) if err != nil { resp.Diagnostics.AddError( "Error reading DNS Record", diff --git a/vercel/resource_project.go b/vercel/resource_project.go index f3be972c..c5578396 100644 --- a/vercel/resource_project.go +++ b/vercel/resource_project.go @@ -7,7 +7,6 @@ import ( "strings" "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" @@ -15,10 +14,38 @@ import ( "github.com/vercel/terraform-provider-vercel/client" ) -type resourceProjectType struct{} +func newProjectResource() resource.Resource { + return &projectResource{} +} + +type projectResource struct { + client *client.Client +} + +func (r *projectResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_project" +} + +func (r *projectResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*client.Client) + 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 +} // GetSchema returns the schema information for a deployment resource. -func (r resourceProjectType) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { +func (r *projectResource) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return tfsdk.Schema{ Description: ` Provides a Project resource. @@ -105,10 +132,9 @@ At this time you cannot use a Vercel Project resource with in-line ` + "`environ Sensitive: true, }, "id": { - Description: "The ID of the Environment Variable.", - Type: types.StringType, - PlanModifiers: tfsdk.AttributePlanModifiers{resource.UseStateForUnknown()}, - Computed: true, + Description: "The ID of the Environment Variable.", + Type: types.StringType, + Computed: true, }, }), }, @@ -171,28 +197,9 @@ At this time you cannot use a Vercel Project resource with in-line ` + "`environ }, nil } -// NewResource instantiates a new Resource of this ResourceType. -func (r resourceProjectType) NewResource(_ context.Context, p provider.Provider) (resource.Resource, diag.Diagnostics) { - return resourceProject{ - p: *(p.(*vercelProvider)), - }, nil -} - -type resourceProject struct { - p vercelProvider -} - // Create will create a project within Vercel by calling the Vercel API. // This is called automatically by the provider when a new resource should be created. -func (r resourceProject) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - if !r.p.configured { - resp.Diagnostics.AddError( - "Provider not configured", - "The provider hasn't been configured before apply. This leads to weird stuff happening, so we'd prefer if you didn't do that. Thanks!", - ) - return - } - +func (r *projectResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var plan Project diags := req.Plan.Get(ctx, &plan) resp.Diagnostics.Append(diags...) @@ -209,7 +216,7 @@ func (r resourceProject) Create(ctx context.Context, req resource.CreateRequest, return } - out, err := r.p.client.CreateProject(ctx, plan.TeamID.Value, plan.toCreateProjectRequest(environment)) + out, err := r.client.CreateProject(ctx, plan.TeamID.Value, plan.toCreateProjectRequest(environment)) if err != nil { resp.Diagnostics.AddError( "Error creating project", @@ -233,7 +240,7 @@ func (r resourceProject) Create(ctx context.Context, req resource.CreateRequest, // Read will read a project from the vercel API and provide terraform with information about it. // It is called by the provider whenever values should be read to update state. -func (r resourceProject) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { +func (r *projectResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var state Project diags := req.State.Get(ctx, &state) resp.Diagnostics.Append(diags...) @@ -241,7 +248,7 @@ func (r resourceProject) Read(ctx context.Context, req resource.ReadRequest, res return } - out, err := r.p.client.GetProject(ctx, state.ID.Value, state.TeamID.Value, !state.Environment.Null) + out, err := r.client.GetProject(ctx, state.ID.Value, state.TeamID.Value, !state.Environment.Null) if client.NotFound(err) { resp.State.RemoveResource(ctx) return @@ -311,7 +318,7 @@ func diffEnvVars(oldVars, newVars []EnvironmentItem) (toCreate, toRemove []Envir // Update will update a project and it's associated environment variables via the vercel API. // Environment variables are manually diffed and updated individually. Once the environment // variables are all updated, the project is updated too. -func (r resourceProject) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { +func (r *projectResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { var plan Project diags := req.Plan.Get(ctx, &plan) resp.Diagnostics.Append(diags...) @@ -351,7 +358,7 @@ func (r resourceProject) Update(ctx context.Context, req resource.UpdateRequest, toCreate, toRemove := diffEnvVars(stateEnvs, planEnvs) for _, v := range toRemove { - err := r.p.client.DeleteEnvironmentVariable(ctx, state.ID.Value, state.TeamID.Value, v.ID.Value) + err := r.client.DeleteEnvironmentVariable(ctx, state.ID.Value, state.TeamID.Value, v.ID.Value) if err != nil { resp.Diagnostics.AddError( "Error updating project", @@ -371,7 +378,7 @@ func (r resourceProject) Update(ctx context.Context, req resource.UpdateRequest, }) } for _, v := range toCreate { - result, err := r.p.client.CreateEnvironmentVariable( + result, err := r.client.CreateEnvironmentVariable( ctx, v.toCreateEnvironmentVariableRequest(plan.ID.Value, plan.TeamID.Value), ) @@ -393,7 +400,7 @@ func (r resourceProject) Update(ctx context.Context, req resource.UpdateRequest, }) } - out, err := r.p.client.UpdateProject(ctx, state.ID.Value, state.TeamID.Value, plan.toUpdateProjectRequest(state.Name.Value), !plan.Environment.Null) + out, err := r.client.UpdateProject(ctx, state.ID.Value, state.TeamID.Value, plan.toUpdateProjectRequest(state.Name.Value), !plan.Environment.Null) if err != nil { resp.Diagnostics.AddError( "Error updating project", @@ -422,7 +429,7 @@ func (r resourceProject) Update(ctx context.Context, req resource.UpdateRequest, // Delete a project and any associated environment variables from within terraform. // Environment variables do not need to be explicitly deleted, as Vercel will automatically prune them. -func (r resourceProject) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { +func (r *projectResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { var state Project diags := req.State.Get(ctx, &state) resp.Diagnostics.Append(diags...) @@ -430,7 +437,7 @@ func (r resourceProject) Delete(ctx context.Context, req resource.DeleteRequest, return } - err := r.p.client.DeleteProject(ctx, state.ID.Value, state.TeamID.Value) + err := r.client.DeleteProject(ctx, state.ID.Value, state.TeamID.Value) if client.NotFound(err) { return } @@ -468,7 +475,7 @@ func splitID(id string) (teamID, _id string, ok bool) { // ImportState takes an identifier and reads all the project information from the Vercel API. // Note that environment variables are also read. The results are then stored in terraform state. -func (r resourceProject) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *projectResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { teamID, projectID, ok := splitID(req.ID) if !ok { resp.Diagnostics.AddError( @@ -477,7 +484,7 @@ func (r resourceProject) ImportState(ctx context.Context, req resource.ImportSta ) } - out, err := r.p.client.GetProject(ctx, projectID, teamID, false) + out, err := r.client.GetProject(ctx, projectID, teamID, false) if err != nil { resp.Diagnostics.AddError( "Error reading project", diff --git a/vercel/resource_project_domain.go b/vercel/resource_project_domain.go index bf30c35c..f5fc207e 100644 --- a/vercel/resource_project_domain.go +++ b/vercel/resource_project_domain.go @@ -6,7 +6,6 @@ import ( "strings" "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" @@ -14,10 +13,38 @@ import ( "github.com/vercel/terraform-provider-vercel/client" ) -type resourceProjectDomainType struct{} +func newProjectDomainResource() resource.Resource { + return &projectDomainResource{} +} + +type projectDomainResource struct { + client *client.Client +} + +func (r *projectDomainResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_project_domain" +} + +func (r *projectDomainResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*client.Client) + 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 +} // GetSchema returns the schema information for a deployment resource. -func (r resourceProjectDomainType) GetSchema(context.Context) (tfsdk.Schema, diag.Diagnostics) { +func (r *projectDomainResource) GetSchema(context.Context) (tfsdk.Schema, diag.Diagnostics) { return tfsdk.Schema{ Description: ` Provides a Project Domain resource. @@ -72,28 +99,9 @@ By default, Project Domains will be automatically applied to any ` + "`productio }, nil } -// NewResource instantiates a new Resource of this ResourceType. -func (r resourceProjectDomainType) NewResource(_ context.Context, p provider.Provider) (resource.Resource, diag.Diagnostics) { - return resourceProjectDomain{ - p: *(p.(*vercelProvider)), - }, nil -} - -type resourceProjectDomain struct { - p vercelProvider -} - // Create will create a project domain within Vercel. // This is called automatically by the provider when a new resource should be created. -func (r resourceProjectDomain) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - if !r.p.configured { - resp.Diagnostics.AddError( - "Provider not configured", - "The provider hasn't been configured before apply. This leads to weird stuff happening, so we'd prefer if you didn't do that. Thanks!", - ) - return - } - +func (r *projectDomainResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var plan ProjectDomain diags := req.Plan.Get(ctx, &plan) resp.Diagnostics.Append(diags...) @@ -101,7 +109,7 @@ func (r resourceProjectDomain) Create(ctx context.Context, req resource.CreateRe return } - _, err := r.p.client.GetProject(ctx, plan.ProjectID.Value, plan.TeamID.Value, false) + _, err := r.client.GetProject(ctx, plan.ProjectID.Value, plan.TeamID.Value, false) if client.NotFound(err) { resp.Diagnostics.AddError( "Error creating project domain", @@ -110,7 +118,7 @@ func (r resourceProjectDomain) Create(ctx context.Context, req resource.CreateRe return } - out, err := r.p.client.CreateProjectDomain(ctx, plan.ProjectID.Value, plan.TeamID.Value, plan.toCreateRequest()) + out, err := r.client.CreateProjectDomain(ctx, plan.ProjectID.Value, plan.TeamID.Value, plan.toCreateRequest()) if err != nil { resp.Diagnostics.AddError( "Error adding domain to project", @@ -140,7 +148,7 @@ func (r resourceProjectDomain) Create(ctx context.Context, req resource.CreateRe // Read will read a project domain from the vercel API and provide terraform with information about it. // It is called by the provider whenever data source values should be read to update state. -func (r resourceProjectDomain) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { +func (r *projectDomainResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var state ProjectDomain diags := req.State.Get(ctx, &state) resp.Diagnostics.Append(diags...) @@ -148,7 +156,7 @@ func (r resourceProjectDomain) Read(ctx context.Context, req resource.ReadReques return } - out, err := r.p.client.GetProjectDomain(ctx, state.ProjectID.Value, state.Domain.Value, state.TeamID.Value) + out, err := r.client.GetProjectDomain(ctx, state.ProjectID.Value, state.Domain.Value, state.TeamID.Value) if client.NotFound(err) { resp.State.RemoveResource(ctx) return @@ -180,7 +188,7 @@ func (r resourceProjectDomain) Read(ctx context.Context, req resource.ReadReques } // Update will update a project domain via the vercel API. -func (r resourceProjectDomain) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { +func (r *projectDomainResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { var plan ProjectDomain diags := req.Plan.Get(ctx, &plan) resp.Diagnostics.Append(diags...) @@ -188,7 +196,7 @@ func (r resourceProjectDomain) Update(ctx context.Context, req resource.UpdateRe return } - out, err := r.p.client.UpdateProjectDomain( + out, err := r.client.UpdateProjectDomain( ctx, plan.ProjectID.Value, plan.Domain.Value, @@ -222,7 +230,7 @@ func (r resourceProjectDomain) Update(ctx context.Context, req resource.UpdateRe } // Delete will remove a project domain via the Vercel API. -func (r resourceProjectDomain) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { +func (r *projectDomainResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { var state ProjectDomain diags := req.State.Get(ctx, &state) resp.Diagnostics.Append(diags...) @@ -230,7 +238,7 @@ func (r resourceProjectDomain) Delete(ctx context.Context, req resource.DeleteRe return } - err := r.p.client.DeleteProjectDomain(ctx, state.ProjectID.Value, state.Domain.Value, state.TeamID.Value) + err := r.client.DeleteProjectDomain(ctx, state.ProjectID.Value, state.Domain.Value, state.TeamID.Value) if client.NotFound(err) { // The domain is already gone - do nothing. resp.State.RemoveResource(ctx) @@ -273,7 +281,7 @@ func splitProjectDomainID(id string) (teamID, projectID, domain string, ok bool) // ImportState takes an identifier and reads all the project domain information from the Vercel API. // Note that environment variables are also read. The results are then stored in terraform state. -func (r resourceProjectDomain) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *projectDomainResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { teamID, projectID, domain, ok := splitProjectDomainID(req.ID) if !ok { resp.Diagnostics.AddError( @@ -282,7 +290,7 @@ func (r resourceProjectDomain) ImportState(ctx context.Context, req resource.Imp ) } - out, err := r.p.client.GetProjectDomain(ctx, projectID, domain, teamID) + out, err := r.client.GetProjectDomain(ctx, projectID, domain, teamID) if err != nil { resp.Diagnostics.AddError( "Error reading project domain", diff --git a/vercel/resource_project_environment_variable.go b/vercel/resource_project_environment_variable.go index 812b93c2..d5de756b 100644 --- a/vercel/resource_project_environment_variable.go +++ b/vercel/resource_project_environment_variable.go @@ -6,7 +6,6 @@ import ( "strings" "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" @@ -14,10 +13,38 @@ import ( "github.com/vercel/terraform-provider-vercel/client" ) -type resourceProjectEnvironmentVariableType struct{} +func newProjectEnvironmentVariableResource() resource.Resource { + return &projectEnvironmentVariableResource{} +} + +type projectEnvironmentVariableResource struct { + client *client.Client +} + +func (r *projectEnvironmentVariableResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_project_environment_variable" +} + +func (r *projectEnvironmentVariableResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*client.Client) + 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 +} // GetSchema returns the schema information for a project environment variable resource. -func (r resourceProjectEnvironmentVariableType) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { +func (r *projectEnvironmentVariableResource) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) { return tfsdk.Schema{ Description: ` Provides a Project Environment Variable resource. @@ -77,28 +104,9 @@ At this time you cannot use a Vercel Project resource with in-line ` + "`environ }, nil } -// NewResource instantiates a new Resource of this ResourceType. -func (r resourceProjectEnvironmentVariableType) NewResource(_ context.Context, p provider.Provider) (resource.Resource, diag.Diagnostics) { - return resourceProjectEnvironmentVariable{ - p: *(p.(*vercelProvider)), - }, nil -} - -type resourceProjectEnvironmentVariable struct { - p vercelProvider -} - // Create will create a new project environment variable for a Vercel project. // This is called automatically by the provider when a new resource should be created. -func (r resourceProjectEnvironmentVariable) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - if !r.p.configured { - resp.Diagnostics.AddError( - "Provider not configured", - "The provider hasn't been configured before apply. This leads to weird stuff happening, so we'd prefer if you didn't do that. Thanks!", - ) - return - } - +func (r *projectEnvironmentVariableResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var plan ProjectEnvironmentVariable diags := req.Plan.Get(ctx, &plan) resp.Diagnostics.Append(diags...) @@ -106,7 +114,7 @@ func (r resourceProjectEnvironmentVariable) Create(ctx context.Context, req reso return } - _, err := r.p.client.GetProject(ctx, plan.ProjectID.Value, plan.TeamID.Value, false) + _, err := r.client.GetProject(ctx, plan.ProjectID.Value, plan.TeamID.Value, false) if client.NotFound(err) { resp.Diagnostics.AddError( "Error creating project environment variable", @@ -115,7 +123,7 @@ func (r resourceProjectEnvironmentVariable) Create(ctx context.Context, req reso return } - response, err := r.p.client.CreateEnvironmentVariable(ctx, plan.toCreateEnvironmentVariableRequest()) + response, err := r.client.CreateEnvironmentVariable(ctx, plan.toCreateEnvironmentVariableRequest()) if err != nil { resp.Diagnostics.AddError( "Error creating project environment variable", @@ -141,7 +149,7 @@ func (r resourceProjectEnvironmentVariable) Create(ctx context.Context, req reso // Read will read an environment variable of a Vercel project by requesting it from the Vercel API, and will update terraform // with this information. -func (r resourceProjectEnvironmentVariable) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { +func (r *projectEnvironmentVariableResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var state ProjectEnvironmentVariable diags := req.State.Get(ctx, &state) resp.Diagnostics.Append(diags...) @@ -149,7 +157,7 @@ func (r resourceProjectEnvironmentVariable) Read(ctx context.Context, req resour return } - out, err := r.p.client.GetEnvironmentVariable(ctx, state.ProjectID.Value, state.TeamID.Value, state.ID.Value) + out, err := r.client.GetEnvironmentVariable(ctx, state.ProjectID.Value, state.TeamID.Value, state.ID.Value) if client.NotFound(err) { resp.State.RemoveResource(ctx) return @@ -182,7 +190,7 @@ func (r resourceProjectEnvironmentVariable) Read(ctx context.Context, req resour } // Update updates the project environment variable of a Vercel project state. -func (r resourceProjectEnvironmentVariable) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { +func (r *projectEnvironmentVariableResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { var plan ProjectEnvironmentVariable diags := req.Plan.Get(ctx, &plan) resp.Diagnostics.Append(diags...) @@ -190,7 +198,7 @@ func (r resourceProjectEnvironmentVariable) Update(ctx context.Context, req reso return } - response, err := r.p.client.UpdateEnvironmentVariable(ctx, plan.toUpdateEnvironmentVariableRequest()) + response, err := r.client.UpdateEnvironmentVariable(ctx, plan.toUpdateEnvironmentVariableRequest()) if err != nil { resp.Diagnostics.AddError( "Error updating project environment variable", @@ -215,7 +223,7 @@ func (r resourceProjectEnvironmentVariable) Update(ctx context.Context, req reso } // Delete deletes a Vercel project environment variable. -func (r resourceProjectEnvironmentVariable) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { +func (r *projectEnvironmentVariableResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { var state ProjectEnvironmentVariable diags := req.State.Get(ctx, &state) resp.Diagnostics.Append(diags...) @@ -223,7 +231,7 @@ func (r resourceProjectEnvironmentVariable) Delete(ctx context.Context, req reso return } - err := r.p.client.DeleteEnvironmentVariable(ctx, state.ProjectID.Value, state.TeamID.Value, state.ID.Value) + err := r.client.DeleteEnvironmentVariable(ctx, state.ProjectID.Value, state.TeamID.Value, state.ID.Value) if client.NotFound(err) { return } @@ -262,7 +270,7 @@ func splitProjectEnvironmentVariableID(id string) (teamID, projectID, envID stri // ImportState takes an identifier and reads all the project environment variable information from the Vercel API. // The results are then stored in terraform state. -func (r resourceProjectEnvironmentVariable) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *projectEnvironmentVariableResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { teamID, projectID, envID, ok := splitProjectEnvironmentVariableID(req.ID) if !ok { resp.Diagnostics.AddError( @@ -271,7 +279,7 @@ func (r resourceProjectEnvironmentVariable) ImportState(ctx context.Context, req ) } - out, err := r.p.client.GetEnvironmentVariable(ctx, projectID, teamID, envID) + out, err := r.client.GetEnvironmentVariable(ctx, projectID, teamID, envID) if err != nil { resp.Diagnostics.AddError( "Error reading project environment variable",