diff --git a/docs/resources/notification.md b/docs/resources/notification.md index 98f79cce..8e3e5c0b 100644 --- a/docs/resources/notification.md +++ b/docs/resources/notification.md @@ -106,7 +106,7 @@ resource "radarr_notification" "example" { - `on_movie_file_delete_for_upgrade` (Boolean) On movie file delete for upgrade flag. - `on_rename` (Boolean) On rename flag. - `on_upgrade` (Boolean) On upgrade flag. -- `password` (String) password. +- `password` (String, Sensitive) password. - `path` (String) Path. - `port` (Number) Port. - `priority` (Number) Priority. diff --git a/docs/resources/notification_webhook.md b/docs/resources/notification_webhook.md index ededd567..6610e1c4 100644 --- a/docs/resources/notification_webhook.md +++ b/docs/resources/notification_webhook.md @@ -61,7 +61,7 @@ resource "radarr_notification_webhook" "example" { - `on_movie_file_delete_for_upgrade` (Boolean) On movie file delete for upgrade flag. - `on_rename` (Boolean) On rename flag. - `on_upgrade` (Boolean) On upgrade flag. -- `password` (String) password. +- `password` (String, Sensitive) password. - `tags` (Set of Number) List of associated tags. - `username` (String) Username. diff --git a/internal/helpers/errors.go b/internal/helpers/errors.go index a56586cb..61e86c54 100644 --- a/internal/helpers/errors.go +++ b/internal/helpers/errors.go @@ -1,7 +1,6 @@ package helpers import ( - "errors" "fmt" "github.com/devopsarr/radarr-go/radarr" @@ -22,12 +21,6 @@ const ( UnexpectedDataSourceConfigureType = "Unexpected DataSource Configure Type" ) -var ErrDataNotFound = errors.New("data source not found") - -func ErrDataNotFoundError(kind, field, search string) error { - return fmt.Errorf("%w: no %s with %s '%s'", ErrDataNotFound, kind, field, search) -} - func ParseNotFoundError(kind, field, search string) string { return fmt.Sprintf("Unable to find %s, got error: data source not found: no %s with %s '%s'", kind, kind, field, search) } diff --git a/internal/helpers/errors_test.go b/internal/helpers/errors_test.go index b888d8e7..8a11b911 100644 --- a/internal/helpers/errors_test.go +++ b/internal/helpers/errors_test.go @@ -8,24 +8,6 @@ import ( "github.com/stretchr/testify/assert" ) -func TestErrDataNotFoundError(t *testing.T) { - t.Parallel() - - tests := map[string]struct { - kind, field, search, expected string - }{ - "tag": {"radarr_tag", "label", "test", "data source not found: no radarr_tag with label 'test'"}, - } - for name, test := range tests { - test := test - - t.Run(name, func(t *testing.T) { - t.Parallel() - assert.Equal(t, test.expected, ErrDataNotFoundError(test.kind, test.field, test.search).Error()) - }) - } -} - func TestParseClientError(t *testing.T) { t.Parallel() @@ -57,3 +39,29 @@ func TestParseClientError(t *testing.T) { }) } } + +func TestParseNotFoundError(t *testing.T) { + t.Parallel() + + tests := map[string]struct { + kind string + field string + search string + expected string + }{ + "generic": { + kind: "radarr_tag", + field: "label", + search: "test", + expected: "Unable to find radarr_tag, got error: data source not found: no radarr_tag with label 'test'", + }, + } + for name, test := range tests { + test := test + + t.Run(name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, test.expected, ParseNotFoundError(test.kind, test.field, test.search)) + }) + } +} diff --git a/internal/provider/custom_format_condition_data_source.go b/internal/provider/custom_format_condition_data_source.go index 43c43981..b140d6eb 100644 --- a/internal/provider/custom_format_condition_data_source.go +++ b/internal/provider/custom_format_condition_data_source.go @@ -5,6 +5,7 @@ import ( "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/path" @@ -43,6 +44,19 @@ type CustomFormatCondition struct { Required types.Bool `tfsdk:"required"` } +func (c CustomFormatCondition) getType() attr.Type { + return types.ObjectType{}.WithAttributeTypes( + map[string]attr.Type{ + "negate": types.BoolType, + "required": types.BoolType, + "min": types.Int64Type, + "max": types.Int64Type, + "name": types.StringType, + "value": types.StringType, + "implementation": types.StringType, + }) +} + // CustomFormatValue describes the custom format value data model. type CustomFormatConditionValue struct { Name types.String `tfsdk:"name"` @@ -142,7 +156,6 @@ func (c *CustomFormatCondition) write(ctx context.Context, spec *radarr.CustomFo func (c *CustomFormatCondition) read(ctx context.Context) *radarr.CustomFormatSpecificationSchema { spec := radarr.NewCustomFormatSpecificationSchema() spec.SetName(c.Name.ValueString()) - spec.SetImplementation(c.Implementation.ValueString()) spec.SetNegate(c.Negate.ValueBool()) spec.SetRequired(c.Required.ValueBool()) diff --git a/internal/provider/custom_format_data_source.go b/internal/provider/custom_format_data_source.go index b9fa713c..a79b3962 100644 --- a/internal/provider/custom_format_data_source.go +++ b/internal/provider/custom_format_data_source.go @@ -2,12 +2,12 @@ package provider import ( "context" - "fmt" "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -109,24 +109,19 @@ func (d *CustomFormatDataSource) Read(ctx context.Context, req datasource.ReadRe return } - customFormat, err := findCustomFormat(data.Name.ValueString(), response) - if err != nil { - resp.Diagnostics.AddError(helpers.DataSourceError, fmt.Sprintf("Unable to find %s, got error: %s", customFormatDataSourceName, err)) - - return - } - + data.find(ctx, data.Name.ValueString(), response, &resp.Diagnostics) tflog.Trace(ctx, "read "+customFormatDataSourceName) - data.write(ctx, customFormat, &resp.Diagnostics) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -func findCustomFormat(name string, customFormats []*radarr.CustomFormatResource) (*radarr.CustomFormatResource, error) { +func (c *CustomFormat) find(ctx context.Context, name string, customFormats []*radarr.CustomFormatResource, diags *diag.Diagnostics) { for _, i := range customFormats { if i.GetName() == name { - return i, nil + c.write(ctx, i, diags) + + return } } - return nil, helpers.ErrDataNotFoundError(customFormatDataSourceName, "name", name) + diags.AddError(helpers.DataSourceError, helpers.ParseNotFoundError(customFormatDataSourceName, "name", name)) } diff --git a/internal/provider/custom_format_resource.go b/internal/provider/custom_format_resource.go index e6c54db7..beb45f7c 100644 --- a/internal/provider/custom_format_resource.go +++ b/internal/provider/custom_format_resource.go @@ -6,13 +6,13 @@ import ( "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "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/int64planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -42,6 +42,16 @@ type CustomFormat struct { IncludeCustomFormatWhenRenaming types.Bool `tfsdk:"include_custom_format_when_renaming"` } +func (c CustomFormat) getType() attr.Type { + return types.ObjectType{}.WithAttributeTypes( + map[string]attr.Type{ + "include_custom_format_when_renaming": types.BoolType, + "id": types.Int64Type, + "name": types.StringType, + "specifications": types.SetType{}.WithElementType(CustomFormatCondition{}.getType()), + }) +} + func (r *CustomFormatResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_" + customFormatResourceName } @@ -240,17 +250,16 @@ func (r *CustomFormatResource) ImportState(ctx context.Context, req resource.Imp func (c *CustomFormat) write(ctx context.Context, customFormat *radarr.CustomFormatResource, diags *diag.Diagnostics) { var tempDiag diag.Diagnostics - c.ID = types.Int64Value(int64(customFormat.GetId())) - c.Name = types.StringValue(customFormat.GetName()) - c.IncludeCustomFormatWhenRenaming = types.BoolValue(customFormat.GetIncludeCustomFormatWhenRenaming()) - c.Specifications = types.SetValueMust(CustomFormatResource{}.getSpecificationSchema().Type(), nil) - specs := make([]CustomFormatCondition, len(customFormat.Specifications)) for n, s := range customFormat.Specifications { specs[n].write(ctx, s) } - tfsdk.ValueFrom(ctx, specs, c.Specifications.Type(ctx), &c.Specifications) + c.ID = types.Int64Value(int64(customFormat.GetId())) + c.Name = types.StringValue(customFormat.GetName()) + c.IncludeCustomFormatWhenRenaming = types.BoolValue(customFormat.GetIncludeCustomFormatWhenRenaming()) + c.Specifications, tempDiag = types.SetValueFrom(ctx, CustomFormatCondition{}.getType(), specs) + diags.Append(tempDiag...) } func (c *CustomFormat) read(ctx context.Context, diags *diag.Diagnostics) *radarr.CustomFormatResource { diff --git a/internal/provider/custom_formats_data_source.go b/internal/provider/custom_formats_data_source.go index 94d6d207..98f4bfdf 100644 --- a/internal/provider/custom_formats_data_source.go +++ b/internal/provider/custom_formats_data_source.go @@ -8,7 +8,6 @@ import ( "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -114,13 +113,6 @@ func (d *CustomFormatsDataSource) Configure(ctx context.Context, req datasource. } func (d *CustomFormatsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var data *CustomFormats - - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - - if resp.Diagnostics.HasError() { - return - } // Get custom formatss current value response, _, err := d.client.CustomFormatApi.ListCustomFormat(ctx).Execute() if err != nil { @@ -131,13 +123,12 @@ func (d *CustomFormatsDataSource) Read(ctx context.Context, req datasource.ReadR tflog.Trace(ctx, "read "+customFormatsDataSourceName) // Map response body to resource schema attribute - profiles := make([]CustomFormat, len(response)) + formats := make([]CustomFormat, len(response)) for i, p := range response { - profiles[i].write(ctx, p, &resp.Diagnostics) + formats[i].write(ctx, p, &resp.Diagnostics) } - tfsdk.ValueFrom(ctx, profiles, data.CustomFormats.Type(ctx), &data.CustomFormats) - // TODO: remove ID once framework support tests without ID https://www.terraform.io/plugin/framework/acctests#implement-id-attribute - data.ID = types.StringValue(strconv.Itoa(len(response))) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + formatList, diags := types.SetValueFrom(ctx, CustomFormat{}.getType(), formats) + resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(resp.State.Set(ctx, CustomFormats{CustomFormats: formatList, ID: types.StringValue(strconv.Itoa(len(response)))})...) } diff --git a/internal/provider/delay_profile_data_source.go b/internal/provider/delay_profile_data_source.go index 13d41584..7ecf33e0 100644 --- a/internal/provider/delay_profile_data_source.go +++ b/internal/provider/delay_profile_data_source.go @@ -2,13 +2,13 @@ package provider import ( "context" - "fmt" "strconv" "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -84,9 +84,9 @@ func (d *DelayProfileDataSource) Configure(ctx context.Context, req datasource.C } func (d *DelayProfileDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var delayProfile *DelayProfile + var data *DelayProfile - resp.Diagnostics.Append(req.Config.Get(ctx, &delayProfile)...) + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) if resp.Diagnostics.HasError() { return @@ -99,24 +99,21 @@ func (d *DelayProfileDataSource) Read(ctx context.Context, req datasource.ReadRe return } - profile, err := findDelayProfile(delayProfile.ID.ValueInt64(), response) - if err != nil { - resp.Diagnostics.AddError(helpers.DataSourceError, fmt.Sprintf("Unable to find %s, got error: %s", delayProfileDataSourceName, err)) - - return - } + data.find(ctx, data.ID.ValueInt64(), response, &resp.Diagnostics) tflog.Trace(ctx, "read "+delayProfileDataSourceName) - delayProfile.write(ctx, profile, &resp.Diagnostics) - resp.Diagnostics.Append(resp.State.Set(ctx, &delayProfile)...) + // Map response body to resource schema attribute + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -func findDelayProfile(id int64, profiles []*radarr.DelayProfileResource) (*radarr.DelayProfileResource, error) { - for _, p := range profiles { - if int64(p.GetId()) == id { - return p, nil +func (p *DelayProfile) find(ctx context.Context, id int64, profiles []*radarr.DelayProfileResource, diags *diag.Diagnostics) { + for _, profile := range profiles { + if int64(profile.GetId()) == id { + p.write(ctx, profile, diags) + + return } } - return nil, helpers.ErrDataNotFoundError(delayProfileDataSourceName, "id", strconv.Itoa(int(id))) + diags.AddError(helpers.DataSourceError, helpers.ParseNotFoundError(delayProfileDataSourceName, "id", strconv.Itoa(int(id)))) } diff --git a/internal/provider/delay_profile_resource.go b/internal/provider/delay_profile_resource.go index e79bbcbd..50c2d8f6 100644 --- a/internal/provider/delay_profile_resource.go +++ b/internal/provider/delay_profile_resource.go @@ -7,6 +7,7 @@ import ( "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -48,6 +49,21 @@ type DelayProfile struct { BypassIfHighestQuality types.Bool `tfsdk:"bypass_if_highest_quality"` } +func (p DelayProfile) getType() attr.Type { + return types.ObjectType{}.WithAttributeTypes( + map[string]attr.Type{ + "tags": types.SetType{}.WithElementType(types.Int64Type), + "preferred_protocol": types.StringType, + "usenet_delay": types.Int64Type, + "torrent_delay": types.Int64Type, + "id": types.Int64Type, + "order": types.Int64Type, + "enable_usenet": types.BoolType, + "enable_torrent": types.BoolType, + "bypass_if_highest_quality": types.BoolType, + }) +} + func (r *DelayProfileResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_" + delayProfileResourceName } @@ -233,7 +249,7 @@ func (r *DelayProfileResource) ImportState(ctx context.Context, req resource.Imp tflog.Trace(ctx, "imported "+delayProfileResourceName+": "+req.ID) } -func (p *DelayProfile) write(ctx context.Context, profile *radarrDelayProfileResource, diags *diag.Diagnostics) { +func (p *DelayProfile) write(ctx context.Context, profile *radarr.DelayProfileResource, diags *diag.Diagnostics) { var tempDiag diag.Diagnostics p.ID = types.Int64Value(int64(profile.GetId())) diff --git a/internal/provider/delay_profiles_data_source.go b/internal/provider/delay_profiles_data_source.go index 911950f2..13f2edb3 100644 --- a/internal/provider/delay_profiles_data_source.go +++ b/internal/provider/delay_profiles_data_source.go @@ -8,7 +8,6 @@ import ( "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -102,13 +101,6 @@ func (d *DelayProfilesDataSource) Configure(ctx context.Context, req datasource. } func (d *DelayProfilesDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var data *DelayProfiles - - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - - if resp.Diagnostics.HasError() { - return - } // Get delayprofiles current value response, _, err := d.client.DelayProfileApi.ListDelayProfile(ctx).Execute() if err != nil { @@ -124,8 +116,7 @@ func (d *DelayProfilesDataSource) Read(ctx context.Context, req datasource.ReadR profiles[i].write(ctx, p, &resp.Diagnostics) } - tfsdk.ValueFrom(ctx, profiles, data.DelayProfiles.Type(ctx), &data.DelayProfiles) - // TODO: remove ID once framework support tests without ID https://www.terraform.io/plugin/framework/acctests#implement-id-attribute - data.ID = types.StringValue(strconv.Itoa(len(response))) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + profileList, diags := types.SetValueFrom(ctx, DelayProfile{}.getType(), profiles) + resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(resp.State.Set(ctx, DelayProfiles{DelayProfiles: profileList, ID: types.StringValue(strconv.Itoa(len(response)))})...) } diff --git a/internal/provider/download_client_data_source.go b/internal/provider/download_client_data_source.go index 9670d8b2..5c42c35d 100644 --- a/internal/provider/download_client_data_source.go +++ b/internal/provider/download_client_data_source.go @@ -2,12 +2,12 @@ package provider import ( "context" - "fmt" "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -263,24 +263,20 @@ func (d *DownloadClientDataSource) Read(ctx context.Context, req datasource.Read return } - downloadClient, err := findDownloadClient(data.Name.ValueString(), response) - if err != nil { - resp.Diagnostics.AddError(helpers.DataSourceError, fmt.Sprintf("Unable to find %s, got error: %s", downloadClientDataSourceName, err)) - - return - } - + data.find(ctx, data.Name.ValueString(), response, &resp.Diagnostics) tflog.Trace(ctx, "read "+downloadClientDataSourceName) - data.write(ctx, downloadClient, &resp.Diagnostics) + // Map response body to resource schema attribute resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -func findDownloadClient(name string, downloadClients []*radarr.DownloadClientResource) (*radarr.DownloadClientResource, error) { - for _, i := range downloadClients { - if i.GetName() == name { - return i, nil +func (d *DownloadClient) find(ctx context.Context, name string, downloadClients []*radarr.DownloadClientResource, diags *diag.Diagnostics) { + for _, client := range downloadClients { + if client.GetName() == name { + d.write(ctx, client, diags) + + return } } - return nil, helpers.ErrDataNotFoundError(downloadClientDataSourceName, "name", name) + diags.AddError(helpers.DataSourceError, helpers.ParseNotFoundError(downloadClientDataSourceName, "name", name)) } diff --git a/internal/provider/download_client_resource.go b/internal/provider/download_client_resource.go index 8088c816..17c33afb 100644 --- a/internal/provider/download_client_resource.go +++ b/internal/provider/download_client_resource.go @@ -8,6 +8,7 @@ import ( "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -98,6 +99,61 @@ type DownloadClient struct { RemoveCompletedDownloads types.Bool `tfsdk:"remove_completed_downloads"` } +func (d DownloadClient) getType() attr.Type { + return types.ObjectType{}.WithAttributeTypes( + map[string]attr.Type{ + "tags": types.SetType{}.WithElementType(types.Int64Type), + "additional_tags": types.SetType{}.WithElementType(types.Int64Type), + "post_import_tags": types.SetType{}.WithElementType(types.StringType), + "field_tags": types.SetType{}.WithElementType(types.StringType), + "nzb_folder": types.StringType, + "category": types.StringType, + "implementation": types.StringType, + "name": types.StringType, + "protocol": types.StringType, + "magnet_file_extension": types.StringType, + "torrent_folder": types.StringType, + "strm_folder": types.StringType, + "host": types.StringType, + "config_contract": types.StringType, + "destination": types.StringType, + "movie_directory": types.StringType, + "username": types.StringType, + "movie_imported_category": types.StringType, + "movie_category": types.StringType, + "password": types.StringType, + "secret_token": types.StringType, + "rpc_path": types.StringType, + "url_base": types.StringType, + "api_url": types.StringType, + "api_key": types.StringType, + "app_id": types.StringType, + "app_token": types.StringType, + "watch_folder": types.StringType, + "destination_directory": types.StringType, + "recent_priority": types.Int64Type, + "older_priority": types.Int64Type, + "recent_movie_priority": types.Int64Type, + "intial_state": types.Int64Type, + "initial_state": types.Int64Type, + "older_movie_priority": types.Int64Type, + "priority": types.Int64Type, + "port": types.Int64Type, + "id": types.Int64Type, + "add_stopped": types.BoolType, + "save_magnet_files": types.BoolType, + "read_only": types.BoolType, + "first_and_last": types.BoolType, + "sequential_order": types.BoolType, + "start_on_add": types.BoolType, + "use_ssl": types.BoolType, + "add_paused": types.BoolType, + "enable": types.BoolType, + "remove_failed_downloads": types.BoolType, + "remove_completed_downloads": types.BoolType, + }) +} + func (r *DownloadClientResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_" + downloadClientResourceName } diff --git a/internal/provider/download_clients_data_source.go b/internal/provider/download_clients_data_source.go index f8b39bdb..d31d8476 100644 --- a/internal/provider/download_clients_data_source.go +++ b/internal/provider/download_clients_data_source.go @@ -8,7 +8,6 @@ import ( "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -267,13 +266,6 @@ func (d *DownloadClientsDataSource) Configure(ctx context.Context, req datasourc } func (d *DownloadClientsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var data *DownloadClients - - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - - if resp.Diagnostics.HasError() { - return - } // Get download clients current value response, _, err := d.client.DownloadClientApi.ListDownloadClient(ctx).Execute() if err != nil { @@ -284,13 +276,12 @@ func (d *DownloadClientsDataSource) Read(ctx context.Context, req datasource.Rea tflog.Trace(ctx, "read "+downloadClientsDataSourceName) // Map response body to resource schema attribute - profiles := make([]DownloadClient, len(response)) - for i, p := range response { - profiles[i].write(ctx, p, &resp.Diagnostics) + clients := make([]DownloadClient, len(response)) + for i, d := range response { + clients[i].write(ctx, d, &resp.Diagnostics) } - tfsdk.ValueFrom(ctx, profiles, data.DownloadClients.Type(ctx), &data.DownloadClients) - // TODO: remove ID once framework support tests without ID https://www.terraform.io/plugin/framework/acctests#implement-id-attribute - data.ID = types.StringValue(strconv.Itoa(len(response))) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + clientList, diags := types.SetValueFrom(ctx, DownloadClient{}.getType(), clients) + resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(resp.State.Set(ctx, DownloadClients{DownloadClients: clientList, ID: types.StringValue(strconv.Itoa(len(response)))})...) } diff --git a/internal/provider/import_list_data_source.go b/internal/provider/import_list_data_source.go index 341659a2..1c892d9b 100644 --- a/internal/provider/import_list_data_source.go +++ b/internal/provider/import_list_data_source.go @@ -2,12 +2,12 @@ package provider import ( "context" - "fmt" "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -292,24 +292,20 @@ func (d *ImportListDataSource) Read(ctx context.Context, req datasource.ReadRequ return } - importList, err := findImportList(data.Name.ValueString(), response) - if err != nil { - resp.Diagnostics.AddError(helpers.DataSourceError, fmt.Sprintf("Unable to find %s, got error: %s", importListDataSourceName, err)) - - return - } - + data.find(ctx, data.Name.ValueString(), response, &resp.Diagnostics) tflog.Trace(ctx, "read "+importListDataSourceName) - data.write(ctx, importList, &resp.Diagnostics) + // Map response body to resource schema attribute resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -func findImportList(name string, importLists []*radarr.ImportListResource) (*radarr.ImportListResource, error) { - for _, i := range importLists { - if i.GetName() == name { - return i, nil +func (i *ImportList) find(ctx context.Context, name string, importLists []*radarr.ImportListResource, diags *diag.Diagnostics) { + for _, list := range importLists { + if list.GetName() == name { + i.write(ctx, list, diags) + + return } } - return nil, helpers.ErrDataNotFoundError(importListDataSourceName, "name", name) + diags.AddError(helpers.DataSourceError, helpers.ParseNotFoundError(importListDataSourceName, "name", name)) } diff --git a/internal/provider/import_list_exclusion_data_source.go b/internal/provider/import_list_exclusion_data_source.go index 3845b143..2eec7aa2 100644 --- a/internal/provider/import_list_exclusion_data_source.go +++ b/internal/provider/import_list_exclusion_data_source.go @@ -2,13 +2,13 @@ package provider import ( "context" - "fmt" "strconv" "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -61,9 +61,9 @@ func (d *ImportListExclusionDataSource) Configure(ctx context.Context, req datas } func (d *ImportListExclusionDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var importListExclusion *ImportListExclusion + var data *ImportListExclusion - resp.Diagnostics.Append(req.Config.Get(ctx, &importListExclusion)...) + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) if resp.Diagnostics.HasError() { return @@ -77,25 +77,20 @@ func (d *ImportListExclusionDataSource) Read(ctx context.Context, req datasource return } - value, err := findImportListExclusion(importListExclusion.TMDBID.ValueInt64(), response) - if err != nil { - resp.Diagnostics.AddError(helpers.DataSourceError, fmt.Sprintf("Unable to find %s, got error: %s", importListExclusionDataSourceName, err)) - - return - } - + data.find(data.TMDBID.ValueInt64(), response, &resp.Diagnostics) tflog.Trace(ctx, "read "+importListExclusionDataSourceName) - importListExclusion.write(value) // Map response body to resource schema attribute - resp.Diagnostics.Append(resp.State.Set(ctx, &importListExclusion)...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -func findImportListExclusion(tvID int64, importListExclusions []*radarr.ImportExclusionsResource) (*radarr.ImportExclusionsResource, error) { +func (i *ImportListExclusion) find(tmdbID int64, importListExclusions []*radarr.ImportExclusionsResource, diags *diag.Diagnostics) { for _, t := range importListExclusions { - if t.GetTmdbId() == int32(tvID) { - return t, nil + if t.GetTmdbId() == int32(tmdbID) { + i.write(t) + + return } } - return nil, helpers.ErrDataNotFoundError(importListExclusionDataSourceName, "tmdb_id", strconv.Itoa(int(tvID))) + diags.AddError(helpers.DataSourceError, helpers.ParseNotFoundError(importListExclusionDataSourceName, "tmdb_id", strconv.Itoa(int(tmdbID)))) } diff --git a/internal/provider/import_list_exclusion_resource.go b/internal/provider/import_list_exclusion_resource.go index 17b81b41..dd07a797 100644 --- a/internal/provider/import_list_exclusion_resource.go +++ b/internal/provider/import_list_exclusion_resource.go @@ -6,6 +6,7 @@ import ( "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" @@ -40,6 +41,16 @@ type ImportListExclusion struct { ID types.Int64 `tfsdk:"id"` } +func (i ImportListExclusion) getType() attr.Type { + return types.ObjectType{}.WithAttributeTypes( + map[string]attr.Type{ + "id": types.Int64Type, + "tmdb_id": types.Int64Type, + "year": types.Int64Type, + "title": types.StringType, + }) +} + func (r *ImportListExclusionResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_" + importListExclusionResourceName } diff --git a/internal/provider/import_list_exclusions_data_source.go b/internal/provider/import_list_exclusions_data_source.go index e91d20ec..f956330b 100644 --- a/internal/provider/import_list_exclusions_data_source.go +++ b/internal/provider/import_list_exclusions_data_source.go @@ -8,7 +8,6 @@ import ( "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -80,14 +79,6 @@ func (d *ImportListExclusionsDataSource) Configure(ctx context.Context, req data } func (d *ImportListExclusionsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var data *ImportListExclusions - - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - - if resp.Diagnostics.HasError() { - return - } - // Get importListExclusions current value response, _, err := d.client.ImportExclusionsApi.ListExclusions(ctx).Execute() if err != nil { @@ -103,8 +94,7 @@ func (d *ImportListExclusionsDataSource) Read(ctx context.Context, req datasourc importListExclusions[i].write(t) } - tfsdk.ValueFrom(ctx, importListExclusions, data.ImportListExclusions.Type(ctx), &data.ImportListExclusions) - // TODO: remove ID once framework support tests without ID https://www.terraform.io/plugin/framework/acctests#implement-id-attribute - data.ID = types.StringValue(strconv.Itoa(len(response))) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + exclusionList, diags := types.SetValueFrom(ctx, ImportListExclusion{}.getType(), importListExclusions) + resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(resp.State.Set(ctx, ImportListExclusions{ImportListExclusions: exclusionList, ID: types.StringValue(strconv.Itoa(len(response)))})...) } diff --git a/internal/provider/import_list_resource.go b/internal/provider/import_list_resource.go index e543317d..e26beeca 100644 --- a/internal/provider/import_list_resource.go +++ b/internal/provider/import_list_resource.go @@ -7,6 +7,7 @@ import ( "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -104,6 +105,68 @@ type ImportList struct { PersonCastWriting types.Bool `tfsdk:"cast_writing"` } +func (i ImportList) getType() attr.Type { + return types.ObjectType{}.WithAttributeTypes( + map[string]attr.Type{ + "tag_ids": types.SetType{}.WithElementType(types.Int64Type), + "tags": types.SetType{}.WithElementType(types.Int64Type), + "profile_ids": types.SetType{}.WithElementType(types.Int64Type), + "name": types.StringType, + "config_contract": types.StringType, + "implementation": types.StringType, + "monitor": types.StringType, + "minimum_availability": types.StringType, + "root_folder_path": types.StringType, + "list_type": types.StringType, + "trakt_additional_parameters": types.StringType, + "certification": types.StringType, + "genres": types.StringType, + "years": types.StringType, + "rating": types.StringType, + "min_vote_average": types.StringType, + "min_votes": types.StringType, + "tmdb_certification": types.StringType, + "include_genre_ids": types.StringType, + "exclude_genre_ids": types.StringType, + "auth_user": types.StringType, + "username": types.StringType, + "listname": types.StringType, + "keyword_id": types.StringType, + "company_id": types.StringType, + "list_id": types.StringType, + "person_id": types.StringType, + "account_id": types.StringType, + "access_token": types.StringType, + "refresh_token": types.StringType, + "expires": types.StringType, + "base_url": types.StringType, + "url_base": types.StringType, + "url": types.StringType, + "link": types.StringType, + "api_key": types.StringType, + "list_order": types.Int64Type, + "id": types.Int64Type, + "quality_profile_id": types.Int64Type, + "port": types.Int64Type, + "source": types.Int64Type, + "min_score": types.Int64Type, + "tmdb_list_type": types.Int64Type, + "user_list_type": types.Int64Type, + "limit": types.Int64Type, + "trakt_list_type": types.Int64Type, + "language_code": types.Int64Type, + "enabled": types.BoolType, + "enable_auto": types.BoolType, + "search_on_add": types.BoolType, + "only_active": types.BoolType, + "cast": types.BoolType, + "cast_director": types.BoolType, + "cast_producer": types.BoolType, + "cast_sound": types.BoolType, + "cast_writing": types.BoolType, + }) +} + func (r *ImportListResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_" + importListResourceName } diff --git a/internal/provider/import_lists_data_source.go b/internal/provider/import_lists_data_source.go index cb5b64fd..a403a151 100644 --- a/internal/provider/import_lists_data_source.go +++ b/internal/provider/import_lists_data_source.go @@ -8,7 +8,6 @@ import ( "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -296,13 +295,6 @@ func (d *ImportListsDataSource) Configure(ctx context.Context, req datasource.Co } func (d *ImportListsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var data *ImportLists - - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - - if resp.Diagnostics.HasError() { - return - } // Get import lists current value response, _, err := d.client.ImportListApi.ListImportList(ctx).Execute() if err != nil { @@ -318,8 +310,7 @@ func (d *ImportListsDataSource) Read(ctx context.Context, req datasource.ReadReq importLists[i].write(ctx, d, &resp.Diagnostics) } - tfsdk.ValueFrom(ctx, importLists, data.ImportLists.Type(ctx), &data.ImportLists) - // TODO: remove ID once framework support tests without ID https://www.terraform.io/plugin/framework/acctests#implement-id-attribute - data.ID = types.StringValue(strconv.Itoa(len(response))) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + listList, diags := types.SetValueFrom(ctx, ImportList{}.getType(), importLists) + resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(resp.State.Set(ctx, ImportLists{ImportLists: listList, ID: types.StringValue(strconv.Itoa(len(response)))})...) } diff --git a/internal/provider/indexer_data_source.go b/internal/provider/indexer_data_source.go index 5ac18efc..a4dacb89 100644 --- a/internal/provider/indexer_data_source.go +++ b/internal/provider/indexer_data_source.go @@ -2,12 +2,12 @@ package provider import ( "context" - "fmt" "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -200,24 +200,20 @@ func (d *IndexerDataSource) Read(ctx context.Context, req datasource.ReadRequest return } - indexer, err := findIndexer(data.Name.ValueString(), response) - if err != nil { - resp.Diagnostics.AddError(helpers.DataSourceError, fmt.Sprintf("Unable to find %s, got error: %s", indexerDataSourceName, err)) - - return - } - + data.find(ctx, data.Name.ValueString(), response, &resp.Diagnostics) tflog.Trace(ctx, "read "+indexerDataSourceName) - data.write(ctx, indexer, &resp.Diagnostics) + // Map response body to resource schema attribute resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -func findIndexer(name string, indexers []*radarr.IndexerResource) (*radarr.IndexerResource, error) { - for _, i := range indexers { - if i.GetName() == name { - return i, nil +func (i *Indexer) find(ctx context.Context, name string, indexers []*radarr.IndexerResource, diags *diag.Diagnostics) { + for _, indexer := range indexers { + if indexer.GetName() == name { + i.write(ctx, indexer, diags) + + return } } - return nil, helpers.ErrDataNotFoundError(indexerDataSourceName, "name", name) + diags.AddError(helpers.DataSourceError, helpers.ParseNotFoundError(indexerDataSourceName, "name", name)) } diff --git a/internal/provider/indexer_resource.go b/internal/provider/indexer_resource.go index f63de89d..f8c9742f 100644 --- a/internal/provider/indexer_resource.go +++ b/internal/provider/indexer_resource.go @@ -7,6 +7,7 @@ import ( "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -82,6 +83,45 @@ type Indexer struct { RemoveYear types.Bool `tfsdk:"remove_year"` } +func (i Indexer) getType() attr.Type { + return types.ObjectType{}.WithAttributeTypes( + map[string]attr.Type{ + "tags": types.SetType{}.WithElementType(types.Int64Type), + "categories": types.SetType{}.WithElementType(types.Int64Type), + "mediums": types.SetType{}.WithElementType(types.Int64Type), + "codecs": types.SetType{}.WithElementType(types.Int64Type), + "required_flags": types.SetType{}.WithElementType(types.Int64Type), + "multi_languages": types.SetType{}.WithElementType(types.Int64Type), + "cookie": types.StringType, + "api_key": types.StringType, + "config_contract": types.StringType, + "implementation": types.StringType, + "protocol": types.StringType, + "username": types.StringType, + "user": types.StringType, + "passkey": types.StringType, + "base_url": types.StringType, + "captcha_token": types.StringType, + "additional_parameters": types.StringType, + "api_path": types.StringType, + "api_user": types.StringType, + "name": types.StringType, + "priority": types.Int64Type, + "seed_time": types.Int64Type, + "minimum_seeders": types.Int64Type, + "download_client_id": types.Int64Type, + "delay": types.Int64Type, + "id": types.Int64Type, + "seed_ratio": types.Float64Type, + "allow_zero_size": types.BoolType, + "ranked_only": types.BoolType, + "enable_rss": types.BoolType, + "enable_automatic_search": types.BoolType, + "enable_interactive_search": types.BoolType, + "remove_year": types.BoolType, + }) +} + func (r *IndexerResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_" + indexerResourceName } diff --git a/internal/provider/indexers_data_source.go b/internal/provider/indexers_data_source.go index 177a8d08..b286f88f 100644 --- a/internal/provider/indexers_data_source.go +++ b/internal/provider/indexers_data_source.go @@ -8,7 +8,6 @@ import ( "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -204,13 +203,6 @@ func (d *IndexersDataSource) Configure(ctx context.Context, req datasource.Confi } func (d *IndexersDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var data *Indexers - - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - - if resp.Diagnostics.HasError() { - return - } // Get indexers current value response, _, err := d.client.IndexerApi.ListIndexer(ctx).Execute() if err != nil { @@ -221,14 +213,12 @@ func (d *IndexersDataSource) Read(ctx context.Context, req datasource.ReadReques tflog.Trace(ctx, "read "+indexersDataSourceName) // Map response body to resource schema attribute - profiles := make([]Indexer, len(response)) + indexers := make([]Indexer, len(response)) for i, p := range response { - profiles[i].write(ctx, p, &resp.Diagnostics) - + indexers[i].write(ctx, p, &resp.Diagnostics) } - tfsdk.ValueFrom(ctx, profiles, data.Indexers.Type(ctx), &data.Indexers) - // TODO: remove ID once framework support tests without ID https://www.terraform.io/plugin/framework/acctests#implement-id-attribute - data.ID = types.StringValue(strconv.Itoa(len(response))) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + indexerList, diags := types.SetValueFrom(ctx, Indexer{}.getType(), indexers) + resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(resp.State.Set(ctx, Indexers{Indexers: indexerList, ID: types.StringValue(strconv.Itoa(len(response)))})...) } diff --git a/internal/provider/language_data_source.go b/internal/provider/language_data_source.go index 6d4145aa..f896fbe4 100644 --- a/internal/provider/language_data_source.go +++ b/internal/provider/language_data_source.go @@ -2,12 +2,13 @@ package provider import ( "context" - "fmt" "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -33,6 +34,15 @@ type Language struct { ID types.Int64 `tfsdk:"id"` } +func (l Language) getType() attr.Type { + return types.ObjectType{}.WithAttributeTypes( + map[string]attr.Type{ + "id": types.Int64Type, + "name": types.StringType, + "name_lower": types.StringType, + }) +} + func (d *LanguageDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_" + languageDataSourceName } @@ -64,9 +74,9 @@ func (d *LanguageDataSource) Configure(ctx context.Context, req datasource.Confi } func (d *LanguageDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var language *Language + var data *Language - resp.Diagnostics.Append(req.Config.Get(ctx, &language)...) + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) if resp.Diagnostics.HasError() { return @@ -80,17 +90,10 @@ func (d *LanguageDataSource) Read(ctx context.Context, req datasource.ReadReques return } - value, err := findLanguage(language.Name.ValueString(), response) - if err != nil { - resp.Diagnostics.AddError(helpers.DataSourceError, fmt.Sprintf("Unable to find %s, got error: %s", languageDataSourceName, err)) - - return - } - + data.find(data.Name.ValueString(), response, &resp.Diagnostics) tflog.Trace(ctx, "read "+languageDataSourceName) - language.write(value) // Map response body to resource schema attribute - resp.Diagnostics.Append(resp.State.Set(ctx, &language)...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } func (l *Language) write(language *radarr.LanguageResource) { @@ -99,12 +102,14 @@ func (l *Language) write(language *radarr.LanguageResource) { l.NameLower = types.StringValue(language.GetNameLower()) } -func findLanguage(name string, languages []*radarr.LanguageResource) (*radarr.LanguageResource, error) { - for _, t := range languages { - if t.GetName() == name { - return t, nil +func (l *Language) find(name string, languages []*radarr.LanguageResource, diags *diag.Diagnostics) { + for _, language := range languages { + if language.GetName() == name { + l.write(language) + + return } } - return nil, helpers.ErrDataNotFoundError(languageDataSourceName, "name", name) + diags.AddError(helpers.DataSourceError, helpers.ParseNotFoundError(languageDataSourceName, "name", name)) } diff --git a/internal/provider/languages_data_source.go b/internal/provider/languages_data_source.go index 319be62e..f4b7ac71 100644 --- a/internal/provider/languages_data_source.go +++ b/internal/provider/languages_data_source.go @@ -8,7 +8,6 @@ import ( "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -76,14 +75,6 @@ func (d *LanguagesDataSource) Configure(ctx context.Context, req datasource.Conf } func (d *LanguagesDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var data *Languages - - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - - if resp.Diagnostics.HasError() { - return - } - // Get languages current value response, _, err := d.client.LanguageApi.ListLanguage(ctx).Execute() if err != nil { @@ -99,8 +90,7 @@ func (d *LanguagesDataSource) Read(ctx context.Context, req datasource.ReadReque languages[i].write(t) } - tfsdk.ValueFrom(ctx, languages, data.Languages.Type(ctx), &data.Languages) - // TODO: remove ID once framework support tests without ID https://www.terraform.io/plugin/framework/acctests#implement-id-attribute - data.ID = types.StringValue(strconv.Itoa(len(response))) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + languageList, diags := types.SetValueFrom(ctx, Language{}.getType(), languages) + resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(resp.State.Set(ctx, Languages{Languages: languageList, ID: types.StringValue(strconv.Itoa(len(response)))})...) } diff --git a/internal/provider/metadata_consumers_data_source.go b/internal/provider/metadata_consumers_data_source.go index b559b14e..f7b8dc8b 100644 --- a/internal/provider/metadata_consumers_data_source.go +++ b/internal/provider/metadata_consumers_data_source.go @@ -8,7 +8,6 @@ import ( "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -115,13 +114,6 @@ func (d *MetadataConsumersDataSource) Configure(ctx context.Context, req datasou } func (d *MetadataConsumersDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var data *MetadataConsumers - - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - - if resp.Diagnostics.HasError() { - return - } // Get metadataConsumers current value response, _, err := d.client.MetadataApi.ListMetadata(ctx).Execute() if err != nil { @@ -132,13 +124,12 @@ func (d *MetadataConsumersDataSource) Read(ctx context.Context, req datasource.R tflog.Trace(ctx, "read "+metadataConsumersDataSourceName) // Map response body to resource schema attribute - profiles := make([]Metadata, len(response)) + consumers := make([]Metadata, len(response)) for i, p := range response { - profiles[i].write(ctx, p, &resp.Diagnostics) + consumers[i].write(ctx, p, &resp.Diagnostics) } - tfsdk.ValueFrom(ctx, profiles, data.MetadataConsumers.Type(ctx), &data.MetadataConsumers) - // TODO: remove ID once framework support tests without ID https://www.terraform.io/plugin/framework/acctests#implement-id-attribute - data.ID = types.StringValue(strconv.Itoa(len(response))) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + metadataList, diags := types.SetValueFrom(ctx, Metadata{}.getType(), consumers) + resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(resp.State.Set(ctx, MetadataConsumers{MetadataConsumers: metadataList, ID: types.StringValue(strconv.Itoa(len(response)))})...) } diff --git a/internal/provider/metadata_data_source.go b/internal/provider/metadata_data_source.go index 502edbc7..952111e8 100644 --- a/internal/provider/metadata_data_source.go +++ b/internal/provider/metadata_data_source.go @@ -2,12 +2,12 @@ package provider import ( "context" - "fmt" "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -111,24 +111,20 @@ func (d *MetadataDataSource) Read(ctx context.Context, req datasource.ReadReques return } - metadata, err := findMetadata(data.Name.ValueString(), response) - if err != nil { - resp.Diagnostics.AddError(helpers.DataSourceError, fmt.Sprintf("Unable to find %s, got error: %s", metadataDataSourceName, err)) - - return - } - + data.find(ctx, data.Name.ValueString(), response, &resp.Diagnostics) tflog.Trace(ctx, "read "+metadataDataSourceName) - data.write(ctx, metadata, &resp.Diagnostics) + // Map response body to resource schema attribute resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -func findMetadata(name string, metadatas []*radarr.MetadataResource) (*radarr.MetadataResource, error) { - for _, i := range metadatas { - if i.GetName() == name { - return i, nil +func (m *Metadata) find(ctx context.Context, name string, metadatas []*radarr.MetadataResource, diags *diag.Diagnostics) { + for _, metadata := range metadatas { + if metadata.GetName() == name { + m.write(ctx, metadata, diags) + + return } } - return nil, helpers.ErrDataNotFoundError(metadataDataSourceName, "name", name) + diags.AddError(helpers.DataSourceError, helpers.ParseNotFoundError(metadataDataSourceName, "name", name)) } diff --git a/internal/provider/metadata_resource.go b/internal/provider/metadata_resource.go index 87b4c80f..a67a570e 100644 --- a/internal/provider/metadata_resource.go +++ b/internal/provider/metadata_resource.go @@ -6,6 +6,7 @@ import ( "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -54,6 +55,24 @@ type Metadata struct { AddCollectionName types.Bool `tfsdk:"add_collection_name"` } +func (m Metadata) getType() attr.Type { + return types.ObjectType{}.WithAttributeTypes( + map[string]attr.Type{ + "tags": types.SetType{}.WithElementType(types.Int64Type), + "name": types.StringType, + "config_contract": types.StringType, + "implementation": types.StringType, + "id": types.Int64Type, + "movie_metadata_language": types.Int64Type, + "enable": types.BoolType, + "movie_metadata": types.BoolType, + "movie_metadata_url": types.BoolType, + "movie_images": types.BoolType, + "use_movie_nfo": types.BoolType, + "add_collection_name": types.BoolType, + }) +} + func (r *MetadataResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_" + metadataResourceName } @@ -247,14 +266,13 @@ func (r *MetadataResource) ImportState(ctx context.Context, req resource.ImportS func (m *Metadata) write(ctx context.Context, metadata *radarr.MetadataResource, diags *diag.Diagnostics) { var localDiag diag.Diagnostics - m.Tags, localDiag = types.SetValueFrom(ctx, types.Int64Type, metadata.Tags) - diags.Append(localDiag...) - m.Enable = types.BoolValue(metadata.GetEnable()) m.ID = types.Int64Value(int64(metadata.GetId())) m.ConfigContract = types.StringValue(metadata.GetConfigContract()) m.Implementation = types.StringValue(metadata.GetImplementation()) m.Name = types.StringValue(metadata.GetName()) + m.Tags, localDiag = types.SetValueFrom(ctx, types.Int64Type, metadata.Tags) + diags.Append(localDiag...) helpers.WriteFields(ctx, m, metadata.GetFields(), metadataFields) } diff --git a/internal/provider/movie_data_source.go b/internal/provider/movie_data_source.go index 8b5dfcd6..458eafe2 100644 --- a/internal/provider/movie_data_source.go +++ b/internal/provider/movie_data_source.go @@ -2,13 +2,13 @@ package provider import ( "context" - "fmt" "strconv" "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -131,9 +131,9 @@ func (d *MovieDataSource) Configure(ctx context.Context, req datasource.Configur } func (d *MovieDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var movie *Movie + var data *Movie - resp.Diagnostics.Append(req.Config.Get(ctx, &movie)...) + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) if resp.Diagnostics.HasError() { return @@ -147,25 +147,20 @@ func (d *MovieDataSource) Read(ctx context.Context, req datasource.ReadRequest, return } - value, err := findMovie(movie.TMDBID.ValueInt64(), response) - if err != nil { - resp.Diagnostics.AddError(helpers.DataSourceError, fmt.Sprintf("Unable to find %s, got error: %s", movieDataSourceName, err)) - - return - } - - tflog.Trace(ctx, "read "+movieDataSourceName) - movie.write(ctx, value) + data.find(ctx, data.TMDBID.ValueInt64(), response, &resp.Diagnostics) + tflog.Trace(ctx, "read "+tagDataSourceName) // Map response body to resource schema attribute - resp.Diagnostics.Append(resp.State.Set(ctx, &movie)...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -func findMovie(ID int64, movies []*radarr.MovieResource) (*radarr.MovieResource, error) { +func (m *Movie) find(ctx context.Context, ID int64, movies []*radarr.MovieResource, diags *diag.Diagnostics) { for _, t := range movies { if t.GetTmdbId() == int32(ID) { - return t, nil + m.write(ctx, t, diags) + + return } } - return nil, helpers.ErrDataNotFoundError(movieDataSourceName, "TMDB ID", strconv.Itoa(int(ID))) + diags.AddError(helpers.DataSourceError, helpers.ParseNotFoundError(movieDataSourceName, "TMDB ID", strconv.Itoa(int(ID)))) } diff --git a/internal/provider/movie_resource.go b/internal/provider/movie_resource.go index 40decbe7..d718cd87 100644 --- a/internal/provider/movie_resource.go +++ b/internal/provider/movie_resource.go @@ -8,13 +8,14 @@ import ( "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" "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/int64planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -78,6 +79,30 @@ type Movie struct { // Collection types.Object `tfsdk:"collection"` } +func (m Movie) getType() attr.Type { + return types.ObjectType{}.WithAttributeTypes( + map[string]attr.Type{ + "genres": types.SetType{}.WithElementType(types.StringType), + "tags": types.SetType{}.WithElementType(types.Int64Type), + "original_language": QualityLanguage{}.getType(), + "title": types.StringType, + "path": types.StringType, + "minimum_availability": types.StringType, + "original_title": types.StringType, + "status": types.StringType, + "imdb_id": types.StringType, + "youtube_trailer_id": types.StringType, + "overview": types.StringType, + "website": types.StringType, + "id": types.Int64Type, + "quality_profile_id": types.Int64Type, + "tmdb_id": types.Int64Type, + "year": types.Int64Type, + "is_available": types.BoolType, + "monitored": types.BoolType, + }) +} + func (r *MovieResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_" + movieResourceName } @@ -190,7 +215,7 @@ func (r *MovieResource) Create(ctx context.Context, req resource.CreateRequest, } // Create new Movie - request := movie.read(ctx) + request := movie.read(ctx, &resp.Diagnostics) // TODO: can parametrize AddMovieOptions options := radarr.NewAddMovieOptions() options.SetMonitor(radarr.MONITORTYPES_MOVIE_ONLY) @@ -205,7 +230,7 @@ func (r *MovieResource) Create(ctx context.Context, req resource.CreateRequest, tflog.Trace(ctx, "created movie: "+strconv.Itoa(int(response.GetId()))) // Generate resource state struct - movie.write(ctx, response) + movie.write(ctx, response, &resp.Diagnostics) resp.Diagnostics.Append(resp.State.Set(ctx, &movie)...) } @@ -229,7 +254,7 @@ func (r *MovieResource) Read(ctx context.Context, req resource.ReadRequest, resp tflog.Trace(ctx, "read "+movieResourceName+": "+strconv.Itoa(int(response.GetId()))) // Map response body to resource schema attribute - movie.write(ctx, response) + movie.write(ctx, response, &resp.Diagnostics) resp.Diagnostics.Append(resp.State.Set(ctx, &movie)...) } @@ -244,7 +269,7 @@ func (r *MovieResource) Update(ctx context.Context, req resource.UpdateRequest, } // Update Movie - request := movie.read(ctx) + request := movie.read(ctx, &resp.Diagnostics) response, _, err := r.client.MovieApi.UpdateMovie(ctx, fmt.Sprint(request.GetId())).MovieResource(*request).Execute() if err != nil { @@ -255,7 +280,7 @@ func (r *MovieResource) Update(ctx context.Context, req resource.UpdateRequest, tflog.Trace(ctx, "updated "+movieResourceName+": "+strconv.Itoa(int(response.GetId()))) // Generate resource state struct - movie.write(ctx, response) + movie.write(ctx, response, &resp.Diagnostics) resp.Diagnostics.Append(resp.State.Set(ctx, &movie)...) } @@ -285,8 +310,9 @@ func (r *MovieResource) ImportState(ctx context.Context, req resource.ImportStat tflog.Trace(ctx, "imported "+movieResourceName+": "+req.ID) } -func (m *Movie) write(ctx context.Context, movie *radarr.MovieResource) { - m.Tags, _ = types.SetValueFrom(ctx, types.Int64Type, movie.GetTags()) +func (m *Movie) write(ctx context.Context, movie *radarr.MovieResource, diags *diag.Diagnostics) { + var tempDiag diag.Diagnostics + m.Monitored = types.BoolValue(movie.GetMonitored()) m.ID = types.Int64Value(int64(movie.GetId())) m.Title = types.StringValue(movie.GetTitle()) @@ -294,7 +320,6 @@ func (m *Movie) write(ctx context.Context, movie *radarr.MovieResource) { m.QualityProfileID = types.Int64Value(int64(movie.GetQualityProfileId())) m.TMDBID = types.Int64Value(int64(movie.GetTmdbId())) m.MinimumAvailability = types.StringValue(string(movie.GetMinimumAvailability())) - // Read only values m.IsAvailable = types.BoolValue(movie.GetIsAvailable()) m.OriginalTitle = types.StringValue(movie.GetOriginalTitle()) m.Status = types.StringValue(string(movie.GetStatus())) @@ -305,15 +330,15 @@ func (m *Movie) write(ctx context.Context, movie *radarr.MovieResource) { m.Website = types.StringValue(movie.GetWebsite()) language := QualityLanguage{} language.write(movie.OriginalLanguage) - tfsdk.ValueFrom(ctx, language, QualityProfileResource{}.getQualityLanguageSchema().Type(), &m.OriginalLanguage) - m.Genres = types.SetValueMust(types.StringType, nil) - tfsdk.ValueFrom(ctx, movie.Genres, m.Genres.Type(ctx), &m.Genres) + m.OriginalLanguage, tempDiag = types.ObjectValueFrom(ctx, QualityLanguage{}.getType().(attr.TypeWithAttributeTypes).AttributeTypes(), language) + diags.Append(tempDiag...) + m.Genres, tempDiag = types.SetValueFrom(ctx, types.StringType, movie.GetGenres()) + diags.Append(tempDiag...) + m.Tags, tempDiag = types.SetValueFrom(ctx, types.Int64Type, movie.GetTags()) + diags.Append(tempDiag...) } -func (m *Movie) read(ctx context.Context) *radarr.MovieResource { - tags := make([]*int32, len(m.Tags.Elements())) - tfsdk.ValueAs(ctx, m.Tags, &tags) - +func (m *Movie) read(ctx context.Context, diags *diag.Diagnostics) *radarr.MovieResource { movie := radarr.NewMovieResource() movie.SetMonitored(m.Monitored.ValueBool()) movie.SetTitle(m.Title.ValueString()) @@ -321,7 +346,7 @@ func (m *Movie) read(ctx context.Context) *radarr.MovieResource { movie.SetQualityProfileId(int32(m.QualityProfileID.ValueInt64())) movie.SetTmdbId(int32(m.TMDBID.ValueInt64())) movie.SetId(int32(m.ID.ValueInt64())) - movie.SetTags(tags) + diags.Append(m.Tags.ElementsAs(ctx, &movie.Tags, true)...) if !m.MinimumAvailability.IsNull() && !m.MinimumAvailability.IsUnknown() { movie.SetMinimumAvailability(radarr.MovieStatusType(m.MinimumAvailability.ValueString())) diff --git a/internal/provider/movies_data_source.go b/internal/provider/movies_data_source.go index b17dd391..3c0fffca 100644 --- a/internal/provider/movies_data_source.go +++ b/internal/provider/movies_data_source.go @@ -8,7 +8,6 @@ import ( "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -149,13 +148,6 @@ func (d *MoviesDataSource) Configure(ctx context.Context, req datasource.Configu } func (d *MoviesDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var data *Movies - - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - - if resp.Diagnostics.HasError() { - return - } // Get movies current value response, _, err := d.client.MovieApi.ListMovie(ctx).Execute() if err != nil { @@ -168,11 +160,10 @@ func (d *MoviesDataSource) Read(ctx context.Context, req datasource.ReadRequest, // Map response body to resource schema attribute movies := make([]Movie, len(response)) for i, m := range response { - movies[i].write(ctx, m) + movies[i].write(ctx, m, &resp.Diagnostics) } - tfsdk.ValueFrom(ctx, movies, data.Movies.Type(ctx), &data.Movies) - // TODO: remove ID once framework support tests without ID https://www.terraform.io/plugin/framework/acctests#implement-id-attribute - data.ID = types.StringValue(strconv.Itoa(len(response))) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + movieList, diags := types.SetValueFrom(ctx, Movie{}.getType(), movies) + resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(resp.State.Set(ctx, Movies{Movies: movieList, ID: types.StringValue(strconv.Itoa(len(response)))})...) } diff --git a/internal/provider/notification_data_source.go b/internal/provider/notification_data_source.go index 4f0d71e9..1f16b8af 100644 --- a/internal/provider/notification_data_source.go +++ b/internal/provider/notification_data_source.go @@ -2,12 +2,12 @@ package provider import ( "context" - "fmt" "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -436,24 +436,20 @@ func (d *NotificationDataSource) Read(ctx context.Context, req datasource.ReadRe return } - notification, err := findNotification(data.Name.ValueString(), response) - if err != nil { - resp.Diagnostics.AddError(helpers.DataSourceError, fmt.Sprintf("Unable to find %s, got error: %s", notificationDataSourceName, err)) - - return - } - + data.find(ctx, data.Name.ValueString(), response, &resp.Diagnostics) tflog.Trace(ctx, "read "+notificationDataSourceName) - data.write(ctx, notification, &resp.Diagnostics) + // Map response body to resource schema attribute resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -func findNotification(name string, notifications []*radarr.NotificationResource) (*radarr.NotificationResource, error) { - for _, i := range notifications { - if i.GetName() == name { - return i, nil +func (n *Notification) find(ctx context.Context, name string, notifications []*radarr.NotificationResource, diags *diag.Diagnostics) { + for _, notification := range notifications { + if notification.GetName() == name { + n.write(ctx, notification, diags) + + return } } - return nil, helpers.ErrDataNotFoundError(notificationDataSourceName, "name", name) + diags.AddError(helpers.DataSourceError, helpers.ParseNotFoundError(notificationDataSourceName, "name", name)) } diff --git a/internal/provider/notification_resource.go b/internal/provider/notification_resource.go index 1bbe1119..6ef1f7a8 100644 --- a/internal/provider/notification_resource.go +++ b/internal/provider/notification_resource.go @@ -7,6 +7,7 @@ import ( "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -138,6 +139,102 @@ type Notification struct { OnManualInteractionRequired types.Bool `tfsdk:"on_manual_interaction_required"` } +func (n Notification) getType() attr.Type { + return types.ObjectType{}.WithAttributeTypes( + map[string]attr.Type{ + "tags": types.SetType{}.WithElementType(types.Int64Type), + "import_fields": types.SetType{}.WithElementType(types.Int64Type), + "grab_fields": types.SetType{}.WithElementType(types.Int64Type), + "field_tags": types.SetType{}.WithElementType(types.StringType), + "recipients": types.SetType{}.WithElementType(types.StringType), + "devices": types.SetType{}.WithElementType(types.StringType), + "device_ids": types.SetType{}.WithElementType(types.StringType), + "to": types.SetType{}.WithElementType(types.StringType), + "cc": types.SetType{}.WithElementType(types.StringType), + "bcc": types.SetType{}.WithElementType(types.StringType), + "channel_tags": types.SetType{}.WithElementType(types.StringType), + "topics": types.SetType{}.WithElementType(types.StringType), + "device_names": types.StringType, + "access_token": types.StringType, + "host": types.StringType, + "instance_name": types.StringType, + "name": types.StringType, + "implementation": types.StringType, + "config_contract": types.StringType, + "click_url": types.StringType, + "consumer_secret": types.StringType, + "path": types.StringType, + "arguments": types.StringType, + "consumer_key": types.StringType, + "chat_id": types.StringType, + "topic_id": types.StringType, + "from": types.StringType, + "icon": types.StringType, + "password": types.StringType, + "event": types.StringType, + "key": types.StringType, + "refresh_token": types.StringType, + "web_hook_url": types.StringType, + "username": types.StringType, + "user_key": types.StringType, + "mention": types.StringType, + "avatar": types.StringType, + "url": types.StringType, + "token": types.StringType, + "sound": types.StringType, + "sign_in": types.StringType, + "server": types.StringType, + "sender_id": types.StringType, + "bot_token": types.StringType, + "sender_domain": types.StringType, + "map_to": types.StringType, + "map_from": types.StringType, + "channel": types.StringType, + "expires": types.StringType, + "server_url": types.StringType, + "access_token_secret": types.StringType, + "api_key": types.StringType, + "app_token": types.StringType, + "author": types.StringType, + "auth_token": types.StringType, + "auth_user": types.StringType, + "stateless_urls": types.StringType, + "auth_username": types.StringType, + "auth_password": types.StringType, + "configuration_key": types.StringType, + "notification_type": types.Int64Type, + "display_time": types.Int64Type, + "priority": types.Int64Type, + "port": types.Int64Type, + "method": types.Int64Type, + "retry": types.Int64Type, + "expire": types.Int64Type, + "id": types.Int64Type, + "clean_library": types.BoolType, + "on_grab": types.BoolType, + "on_movie_added": types.BoolType, + "send_silently": types.BoolType, + "always_update": types.BoolType, + "on_health_issue": types.BoolType, + "direct_message": types.BoolType, + "require_encryption": types.BoolType, + "use_ssl": types.BoolType, + "notify": types.BoolType, + "use_eu_endpoint": types.BoolType, + "update_library": types.BoolType, + "on_movie_file_delete_for_upgrade": types.BoolType, + "include_health_warnings": types.BoolType, + "on_movie_file_delete": types.BoolType, + "on_movie_delete": types.BoolType, + "on_application_update": types.BoolType, + "on_rename": types.BoolType, + "on_upgrade": types.BoolType, + "on_download": types.BoolType, + "on_health_restored": types.BoolType, + "on_manual_interaction_required": types.BoolType, + }) +} + func (r *NotificationResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_" + notificationResourceName } @@ -439,6 +536,7 @@ func (r *NotificationResource) Schema(ctx context.Context, req resource.SchemaRe MarkdownDescription: "password.", Optional: true, Computed: true, + Sensitive: true, }, "path": schema.StringAttribute{ MarkdownDescription: "Path.", diff --git a/internal/provider/notification_webhook_resource.go b/internal/provider/notification_webhook_resource.go index dfecda8f..23bc3fcc 100644 --- a/internal/provider/notification_webhook_resource.go +++ b/internal/provider/notification_webhook_resource.go @@ -216,6 +216,7 @@ func (r *NotificationWebhookResource) Schema(ctx context.Context, req resource.S MarkdownDescription: "password.", Optional: true, Computed: true, + Sensitive: true, }, "method": schema.Int64Attribute{ MarkdownDescription: "Method. `1` POST, `2` PUT.", diff --git a/internal/provider/notifications_data_source.go b/internal/provider/notifications_data_source.go index 3558948e..f60004e0 100644 --- a/internal/provider/notifications_data_source.go +++ b/internal/provider/notifications_data_source.go @@ -8,7 +8,6 @@ import ( "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -440,13 +439,6 @@ func (d *NotificationsDataSource) Configure(ctx context.Context, req datasource. } func (d *NotificationsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var data *Notifications - - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - - if resp.Diagnostics.HasError() { - return - } // Get notifications current value response, _, err := d.client.NotificationApi.ListNotification(ctx).Execute() if err != nil { @@ -457,13 +449,12 @@ func (d *NotificationsDataSource) Read(ctx context.Context, req datasource.ReadR tflog.Trace(ctx, "read "+notificationsDataSourceName) // Map response body to resource schema attribute - profiles := make([]Notification, len(response)) - for i, p := range response { - profiles[i].write(ctx, p, &resp.Diagnostics) + notifications := make([]Notification, len(response)) + for i, n := range response { + notifications[i].write(ctx, n, &resp.Diagnostics) } - tfsdk.ValueFrom(ctx, profiles, data.Notifications.Type(ctx), &data.Notifications) - // TODO: remove ID once framework support tests without ID https://www.terraform.io/plugin/framework/acctests#implement-id-attribute - data.ID = types.StringValue(strconv.Itoa(len(response))) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + notificationList, diags := types.SetValueFrom(ctx, Notification{}.getType(), notifications) + resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(resp.State.Set(ctx, Notifications{Notifications: notificationList, ID: types.StringValue(strconv.Itoa(len(response)))})...) } diff --git a/internal/provider/quality_data_source.go b/internal/provider/quality_data_source.go index e8b507bc..826b135e 100644 --- a/internal/provider/quality_data_source.go +++ b/internal/provider/quality_data_source.go @@ -2,13 +2,13 @@ package provider import ( "context" - "fmt" "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -96,26 +96,22 @@ func (d *QualityDataSource) Read(ctx context.Context, req datasource.ReadRequest return } - quality, err := findQuality(data.Name.ValueString(), response) - if err != nil { - resp.Diagnostics.AddError(helpers.DataSourceError, fmt.Sprintf("Unable to find %s, got error: %s", qualityDataSourceName, err)) - - return - } - + data.find(data.Name.ValueString(), response, &resp.Diagnostics) tflog.Trace(ctx, "read "+qualityDataSourceName) - data.writeFromDefinition(quality) + // Map response body to resource schema attribute resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -func findQuality(name string, s []*radarr.QualityDefinitionResource) (*radarr.QualityDefinitionResource, error) { - for _, p := range s { - if p.Quality.GetName() == name { - return p, nil +func (q *Quality) find(name string, definitions []*radarr.QualityDefinitionResource, diags *diag.Diagnostics) { + for _, def := range definitions { + if def.Quality.GetName() == name { + q.writeFromDefinition(def) + + return } } - return nil, helpers.ErrDataNotFoundError(qualityDataSourceName, "name", name) + diags.AddError(helpers.DataSourceError, helpers.ParseNotFoundError(qualityDataSourceName, "name", name)) } func (q *Quality) writeFromDefinition(quality *radarr.QualityDefinitionResource) { diff --git a/internal/provider/quality_definition_data_source.go b/internal/provider/quality_definition_data_source.go index 357e0e40..cbc6e289 100644 --- a/internal/provider/quality_definition_data_source.go +++ b/internal/provider/quality_definition_data_source.go @@ -2,12 +2,13 @@ package provider import ( "context" - "fmt" + "strconv" "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -97,24 +98,20 @@ func (d *QualityDefinitionDataSource) Read(ctx context.Context, req datasource.R return } - definition, err := findQualityDefinition(data.ID.ValueInt64(), response) - if err != nil { - resp.Diagnostics.AddError(helpers.DataSourceError, fmt.Sprintf("Unable to find %s, got error: %s", qualityDefinitionDataSourceName, err)) - - return - } - + data.find(data.ID.ValueInt64(), response, &resp.Diagnostics) tflog.Trace(ctx, "read "+qualityDefinitionDataSourceName) - data.write(definition) + // Map response body to resource schema attribute resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -func findQualityDefinition(id int64, definitions []*radarr.QualityDefinitionResource) (*radarr.QualityDefinitionResource, error) { - for _, p := range definitions { - if int64(p.GetId()) == id { - return p, nil +func (p *QualityDefinition) find(id int64, definitions []*radarr.QualityDefinitionResource, diags *diag.Diagnostics) { + for _, def := range definitions { + if int64(def.GetId()) == id { + p.write(def) + + return } } - return nil, helpers.ErrDataNotFoundError(qualityDefinitionDataSourceName, "ID", fmt.Sprint(id)) + diags.AddError(helpers.DataSourceError, helpers.ParseNotFoundError(qualityDefinitionDataSourceName, "id", strconv.Itoa(int(id)))) } diff --git a/internal/provider/quality_definition_resource.go b/internal/provider/quality_definition_resource.go index cfc601fa..caa0b983 100644 --- a/internal/provider/quality_definition_resource.go +++ b/internal/provider/quality_definition_resource.go @@ -6,6 +6,7 @@ import ( "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" @@ -46,6 +47,21 @@ type QualityDefinition struct { Resolution types.Int64 `tfsdk:"resolution"` } +func (p QualityDefinition) getType() attr.Type { + return types.ObjectType{}.WithAttributeTypes( + map[string]attr.Type{ + "id": types.Int64Type, + "quality_id": types.Int64Type, + "resolution": types.Int64Type, + "min_size": types.Float64Type, + "max_size": types.Float64Type, + "preferred_size": types.Float64Type, + "title": types.StringType, + "quality_name": types.StringType, + "source": types.StringType, + }) +} + func (r *QualityDefinitionResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_" + qualityDefinitionResourceName } diff --git a/internal/provider/quality_definitions_data_source.go b/internal/provider/quality_definitions_data_source.go index 938f30df..26f26fac 100644 --- a/internal/provider/quality_definitions_data_source.go +++ b/internal/provider/quality_definitions_data_source.go @@ -8,7 +8,6 @@ import ( "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -102,13 +101,6 @@ func (d *QualityDefinitionsDataSource) Configure(ctx context.Context, req dataso } func (d *QualityDefinitionsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var data *QualityDefinitions - - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - - if resp.Diagnostics.HasError() { - return - } // Get qualitydefinitions current value response, _, err := d.client.QualityDefinitionApi.ListQualityDefinition(ctx).Execute() if err != nil { @@ -119,19 +111,12 @@ func (d *QualityDefinitionsDataSource) Read(ctx context.Context, req datasource. tflog.Trace(ctx, "read "+qualityDefinitionsDataSourceName) // Map response body to resource schema attribute - definitions := *writeQualitiydefinitions(response) - tfsdk.ValueFrom(ctx, definitions, data.QualityDefinitions.Type(ctx), &data.QualityDefinitions) - - // TODO: remove ID once framework support tests without ID https://www.terraform.io/plugin/framework/acctests#implement-id-attribute - data.ID = types.StringValue(strconv.Itoa(len(response))) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) -} - -func writeQualitiydefinitions(qualities []*radarr.QualityDefinitionResource) *[]QualityDefinition { - output := make([]QualityDefinition, len(qualities)) - for i, p := range qualities { - output[i].write(p) + definitions := make([]QualityDefinition, len(response)) + for i, p := range response { + definitions[i].write(p) } - return &output + qualityList, diags := types.SetValueFrom(ctx, QualityDefinition{}.getType(), definitions) + resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(resp.State.Set(ctx, QualityDefinitions{QualityDefinitions: qualityList, ID: types.StringValue(strconv.Itoa(len(response)))})...) } diff --git a/internal/provider/quality_profile_data_source.go b/internal/provider/quality_profile_data_source.go index bc7b2877..eebaad7e 100644 --- a/internal/provider/quality_profile_data_source.go +++ b/internal/provider/quality_profile_data_source.go @@ -2,12 +2,12 @@ package provider import ( "context" - "fmt" "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -158,24 +158,21 @@ func (d *QualityProfileDataSource) Read(ctx context.Context, req datasource.Read return } - profile, err := findQualityProfile(data.Name.ValueString(), response) - if err != nil { - resp.Diagnostics.AddError(helpers.DataSourceError, fmt.Sprintf("Unable to find %s, got error: %s", qualityProfileDataSourceName, err)) - - return - } + data.find(ctx, data.Name.ValueString(), response, &resp.Diagnostics) tflog.Trace(ctx, "read "+qualityProfileDataSourceName) - data.write(ctx, profile, &resp.Diagnostics) + // Map response body to resource schema attribute resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -func findQualityProfile(name string, profiles []*radarr.QualityProfileResource) (*radarr.QualityProfileResource, error) { - for _, p := range profiles { - if p.GetName() == name { - return p, nil +func (p *QualityProfile) find(ctx context.Context, name string, profiles []*radarr.QualityProfileResource, diags *diag.Diagnostics) { + for _, profile := range profiles { + if profile.GetName() == name { + p.write(ctx, profile, diags) + + return } } - return nil, helpers.ErrDataNotFoundError(qualityProfileDataSourceName, "name", name) + diags.AddError(helpers.DataSourceError, helpers.ParseNotFoundError(qualityProfileDataSourceName, "name", name)) } diff --git a/internal/provider/quality_profile_resource.go b/internal/provider/quality_profile_resource.go index 694d42b2..8c1a405e 100644 --- a/internal/provider/quality_profile_resource.go +++ b/internal/provider/quality_profile_resource.go @@ -102,7 +102,7 @@ type QualityLanguage struct { ID types.Int64 `tfsdk:"id"` } -func (q QualityLanguage) getType() attr.Type { +func (l QualityLanguage) getType() attr.Type { return types.ObjectType{}.WithAttributeTypes( map[string]attr.Type{ "name": types.StringType, @@ -465,8 +465,8 @@ func (l *QualityLanguage) write(language *radarr.Language) { func (p *QualityProfile) read(ctx context.Context, diags *diag.Diagnostics) *radarr.QualityProfileResource { groups := make([]QualityGroup, len(p.QualityGroups.Elements())) diags.Append(p.QualityGroups.ElementsAs(ctx, &groups, false)...) - qualities := make([]*radarr.QualityProfileQualityItemResource, len(groups)) + for n, g := range groups { q := make([]Quality, len(g.Qualities.Elements())) diags.Append(g.Qualities.ElementsAs(ctx, &q, false)...) diff --git a/internal/provider/restriction_data_source.go b/internal/provider/restriction_data_source.go index 6c35faf6..f73ed2be 100644 --- a/internal/provider/restriction_data_source.go +++ b/internal/provider/restriction_data_source.go @@ -2,13 +2,13 @@ package provider import ( "context" - "fmt" "strconv" "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -64,9 +64,9 @@ func (d *RestrictionDataSource) Configure(ctx context.Context, req datasource.Co } func (d *RestrictionDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var restriction *Restriction + var data *Restriction - resp.Diagnostics.Append(req.Config.Get(ctx, &restriction)...) + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) if resp.Diagnostics.HasError() { return @@ -79,26 +79,20 @@ func (d *RestrictionDataSource) Read(ctx context.Context, req datasource.ReadReq return } - // Map response body to resource schema attribute - value, err := findRestriction(restriction.ID.ValueInt64(), response) - if err != nil { - resp.Diagnostics.AddError(helpers.DataSourceError, fmt.Sprintf("Unable to find %s, got error: %s", restrictionDataSourceName, err)) - - return - } - + data.find(ctx, data.ID.ValueInt64(), response, &resp.Diagnostics) tflog.Trace(ctx, "read "+restrictionDataSourceName) - - restriction.write(ctx, value) - resp.Diagnostics.Append(resp.State.Set(ctx, &restriction)...) + // Map response body to resource schema attribute + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -func findRestriction(id int64, restrictions []*radarr.RestrictionResource) (*radarr.RestrictionResource, error) { - for _, m := range restrictions { - if int64(m.GetId()) == id { - return m, nil +func (r *Restriction) find(ctx context.Context, id int64, restrictions []*radarr.RestrictionResource, diags *diag.Diagnostics) { + for _, restriction := range restrictions { + if int64(restriction.GetId()) == id { + r.write(ctx, restriction, diags) + + return } } - return nil, helpers.ErrDataNotFoundError(restrictionDataSourceName, "id", strconv.Itoa(int(id))) + diags.AddError(helpers.DataSourceError, helpers.ParseNotFoundError(restrictionDataSourceName, "id", strconv.Itoa(int(id)))) } diff --git a/internal/provider/restriction_resource.go b/internal/provider/restriction_resource.go index 8d456b93..6c0004cd 100644 --- a/internal/provider/restriction_resource.go +++ b/internal/provider/restriction_resource.go @@ -6,12 +6,13 @@ import ( "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" "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/int64planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -41,6 +42,16 @@ type Restriction struct { ID types.Int64 `tfsdk:"id"` } +func (r Restriction) getType() attr.Type { + return types.ObjectType{}.WithAttributeTypes( + map[string]attr.Type{ + "id": types.Int64Type, + "required": types.StringType, + "ignored": types.StringType, + "tags": types.SetType{}.WithElementType(types.Int64Type), + }) +} + func (r *RestrictionResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ MarkdownDescription: "Restriction resource.\nFor more information refer to [Restriction](https://wiki.servarr.com/radarr/settings#remote-path-restrictions) documentation.", @@ -93,7 +104,7 @@ func (r *RestrictionResource) Create(ctx context.Context, req resource.CreateReq } // Create new Restriction - request := restriction.read(ctx) + request := restriction.read(ctx, &resp.Diagnostics) response, _, err := r.client.RestrictionApi.CreateRestriction(ctx).RestrictionResource(*request).Execute() if err != nil { @@ -104,7 +115,7 @@ func (r *RestrictionResource) Create(ctx context.Context, req resource.CreateReq tflog.Trace(ctx, "created "+restrictionName+": "+strconv.Itoa(int(response.GetId()))) // Generate resource state struct - restriction.write(ctx, response) + restriction.write(ctx, response, &resp.Diagnostics) resp.Diagnostics.Append(resp.State.Set(ctx, &restriction)...) } @@ -128,7 +139,7 @@ func (r *RestrictionResource) Read(ctx context.Context, req resource.ReadRequest tflog.Trace(ctx, "read "+restrictionName+": "+strconv.Itoa(int(response.GetId()))) // Map response body to resource schema attribute - restriction.write(ctx, response) + restriction.write(ctx, response, &resp.Diagnostics) resp.Diagnostics.Append(resp.State.Set(ctx, &restriction)...) } @@ -143,7 +154,7 @@ func (r *RestrictionResource) Update(ctx context.Context, req resource.UpdateReq } // Update Restriction - request := restriction.read(ctx) + request := restriction.read(ctx, &resp.Diagnostics) response, _, err := r.client.RestrictionApi.UpdateRestriction(ctx, strconv.Itoa(int(request.GetId()))).RestrictionResource(*request).Execute() if err != nil { @@ -154,7 +165,7 @@ func (r *RestrictionResource) Update(ctx context.Context, req resource.UpdateReq tflog.Trace(ctx, "updated "+restrictionName+": "+strconv.Itoa(int(response.GetId()))) // Generate resource state struct - restriction.write(ctx, response) + restriction.write(ctx, response, &resp.Diagnostics) resp.Diagnostics.Append(resp.State.Set(ctx, &restriction)...) } @@ -184,22 +195,22 @@ func (r *RestrictionResource) ImportState(ctx context.Context, req resource.Impo tflog.Trace(ctx, "imported "+restrictionName+": "+req.ID) } -func (r *Restriction) write(ctx context.Context, restriction *radarr.RestrictionResource) { - r.Tags, _ = types.SetValueFrom(ctx, types.Int64Type, restriction.GetTags()) +func (r *Restriction) write(ctx context.Context, restriction *radarr.RestrictionResource, diags *diag.Diagnostics) { + var tempDiag diag.Diagnostics + r.ID = types.Int64Value(int64(restriction.GetId())) r.Ignored = types.StringValue(restriction.GetIgnored()) r.Required = types.StringValue(restriction.GetRequired()) + r.Tags, tempDiag = types.SetValueFrom(ctx, types.Int64Type, restriction.GetTags()) + diags.Append(tempDiag...) } -func (r *Restriction) read(ctx context.Context) *radarr.RestrictionResource { - tags := make([]*int32, len(r.Tags.Elements())) - tfsdk.ValueAs(ctx, r.Tags, &tags) - +func (r *Restriction) read(ctx context.Context, diags *diag.Diagnostics) *radarr.RestrictionResource { restriction := radarr.NewRestrictionResource() restriction.SetId(int32(r.ID.ValueInt64())) restriction.SetIgnored(r.Ignored.ValueString()) restriction.SetRequired(r.Required.ValueString()) - restriction.SetTags(tags) + diags.Append(r.Tags.ElementsAs(ctx, &restriction.Tags, true)...) return restriction } diff --git a/internal/provider/restrictions_data_source.go b/internal/provider/restrictions_data_source.go index 739288e7..3be64d48 100644 --- a/internal/provider/restrictions_data_source.go +++ b/internal/provider/restrictions_data_source.go @@ -8,7 +8,6 @@ import ( "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -82,13 +81,6 @@ func (d *RestrictionsDataSource) Configure(ctx context.Context, req datasource.C } func (d *RestrictionsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var data *Restrictions - - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - - if resp.Diagnostics.HasError() { - return - } // Get restrictions current value response, _, err := d.client.RestrictionApi.ListRestriction(ctx).Execute() if err != nil { @@ -101,11 +93,10 @@ func (d *RestrictionsDataSource) Read(ctx context.Context, req datasource.ReadRe // Map response body to resource schema attribute restrictions := make([]Restriction, len(response)) for i, p := range response { - restrictions[i].write(ctx, p) + restrictions[i].write(ctx, p, &resp.Diagnostics) } - tfsdk.ValueFrom(ctx, restrictions, data.Restrictions.Type(ctx), &data.Restrictions) - // TODO: remove ID once framework support tests without ID https://www.terraform.io/plugin/framework/acctests#implement-id-attribute - data.ID = types.StringValue(strconv.Itoa(len(response))) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + restrictionList, diags := types.SetValueFrom(ctx, Restriction{}.getType(), restrictions) + resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(resp.State.Set(ctx, Restrictions{Restrictions: restrictionList, ID: types.StringValue(strconv.Itoa(len(response)))})...) } diff --git a/internal/provider/root_folder_data_source.go b/internal/provider/root_folder_data_source.go index 23a0fb58..5a97612a 100644 --- a/internal/provider/root_folder_data_source.go +++ b/internal/provider/root_folder_data_source.go @@ -2,12 +2,12 @@ package provider import ( "context" - "fmt" "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -88,25 +88,21 @@ func (d *RootFolderDataSource) Read(ctx context.Context, req datasource.ReadRequ return } - // Map response body to resource schema attribute - rootFolder, err := findRootFolder(folder.Path.ValueString(), response) - if err != nil { - resp.Diagnostics.AddError(helpers.DataSourceError, fmt.Sprintf("Unable to find %s, got error: %s", rootFolderDataSourceName, err)) - - return - } + folder.find(ctx, folder.Path.ValueString(), response, &resp.Diagnostics) tflog.Trace(ctx, "read "+rootFolderDataSourceName) - folder.write(ctx, rootFolder) + // Map response body to resource schema attribute resp.Diagnostics.Append(resp.State.Set(ctx, &folder)...) } -func findRootFolder(path string, folders []*radarr.RootFolderResource) (*radarr.RootFolderResource, error) { - for _, f := range folders { - if f.GetPath() == path { - return f, nil +func (r *RootFolder) find(ctx context.Context, path string, folders []*radarr.RootFolderResource, diags *diag.Diagnostics) { + for _, folder := range folders { + if folder.GetPath() == path { + r.write(ctx, folder, diags) + + return } } - return nil, helpers.ErrDataNotFoundError(rootFolderDataSourceName, "path", path) + diags.AddError(helpers.DataSourceError, helpers.ParseNotFoundError(rootFolderDataSourceName, "path", path)) } diff --git a/internal/provider/root_folder_resource.go b/internal/provider/root_folder_resource.go index ee845b1e..bbe26b74 100644 --- a/internal/provider/root_folder_resource.go +++ b/internal/provider/root_folder_resource.go @@ -6,13 +6,14 @@ import ( "github.com/devopsarr/radarr-go/radarr" "github.com/devopsarr/terraform-provider-radarr/internal/helpers" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" "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/int64planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -42,12 +43,30 @@ type RootFolder struct { Accessible types.Bool `tfsdk:"accessible"` } +func (r RootFolder) getType() attr.Type { + return types.ObjectType{}.WithAttributeTypes( + map[string]attr.Type{ + "unmapped_folders": types.SetType{}.WithElementType(Path{}.getType()), + "path": types.StringType, + "id": types.Int64Type, + "accessible": types.BoolType, + }) +} + // Path part of RootFolder. type Path struct { Name types.String `tfsdk:"name"` Path types.String `tfsdk:"path"` } +func (p Path) getType() attr.Type { + return types.ObjectType{}.WithAttributeTypes( + map[string]attr.Type{ + "name": types.StringType, + "path": types.StringType, + }) +} + func (r *RootFolderResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_" + rootFolderResourceName } @@ -130,7 +149,7 @@ func (r *RootFolderResource) Create(ctx context.Context, req resource.CreateRequ tflog.Trace(ctx, "created "+rootFolderResourceName+": "+strconv.Itoa(int(response.GetId()))) // Generate resource state struct - folder.write(ctx, response) + folder.write(ctx, response, &resp.Diagnostics) resp.Diagnostics.Append(resp.State.Set(ctx, &folder)...) } @@ -154,7 +173,7 @@ func (r *RootFolderResource) Read(ctx context.Context, req resource.ReadRequest, tflog.Trace(ctx, "read "+rootFolderResourceName+": "+strconv.Itoa(int(response.GetId()))) // Map response body to resource schema attribute - folder.write(ctx, response) + folder.write(ctx, response, &resp.Diagnostics) resp.Diagnostics.Append(resp.State.Set(ctx, &folder)...) } @@ -188,18 +207,20 @@ func (r *RootFolderResource) ImportState(ctx context.Context, req resource.Impor tflog.Trace(ctx, "imported "+rootFolderResourceName+": "+req.ID) } -func (r *RootFolder) write(ctx context.Context, rootFolder *radarr.RootFolderResource) { +func (r *RootFolder) write(ctx context.Context, rootFolder *radarr.RootFolderResource, diags *diag.Diagnostics) { + var tempDiag diag.Diagnostics + r.Accessible = types.BoolValue(rootFolder.GetAccessible()) r.ID = types.Int64Value(int64(rootFolder.GetId())) r.Path = types.StringValue(rootFolder.GetPath()) - r.UnmappedFolders = types.SetValueMust(RootFolderResource{}.getUnmappedFolderSchema().Type(), nil) unmapped := make([]Path, len(rootFolder.GetUnmappedFolders())) for i, f := range rootFolder.UnmappedFolders { unmapped[i].write(f) } - tfsdk.ValueFrom(ctx, unmapped, r.UnmappedFolders.Type(ctx), r.UnmappedFolders) + r.UnmappedFolders, tempDiag = types.SetValueFrom(ctx, Path{}.getType(), unmapped) + diags.Append(tempDiag...) } func (p *Path) write(folder *radarr.UnmappedFolder) { diff --git a/internal/provider/root_folders_data_source.go b/internal/provider/root_folders_data_source.go index 6740a2aa..10a719db 100644 --- a/internal/provider/root_folders_data_source.go +++ b/internal/provider/root_folders_data_source.go @@ -8,7 +8,6 @@ import ( "github.com/devopsarr/terraform-provider-radarr/internal/helpers" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" - "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" ) @@ -110,18 +109,12 @@ func (d *RootFoldersDataSource) Read(ctx context.Context, req datasource.ReadReq tflog.Trace(ctx, "read "+rootFoldersDataSourceName) // Map response body to resource schema attribute - rootFolders := *writes(ctx, response) - tfsdk.ValueFrom(ctx, rootFolders, data.RootFolders.Type(ctx), &data.RootFolders) - // TODO: remove ID once framework support tests without ID https://www.terraform.io/plugin/framework/acctests#implement-id-attribute - data.ID = types.StringValue(strconv.Itoa(len(response))) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) -} - -func writes(ctx context.Context, folders []*radarr.RootFolderResource) *[]RootFolder { - output := make([]RootFolder, len(folders)) - for i, f := range folders { - output[i].write(ctx, f) + rootFolders := make([]RootFolder, len(response)) + for i, f := range response { + rootFolders[i].write(ctx, f, &resp.Diagnostics) } - return &output + folderList, diags := types.SetValueFrom(ctx, RootFolder{}.getType(), rootFolders) + resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(resp.State.Set(ctx, RootFolders{RootFolders: folderList, ID: types.StringValue(strconv.Itoa(len(response)))})...) }