diff --git a/.changes/unreleased/Added-20251023-141459.yaml b/.changes/unreleased/Added-20251023-141459.yaml new file mode 100644 index 00000000..695d4232 --- /dev/null +++ b/.changes/unreleased/Added-20251023-141459.yaml @@ -0,0 +1,3 @@ +kind: Added +body: Product type data source +time: 2025-10-23T14:14:59.466793+01:00 diff --git a/internal/datasource/product_type/resource.go b/internal/datasource/product_type/resource.go new file mode 100644 index 00000000..fe83e9e3 --- /dev/null +++ b/internal/datasource/product_type/resource.go @@ -0,0 +1,96 @@ +package custom_product_type + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/labd/commercetools-go-sdk/platform" + + "github.com/labd/terraform-provider-commercetools/internal/utils" +) + +// Ensure the implementation satisfies the expected interfaces. +var ( + _ datasource.DataSource = &ProductTypeSource{} + _ datasource.DataSourceWithConfigure = &ProductTypeSource{} +) + +// NewDataSource is a helper function to simplify the provider implementation. +func NewDataSource() datasource.DataSource { + return &ProductTypeSource{} +} + +// ProductTypeSource is the data source implementation. +type ProductTypeSource struct { + client *platform.ByProjectKeyRequestBuilder + mutex *utils.MutexKV +} + +// ProductTypeSourceModel maps the data source schema data. +type ProductTypeSourceModel struct { + ID types.String `tfsdk:"id"` + Key types.String `tfsdk:"key"` +} + +// Metadata returns the data source type name. +func (d *ProductTypeSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_product_type" +} + +// Schema defines the schema for the data source. +func (d *ProductTypeSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Fetches type information", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "ID of the custom type", + Computed: true, + }, + "key": schema.StringAttribute{ + Description: "Key of the custom type", + Required: true, + }, + }, + } +} + +// Configure adds the provider configured client to the data source. +func (d *ProductTypeSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + data := req.ProviderData.(*utils.ProviderData) + d.client = data.Client + d.mutex = data.Mutex +} + +// Read refreshes the Terraform state with the latest data. +func (d *ProductTypeSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var state ProductTypeSourceModel + + diags := req.Config.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + resource, err := d.client.ProductTypes().WithKey(state.Key.ValueString()).Get().Execute(ctx) + if err != nil { + resp.Diagnostics.AddError( + "Unable to Product Read Type", + err.Error(), + ) + return + } + + state.ID = types.StringValue(resource.ID) + + // Set state + diags = resp.State.Set(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} diff --git a/internal/datasource/product_type/resource_test.go b/internal/datasource/product_type/resource_test.go new file mode 100644 index 00000000..be4f1a11 --- /dev/null +++ b/internal/datasource/product_type/resource_test.go @@ -0,0 +1,116 @@ +package custom_product_type_test + +import ( + "context" + "fmt" + "testing" + + acctest "github.com/labd/terraform-provider-commercetools/internal/acctest" + "github.com/labd/terraform-provider-commercetools/internal/utils" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/stretchr/testify/assert" +) + +func TestAccProductType_DataSource(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckProductTypeDestroy, + Steps: []resource.TestStep{{ + Config: testAccConfigCreateProductType(), + Check: resource.ComposeTestCheckFunc( + func(s *terraform.State) error { + client, err := acctest.GetClient() + if err != nil { + return err + } + result, err := client.ProductTypes().WithKey("test").Get().Execute(context.Background()) + if err != nil { + return err + } + assert.NotNil(t, result) + assert.Equal(t, "test", result.Key) + assert.Equal(t, "my-attribute", result.Attributes[0].Name) + return nil + }, + ), + }, + { + Config: testAccConfigWithDataSource(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.commercetools_product_type.test_product_type", "key", "test"), + func(s *terraform.State) error { + client, err := acctest.GetClient() + if err != nil { + return err + } + result_product_type, err := client.ProductTypes().WithKey("test").Get().Execute(context.Background()) + if err != nil { + return err + } + assert.NotNil(t, result_product_type) + + // Verify the data source returns the correct ID + rs, ok := s.RootModule().Resources["data.commercetools_product_type.test_product_type"] + if !ok { + return fmt.Errorf("data source not found") + } + assert.Equal(t, result_product_type.ID, rs.Primary.ID) + return nil + }, + ), + }, + }, + }) +} + +func testAccCheckProductTypeDestroy(s *terraform.State) error { + return nil +} + +func testAccConfigCreateProductType() string { + return utils.HCLTemplate(` + resource "commercetools_product_type" "test" { + key = "test" + name = "Test Product Type" + description = "Test product type for data source testing" + + attribute { + name = "my-attribute" + label = { + en = "My Attribute" + } + type { + name = "text" + } + } + } + `, map[string]any{}) +} + +func testAccConfigWithDataSource() string { + return utils.HCLTemplate(` + resource "commercetools_product_type" "test" { + key = "test" + name = "Test Product Type" + description = "Test product type for data source testing" + + attribute { + name = "my-attribute" + label = { + en = "My Attribute" + } + type { + name = "text" + } + } + } + + data "commercetools_product_type" "test_product_type"{ + key = "test" + } + + `, map[string]any{}) +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index e7217475..ceec100d 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -16,6 +16,7 @@ import ( "github.com/labd/commercetools-go-sdk/platform" "golang.org/x/oauth2/clientcredentials" + datasourceproducttype "github.com/labd/terraform-provider-commercetools/internal/datasource/product_type" datasourcestate "github.com/labd/terraform-provider-commercetools/internal/datasource/state" datasourcetype "github.com/labd/terraform-provider-commercetools/internal/datasource/type" "github.com/labd/terraform-provider-commercetools/internal/resources/associate_role" @@ -185,6 +186,7 @@ func (p *ctProvider) DataSources(_ context.Context) []func() datasource.DataSour return []func() datasource.DataSource{ datasourcetype.NewDataSource, datasourcestate.NewDataSource, + datasourceproducttype.NewDataSource, } }