├── .changes
├── unreleased
│ ├── .gitkeep
│ └── Dependency-20250201-204222.yaml
├── 0.18.3.md
├── v1.0.1.md
├── 0.21.2.md
├── 0.1.1.md
├── 0.18.0.md
├── v1.11.1.md
├── 0.20.0.md
├── 0.8.0.md
├── v0.25.0.md
├── v1.10.0.md
├── v1.11.2.md
├── 0.2.0.md
├── 0.4.0.md
├── 0.9.0.md
├── v0.29.3.md
├── v1.18.1.md
├── 0.13.1.md
├── 0.18.1.md
├── 0.5.2.md
├── v0.25.2.md
├── v1.8.0.md
├── 0.13.0.md
├── 0.15.1.md
├── v1.7.1.md
├── 0.12.1.md
├── 0.19.0.md
├── 0.7.1.md
├── v0.29.1.md
├── v1.11.3.md
├── 0.11.1.md
├── 0.21.1.md
├── 0.22.1.md
├── 0.4.2.md
├── v0.25.1.md
├── v1.4.1.md
├── 0.10.0.md
├── v1.14.2.md
├── v1.16.0.md
├── 0.5.4.md
├── 0.12.0.md
├── v0.29.0.md
├── 0.11.0.md
├── 0.18.2.md
├── v1.14.0.md
├── v1.15.0.md
├── v1.4.2.md
├── v0.24.1.md
├── v1.11.4.md
├── v1.2.1.md
├── 0.14.0.md
├── v0.1.0.md
├── v0.26.1.md
├── v0.29.2.md
├── v1.11.0.md
├── v1.6.7.md
├── 0.5.3.md
├── v0.25.3.md
├── v1.6.5.md
├── 0.5.1.md
├── v1.13.1.md
├── 0.4.1.md
├── v0.24.0.md
├── v1.1.0.md
├── v1.15.1.md
├── v1.6.9.md
├── 0.17.0.md
├── 0.16.0.md
├── 0.7.0.md
├── v0.23.0.md
├── v1.6.6.md
├── 0.1.0.md
├── v1.12.0.md
├── v1.14.1.md
├── v1.6.8.md
├── 0.6.0.md
├── 0.15.0.md
├── 0.22.0.md
├── v1.6.4.md
├── v0.30.0.md
├── 0.5.0.md
├── v1.7.0.md
├── v1.6.1.md
├── v0.28.0.md
├── v1.6.2.md
├── v1.4.4.md
├── v1.5.1.md
├── v1.6.3.md
├── v1.10.1.md
├── v1.17.0.md
├── v0.26.0.md
├── v0.27.0.md
├── header.tpl.md
├── v1.19.0.md
├── v1.9.0.md
├── v1.13.0.md
├── v1.14.3.md
├── 0.21.0.md
├── v1.2.0.md
├── v1.18.0.md
├── 0.3.0.md
├── v1.4.0.md
├── v1.6.0.md
├── v1.0.0.md
├── v1.5.0.md
└── v1.3.0.md
├── .github
├── CODEOWNERS
├── ISSUE_TEMPLATE
│ ├── config.yml
│ ├── support-request.md
│ ├── feature-request.md
│ └── bug-report.md
├── FUNDING.yml
├── pull-request-template.md
├── dependabot.yaml
└── workflows
│ ├── triage.yaml
│ ├── release.yaml
│ ├── dependabot-changie.yaml
│ └── tests.yaml
├── codecov.yaml
├── docker-compose.yaml
├── internal
├── utils
│ ├── value.go
│ ├── container.go
│ ├── hcl.go
│ ├── errors_test.go
│ ├── decode.go
│ ├── mutex.go
│ ├── fields.go
│ └── errors.go
├── acctest
│ ├── utils.go
│ ├── provider_test.go
│ └── client.go
├── customtypes
│ └── localized_string_test.go
├── models
│ └── models.go
├── sharedtypes
│ └── store_key_reference.go
├── resources
│ ├── state_transition
│ │ └── model.go
│ ├── subscription
│ │ ├── upgrade_v0.go
│ │ └── downgrade_v2.go
│ ├── state
│ │ └── resource_test.go
│ ├── product_selection
│ │ ├── model_test.go
│ │ └── model.go
│ └── attribute_group
│ │ └── model.go
├── custommodifiers
│ ├── booldefault.go
│ └── emptylist.go
├── datasource
│ ├── state
│ │ ├── resource_test.go
│ │ └── resource.go
│ └── type
│ │ └── resource.go
└── customvalidator
│ ├── requires.go
│ └── field.go
├── tools
└── tools.go
├── examples
├── resources
│ ├── commercetools_custom_object
│ │ └── resource.tf
│ ├── commercetools_api_client
│ │ └── resource.tf
│ ├── commercetools_tax_category
│ │ └── resource.tf
│ ├── commercetools_channel
│ │ └── resource.tf
│ ├── commercetools_customer_group
│ │ └── resource.tf
│ ├── commercetools_shipping_zone
│ │ └── resource.tf
│ ├── commercetools_attribute_group
│ │ └── resource.tf
│ ├── commercetools_shipping_method
│ │ └── resource.tf
│ ├── commercetools_subscription
│ │ └── resource.tf
│ ├── commercetools_product_selection
│ │ └── resource.tf
│ ├── commercetools_project_settings
│ │ └── resource.tf
│ ├── commercetools_tax_category_rate
│ │ └── resource.tf
│ ├── commercetools_discount_code
│ │ └── resource.tf
│ ├── commercetools_state
│ │ └── resource.tf
│ ├── commercetools_category
│ │ └── resource.tf
│ ├── commercetools_state_transitions
│ │ └── resource.tf
│ ├── commercetools_product_discount
│ │ └── resource.tf
│ ├── commercetools_store
│ │ └── resource.tf
│ ├── commercetools_type
│ │ └── resource.tf
│ ├── commercetools_shipping_zone_rate
│ │ └── resource.tf
│ ├── commercetools_associate_role
│ │ └── resource.tf
│ ├── commercetools_business_unit_company
│ │ └── resource.tf
│ ├── commercetools_business_unit_division
│ │ └── resource.tf
│ ├── commercetools_api_extension
│ │ └── resource.tf
│ └── commercetools_product_type
│ │ └── resource.tf
└── data-sources
│ ├── commercetools_type
│ └── data-source.tf
│ └── commercetools_state
│ └── data-source.tf
├── commercetools
├── testdata
│ └── custom_fields_test
│ │ ├── commercetools_product_type.tmpl
│ │ ├── commercetools_store.tmpl
│ │ ├── commercetools_customer_group.tmpl
│ │ ├── commercetools_category.tmpl
│ │ ├── commercetools_channel.tmpl
│ │ ├── commercetools_shipping_method.tmpl
│ │ ├── commercetools_cart_discount.tmpl
│ │ ├── main.tmpl
│ │ ├── commercetools_discount_code.tmpl
│ │ └── commercetools_custom_fields.tmpl
├── helpers_test.go
├── resource_cart_discount_utils_test.go
├── provider_test.go
├── resource_cart_discount_giftlineitem_test.go
├── resource_cart_discount_totalprice_test.go
├── resource_api_extension_migrate.go
├── resource_cart_discount_absolute_test.go
├── resource_tax_category_test.go
├── resource_cart_discount_stores_test.go
├── marshalling.go
└── utils_test.go
├── .gitignore
├── .golangci.yml
├── .vscode
├── settings.json
└── launch.json
├── Dockerfile
├── templates
├── resources
│ └── shipping_zone_rate.md.tmpl
├── index.md.tmpl
└── guides
│ ├── extensions.md.tmpl
│ └── custom-fields.md.tmpl
├── .changie.yaml
├── docs
├── data-sources
│ ├── type.md
│ └── state.md
├── resources
│ ├── tax_category.md
│ ├── shipping_zone.md
│ ├── custom_object.md
│ ├── customer_group.md
│ ├── api_client.md
│ ├── attribute_group.md
│ ├── tax_category_rate.md
│ ├── state.md
│ ├── product_selection.md
│ ├── shipping_method.md
│ ├── channel.md
│ └── state_transitions.md
├── guides
│ ├── extensions.md
│ └── custom-fields.md
└── index.md
├── .goreleaser.yml
├── Taskfile.yml
└── main.go
/.changes/unreleased/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @labd/go
2 |
--------------------------------------------------------------------------------
/codecov.yaml:
--------------------------------------------------------------------------------
1 | comment: off
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 |
--------------------------------------------------------------------------------
/.changes/0.18.3.md:
--------------------------------------------------------------------------------
1 | ## 0.18.3 (2019-09-11)
2 |
3 | - Use Terraform 0.12.8 dependency
4 |
--------------------------------------------------------------------------------
/.changes/v1.0.1.md:
--------------------------------------------------------------------------------
1 | ## v1.0.1 (2022-05-25)
2 |
3 | - Minor release to fix hash error
4 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platform
2 | github: [labd]
3 |
--------------------------------------------------------------------------------
/.changes/0.21.2.md:
--------------------------------------------------------------------------------
1 | ## 0.21.2 (2020-06-11)
2 |
3 | - Resource store: Add `languages` field
4 |
--------------------------------------------------------------------------------
/.changes/0.1.1.md:
--------------------------------------------------------------------------------
1 | ## 0.1.1 (2018-10-04)
2 | ### Added
3 | - **New resource:** `commercetools_type`
4 |
--------------------------------------------------------------------------------
/.changes/0.18.0.md:
--------------------------------------------------------------------------------
1 | ## 0.18.0 (2019-08-14)
2 |
3 | - Resource state: Add `transitions` field (#74)
4 |
--------------------------------------------------------------------------------
/.changes/v1.11.1.md:
--------------------------------------------------------------------------------
1 | ## v1.11.1 - 2023-08-25
2 | ### Fixed
3 | * Change store countries to set type
4 |
--------------------------------------------------------------------------------
/.changes/0.20.0.md:
--------------------------------------------------------------------------------
1 | ## 0.20.0 (2020-02-22)
2 |
3 | - Resource subscription: Add Azure Event Grid support
4 |
--------------------------------------------------------------------------------
/.changes/0.8.0.md:
--------------------------------------------------------------------------------
1 | ## 0.8.0 (2019-05-20)
2 | ### Added
3 | - **New resource:** `commercetools_state`
4 |
--------------------------------------------------------------------------------
/.changes/v0.25.0.md:
--------------------------------------------------------------------------------
1 | ## v0.25.0 (2020-11-27)
2 |
3 | - **New resource:** `commercetools_custom_object`
4 |
--------------------------------------------------------------------------------
/.changes/v1.10.0.md:
--------------------------------------------------------------------------------
1 | ## v1.10.0 - 2023-08-11
2 | ### Added
3 | * **New data source:** commercetools_state
4 |
--------------------------------------------------------------------------------
/.changes/v1.11.2.md:
--------------------------------------------------------------------------------
1 | ## v1.11.2 - 2023-08-31
2 | ### Fixed
3 | * NotFound error not handled correctly
4 |
--------------------------------------------------------------------------------
/.changes/0.2.0.md:
--------------------------------------------------------------------------------
1 | ## 0.2.0 (2018-12-10)
2 | ### Added
3 | - **New resource:** `commercetools_product_type`
4 |
--------------------------------------------------------------------------------
/.changes/0.4.0.md:
--------------------------------------------------------------------------------
1 | ## 0.4.0 (2019-01-10)
2 | ### Fixed
3 | - Use auto-generated commercetools-go-sdk types
4 |
--------------------------------------------------------------------------------
/.changes/0.9.0.md:
--------------------------------------------------------------------------------
1 | ## 0.9.0 (2019-05-20)
2 |
3 | - Use Terraform 0.12 dependency to prepare for 0.12 release
4 |
--------------------------------------------------------------------------------
/.changes/v0.29.3.md:
--------------------------------------------------------------------------------
1 | ## v0.29.3 (2021-06-16)
2 |
3 | - Fix custom object not being read / updated correctly
4 |
--------------------------------------------------------------------------------
/.changes/v1.18.1.md:
--------------------------------------------------------------------------------
1 | ## v1.18.1 - 2024-12-04
2 | ### Fixed
3 | * Fixed default shipping_method active field
4 |
--------------------------------------------------------------------------------
/.changes/0.13.1.md:
--------------------------------------------------------------------------------
1 | ## 0.13.1 (2019-07-02)
2 |
3 | - Small fix for incorrect binary name in homebrew installation
4 |
--------------------------------------------------------------------------------
/.changes/0.18.1.md:
--------------------------------------------------------------------------------
1 | ## 0.18.1 (2019-08-19)
2 |
3 | - Change Linux release artifact back to default archive format
4 |
--------------------------------------------------------------------------------
/.changes/0.5.2.md:
--------------------------------------------------------------------------------
1 | ## 0.5.2 (2019-03-26)
2 | ### Fixed
3 | - Resource type: Fix error reading field type `Money`
4 |
--------------------------------------------------------------------------------
/.changes/v0.25.2.md:
--------------------------------------------------------------------------------
1 | ## v0.25.2 (2020-12-17)
2 |
3 | - Resource channel: Add support for updating the `key` field
4 |
--------------------------------------------------------------------------------
/.changes/v1.8.0.md:
--------------------------------------------------------------------------------
1 | ## v1.8.0 - 2023-08-03
2 | ### Added
3 | * **New resource:** `commercetools_attribute_group`
4 |
--------------------------------------------------------------------------------
/.changes/0.13.0.md:
--------------------------------------------------------------------------------
1 | ## 0.13.0 (2019-07-02)
2 |
3 | - Add brew install option to goreleaser, see README for more info
4 |
--------------------------------------------------------------------------------
/.changes/0.15.1.md:
--------------------------------------------------------------------------------
1 | ## 0.15.1 (2019-07-16)
2 |
3 | - Trying to fix Brew release now that version number is in binary
4 |
--------------------------------------------------------------------------------
/.changes/v1.7.1.md:
--------------------------------------------------------------------------------
1 | ## v1.7.1 - 2023-07-13
2 | ### Fixed
3 | * Fix discount_code resource when no predicate is given
4 |
--------------------------------------------------------------------------------
/.changes/0.12.1.md:
--------------------------------------------------------------------------------
1 | ## 0.12.1 (2019-06-26)
2 |
3 | - Resource api_client: Small fix in creating api client with new scopes
4 |
--------------------------------------------------------------------------------
/.changes/0.19.0.md:
--------------------------------------------------------------------------------
1 | ## 0.19.0 (2019-10-02)
2 |
3 | - Update all dependencies (use go 1.13, switch to terraform plugin sdk)
4 |
--------------------------------------------------------------------------------
/.changes/0.7.1.md:
--------------------------------------------------------------------------------
1 | ## 0.7.1 (2019-05-14)
2 | ### Added
3 | - Resource shipping_zone_rate: Add validation for currency codes
4 |
--------------------------------------------------------------------------------
/.changes/v0.29.1.md:
--------------------------------------------------------------------------------
1 | ## v0.29.1 (2021-05-19)
2 |
3 | - Fix category create not working with only name and slug filled in
4 |
--------------------------------------------------------------------------------
/.changes/v1.11.3.md:
--------------------------------------------------------------------------------
1 | ## v1.11.3 - 2023-09-20
2 | ### Fixed
3 | * Added fix to update countryTaxRateFallbackEnabled separately
4 |
--------------------------------------------------------------------------------
/.changes/0.11.1.md:
--------------------------------------------------------------------------------
1 | ## 0.11.1 (2019-06-26)
2 |
3 | - Resource shipping_zone: Fix creation and deletion, thanks to @sshibani !
4 |
--------------------------------------------------------------------------------
/.changes/0.21.1.md:
--------------------------------------------------------------------------------
1 | ## 0.21.1 (2020-04-22)
2 |
3 | - Resource channel: Fix read null pointer exception. Name should be optional.
4 |
--------------------------------------------------------------------------------
/.changes/0.22.1.md:
--------------------------------------------------------------------------------
1 | ## 0.22.1 (2020-07-21)
2 |
3 | - Resource store: Fix edge case where distribution channels were not updated
4 |
--------------------------------------------------------------------------------
/.changes/0.4.2.md:
--------------------------------------------------------------------------------
1 | ## 0.4.2 (2019-02-11)
2 |
3 | ### Fixed
4 | * Resource tax_category: Fix tax rate 0.0 case not being handled
5 |
--------------------------------------------------------------------------------
/.changes/v0.25.1.md:
--------------------------------------------------------------------------------
1 | ## v0.25.1 (2020-12-05)
2 |
3 | - Resource type: Fix a bug when the `input_hint` of a field was modified.
4 |
--------------------------------------------------------------------------------
/.changes/v1.4.1.md:
--------------------------------------------------------------------------------
1 | ## v1.4.1 (2022-08-19)
2 |
3 | - `resource_product_type` fix parsing the enums from the state file (#294)
4 |
--------------------------------------------------------------------------------
/.changes/0.10.0.md:
--------------------------------------------------------------------------------
1 | ## 0.10.0 (2019-06-17)
2 | ### Added
3 | - Use Terraform 0.12.2 dependency for compatability with latest version
4 |
--------------------------------------------------------------------------------
/.changes/v1.14.2.md:
--------------------------------------------------------------------------------
1 | ## v1.14.2 - 2024-04-19
2 | ### Fixed
3 | * Added documentation hint on importing commercetools_shipping_zone_rate
4 |
--------------------------------------------------------------------------------
/.changes/v1.16.0.md:
--------------------------------------------------------------------------------
1 | ## v1.16.0 - 2024-10-10
2 | ### Added
3 | * `resource_api_extension` add support for triggers on `shopping-list``
4 |
--------------------------------------------------------------------------------
/.changes/0.5.4.md:
--------------------------------------------------------------------------------
1 | ## 0.5.4 (2019-04-14)
2 |
3 | - Resource product_type: Fixed localized enum values being updated even if not changed
4 |
--------------------------------------------------------------------------------
/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | services:
2 | commercetools:
3 | image: labdigital/commercetools-mock-server
4 | ports:
5 | - 8989:8989
6 |
--------------------------------------------------------------------------------
/.changes/0.12.0.md:
--------------------------------------------------------------------------------
1 | ## 0.12.0 (2019-06-26)
2 |
3 | **Breaking chanages**
4 |
5 | - Resource api_client: Changed scope type from string to set
6 |
--------------------------------------------------------------------------------
/.changes/v0.29.0.md:
--------------------------------------------------------------------------------
1 | ## v0.29.0 (2021-04-23)
2 |
3 | - Resource Project: Add project level cart `delete_days_after_last_modification` setting
4 |
--------------------------------------------------------------------------------
/.changes/0.11.0.md:
--------------------------------------------------------------------------------
1 | ## 0.11.0 (2019-06-20)
2 | ### Added
3 | - Use new Commercetools Go SDK to set the User-Agent header on Commercetools HTTP requests.
4 |
--------------------------------------------------------------------------------
/.changes/0.18.2.md:
--------------------------------------------------------------------------------
1 | ## 0.18.2 (2019-09-10)
2 |
3 | - Brew release Linux has incorrect artifact name
4 | - Set GOPROXY for possible unreachable go packages
5 |
--------------------------------------------------------------------------------
/.changes/v1.14.0.md:
--------------------------------------------------------------------------------
1 | ## v1.14.0 - 2024-01-26
2 | ### Added
3 | * Added support for confluence cloud subscriptions
4 | ### Fixed
5 | * Updated documentation
6 |
--------------------------------------------------------------------------------
/.changes/v1.15.0.md:
--------------------------------------------------------------------------------
1 | ## v1.15.0 - 2024-08-30
2 | ### Added
3 | * Added resources for associate role and business units and extended project setting options
4 |
--------------------------------------------------------------------------------
/.changes/v1.4.2.md:
--------------------------------------------------------------------------------
1 | ## v1.4.2 (2022-08-24)
2 |
3 | - Fix setting custom field values on supported resources when the fiedl type
4 | is a set (#299)
5 |
--------------------------------------------------------------------------------
/.changes/v0.24.1.md:
--------------------------------------------------------------------------------
1 | ## v0.24.1 (2020-11-13)
2 |
3 | - Resource tax_rate: Add a workaround to handle an issue with changing id's after a tax category update
4 |
--------------------------------------------------------------------------------
/.changes/v1.11.4.md:
--------------------------------------------------------------------------------
1 | ## v1.11.4 - 2023-09-26
2 | ### Fixed
3 | * prevented issue with bool valueunknown check
4 | * Custom Field Unset Causing Provider Crash
5 |
--------------------------------------------------------------------------------
/.changes/v1.2.1.md:
--------------------------------------------------------------------------------
1 | ## v1.2.1 (2022-06-16)
2 |
3 | - Fix api_extension resource to not error out when the new condition field is
4 | not defined. (#261)
5 |
--------------------------------------------------------------------------------
/.changes/0.14.0.md:
--------------------------------------------------------------------------------
1 | ## 0.14.0 (2019-07-04)
2 |
3 | - Use new Commercetools Go SDK definitions (main change is Reference is now
4 | ResourceIdentifier resource)
5 |
--------------------------------------------------------------------------------
/internal/utils/value.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | // GetRef gets the reference of value with generic type
4 | func GetRef[T any](value T) *T {
5 | return &value
6 | }
7 |
--------------------------------------------------------------------------------
/.changes/unreleased/Dependency-20250201-204222.yaml:
--------------------------------------------------------------------------------
1 | kind: Dependency
2 | body: 'chore(deps): bump the go group with 4 updates'
3 | time: 2025-02-01T20:42:22.21194155Z
4 |
--------------------------------------------------------------------------------
/.changes/v0.1.0.md:
--------------------------------------------------------------------------------
1 |
2 | ## 0.1.0 (2018-09-14)
3 | ### Added
4 | * `commercetools_api_extension`
5 | * `commercetools_subscription`
6 | * `commercetools_project_settings`
7 |
--------------------------------------------------------------------------------
/.changes/v0.26.1.md:
--------------------------------------------------------------------------------
1 | ## v0.26.1 (2021-01-21)
2 |
3 | - Resource api_extension: Fixed typo in `trigger` field name that caused updates to actions in triggers to fail
4 |
--------------------------------------------------------------------------------
/.changes/v0.29.2.md:
--------------------------------------------------------------------------------
1 | ## v0.29.2 (2021-05-19)
2 |
3 | - Fix orderHint not being set but key on category being cleared. Note this will clear orderHint if it's not set.
4 |
--------------------------------------------------------------------------------
/.changes/v1.11.0.md:
--------------------------------------------------------------------------------
1 | ## v1.11.0 - 2023-08-25
2 | ### Added
3 | * Added associate role resource
4 | ### Fixed
5 | * Fixed bad handling of secrets on subscription import
6 |
--------------------------------------------------------------------------------
/.changes/v1.6.7.md:
--------------------------------------------------------------------------------
1 | ## v1.6.7 (2023-01-24)
2 | ### Fixed
3 | * `resource_project` Add extra checks to make sure we have a `message` block
4 | before reading it(#340)
5 |
--------------------------------------------------------------------------------
/.changes/0.5.3.md:
--------------------------------------------------------------------------------
1 | ## 0.5.3 (2019-03-27)
2 |
3 | - Resource product_type: Implement description update
4 | - Resource product_type: Implement localized enum label change
5 |
--------------------------------------------------------------------------------
/.changes/v0.25.3.md:
--------------------------------------------------------------------------------
1 | ## v0.25.3 (2020-12-17)
2 |
3 | - Resource store: Force creation of new resource when changing the keyL there is no update action for this available.
4 |
--------------------------------------------------------------------------------
/.changes/v1.6.5.md:
--------------------------------------------------------------------------------
1 | ## v1.6.5 (2023-01-24)
2 |
3 | ### Added
4 | * Add new data source data `commercetools_type` to retrieve information
5 | about a type based on the key.
6 |
--------------------------------------------------------------------------------
/.changes/0.5.1.md:
--------------------------------------------------------------------------------
1 | ## 0.5.1 (2019-03-20)
2 |
3 | - Resource tax_category_rate: Fix import existing instance
4 | - Resource tax_category_rate: Fix tax rate edge case for 0 amount
5 |
--------------------------------------------------------------------------------
/.changes/v1.13.1.md:
--------------------------------------------------------------------------------
1 | ## v1.13.1 - 2024-01-22
2 | ### Fixed
3 | * Added more support for IETF BCP 47 language tags
4 | * Added support for totalPrice target on cart_discount resource
5 |
--------------------------------------------------------------------------------
/.changes/0.4.1.md:
--------------------------------------------------------------------------------
1 | ## 0.4.1 (2019-01-28)
2 | ### Added
3 | * **New resource:** `commercetools_shipping_zone`
4 |
5 | ### Fixed
6 | * Fix resource\_type attribute label not mapping correctly
7 |
--------------------------------------------------------------------------------
/.changes/v0.24.0.md:
--------------------------------------------------------------------------------
1 | ## v0.24.0 (2020-11-13)
2 |
3 | - Resource store: Add `supply_channels` field
4 | - Resource tax_category_rate: Handle non-existing tax rates when refreshing state
5 |
--------------------------------------------------------------------------------
/.changes/v1.1.0.md:
--------------------------------------------------------------------------------
1 | ## v1.1.0 (2022-06-01)
2 |
3 | - Fix out of bounds error in the commercetools_type resource (#241)
4 | - Handle changes to access_secret in api_extension resource (#243)
5 |
--------------------------------------------------------------------------------
/.changes/v1.15.1.md:
--------------------------------------------------------------------------------
1 | ## v1.15.1 - 2024-09-03
2 | ### Fixed
3 | * Fixed shipping_zone_rate freeAbove handling when empty
4 | ### Dependency
5 | * chore(deps): bump the go group with 5 updates
6 |
--------------------------------------------------------------------------------
/.changes/v1.6.9.md:
--------------------------------------------------------------------------------
1 | ## v1.6.9 (2023-02-27)
2 | ### Fixed
3 | * `resource_subscription` Fix handling of missing subscriptions available in
4 | the state but not in commercetools. (#345)
5 |
--------------------------------------------------------------------------------
/internal/acctest/utils.go:
--------------------------------------------------------------------------------
1 | package acctest
2 |
3 | import "github.com/google/uuid"
4 |
5 | func IsValidUUID(value string) error {
6 | _, err := uuid.Parse(value)
7 | return err
8 | }
9 |
--------------------------------------------------------------------------------
/.changes/0.17.0.md:
--------------------------------------------------------------------------------
1 | ## 0.17.0 (2019-08-06)
2 |
3 | - Resource api_extension: Update Extension resource to add `timeout_in_ms` (#80)
4 | - Resource shipping_method: Add `predicate` field (#82)
5 |
--------------------------------------------------------------------------------
/.changes/0.16.0.md:
--------------------------------------------------------------------------------
1 | ## 0.16.0 (2019-07-22)
2 |
3 | - Resource project: Add support for setting the externalOAuth field (#73)
4 | - Resource state: Add support for the StateRole Return item (#77)
5 |
--------------------------------------------------------------------------------
/.changes/0.7.0.md:
--------------------------------------------------------------------------------
1 | ## 0.7.0 (2019-05-08)
2 | ### Added
3 | - **New resource:** `commercetools_store` **This is an alpha Commercetools resource**
4 |
5 | ### Fixed
6 | - Use latest commercetools Go SDK
7 |
--------------------------------------------------------------------------------
/.changes/v0.23.0.md:
--------------------------------------------------------------------------------
1 | ## v0.23.0 (2020-08-28)
2 |
3 | - New tag naming scheme (prefix with v) to conform to terraform repository requirements
4 | - Update terraform-plugin-sdk for compatibility with terraform 0.13
5 |
--------------------------------------------------------------------------------
/.changes/v1.6.6.md:
--------------------------------------------------------------------------------
1 | ## v1.6.6 (2023-01-24)
2 | ### Fixed
3 | * `resource_subscription` Remove requirement to specify `access_key` when
4 | the `access_secret` is defined. The latter is only needed for EventGrid.
5 |
--------------------------------------------------------------------------------
/tools/tools.go:
--------------------------------------------------------------------------------
1 | //go:build tools
2 | // +build tools
3 |
4 | package tools
5 |
6 | import (
7 | // document generation
8 |
9 | _ "github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs"
10 | )
11 |
--------------------------------------------------------------------------------
/.changes/0.1.0.md:
--------------------------------------------------------------------------------
1 | ## 0.1.0 (2018-09-14)
2 | ### Added
3 | * **New resource:** `commercetools_api_extension`
4 | * **New resource:** `commercetools_subscription`
5 | * **New resource:** `commercetools_project_settings`
6 |
--------------------------------------------------------------------------------
/.changes/v1.12.0.md:
--------------------------------------------------------------------------------
1 | ## v1.12.0 - 2023-10-06
2 | ### Added
3 | * Add new resource `commercetools_product_selection`
4 | * Add property `product_selection` to `commercetools_store` for binding product selections to stores
5 |
--------------------------------------------------------------------------------
/.changes/v1.14.1.md:
--------------------------------------------------------------------------------
1 | ## v1.14.1 - 2024-02-09
2 | ### Fixed
3 | * Properly handle resource not found errors for `subscription`, `state`, `state_transitions`, `product_selection`, `attribute_group` and `associate_role`.
4 |
--------------------------------------------------------------------------------
/.changes/v1.6.8.md:
--------------------------------------------------------------------------------
1 | ## v1.6.8 (2023-02-02)
2 | ### Fixed
3 | * `resource_subscription` Fix removing requirement to specify `access_key` when
4 | the `access_secret` is defined. The latter is only needed for EventGrid.
5 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_custom_object/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_custom_object" "my-custom-object" {
2 | container = "my-container"
3 | key = "my-key"
4 | value = jsonencode(10)
5 | }
6 |
--------------------------------------------------------------------------------
/.changes/0.6.0.md:
--------------------------------------------------------------------------------
1 | ## 0.6.0 (2019-04-26)
2 |
3 | - **New resource:** `commercetools_shipping_method`
4 | - **New resource:** `commercetools_shipping_zone_rate`, *Subject to changes, tiers/validation is not yet implemented*
5 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_api_client/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_api_client" "my-api-client" {
2 | name = "My API Client"
3 | scope = ["manage_orders:my-ct-project-key", "manage_payments:my-ct-project-key"]
4 | }
5 |
--------------------------------------------------------------------------------
/.changes/0.15.0.md:
--------------------------------------------------------------------------------
1 | ## 0.15.0 (2019-07-16)
2 |
3 | - Use new Commercetools Go SDK definitions (main change is auto generated
4 | services, most CRUD actions are renamed)
5 | - Fix Goreleaser not putting version number in released binary
6 |
--------------------------------------------------------------------------------
/.changes/0.22.0.md:
--------------------------------------------------------------------------------
1 | ## 0.22.0 (2020-07-20)
2 |
3 | - Resource store: Add `distribution_channels` field
4 | - Update commercetools-go-sdk dependency to v0.2.0. This version now properly
5 | handles oauth2 authentication failures (#117)
6 |
--------------------------------------------------------------------------------
/.changes/v1.6.4.md:
--------------------------------------------------------------------------------
1 | ## v1.6.4 (2023-01-23)
2 |
3 | - `resource_subscription` fix issue in the state upgrader when upgrading
4 | from schema version 0 to 1.
5 | - `resource_state` fix handling of both the name and description attributes.
6 |
--------------------------------------------------------------------------------
/internal/utils/container.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "github.com/labd/commercetools-go-sdk/platform"
5 | )
6 |
7 | type ProviderData struct {
8 | Client *platform.ByProjectKeyRequestBuilder
9 | Mutex *MutexKV
10 | }
11 |
--------------------------------------------------------------------------------
/commercetools/testdata/custom_fields_test/commercetools_product_type.tmpl:
--------------------------------------------------------------------------------
1 | {{define "commercetools_product_type"}}
2 | resource "commercetools_product_type" "test" {
3 | key = "product-type"
4 | name = "Product Type"
5 | }
6 | {{end}}
--------------------------------------------------------------------------------
/examples/resources/commercetools_tax_category/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_tax_category" "my-tax-category" {
2 | key = "my-tax-category-key"
3 | name = "Standard tax category"
4 | description = "Example category"
5 | }
6 |
--------------------------------------------------------------------------------
/.changes/v0.30.0.md:
--------------------------------------------------------------------------------
1 | ## v0.30.0 (2021-08-04)
2 |
3 | - Resource project: Add `shipping_rate_input_type` setting to enable tiered pricing for a project
4 | - Resource shipping_zone_rate: Add `shipping_rate_price_tier` setting to set up tiered pricing
5 |
6 |
--------------------------------------------------------------------------------
/.changes/0.5.0.md:
--------------------------------------------------------------------------------
1 | ## 0.5.0 (2019-03-19)
2 |
3 | - **New resource** `commercetools_tax_category_rate`
4 | - Resource tax_category: removed `rate` in favour of `commercetools_tax_category_rate`
5 | - Resource shipping_zone: Fix add/remove location logic.
6 |
--------------------------------------------------------------------------------
/.changes/v1.7.0.md:
--------------------------------------------------------------------------------
1 | ## v1.7.0 (2023-05-22)
2 | ### Fixed
3 | * fix: remove duplicate project_key in example. (#350)
4 | * chore: update to latest packages
5 | * fix: set `URI` for destination of EventGrid (#364)
6 | * fix: improve README for local run (#370)
7 |
--------------------------------------------------------------------------------
/commercetools/testdata/custom_fields_test/commercetools_store.tmpl:
--------------------------------------------------------------------------------
1 | {{define "commercetools_store"}}
2 | resource "commercetools_store" "{{.resource_name}}" {
3 | key = "{{.resource_key}}"
4 | {{if .custom}}{{template "custom" .}}{{end}}
5 | }
6 | {{end}}
--------------------------------------------------------------------------------
/.changes/v1.6.1.md:
--------------------------------------------------------------------------------
1 | ## v1.6.1 (2023-01-11)
2 |
3 | - `resource_project_settings` fix validation of values for the
4 | `delete_days_after_creation` field (should be between 1-90)
5 | - `resource_subscription` fix errors when the `format` block was missing (#331)
6 |
7 |
--------------------------------------------------------------------------------
/.changes/v0.28.0.md:
--------------------------------------------------------------------------------
1 | ## v0.28.0 (2021-04-08)
2 |
3 | - **New resource:** `commercetools_category`
4 | - Resource API Extension: Removed unused `azure_functions` type
5 | - Add CheckDestroy funcs to all tests
6 | - Add TFDocs documentation parallel to readthedocs documentation
7 |
--------------------------------------------------------------------------------
/.changes/v1.6.2.md:
--------------------------------------------------------------------------------
1 | ## v1.6.2 (2023-01-11)
2 |
3 | - `resource_state` rewrite both the `state` and `state_transitions` resource
4 | and move the code to the new plugin-framework. This should fix some related
5 | to mismatching version values by always refreshing these. (#333)
6 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_channel/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_channel" "my-channel" {
2 | key = "my-channel-key"
3 | roles = ["ProductDistribution"]
4 | name = {
5 | nl-NL = "Channel"
6 | }
7 | description = {
8 | nl-NL = "Channel"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/.changes/v1.4.4.md:
--------------------------------------------------------------------------------
1 | ## v1.4.4 (2022-09-23)
2 |
3 | - Additional fixes to setting custom field values on supported resources. (#303)
4 | - `resource_api_extension` Fix handling masked values for `azure_authentication` (#306)
5 | - `resource_subscription` Fix handling masked values for `event_grid` (#306)
6 |
--------------------------------------------------------------------------------
/.changes/v1.5.1.md:
--------------------------------------------------------------------------------
1 | ## v1.5.1 (2022-10-04)
2 |
3 | - `resource_state_transitions` fix error when we tried to set the transitions
4 | value to a value already set in commercetools, causing an error. See #312
5 | - `resource_state_transitions` add support for importing existing state
6 | transitions
7 |
--------------------------------------------------------------------------------
/.changes/v1.6.3.md:
--------------------------------------------------------------------------------
1 | ## v1.6.3 (2023-01-20)
2 |
3 | - `resource_subscription` fix the `GoogleCloudPubSub` integration where the
4 | wrong topic value was used (#337).
5 | - `resource_project_settings` fix continous terraform updates for the
6 | `shipping_rate_cart_classification_value` block (#335)
7 |
--------------------------------------------------------------------------------
/commercetools/testdata/custom_fields_test/commercetools_customer_group.tmpl:
--------------------------------------------------------------------------------
1 | {{define "commercetools_customer_group"}}
2 | resource "commercetools_customer_group" "{{.resource_name}}" {
3 | key = "{{.resource_key}}"
4 | name = "Test Customer Group"
5 | {{if .custom}}{{template "custom" .}}{{end}}
6 | }
7 | {{end}}
--------------------------------------------------------------------------------
/.changes/v1.10.1.md:
--------------------------------------------------------------------------------
1 | ## v1.10.1 - 2023-08-17
2 | ### Fixed
3 | * Fixed forced replacement issue in commercetools_category when name or key change
4 | * Fixed custom field encoding with non-string field values
5 | * Added correct handling of azure_authentication to prevent unnecessary updates
6 | * Added custom field for cart discount
7 |
--------------------------------------------------------------------------------
/.changes/v1.17.0.md:
--------------------------------------------------------------------------------
1 | ## v1.17.0 - 2024-11-01
2 | ### Added
3 | * Added handling of product search and customer search indexes
4 | * Added stores to cart discounts
5 | ### Dependency
6 | * chore(deps): bump labd/changie-release-action from 0.4.0 to 0.5.0 in the github-actions group
7 | * chore(deps): bump the go group with 4 updates
8 |
--------------------------------------------------------------------------------
/.changes/v0.26.0.md:
--------------------------------------------------------------------------------
1 | ## v0.26.0 (2021-01-12)
2 |
3 | - **New resource** `commercetools_customer_group` (#141)
4 | - Resource type: Allow updating the label of an existing Enum value
5 | - Resource type: Add support to update a set of enum in a custom type
6 | - Fix ProductType and DiscountCode tests with real commercetools environment
7 |
--------------------------------------------------------------------------------
/.changes/v0.27.0.md:
--------------------------------------------------------------------------------
1 | ## v0.27.0 (2021-03-01)
2 |
3 | - Resource project: Add `carts` field with countryTaxRateFallBackEnabled setting
4 | - Resource project: Fix updating of `messages` field to explicitly set `false` when deleted or set to false in terraform instead of relying on commercetools default settings for project in these scenarios
5 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_customer_group/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_customer_group" "standard" {
2 | key = "my-customer-group-key"
3 | name = "Standard Customer Group"
4 | }
5 |
6 | resource "commercetools_customer_group" "golden" {
7 | key = "my-customer-group-key"
8 | name = "Golden Customer Group"
9 | }
10 |
--------------------------------------------------------------------------------
/.changes/header.tpl.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 | All notable changes to this project will be documented in this file.
3 |
4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5 | adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
6 | and is generated by [Changie](https://github.com/miniscruff/changie).
7 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_shipping_zone/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_shipping_zone" "de-us" {
2 | key = "some-key"
3 | name = "DE and US"
4 | description = "Germany and US"
5 | location {
6 | country = "DE"
7 | }
8 | location {
9 | country = "US"
10 | state = "Nevada"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/internal/acctest/provider_test.go:
--------------------------------------------------------------------------------
1 | package acctest
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/assert"
7 |
8 | "github.com/labd/terraform-provider-commercetools/internal/provider"
9 | )
10 |
11 | func TestProvider(t *testing.T) {
12 | p := provider.New("version")
13 |
14 | assert.NotNil(t, p)
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/support-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Support request
3 | about: When you have a generic question
4 | title: ''
5 | labels: question, triage
6 | assignees: ''
7 |
8 | ---
9 |
10 | Describe your question here. Please provide as much detail as possible. If you
11 | have a specific use case, please provide that as well.
12 | ```
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | terraform-provider-commercetools
2 | terraform-provider-commercetools_*
3 | *.backup
4 | /dist/*
5 | coverage.txt
6 |
7 | # Terraform files
8 | .terraform/
9 | terraform.*
10 | crash.log
11 |
12 |
13 | # Local files
14 | /local/*
15 | !/local/*.example
16 |
17 | # Go modules
18 | vendor/
19 |
20 | /.idea
21 | /.env
22 | /go.work*
23 |
--------------------------------------------------------------------------------
/internal/utils/hcl.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "bytes"
5 | "text/template"
6 | )
7 |
8 | func HCLTemplate(data string, params map[string]any) string {
9 | var out bytes.Buffer
10 | tmpl := template.Must(template.New("hcl").Parse(data))
11 | err := tmpl.Execute(&out, params)
12 | if err != nil {
13 | panic(err)
14 | }
15 | return out.String()
16 | }
17 |
--------------------------------------------------------------------------------
/.changes/v1.19.0.md:
--------------------------------------------------------------------------------
1 | ## v1.19.0 - 2025-01-10
2 | ### Added
3 | * Added generic custom field support to all newer resources
4 | ### Fixed
5 | * This adds a sorting of the permissions we get from the commercetools API response, so that it's identical to the one from the plan.
6 | * Fixed broken links in documentation
7 | ### Dependency
8 | * chore(deps): bump the go group with 3 updates
9 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: When you are missing a specific feature
4 | title: ''
5 | labels: enhancement, triage
6 | assignees: ''
7 |
8 | ---
9 |
10 | Describe the feature you would like to see implemented. Please provide as much
11 | detail as possible. If you have a specific use case, please provide that as
12 | well.
13 |
--------------------------------------------------------------------------------
/commercetools/helpers_test.go:
--------------------------------------------------------------------------------
1 | package commercetools
2 |
3 | import (
4 | "bytes"
5 | "text/template"
6 | )
7 |
8 | func hclTemplate(data string, params map[string]any) string {
9 | var out bytes.Buffer
10 | tmpl := template.Must(template.New("hcl").Parse(data))
11 | err := tmpl.Execute(&out, params)
12 | if err != nil {
13 | panic(err)
14 | }
15 | return out.String()
16 | }
17 |
--------------------------------------------------------------------------------
/examples/data-sources/commercetools_type/data-source.tf:
--------------------------------------------------------------------------------
1 | data "commercetools_type" "existing_type" {
2 | key = "test"
3 | }
4 |
5 | resource "commercetools_channel" "test" {
6 | key = "test"
7 | roles = ["ProductDistribution"]
8 | custom {
9 | type_id = data.commercetools_type.existing_type.id
10 | fields = {
11 | "my-field" = "foobar"
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/.changes/v1.9.0.md:
--------------------------------------------------------------------------------
1 | ## v1.9.0 - 2023-08-09
2 | ### Added
3 | * **commercertools_api_extension:** added googlecloudfunction as option
4 | * **commercertools_cart_discount:** added multiBuyLineItems and multiBuyCustomLineItems
5 | * **commercertools_store:** added countries field
6 | ### Fixed
7 | * **commercertools_type:** doc changes to source files
8 | * **commercertools_cart_discount:** fixed money list issue
9 |
--------------------------------------------------------------------------------
/.golangci.yml:
--------------------------------------------------------------------------------
1 | linters:
2 | disable-all: true
3 | enable:
4 | - asciicheck
5 | - bodyclose
6 | - contextcheck
7 | - cyclop
8 | - errcheck
9 | - exhaustive
10 | - exportloopref
11 | - forcetypeassert
12 | - goimports
13 | - gosimple
14 | - govet
15 | - ineffassign
16 | - predeclared
17 | - staticcheck
18 | - tenv
19 | - typecheck
20 | - unused
21 | - whitespace
22 |
--------------------------------------------------------------------------------
/commercetools/testdata/custom_fields_test/commercetools_category.tmpl:
--------------------------------------------------------------------------------
1 | {{define "commercetools_category"}}
2 | resource "commercetools_category" "{{.resource_name}}" {
3 | key = "{{.resource_key}}"
4 | name = {
5 | en = "commercetools category name"
6 | }
7 | slug = {
8 | en = "commercetools_category"
9 | }
10 | {{if .custom}}{{template "custom" .}}{{end}}
11 | }
12 | {{end}}
--------------------------------------------------------------------------------
/.changes/v1.13.0.md:
--------------------------------------------------------------------------------
1 | ## v1.13.0 - 2023-11-16
2 | ### Added
3 | * update to latest commercetools go sdk
4 | * Code cleanup
5 | ### Fixed
6 | * Added additional check for unset values on discount_code resource
7 | * ensure an empty slice is set if subscription messages or changes are removed
8 | * fixed check on project ExternalOAuth setting when processing state and plan differences
9 | * Updated deprecated code
10 |
--------------------------------------------------------------------------------
/commercetools/testdata/custom_fields_test/commercetools_channel.tmpl:
--------------------------------------------------------------------------------
1 | {{define "commercetools_channel"}}
2 | resource "commercetools_channel" {{.resource_name}} {
3 | key = "{{.resource_key}}"
4 | roles = ["ProductDistribution"]
5 | name = {
6 | nl-NL = "Channel"
7 | }
8 | description = {
9 | nl-NL = "Channel"
10 | }
11 | {{if .custom}}{{template "custom" .}}{{end}}
12 | }
13 | {{end}}
14 |
--------------------------------------------------------------------------------
/.changes/v1.14.3.md:
--------------------------------------------------------------------------------
1 | ## v1.14.3 - 2024-05-17
2 | ### Dependency
3 | * chore(deps): bump the go group across 1 directory with 9 updates
4 | * chore(deps): bump the github-actions group across 1 directory with 7 updates
5 | * chore(deps): bump golang.org/x/net from 0.22.0 to 0.23.0
6 | * chore(deps): bump the go group with 3 updates
7 | * chore(deps): bump actions/add-to-project from 0.5.0 to 1.0.1 in the github-actions group
8 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_attribute_group/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_attribute_group" "my-attribute-group" {
2 | key = "my-attribute-group-key"
3 | name = {
4 | en = "my-attribute-group-name"
5 | }
6 | description = {
7 | en = "my-attribute-group-description"
8 | }
9 |
10 | attribute {
11 | key = "attribute-key-1"
12 | }
13 |
14 | attribute {
15 | key = "attribute-key-2"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "go.testEnvVars": {
3 | "TF_ACC": "1",
4 | "TF_LOG": "INFO",
5 | "CTP_DEBUG": "1",
6 | "CTP_CLIENT_ID": "unittest",
7 | "CTP_CLIENT_SECRET": "x",
8 | "CTP_PROJECT_KEY": "unittest",
9 | "CTP_SCOPES": "manage_project:projectkey",
10 | "CTP_API_URL": "http://localhost:8989",
11 | "CTP_AUTH_URL": "http://localhost:8989",
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/.changes/0.21.0.md:
--------------------------------------------------------------------------------
1 | ## 0.21.0 (2020-02-27)
2 |
3 | - Provider arguments (`client_id`, `client_secret`, `project_key`,
4 | `scopes`, `token_url` and `api_url`) are now required
5 | - Resource api_client: Updating now recreates the resource since
6 | it cannot be updated.
7 | - Don't retry various calls if Commercetools returns an error (resulting in
8 | unnecessary retries/waiting times).
9 | - Dependency update: use terraform-plugin-sdk 1.7.0
10 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:1.13.1-stretch AS build-env
2 | WORKDIR /terraform-provider
3 |
4 | ADD . /terraform-provider
5 |
6 | ENV GOPROXY=https://proxy.golang.org
7 | RUN go mod download
8 | RUN go build -o terraform-provider-commercetools
9 |
10 | # final stage
11 | FROM hashicorp/terraform:0.12.9
12 |
13 | RUN apk add libc6-compat
14 |
15 | WORKDIR /config
16 |
17 | COPY --from=build-env /terraform-provider/terraform-provider-commercetools /bin
18 |
--------------------------------------------------------------------------------
/.changes/v1.2.0.md:
--------------------------------------------------------------------------------
1 | ## v1.2.0 (2022-06-15)
2 |
3 | - Fix shipping_zone locations ordering by switching to a set instead of a list
4 | of locations (#259)
5 | - Add aliases for destination and platform on subscription and extension
6 | resources (#245, #247, #251)
7 | - Add condition field to api extension resource
8 | - Add support for terraform import on the api_extension resource
9 | - Improve error handling, show errors returned by commercetools in terraform
10 | output.
11 |
--------------------------------------------------------------------------------
/.changes/v1.18.0.md:
--------------------------------------------------------------------------------
1 | ## v1.18.0 - 2024-12-03
2 | ### Added
3 | * `resource_api_client` add support for setting and managing token validity via Terraform.
4 | * Added the attribute ShippingMethod.active to the resource shipping_method.
5 | ### Dependency
6 | * chore(deps): bump the go group with 6 updates
7 | * chore(deps): bump actions/add-to-project from 0.5.0 to 1.0.2 in the github-actions group
8 | * chore(deps): bump the go group with 6 updates
9 | * chore(deps): bump codecov/codecov-action from 4 to 5 in the github-actions group
10 |
--------------------------------------------------------------------------------
/.github/pull-request-template.md:
--------------------------------------------------------------------------------
1 |
6 |
7 |
12 |
13 | Fixes #
14 |
15 | ### NEW FEATURES | UPGRADE NOTES | ENHANCEMENTS | BUG FIXES | EXPERIMENTS
16 |
17 |
26 |
27 | -
28 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_shipping_method/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_tax_category" "some-tax-category" {
2 | key = "some-tax-category-key"
3 | name = "some test cateogry"
4 | description = "test category"
5 | }
6 |
7 | resource "commercetools_shipping_method" "standard" {
8 | key = "standard-key"
9 | name = "Standard tax category"
10 | description = "Standard tax category"
11 | is_default = true
12 | tax_category_id = commercetools_tax_category.some-tax-category.id
13 | predicate = "1 = 1"
14 | }
15 |
--------------------------------------------------------------------------------
/.github/dependabot.yaml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "gomod"
4 | directory: "/"
5 | schedule:
6 | interval: "monthly"
7 | day: tuesday
8 | commit-message:
9 | prefix: "chore(deps)"
10 | groups:
11 | go:
12 | patterns:
13 | - "*"
14 |
15 | - package-ecosystem: "github-actions"
16 | directory: "/"
17 | schedule:
18 | interval: "monthly"
19 | day: tuesday
20 | commit-message:
21 | prefix: "chore(deps)"
22 | groups:
23 | github-actions:
24 | patterns:
25 | - "*"
26 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_subscription/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_subscription" "my-sqs-subscription" {
2 | key = "my-sqs-subscription-key"
3 | destination {
4 | type = "SQS"
5 | queue_url = aws_sqs_queue.your-queue.id
6 | access_key = aws_iam_access_key.ct.id
7 | access_secret = aws_iam_access_key.ct.secret
8 | region = "eu-west-1"
9 | }
10 |
11 | changes {
12 | resource_type_ids = ["product"]
13 | }
14 |
15 | message {
16 | resource_type_id = "product"
17 | types = ["ProductPublished", "ProductCreated"]
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/.changes/0.3.0.md:
--------------------------------------------------------------------------------
1 | ## 0.3.0 (2018-12-10)
2 | ### Added
3 | - **New resource:** `commercetools_channel`
4 | - **New resource:** `commercetools_tax_category`
5 |
6 | ### Fixed
7 | - Resource product_type: made `attribute` elements optional
8 | - Resource product_type: Validate/protect `required` element on Product type attribute
9 | - Resource product_type: Avoid `changeAttributeOrder` update action when new attribute gets added
10 | - Resource product_type: Added support for Nested types
11 | - Resource type: Validate/protect `required` element on Type attribute
12 | - Resource type: Avoid `changeAttributeOrder` update action when new attribute gets added
13 |
--------------------------------------------------------------------------------
/templates/resources/shipping_zone_rate.md.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}"
3 | subcategory: ""
4 | description: |-
5 | {{ .Description | plainmarkdown | trimspace | prefixlines " " }}
6 | ---
7 |
8 | # {{.Name}} ({{.Type}})
9 |
10 | {{ .Description | trimspace }}
11 |
12 | ## Example Usage
13 |
14 | {{ tffile (printf "examples/resources/%s/resource.tf" .Name)}}
15 |
16 | {{ .SchemaMarkdown | trimspace }}
17 |
18 | ## Import
19 |
20 | Import is supported using the following syntax:
21 |
22 | ```shell
23 | terraform import commercetools_shipping_zone_rate.my-shipping-zone-rate {my-shipping-method-id}@{my-shipping-zone-id}@{currency}
24 | ```
25 |
--------------------------------------------------------------------------------
/.changes/v1.4.0.md:
--------------------------------------------------------------------------------
1 | ## v1.4.0 (2022-08-18)
2 |
3 | - `resource_product_discount` new resource to manage product discounts (#266)
4 | - `resource_subscription`: Fix a bug where remove the `changes` or `messages`
5 | from the resource was resulting in an invalid request. (#138)
6 | - `resource_shipping_zone_rate` Fix persisting the shipping rate tiers in the
7 | terraform state (#184)
8 | - `resource_api_extension` Fix handling of retrieving secrets from
9 | commercetools (#284)
10 | - `resource_subscription` Fix handling changes in both `changes` and `messages`
11 | attributes (#138)
12 | - Fix setting custom fields on the various resources when the type is not a
13 | string (#289)
14 |
--------------------------------------------------------------------------------
/examples/data-sources/commercetools_state/data-source.tf:
--------------------------------------------------------------------------------
1 | # The Initial state is a state that is provided in a new commercetools environment by default
2 | data "commercetools_state" "initial_state" {
3 | key = "Initial"
4 | }
5 |
6 | resource "commercetools_state_transitions" "from_created_to_allocated" {
7 | from = data.commercetools_state.initial_state.id
8 | to = [
9 | commercetools_state.backorder.id,
10 | ]
11 | }
12 |
13 | resource "commercetools_state" "backorder" {
14 | key = "backorder"
15 | type = "LineItemState"
16 | name = {
17 | en = "Back Order",
18 |
19 | }
20 | description = {
21 | en = "Not available - on back order"
22 | }
23 | initial = false
24 | }
25 |
--------------------------------------------------------------------------------
/.changie.yaml:
--------------------------------------------------------------------------------
1 | changesDir: .changes
2 | unreleasedDir: unreleased
3 | headerPath: header.tpl.md
4 | changelogPath: CHANGELOG.md
5 | versionExt: md
6 | versionFormat: '## {{.Version}} - {{.Time.Format "2006-01-02"}}'
7 | kindFormat: '### {{.Kind}}'
8 | changeFormat: '* {{.Body}}'
9 | kinds:
10 | - label: Added
11 | auto: minor
12 | - label: Changed
13 | auto: major
14 | - label: Deprecated
15 | auto: minor
16 | - label: Removed
17 | auto: major
18 | - label: Fixed
19 | auto: patch
20 | - label: Security
21 | auto: patch
22 | - label: Dependency
23 | auto: patch
24 | newlines:
25 | afterChangelogHeader: 1
26 | beforeChangelogVersion: 1
27 | endOfVersion: 1
28 | envPrefix: CHANGIE_
29 |
--------------------------------------------------------------------------------
/commercetools/testdata/custom_fields_test/commercetools_shipping_method.tmpl:
--------------------------------------------------------------------------------
1 | {{define "commercetools_shipping_method"}}
2 | resource "commercetools_tax_category" "test_tax_category" {
3 | key = "test-tax-category-key"
4 | name = "test-tax-cateogry"
5 | description = "test tax category"
6 | }
7 | resource "commercetools_shipping_method" "{{.resource_name}}" {
8 | key = "{{.resource_key}}"
9 | name = "Test tax category"
10 | description = "Test tax category"
11 | is_default = true
12 | tax_category_id = commercetools_tax_category.test_tax_category.id
13 | predicate = "1 = 1"
14 | {{if .custom}}{{template "custom" .}}{{end}}
15 | }
16 | {{end}}
17 |
--------------------------------------------------------------------------------
/internal/utils/errors_test.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "github.com/labd/commercetools-go-sdk/platform"
5 | "github.com/stretchr/testify/assert"
6 | "testing"
7 | )
8 |
9 | func TestIsResourceNotFoundError(t *testing.T) {
10 | var cases = []struct {
11 | err error
12 | expected bool
13 | }{
14 | {platform.ErrNotFound, true},
15 | {platform.ResourceNotFoundError{}, true},
16 | {platform.ErrorResponse{StatusCode: 404}, true},
17 | {platform.ErrorResponse{StatusCode: 500}, false},
18 | {platform.GenericRequestError{StatusCode: 404}, true},
19 | {platform.GenericRequestError{StatusCode: 500}, false},
20 | }
21 |
22 | for _, tt := range cases {
23 | assert.Equal(t, tt.expected, IsResourceNotFoundError(tt.err))
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/.changes/v1.6.0.md:
--------------------------------------------------------------------------------
1 | ## v1.6.0 (2023-01-09)
2 |
3 | - `resource_project_settings` migrate the resource to the new
4 | terraform-plugin-framework.
5 | - `resource_project_settings` add property `delete_days_after_creation` to
6 | the `messages` block (#322)
7 | - `resource_subscription` Support using IAM authentication for SQS and SNS by
8 | making the access_key and access_secret attributes optional. (#316)
9 | - `resource_subscription` migrate the resource to the new
10 | terraform-plugin-framework.
11 | - `resource_subscription` fix handling of changes in the `connection_string`
12 | value when the `AzureServiceBus` is used (#320)
13 | - `resource_api_extension` add support for triggers on `business-unit`,
14 | `quote-request`, `quote`, `staged-quote` (#326)
15 |
--------------------------------------------------------------------------------
/.github/workflows/triage.yaml:
--------------------------------------------------------------------------------
1 | name: Triage
2 |
3 | on:
4 | issues:
5 | types:
6 | - opened
7 |
8 | jobs:
9 | add_to_project:
10 | name: Push issue or PR to board
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: get app token
14 | id: get-app-token
15 | uses: labd/action-gh-app-token@main
16 | with:
17 | app-id: ${{ secrets.RD_APP_ID }}
18 | private-key: ${{ secrets.RD_APP_PRIVATE_KEY }}
19 | installation-id: ${{ secrets.RD_APP_INSTALLATION_ID }}
20 | - name: set to project board
21 | uses: actions/add-to-project@v1.0.2
22 | with:
23 | project-url: https://github.com/orgs/labd/projects/3
24 | github-token: ${{ steps.get-app-token.outputs.app-token }}
25 |
--------------------------------------------------------------------------------
/commercetools/testdata/custom_fields_test/commercetools_cart_discount.tmpl:
--------------------------------------------------------------------------------
1 | {{define "commercetools_cart_discount"}}
2 | resource "commercetools_cart_discount" "{{.resource_name}}" {
3 | key = "{{.resource_key}}"
4 | name = {
5 | en = "relative name"
6 | }
7 | description = {
8 | en = "relative description"
9 | }
10 | sort_order = "0.9"
11 | predicate = "1=1"
12 | stacking_mode = "Stacking"
13 | requires_discount_code = true
14 | valid_from = "2018-01-02T15:04:05Z"
15 | valid_until = "2019-01-02T15:04:05Z"
16 | target {
17 | type = "lineItems"
18 | predicate = "1=1"
19 | }
20 | value {
21 | type = "relative"
22 | permyriad = 1000
23 | }
24 | {{if .custom}}{{template "custom" .}}{{end}}
25 | }
26 | {{end}}
--------------------------------------------------------------------------------
/examples/resources/commercetools_product_selection/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_type" "my-type" {
2 | key = "my-type"
3 | name = {
4 | en = "My type"
5 | nl = "Mijn type"
6 | }
7 |
8 | resource_type_ids = ["product-selection"]
9 |
10 | field {
11 | name = "my-field"
12 | label = {
13 | en = "My field"
14 | nl = "Mijn veld"
15 | }
16 | type {
17 | name = "String"
18 | }
19 | }
20 | }
21 |
22 | resource "commercetools_product_selection" "product-selection-us" {
23 | key = "product-selection-us"
24 | name = {
25 | en = "US Product Selection"
26 | }
27 | mode = "Individual"
28 |
29 | custom {
30 | type_id = commercetools_type.my-type.id
31 | fields = {
32 | my-field = "my-value"
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/.changes/v1.0.0.md:
--------------------------------------------------------------------------------
1 | ## v1.0.0 (2022-05-23)
2 |
3 | - Use terraform plugin sdk v2. This changed required various changes and should
4 | have made the codebase more robust.
5 | - Fix marshalling the commercetools to terraform state for various resources.
6 | - Move documentation to the terraform registry, see
7 | https://registry.terraform.io/providers/labd/commercetools/latest/docs
8 | - Use Go 1.18
9 | - Add support for AWS EventBridge subscription
10 | - Resource updates:
11 | - project_settings: do case insensitive comparison of the languages, currencies
12 | and countries
13 | - shipping_zone: make the name required
14 | - api_extension: Fix handling of timeout_in_ms when empty
15 | - category: add support for setting external_id
16 | - category: fix empty key being set on creation
17 |
18 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: When you are running into an issue
4 | title: ''
5 | labels: bug, triage
6 | assignees: ''
7 |
8 | ---
9 |
10 | ### Version information
11 | - **terraform**: _Please specify the version of Terraform you are using._
12 | - **terraform provider**: _Please specify the version of the provider you are using._
13 |
14 | ### Describe the bug
15 | A clear and concise description of what the bug is.
16 |
17 | ### To Reproduce
18 | Steps to reproduce the behavior.
19 |
20 | ### Expected behavior
21 | A clear and concise description of what you expected to happen.
22 |
23 | ### Screenshots
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | ### Additional context
27 | Add any other context about the problem here.
28 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_project_settings/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_project_settings" "my-project" {
2 | key = "my-project-key"
3 | name = "My project"
4 | countries = ["NL", "DE", "US", "CA"]
5 | currencies = ["EUR", "USD", "CAD"]
6 | languages = ["nl", "de", "en", "fr-CA"]
7 | external_oauth {
8 | url = "https://example.com/oauth/introspection"
9 | authorization_header = "Bearer secret"
10 | }
11 | messages {
12 | enabled = true
13 | }
14 | carts {
15 | country_tax_rate_fallback_enabled = true
16 | }
17 | shipping_rate_input_type = "CartClassification"
18 |
19 | shipping_rate_cart_classification_value {
20 | key = "Small"
21 | label = {
22 | "en" = "Small"
23 | "nl" = "Klein"
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/.changes/v1.5.0.md:
--------------------------------------------------------------------------------
1 | ## v1.5.0 (2022-09-30)
2 |
3 | - `resource_state_transitions` New resource to manage transitions between states.
4 | This was previously part of the `resource_state` but that made it imposible
5 | to have recursive transitions. This means that `transitions` attribute is now
6 | removed from the `resource_state` resource.
7 |
8 | example:
9 | ```hcl
10 | // Only allow transition from sale to clearance
11 | resource "commercetools_state_transitions" "transition-1" {
12 | from = commercetools_state.product_for_sale.id
13 | to = [
14 | commercetools_state.product_clearance.id,
15 | ]
16 | }
17 | ```
18 | See #86 for more information
19 | - `resource_shipping_zone_rate` Add support for `price_function` when the type
20 | is `CartScore` (#202)
21 |
22 |
--------------------------------------------------------------------------------
/commercetools/resource_cart_discount_utils_test.go:
--------------------------------------------------------------------------------
1 | package commercetools
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
7 | )
8 |
9 | func testAccCheckCartDiscountDestroy(s *terraform.State) error {
10 | client := getClient(testAccProvider.Meta())
11 |
12 | for _, rs := range s.RootModule().Resources {
13 | if rs.Type != "commercetools_cart_discount" {
14 | continue
15 | }
16 | response, err := client.CartDiscounts().WithId(rs.Primary.ID).Get().Execute(context.Background())
17 | if err == nil {
18 | if response != nil && response.ID == rs.Primary.ID {
19 | return fmt.Errorf("cart discount (%s) still exists", rs.Primary.ID)
20 | }
21 | return nil
22 | }
23 | if newErr := checkApiResult(err); newErr != nil {
24 | return newErr
25 | }
26 | }
27 | return nil
28 | }
29 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_tax_category_rate/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_tax_category" "my-tax-category" {
2 | name = "Standard tax category"
3 | description = "Example category"
4 | }
5 |
6 | resource "commercetools_tax_category_rate" "standard-tax-category-DE" {
7 | tax_category_id = commercetools_tax_category.my-tax-category.id
8 | name = "19% MwSt"
9 | amount = 0.19
10 | included_in_price = false
11 | country = "DE"
12 | sub_rate {
13 | name = "example"
14 | amount = 0.19
15 | }
16 | }
17 |
18 | resource "commercetools_tax_category_rate" "standard-tax-category-NL" {
19 | tax_category_id = commercetools_tax_category.my-tax-category.id
20 | name = "21% BTW"
21 | amount = 0.21
22 | included_in_price = true
23 | country = "NL"
24 | }
25 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_discount_code/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_discount_code" "my_discount_code" {
2 | name = {
3 | en = "My Discount code name"
4 | }
5 | description = {
6 | en = "My Discount code description"
7 | }
8 | code = "2"
9 | valid_from = "2020-01-02T15:04:05.000Z"
10 | valid_until = "2021-01-02T15:04:05.000Z"
11 | is_active = true
12 | predicate = "1=1"
13 | max_applications_per_customer = 3
14 | max_applications = 100
15 | groups = ["0", "1"]
16 | cart_discounts = ["cart-discount-id-1", "cart-discount-id-2"]
17 | }
18 |
19 | resource "commercetools_discount_code" "my_discount_code" {
20 | code = "2"
21 | cart_discounts = ["cart-discount-id-1"]
22 | }
23 |
--------------------------------------------------------------------------------
/commercetools/testdata/custom_fields_test/main.tmpl:
--------------------------------------------------------------------------------
1 | {{define "main"}}
2 | {{template "commercetools_product_type"}}
3 | {{template "commercetools_type" .}}
4 | {{if eq .resource_type "commercetools_channel"}}{{template "commercetools_channel" .}}{{end}}
5 | {{if eq .resource_type "commercetools_cart_discount"}}{{template "commercetools_cart_discount" .}}{{end}}
6 | {{if eq .resource_type "commercetools_category"}}{{template "commercetools_category" .}}{{end}}
7 | {{if eq .resource_type "commercetools_customer_group"}}{{template "commercetools_customer_group" .}}{{end}}
8 | {{if eq .resource_type "commercetools_discount_code"}}{{template "commercetools_discount_code" .}}{{end}}
9 | {{if eq .resource_type "commercetools_shipping_method"}}{{template "commercetools_shipping_method" .}}{{end}}
10 | {{if eq .resource_type "commercetools_store"}}{{template "commercetools_store" .}}{{end}}
11 | {{end}}
--------------------------------------------------------------------------------
/internal/customtypes/localized_string_test.go:
--------------------------------------------------------------------------------
1 | package customtypes
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/hashicorp/terraform-plugin-framework/attr"
7 | "github.com/hashicorp/terraform-plugin-framework/types"
8 | "github.com/labd/commercetools-go-sdk/platform"
9 | "github.com/stretchr/testify/assert"
10 | )
11 |
12 | func TestLocalizedString(t *testing.T) {
13 | val := NewLocalizedStringValue(map[string]attr.Value{
14 | "nl": types.StringValue("foobar"),
15 | })
16 |
17 | result := val.ValueLocalizedString()
18 | expected := platform.LocalizedString{
19 | "nl": "foobar",
20 | }
21 | assert.Equal(t, expected, result)
22 | }
23 |
24 | func TestLocalizedStringUnknown(t *testing.T) {
25 | val := NewLocalizedStringNull()
26 |
27 | result := val.ValueLocalizedString()
28 | expected := platform.LocalizedString(nil)
29 | assert.Equal(t, expected, result)
30 | }
31 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_state/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_state" "review_unreviewed" {
2 | key = "review-unreviewed"
3 | type = "ReviewState"
4 | name = {
5 | en = "Unreviewed"
6 | }
7 | description = {
8 | en = "Not reviewed yet"
9 | }
10 | initial = true
11 | roles = ["ReviewIncludedInStatistics"]
12 | }
13 |
14 | resource "commercetools_state" "product_for_sale" {
15 | key = "product-for-sale"
16 | type = "ProductState"
17 | name = {
18 | en = "For Sale"
19 | }
20 | description = {
21 | en = "Regularly stocked product."
22 | }
23 | initial = true
24 | }
25 |
26 | resource "commercetools_state" "product_clearance" {
27 | key = "product-clearance"
28 | type = "ProductState"
29 | name = {
30 | en = "On Clearance"
31 | }
32 | description = {
33 | en = "The product line will not be ordered again."
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/docs/data-sources/type.md:
--------------------------------------------------------------------------------
1 | ---
2 | # generated by https://github.com/hashicorp/terraform-plugin-docs
3 | page_title: "commercetools_type Data Source - terraform-provider-commercetools"
4 | subcategory: ""
5 | description: |-
6 | Fetches type information
7 | ---
8 |
9 | # commercetools_type (Data Source)
10 |
11 | Fetches type information
12 |
13 | ## Example Usage
14 |
15 | ```terraform
16 | data "commercetools_type" "existing_type" {
17 | key = "test"
18 | }
19 |
20 | resource "commercetools_channel" "test" {
21 | key = "test"
22 | roles = ["ProductDistribution"]
23 | custom {
24 | type_id = data.commercetools_type.existing_type.id
25 | fields = {
26 | "my-field" = "foobar"
27 | }
28 | }
29 | }
30 | ```
31 |
32 |
33 | ## Schema
34 |
35 | ### Required
36 |
37 | - `key` (String) Key of the custom type
38 |
39 | ### Read-Only
40 |
41 | - `id` (String) ID of the custom type
42 |
--------------------------------------------------------------------------------
/.github/workflows/release.yaml:
--------------------------------------------------------------------------------
1 | name: release
2 | on:
3 | workflow_dispatch:
4 |
5 | jobs:
6 | goreleaser:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - name: Checkout
10 | uses: actions/checkout@v4
11 | with:
12 | fetch-depth: 0
13 |
14 | - name: Set up Go
15 | uses: actions/setup-go@v5
16 | with:
17 | go-version-file: go.mod
18 |
19 | - name: Import GPG key
20 | id: import_gpg
21 | uses: paultyng/ghaction-import-gpg@v2.1.0
22 | env:
23 | GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
24 | PASSPHRASE: ${{ secrets.PASSPHRASE }}
25 |
26 | - name: Run GoReleaser
27 | uses: goreleaser/goreleaser-action@v6
28 | with:
29 | version: latest
30 | args: release --clean
31 | env:
32 | GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}
33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
34 |
--------------------------------------------------------------------------------
/commercetools/testdata/custom_fields_test/commercetools_discount_code.tmpl:
--------------------------------------------------------------------------------
1 |
2 | {{define "commercetools_discount_code"}}
3 | resource "commercetools_cart_discount" "commercetools_cart_discount_test" {
4 | key = "commercetools_cart_discount_test"
5 | name = {
6 | en = "relative name"
7 | }
8 | description = {
9 | en = "relative description"
10 | }
11 | sort_order = "0.9"
12 | predicate = "1=1"
13 | stacking_mode = "Stacking"
14 | requires_discount_code = true
15 | valid_from = "2018-01-02T15:04:05Z"
16 | valid_until = "2019-01-02T15:04:05Z"
17 | target {
18 | type = "lineItems"
19 | predicate = "1=1"
20 | }
21 | value {
22 | type = "relative"
23 | permyriad = 1000
24 | }
25 | }
26 |
27 | resource "commercetools_discount_code" "{{.resource_name}}" {
28 | code = "2"
29 | cart_discounts = [commercetools_cart_discount.commercetools_cart_discount_test.id]
30 | {{if .custom}}{{template "custom" .}}{{end}}
31 | }
32 | {{end}}
--------------------------------------------------------------------------------
/examples/resources/commercetools_category/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_category" "my-category" {
2 | key = "my-category-key"
3 |
4 | name = {
5 | en = "My category"
6 | }
7 | description = {
8 | en = "Standard description"
9 | }
10 | slug = {
11 | en = "my_category"
12 | }
13 | meta_title = {
14 | en = "Meta title"
15 | }
16 | }
17 |
18 | resource "commercetools_category" "my-second-category" {
19 | key = "my-category-key"
20 |
21 | name = {
22 | en = "Second category"
23 | }
24 | description = {
25 | en = "Standard description"
26 | }
27 | parent = commercetools_category.my-category.id
28 | slug = {
29 | en = "my_second_category"
30 | }
31 | meta_title = {
32 | en = "Meta title"
33 | }
34 | assets {
35 | key = "some_key"
36 | name = {
37 | en = "Image name"
38 | }
39 | description = {
40 | en = "Image description"
41 | }
42 | sources {
43 | uri = "https://example.com/test.jpg"
44 | key = "image"
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_state_transitions/resource.tf:
--------------------------------------------------------------------------------
1 |
2 | resource "commercetools_state" "product_for_sale" {
3 | key = "product-for-sale"
4 | type = "ProductState"
5 | name = {
6 | en = "For Sale"
7 | }
8 | description = {
9 | en = "Regularly stocked product."
10 | }
11 | initial = true
12 | }
13 |
14 | resource "commercetools_state" "product_clearance" {
15 | key = "product-clearance"
16 | type = "ProductState"
17 | name = {
18 | en = "On Clearance"
19 | }
20 | description = {
21 | en = "The product line will not be ordered again."
22 | }
23 | }
24 |
25 |
26 | // Only allow transition from sale to clearance
27 | resource "commercetools_state_transitions" "transition_1" {
28 | from = commercetools_state.product_for_sale.id
29 | to = [
30 | commercetools_state.product_clearance.id,
31 | ]
32 | }
33 |
34 | // Disable transitions from product clearance to other
35 | resource "commercetools_state_transitions" "transition_2" {
36 | from = commercetools_state.product_clearance.id
37 | to = []
38 | }
39 |
--------------------------------------------------------------------------------
/internal/models/models.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "github.com/hashicorp/terraform-plugin-framework/types"
5 | "github.com/labd/commercetools-go-sdk/platform"
6 |
7 | "github.com/labd/terraform-provider-commercetools/internal/customtypes"
8 | "github.com/labd/terraform-provider-commercetools/internal/utils"
9 | )
10 |
11 | type CustomFieldLocalizedEnumValue struct {
12 | Key types.String `tfsdk:"key"`
13 | Label customtypes.LocalizedStringValue `tfsdk:"label"`
14 | }
15 |
16 | func (c CustomFieldLocalizedEnumValue) ToNative() platform.CustomFieldLocalizedEnumValue {
17 | return platform.CustomFieldLocalizedEnumValue{
18 | Key: c.Key.ValueString(),
19 | Label: c.Label.ValueLocalizedString(),
20 | }
21 | }
22 |
23 | func NewCustomFieldLocalizedEnumValue(s platform.CustomFieldLocalizedEnumValue) CustomFieldLocalizedEnumValue {
24 | label := utils.FromOptionalLocalizedString(&s.Label)
25 | result := CustomFieldLocalizedEnumValue{
26 | Key: types.StringValue(s.Key),
27 | Label: label,
28 | }
29 |
30 | return result
31 | }
32 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_product_discount/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_product_discount" "my-product-discount" {
2 | key = "my-product-discount-key"
3 | name = {
4 | en = "Product discount name"
5 | }
6 | description = {
7 | en = "Product discount description"
8 | }
9 | predicate = "1=1"
10 | sort_order = "0.9"
11 | is_active = true
12 | valid_from = "2018-01-02T15:04:05Z"
13 | valid_until = "2019-01-02T15:04:05Z"
14 |
15 | value {
16 | type = "relative"
17 | permyriad = 1000
18 | }
19 | }
20 |
21 | resource "commercetools_product_discount" "my-product-discount-absolute" {
22 | key = "my-product-discount-absolute-key"
23 | name = {
24 | en = "Product discount name"
25 | }
26 | description = {
27 | en = "Product discount description"
28 | }
29 | predicate = "1=1"
30 | sort_order = "0.9"
31 | is_active = true
32 | valid_from = "2018-01-02T15:04:05Z"
33 | valid_until = "2019-01-02T15:04:05Z"
34 |
35 | value {
36 | type = "absolute"
37 | money {
38 | currency_code = "EUR"
39 | cent_amount = 500
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/.github/workflows/dependabot-changie.yaml:
--------------------------------------------------------------------------------
1 | name: Dependabot add changie file
2 | on:
3 | pull_request:
4 | types: [opened]
5 |
6 | permissions:
7 | pull-requests: write
8 | issues: write
9 | repository-projects: write
10 | contents: write
11 |
12 | jobs:
13 | dependabot-changie:
14 | runs-on: ubuntu-latest
15 | if: github.actor == 'dependabot[bot]'
16 | steps:
17 | - name: Checkout
18 | uses: actions/checkout@v4
19 |
20 | - name: Fetch Dependabot metadata
21 | id: dependabot-metadata
22 | uses: dependabot/fetch-metadata@v2
23 | with:
24 | github-token: "${{ secrets.GITHUB_TOKEN }}"
25 |
26 | - name: Create change file
27 | uses: miniscruff/changie-action@v2
28 | with:
29 | version: latest
30 | args: new --body "${{ github.event.pull_request.title }}" --kind Dependency
31 |
32 | - uses: stefanzweifel/git-auto-commit-action@v5
33 | with:
34 | commit_message: "chore(deps): add changelog for dependabot updates"
35 | commit_user_name: "dependabot[bot]"
36 | commit_user_email: "dependabot[bot]@users.noreply.github.com"
37 |
--------------------------------------------------------------------------------
/docs/resources/tax_category.md:
--------------------------------------------------------------------------------
1 | ---
2 | # generated by https://github.com/hashicorp/terraform-plugin-docs
3 | page_title: "commercetools_tax_category Resource - terraform-provider-commercetools"
4 | subcategory: ""
5 | description: |-
6 | Tax Categories define how products are to be taxed in different countries.
7 | See also the Tax Category API Documentation https://docs.commercetools.com/api/projects/taxCategories
8 | ---
9 |
10 | # commercetools_tax_category (Resource)
11 |
12 | Tax Categories define how products are to be taxed in different countries.
13 |
14 | See also the [Tax Category API Documentation](https://docs.commercetools.com/api/projects/taxCategories)
15 |
16 | ## Example Usage
17 |
18 | ```terraform
19 | resource "commercetools_tax_category" "my-tax-category" {
20 | key = "my-tax-category-key"
21 | name = "Standard tax category"
22 | description = "Example category"
23 | }
24 | ```
25 |
26 |
27 | ## Schema
28 |
29 | ### Required
30 |
31 | - `name` (String)
32 |
33 | ### Optional
34 |
35 | - `description` (String)
36 | - `key` (String) User-specific unique identifier for the category
37 |
38 | ### Read-Only
39 |
40 | - `id` (String) The ID of this resource.
41 | - `version` (Number)
42 |
--------------------------------------------------------------------------------
/internal/sharedtypes/store_key_reference.go:
--------------------------------------------------------------------------------
1 | package sharedtypes
2 |
3 | import (
4 | "github.com/hashicorp/terraform-plugin-framework/resource/schema"
5 | "github.com/hashicorp/terraform-plugin-framework/types"
6 | "github.com/labd/commercetools-go-sdk/platform"
7 | )
8 |
9 | var (
10 | StoreKeyReferenceBlockSchema = schema.ListNestedBlock{
11 | MarkdownDescription: "Sets the Stores the Business Unit is associated with. \n\nIf the Business Unit has Stores defined, " +
12 | "then all of its Carts, Orders, Quotes, or Quote Requests must belong to one of the Business Unit's " +
13 | "Stores.\n\nIf the Business Unit has no Stores, then all of its Carts, Orders, Quotes, or Quote Requests " +
14 | "must not belong to any Store.",
15 | NestedObject: schema.NestedBlockObject{
16 | Attributes: map[string]schema.Attribute{
17 | "key": schema.StringAttribute{
18 | MarkdownDescription: "User-defined unique identifier of the Store",
19 | Optional: true,
20 | },
21 | },
22 | },
23 | }
24 | )
25 |
26 | // StoreKeyReference is a type to model the fields that all types of StoreKeyReference have in common.
27 | type StoreKeyReference struct {
28 | Key types.String `tfsdk:"key"`
29 | }
30 |
31 | func NewStoreKeyReferenceFromNative(n *platform.StoreKeyReference) StoreKeyReference {
32 | return StoreKeyReference{
33 | Key: types.StringValue(n.Key),
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/.changes/v1.3.0.md:
--------------------------------------------------------------------------------
1 | ## v1.3.0 (2022-08-03)
2 |
3 | - **Backwards incompatible** Use a list type for enum values instead of a map
4 | to keep the ordering intact. This change requires an update to the way the
5 | values are defined (#98, #278):
6 |
7 | ```hcl
8 | type {
9 | name = "enum"
10 | values {
11 | FLAG-1 = "Flag 1"
12 | FLAG-2 = "Flag 2"
13 | }
14 | }
15 | ```
16 |
17 | to
18 |
19 | ```hcl
20 | type {
21 | name = "enum"
22 | value {
23 | key = "FLAG-1"
24 | label = "Flag 1"
25 | }
26 | value {
27 | key = "FLAG-2"
28 | label = "FLAG-2"
29 | }
30 | }
31 | ```
32 |
33 | - Update documentation and examples
34 | - Add support for custom fields on category, channel, customer_group,
35 | discount_code, shipping_method and store resources. (#265)
36 | - Improve logic to set the user-agent used in the requests. We now use the
37 | provider version. For example:
38 | `User-Agent: terraform-provider-commercetools/1.3.0 (bd9cae0)`
39 | - Improve the error handling by better communicating the errors raised by
40 | commercetools.
41 | - Accept a trailing slash in the token url (#182)
42 | - Large rewrite of the `type` and `product_type` resources to fix a number
43 | of issues (#165, #262, #263, #267)
44 |
--------------------------------------------------------------------------------
/docs/data-sources/state.md:
--------------------------------------------------------------------------------
1 | ---
2 | # generated by https://github.com/hashicorp/terraform-plugin-docs
3 | page_title: "commercetools_state Data Source - terraform-provider-commercetools"
4 | subcategory: ""
5 | description: |-
6 | Fetches state information for the given key. This is an easy way to import the id of an existing state for a given key.
7 | ---
8 |
9 | # commercetools_state (Data Source)
10 |
11 | Fetches state information for the given key. This is an easy way to import the id of an existing state for a given key.
12 |
13 | ## Example Usage
14 |
15 | ```terraform
16 | # The Initial state is a state that is provided in a new commercetools environment by default
17 | data "commercetools_state" "initial_state" {
18 | key = "Initial"
19 | }
20 |
21 | resource "commercetools_state_transitions" "from_created_to_allocated" {
22 | from = data.commercetools_state.initial_state.id
23 | to = [
24 | commercetools_state.backorder.id,
25 | ]
26 | }
27 |
28 | resource "commercetools_state" "backorder" {
29 | key = "backorder"
30 | type = "LineItemState"
31 | name = {
32 | en = "Back Order",
33 |
34 | }
35 | description = {
36 | en = "Not available - on back order"
37 | }
38 | initial = false
39 | }
40 | ```
41 |
42 |
43 | ## Schema
44 |
45 | ### Required
46 |
47 | - `key` (String) Key of the state
48 |
49 | ### Read-Only
50 |
51 | - `id` (String) ID of the state
52 |
--------------------------------------------------------------------------------
/docs/resources/shipping_zone.md:
--------------------------------------------------------------------------------
1 | ---
2 | # generated by https://github.com/hashicorp/terraform-plugin-docs
3 | page_title: "commercetools_shipping_zone Resource - terraform-provider-commercetools"
4 | subcategory: ""
5 | description: |-
6 |
7 | ---
8 |
9 | # commercetools_shipping_zone (Resource)
10 |
11 |
12 |
13 | ## Example Usage
14 |
15 | ```terraform
16 | resource "commercetools_shipping_zone" "de-us" {
17 | key = "some-key"
18 | name = "DE and US"
19 | description = "Germany and US"
20 | location {
21 | country = "DE"
22 | }
23 | location {
24 | country = "US"
25 | state = "Nevada"
26 | }
27 | }
28 | ```
29 |
30 |
31 | ## Schema
32 |
33 | ### Required
34 |
35 | - `name` (String)
36 |
37 | ### Optional
38 |
39 | - `description` (String)
40 | - `key` (String) User-specific unique identifier for a zone. Must be unique across a project
41 | - `location` (Block Set) [Location](https://docs.commercetoolstools.pi/projects/zones#location) (see [below for nested schema](#nestedblock--location))
42 |
43 | ### Read-Only
44 |
45 | - `id` (String) The ID of this resource.
46 | - `version` (Number)
47 |
48 |
49 | ### Nested Schema for `location`
50 |
51 | Required:
52 |
53 | - `country` (String) A two-digit country code as per [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)
54 |
55 | Optional:
56 |
57 | - `state` (String)
58 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 |
8 | {
9 | "name": "Acceptance Tests",
10 | "type": "go",
11 | "request": "launch",
12 | "mode": "test",
13 | // this assumes your workspace is the root of the repo
14 | "program": "${fileDirname}",
15 | "env": {
16 | "TF_ACC": "1",
17 | "CTP_CLIENT_ID": "unittest",
18 | "CTP_CLIENT_SECRET": "x",
19 | "CTP_PROJECT_KEY": "unittest",
20 | "CTP_SCOPES": "manage_project:projectkey",
21 | "CTP_API_URL": "http://localhost:8989",
22 | "CTP_AUTH_URL": "http://localhost:8989",
23 | },
24 | "args": [],
25 | },
26 | {
27 | "name": "Debug - Attach External CLI",
28 | "type": "go",
29 | "request": "launch",
30 | "mode": "debug",
31 | // this assumes your workspace is the root of the repo
32 | "program": "${workspaceFolder}",
33 | "env": {},
34 | "args": [
35 | // pass the debug flag for reattaching
36 | "-debug",
37 | ],
38 | }
39 | ]
40 | }
41 |
--------------------------------------------------------------------------------
/commercetools/provider_test.go:
--------------------------------------------------------------------------------
1 | package commercetools
2 |
3 | import (
4 | "context"
5 | "os"
6 | "testing"
7 |
8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
9 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
10 | )
11 |
12 | var testAccProviders map[string]func() (*schema.Provider, error)
13 | var testAccProvider *schema.Provider
14 |
15 | func init() {
16 | testAccProvider = New("snapshot")()
17 | testAccProviders = map[string]func() (*schema.Provider, error){
18 | "commercetools": func() (*schema.Provider, error) {
19 | return testAccProvider, nil
20 | },
21 | }
22 | }
23 |
24 | func TestProvider(t *testing.T) {
25 | provider := New("snapshot")()
26 | if err := provider.InternalValidate(); err != nil {
27 | t.Fatalf("err: %s", err)
28 | }
29 | }
30 |
31 | func testAccPreCheck(t *testing.T) {
32 | requiredEnvs := []string{
33 | "CTP_CLIENT_ID",
34 | "CTP_CLIENT_SECRET",
35 | "CTP_PROJECT_KEY",
36 | "CTP_SCOPES",
37 | "CTP_API_URL",
38 | "CTP_AUTH_URL",
39 | }
40 | for _, val := range requiredEnvs {
41 | if os.Getenv(val) == "" {
42 | t.Fatalf("%v must be set for acceptance tests", val)
43 | }
44 | }
45 |
46 | cfg := map[string]any{
47 | "client_id": "dummy-client-id",
48 | "client_secret": "dummy-client-secret",
49 | "project_key": "terraform-provider-commercetools",
50 | }
51 |
52 | err := testAccProvider.Configure(context.Background(), terraform.NewResourceConfigRaw(cfg))
53 | if err != nil {
54 | t.Fatal(err)
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/internal/resources/state_transition/model.go:
--------------------------------------------------------------------------------
1 | package state_transition
2 |
3 | import (
4 | "reflect"
5 |
6 | "github.com/elliotchance/pie/v2"
7 | "github.com/hashicorp/terraform-plugin-framework/types"
8 | "github.com/labd/commercetools-go-sdk/platform"
9 |
10 | "github.com/labd/terraform-provider-commercetools/internal/utils"
11 | )
12 |
13 | type StateTransition struct {
14 | ID types.String `tfsdk:"id"`
15 | From types.String `tfsdk:"from"`
16 | To []types.String `tfsdk:"to"`
17 | Version types.Int64 `tfsdk:"-"`
18 | }
19 |
20 | func (s StateTransition) updateActions(plan StateTransition) platform.StateUpdate {
21 | result := platform.StateUpdate{
22 | Version: int(s.Version.ValueInt64()),
23 | Actions: []platform.StateUpdateAction{},
24 | }
25 |
26 | if !reflect.DeepEqual(s.To, plan.To) {
27 | result.Actions = append(
28 | result.Actions,
29 | platform.StateSetTransitionsAction{
30 | Transitions: pie.Map(plan.To, func(v types.String) platform.StateResourceIdentifier {
31 | return platform.StateResourceIdentifier{
32 | ID: utils.StringRef(v.ValueString()),
33 | }
34 | }),
35 | })
36 | }
37 |
38 | return result
39 | }
40 |
41 | func NewStateTransitionFromNative(n *platform.State) StateTransition {
42 | return StateTransition{
43 | ID: types.StringValue(n.ID),
44 | From: types.StringValue(n.ID),
45 | To: pie.Map(n.Transitions, func(ref platform.StateReference) types.String {
46 | return types.StringValue(ref.ID)
47 | }),
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_store/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_channel" "us-supply-channel" {
2 | key = "US-SUP"
3 | roles = ["InventorySupply"]
4 | name = {
5 | en-US = "Supply channel"
6 | }
7 | description = {
8 | en-US = "Supply channel desc"
9 | }
10 | }
11 |
12 | resource "commercetools_channel" "us-dist-channel" {
13 | key = "US-DIST"
14 | roles = ["ProductDistribution"]
15 | name = {
16 | en-US = "Dist channel"
17 | }
18 | description = {
19 | en-US = "Dist channel desc"
20 | }
21 | }
22 |
23 | resource "commercetools_type" "my-store-type" {
24 | key = "my-custom-store-type"
25 | name = {
26 | en = "My Store Type"
27 | }
28 | description = {
29 | en = "A custom store type"
30 | }
31 |
32 | resource_type_ids = ["store"]
33 |
34 | field {
35 | name = "some-field"
36 | label = {
37 | en = "Some Field"
38 | }
39 | type {
40 | name = "String"
41 | }
42 | }
43 | }
44 |
45 |
46 | resource "commercetools_store" "my-store" {
47 | key = "my-store"
48 | name = {
49 | en-US = "My store"
50 | }
51 | countries = ["NL", "BE"]
52 | languages = ["en-US"]
53 | distribution_channels = ["US-DIST"]
54 | supply_channels = ["US-SUP"]
55 |
56 | custom {
57 | type_id = commercetools_type.my-store-type.id
58 | fields = {
59 | my-field = "ja"
60 | }
61 | }
62 |
63 | depends_on = [
64 | commercetools_channel.us-supply-channel,
65 | commercetools_channel.us-dist-channel,
66 | ]
67 | }
68 |
--------------------------------------------------------------------------------
/.goreleaser.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | project_name: terraform-provider-commercetools
3 |
4 | builds:
5 | - env:
6 | # goreleaser does not work with CGO, it could also complicate
7 | # usage by users in CI/CD systems like Terraform Cloud where
8 | # they are unable to install libraries.
9 | - CGO_ENABLED=0
10 | mod_timestamp: '{{ .CommitTimestamp }}'
11 | flags:
12 | - -trimpath
13 | ldflags:
14 | - '-s -w -X main.version={{.Version}} -X main.commit={{.ShortCommit}}'
15 | goos:
16 | - freebsd
17 | - windows
18 | - linux
19 | - darwin
20 | goarch:
21 | - amd64
22 | - '386'
23 | - arm
24 | - arm64
25 | ignore:
26 | - goos: darwin
27 | goarch: '386'
28 | binary: '{{ .ProjectName }}_v{{ .Version }}'
29 |
30 | archives:
31 | - format: zip
32 | name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}'
33 |
34 | checksum:
35 | name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS'
36 | algorithm: sha256
37 |
38 | changelog:
39 | sort: asc
40 | filters:
41 | exclude:
42 | - "^docs:"
43 | - "^test:"
44 |
45 | signs:
46 | - artifacts: checksum
47 | args:
48 | # if you are using this is a GitHub action or some other automated pipeline, you
49 | # need to pass the batch flag to indicate its not interactive.
50 | - "--batch"
51 | - "--local-user"
52 | - "{{ .Env.GPG_FINGERPRINT }}" # set this environment variable for your signing key
53 | - "--output"
54 | - "${signature}"
55 | - "--detach-sign"
56 | - "${artifact}"
57 |
--------------------------------------------------------------------------------
/internal/resources/subscription/upgrade_v0.go:
--------------------------------------------------------------------------------
1 | package subscription
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/hashicorp/terraform-plugin-framework/resource"
7 | "github.com/hashicorp/terraform-plugin-go/tfprotov6"
8 | "github.com/hashicorp/terraform-plugin-go/tftypes"
9 | )
10 |
11 | // Upgrade from V0 to V1
12 | func upgradeStateV0(_ context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) {
13 | rawStateValue, err := req.RawState.Unmarshal(SubscriptionResourceV2)
14 | if err != nil {
15 | resp.Diagnostics.AddError(
16 | "Unable to Unmarshal Prior State",
17 | err.Error(),
18 | )
19 | return
20 | }
21 |
22 | var rawState map[string]tftypes.Value
23 | if err := rawStateValue.As(&rawState); err != nil {
24 | resp.Diagnostics.AddError(
25 | "Unable to Convert Prior State",
26 | err.Error(),
27 | )
28 | return
29 | }
30 |
31 | dynamicValue, err := tfprotov6.NewDynamicValue(
32 | SubscriptionResourceV1,
33 | tftypes.NewValue(SubscriptionResourceV1, map[string]tftypes.Value{
34 | "id": rawState["id"],
35 | "key": rawState["key"],
36 | "version": rawState["version"],
37 | "changes": rawState["changes"],
38 | "destination": valueDestinationV1(rawState, "destination"),
39 | "format": valueToFormatV1(rawState, "format"),
40 | "message": rawState["message"],
41 | }),
42 | )
43 |
44 | if err != nil {
45 | resp.Diagnostics.AddError(
46 | "Unable to Convert Upgraded State",
47 | err.Error(),
48 | )
49 | return
50 | }
51 |
52 | resp.DynamicValue = &dynamicValue
53 | }
54 |
--------------------------------------------------------------------------------
/internal/utils/decode.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "github.com/mitchellh/mapstructure"
5 | "reflect"
6 | "time"
7 | )
8 |
9 | func toTimeHookFunc() mapstructure.DecodeHookFunc {
10 | return func(
11 | f reflect.Type,
12 | t reflect.Type,
13 | data interface{}) (interface{}, error) {
14 | if t != reflect.TypeOf(time.Time{}) {
15 | return data, nil
16 | }
17 |
18 | switch f.Kind() {
19 | case reflect.String:
20 | return time.Parse(time.RFC3339, data.(string))
21 | case reflect.Float64:
22 | return time.Unix(0, int64(data.(float64))*int64(time.Millisecond)), nil
23 | case reflect.Int64:
24 | return time.Unix(0, data.(int64)*int64(time.Millisecond)), nil
25 | default:
26 | return data, nil
27 | }
28 | // Convert it by parsing
29 | }
30 | }
31 |
32 | func DecodeStruct(input interface{}, result interface{}) error {
33 | meta := &mapstructure.Metadata{}
34 | decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
35 | Metadata: meta,
36 | DecodeHook: mapstructure.ComposeDecodeHookFunc(
37 | toTimeHookFunc()),
38 | Result: result,
39 | })
40 | if err != nil {
41 | return err
42 | }
43 |
44 | if err := decoder.Decode(input); err != nil {
45 | return err
46 | }
47 |
48 | if val, ok := result.(Decoder); ok {
49 | if raw, ok := input.(map[string]interface{}); ok {
50 | unused := make(map[string]interface{})
51 | for _, key := range meta.Unused {
52 | unused[key] = raw[key]
53 | }
54 | val.DecodeStruct(unused)
55 | }
56 | }
57 |
58 | return err
59 | }
60 |
61 | type Decoder interface {
62 | DecodeStruct(map[string]interface{}) error
63 | }
64 |
--------------------------------------------------------------------------------
/internal/utils/mutex.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "log"
5 | "sync"
6 | )
7 |
8 | // Copied from https://www.terraform.io/plugin/sdkv2/guides/v2-upgrade-guide#removal-of-helper-mutexkv-package
9 | //
10 | // MutexKV is a simple key/value store for arbitrary mutexes. It can be used to
11 | // serialize changes across arbitrary collaborators that share knowledge of the
12 | // keys they must serialize on.
13 | //
14 | // The initial use case is to let aws_security_group_rule resources serialize
15 | // their access to individual security groups based on SG ID.
16 | type MutexKV struct {
17 | lock sync.Mutex
18 | store map[string]*sync.Mutex
19 | }
20 |
21 | // Locks the mutex for the given key. Caller is responsible for calling Unlock
22 | // for the same key
23 | func (m *MutexKV) Lock(key string) {
24 | log.Printf("[DEBUG] Locking %q", key)
25 | m.get(key).Lock()
26 | log.Printf("[DEBUG] Locked %q", key)
27 | }
28 |
29 | // Unlock the mutex for the given key. Caller must have called Lock for the same key first
30 | func (m *MutexKV) Unlock(key string) {
31 | log.Printf("[DEBUG] Unlocking %q", key)
32 | m.get(key).Unlock()
33 | log.Printf("[DEBUG] Unlocked %q", key)
34 | }
35 |
36 | // Returns a mutex for the given key, no guarantee of its lock status
37 | func (m *MutexKV) get(key string) *sync.Mutex {
38 | m.lock.Lock()
39 | defer m.lock.Unlock()
40 | mutex, ok := m.store[key]
41 | if !ok {
42 | mutex = &sync.Mutex{}
43 | m.store[key] = mutex
44 | }
45 | return mutex
46 | }
47 |
48 | // Returns a properly initialized MutexKV
49 | func NewMutexKV() *MutexKV {
50 | return &MutexKV{
51 | store: make(map[string]*sync.Mutex),
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_type/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_type" "my-custom-type" {
2 | key = "my-custom-type"
3 | name = {
4 | en = "Contact info"
5 | nl = "Contact informatie"
6 | }
7 | description = {
8 | en = "All things related communication"
9 | nl = "Alle communicatie-gerelateerde zaken"
10 | }
11 |
12 | resource_type_ids = ["customer"]
13 |
14 | field {
15 | name = "skype_name"
16 | label = {
17 | en = "Skype name"
18 | nl = "Skype naam"
19 | }
20 | type {
21 | name = "String"
22 | }
23 | }
24 |
25 | field {
26 | name = "contact_time"
27 | label = {
28 | en = "Contact time"
29 | nl = "Contact tijd"
30 | }
31 | type {
32 | name = "Enum"
33 | value {
34 | key = "day"
35 | label = "Daytime"
36 | }
37 | value {
38 | key = "evening"
39 | label = "Evening"
40 | }
41 | }
42 | }
43 |
44 | field {
45 | name = "emails"
46 |
47 | label = {
48 | en = "Emails"
49 | nl = "Emails"
50 | }
51 |
52 | type {
53 | name = "Set"
54 | element_type {
55 | name = "String"
56 | }
57 | }
58 | }
59 |
60 | field {
61 | name = "contact_preference"
62 | label = {
63 | en = "Contact preference"
64 | nl = "Contact voorkeur"
65 | }
66 | type {
67 | name = "LocalizedEnum"
68 | localized_value {
69 | key = "phone"
70 | label = {
71 | en = "Phone"
72 | nl = "Telefoon"
73 | }
74 | }
75 | localized_value {
76 | key = "skype"
77 | label = {
78 | en = "Skype"
79 | nl = "Skype"
80 | }
81 | }
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/docs/resources/custom_object.md:
--------------------------------------------------------------------------------
1 | ---
2 | # generated by https://github.com/hashicorp/terraform-plugin-docs
3 | page_title: "commercetools_custom_object Resource - terraform-provider-commercetools"
4 | subcategory: ""
5 | description: |-
6 | Custom objects are a way to store arbitrary JSON-formatted data on the commercetools platform. It allows you to persist data that does not fit the standard data model. This frees your application completely from any third-party persistence solution and means that all your data stays on the commercetools platform.
7 | See also the Custom Object API Documentation https://docs.commercetools.com/api/projects/custom-objects
8 | ---
9 |
10 | # commercetools_custom_object (Resource)
11 |
12 | Custom objects are a way to store arbitrary JSON-formatted data on the commercetools platform. It allows you to persist data that does not fit the standard data model. This frees your application completely from any third-party persistence solution and means that all your data stays on the commercetools platform.
13 |
14 | See also the [Custom Object API Documentation](https://docs.commercetools.com/api/projects/custom-objects)
15 |
16 | ## Example Usage
17 |
18 | ```terraform
19 | resource "commercetools_custom_object" "my-custom-object" {
20 | container = "my-container"
21 | key = "my-key"
22 | value = jsonencode(10)
23 | }
24 | ```
25 |
26 |
27 | ## Schema
28 |
29 | ### Required
30 |
31 | - `container` (String) A namespace to group custom objects matching the pattern '[-_~.a-zA-Z0-9]+'
32 | - `key` (String) String matching the pattern '[-_~.a-zA-Z0-9]+'
33 | - `value` (String) JSON types Number, String, Boolean, Array, Object
34 |
35 | ### Read-Only
36 |
37 | - `id` (String) The ID of this resource.
38 | - `version` (Number)
39 |
--------------------------------------------------------------------------------
/internal/acctest/client.go:
--------------------------------------------------------------------------------
1 | package acctest
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "net/http"
7 | "os"
8 | "strings"
9 |
10 | "github.com/labd/commercetools-go-sdk/ctutils"
11 | "github.com/labd/commercetools-go-sdk/platform"
12 | "golang.org/x/oauth2/clientcredentials"
13 | )
14 |
15 | func GetClient() (*platform.ByProjectKeyRequestBuilder, error) {
16 | clientID := os.Getenv("CTP_CLIENT_ID")
17 | clientSecret := os.Getenv("CTP_CLIENT_SECRET")
18 | projectKey := os.Getenv("CTP_PROJECT_KEY")
19 | authURL := os.Getenv("CTP_AUTH_URL")
20 | apiURL := os.Getenv("CTP_API_URL")
21 | scopesRaw := os.Getenv("CTP_SCOPES")
22 |
23 | oauthScopes := strings.Split(scopesRaw, " ")
24 | oauth2Config := &clientcredentials.Config{
25 | ClientID: clientID,
26 | ClientSecret: clientSecret,
27 | Scopes: oauthScopes,
28 | TokenURL: fmt.Sprintf("%s/oauth/token", authURL),
29 | }
30 |
31 | httpClient := &http.Client{
32 | Transport: ctutils.DebugTransport,
33 | }
34 |
35 | client, err := platform.NewClient(&platform.ClientConfig{
36 | URL: apiURL,
37 | Credentials: oauth2Config,
38 | UserAgent: "terraform-provider-commercetools/testing",
39 | HTTPClient: httpClient,
40 | })
41 | if err != nil {
42 | return nil, err
43 | }
44 |
45 | return client.WithProjectKey(projectKey), nil
46 | }
47 |
48 | func CheckApiResult(err error) error {
49 | if errors.Is(err, platform.ErrNotFound) {
50 | return nil
51 | }
52 |
53 | switch v := err.(type) {
54 | case platform.GenericRequestError:
55 | if v.StatusCode == 404 {
56 | return nil
57 | }
58 | return fmt.Errorf("unhandled error generic error returned (%d)", v.StatusCode)
59 | case platform.ResourceNotFoundError:
60 | return nil
61 | default:
62 | return fmt.Errorf("unexpected result returned")
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_shipping_zone_rate/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_tax_category" "my-tax-category" {
2 | key = "some-tax-category-key"
3 | name = "My tax category"
4 | description = "Example"
5 | }
6 |
7 | resource "commercetools_shipping_method" "my-shipping-method" {
8 | key = "some-shipping-method-key"
9 | name = "My shipping method"
10 | description = "Standard method"
11 | is_default = true
12 | tax_category_id = commercetools_tax_category.my-tax-category.id
13 | predicate = "1 = 1"
14 | }
15 |
16 | resource "commercetools_shipping_zone" "my-shipping-zone" {
17 | key = "some-shipping-zone-key"
18 | name = "DE"
19 | description = "My shipping zone"
20 | location {
21 | country = "DE"
22 | }
23 | }
24 |
25 | resource "commercetools_shipping_zone_rate" "my-shipping-zone-rate" {
26 | shipping_method_id = commercetools_shipping_method.my-shipping-method.id
27 | shipping_zone_id = commercetools_shipping_zone.my-shipping-zone.id
28 |
29 | price {
30 | cent_amount = 5000
31 | currency_code = "EUR"
32 | }
33 |
34 | free_above {
35 | cent_amount = 50000
36 | currency_code = "EUR"
37 | }
38 |
39 | shipping_rate_price_tier {
40 | type = "CartScore"
41 | score = 10
42 |
43 | price {
44 | cent_amount = 5000
45 | currency_code = "EUR"
46 | }
47 | }
48 |
49 | shipping_rate_price_tier {
50 | type = "CartScore"
51 | score = 20
52 |
53 | price {
54 | cent_amount = 2000
55 | currency_code = "EUR"
56 | }
57 | }
58 |
59 | shipping_rate_price_tier {
60 | type = "CartScore"
61 | score = 30
62 |
63 | price_function {
64 | function = "x + 1"
65 | currency_code = "EUR"
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/internal/custommodifiers/booldefault.go:
--------------------------------------------------------------------------------
1 | package custommodifiers
2 |
3 | // From https://developer.hashicorp.com/terraform/plugin/framework/resources/plan-modification#creating-attribute-plan-modifiers
4 |
5 | import (
6 | "context"
7 | "fmt"
8 |
9 | "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
10 | "github.com/hashicorp/terraform-plugin-framework/types/basetypes"
11 | )
12 |
13 | // stringDefaultModifier is a plan modifier that sets a default value for a
14 | // types.StringType attribute when it is not configured. The attribute must be
15 | // marked as Optional and Computed. When setting the state during the resource
16 | // Create, Read, or Update methods, this default value must also be included or
17 | // the Terraform CLI will generate an error.
18 | type boolDefaultModifier struct {
19 | Default bool
20 | }
21 |
22 | // Description returns a plain text description of the validator's behavior, suitable for a practitioner to understand its impact.
23 | func (m boolDefaultModifier) Description(ctx context.Context) string {
24 | return fmt.Sprintf("If value is not configured, defaults to %v", m.Default)
25 | }
26 |
27 | // MarkdownDescription returns a markdown formatted description of the validator's behavior, suitable for a practitioner to understand its impact.
28 | func (m boolDefaultModifier) MarkdownDescription(ctx context.Context) string {
29 | return fmt.Sprintf("If value is not configured, defaults to `%v`", m.Default)
30 | }
31 |
32 | func (m boolDefaultModifier) PlanModifyBool(ctx context.Context, req planmodifier.BoolRequest, resp *planmodifier.BoolResponse) {
33 | if req.ConfigValue.IsNull() {
34 | resp.PlanValue = basetypes.NewBoolValue(m.Default)
35 | }
36 | }
37 |
38 | func BoolDefault(defaultValue bool) planmodifier.Bool {
39 | return boolDefaultModifier{
40 | Default: defaultValue,
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/commercetools/testdata/custom_fields_test/commercetools_custom_fields.tmpl:
--------------------------------------------------------------------------------
1 | {{define "custom"}}
2 | custom {
3 | type_id = commercetools_type.test.id
4 | fields = {
5 | {{range $key, $value := .custom}}
6 | {{if eq $value "Boolean"}}
7 | "Boolean-field" : true
8 | {{end}}
9 | {{if eq $value "Number"}}
10 | "Number-field" : 1234
11 | {{end}}
12 | {{if eq $value "String"}}
13 | "String-field" : "foobar"
14 | {{end}}
15 | {{if eq $value "LocalizedString"}}
16 | "LocalizedString-field" = jsonencode({
17 | en = "Localized String"
18 | fr = "Chaîne localisée"
19 | })
20 | {{end}}
21 | {{if eq $value "Enum"}}
22 | "Enum-field" : "value2"
23 | {{end}}
24 | {{if eq $value "LocalizedEnum"}}
25 | "LocalizedEnum-field" = "value1"
26 | {{end}}
27 | {{if eq $value "Money"}}
28 | "Money-field" = jsonencode({
29 | "type" : "centPrecision",
30 | "currencyCode" : "EUR",
31 | "centAmount" : 150000,
32 | "fractionDigits" : 2
33 | })
34 | {{end}}
35 | {{if eq $value "Date"}}
36 | "Date-field" : "2023-08-29"
37 | {{end}}
38 | {{if eq $value "Time"}}
39 | "Time-field" : "20:22:11.123"
40 | {{end}}
41 | {{if eq $value "DateTime"}}
42 | "DateTime-field" : "2023-08-29T20:22:11.123Z"
43 | {{end}}
44 | {{if eq $value "Reference"}}
45 | "Reference-field" = jsonencode({
46 | "typeId": "product-type",
47 | "id": commercetools_product_type.test.id
48 | })
49 | {{end}}
50 | {{if eq $value "Set"}}
51 | "Set-field" = jsonencode(["ENUM-1", "ENUM-3"])
52 | {{end}}
53 | {{end}}
54 | }
55 | }
56 | {{end}}
57 |
--------------------------------------------------------------------------------
/docs/resources/customer_group.md:
--------------------------------------------------------------------------------
1 | ---
2 | # generated by https://github.com/hashicorp/terraform-plugin-docs
3 | page_title: "commercetools_customer_group Resource - terraform-provider-commercetools"
4 | subcategory: ""
5 | description: |-
6 | A Customer can be a member of a customer group (for example reseller, gold member). Special prices can be assigned to specific products based on a customer group.
7 | See also the Customer Group API Documentation https://docs.commercetools.com/api/projects/customerGroups
8 | ---
9 |
10 | # commercetools_customer_group (Resource)
11 |
12 | A Customer can be a member of a customer group (for example reseller, gold member). Special prices can be assigned to specific products based on a customer group.
13 |
14 | See also the [Customer Group API Documentation](https://docs.commercetools.com/api/projects/customerGroups)
15 |
16 | ## Example Usage
17 |
18 | ```terraform
19 | resource "commercetools_customer_group" "standard" {
20 | key = "my-customer-group-key"
21 | name = "Standard Customer Group"
22 | }
23 |
24 | resource "commercetools_customer_group" "golden" {
25 | key = "my-customer-group-key"
26 | name = "Golden Customer Group"
27 | }
28 | ```
29 |
30 |
31 | ## Schema
32 |
33 | ### Required
34 |
35 | - `name` (String) Unique within the project
36 |
37 | ### Optional
38 |
39 | - `custom` (Block List, Max: 1) (see [below for nested schema](#nestedblock--custom))
40 | - `key` (String) User-specific unique identifier for the customer group
41 |
42 | ### Read-Only
43 |
44 | - `id` (String) The ID of this resource.
45 | - `version` (Number)
46 |
47 |
48 | ### Nested Schema for `custom`
49 |
50 | Required:
51 |
52 | - `type_id` (String)
53 |
54 | Optional:
55 |
56 | - `fields` (Map of String) Custom fields for this resource. Note that the values need to be provided as JSON encoded strings: `my-value = jsonencode({"key": "value"})`
57 |
--------------------------------------------------------------------------------
/.github/workflows/tests.yaml:
--------------------------------------------------------------------------------
1 | name: Run Tests
2 |
3 | on: [push]
4 |
5 | jobs:
6 |
7 | test:
8 | runs-on: ubuntu-latest
9 |
10 | services:
11 | commercetools:
12 | image: labdigital/commercetools-mock-server
13 | ports:
14 | - 8989:8989
15 |
16 | steps:
17 | - uses: actions/checkout@v4
18 |
19 | - name: Set up Go
20 | uses: actions/setup-go@v5
21 | with:
22 | go-version-file: go.mod
23 |
24 | - name: golangci-lint
25 | continue-on-error: true
26 | uses: golangci/golangci-lint-action@v6
27 | with:
28 | args: --issues-exit-code=0 --timeout=5m
29 |
30 | - name: Run tests
31 | run: go test -race -coverprofile=coverage.out -covermode=atomic -coverpkg=./... -v ./...
32 | env:
33 | TF_ACC: 1
34 | CTP_CLIENT_ID: unittest
35 | CTP_CLIENT_SECRET: x
36 | CTP_PROJECT_KEY: unittest
37 | CTP_SCOPES: manage_project:unittest
38 | CTP_API_URL: http://localhost:8989
39 | CTP_AUTH_URL: http://localhost:8989
40 |
41 | - name: Upload to codecov
42 | uses: codecov/codecov-action@v5
43 | with:
44 | verbose: true
45 |
46 | - name: build binary
47 | uses: goreleaser/goreleaser-action@v6
48 | with:
49 | args: build --snapshot --clean --single-target
50 | env:
51 | GOPATH: ${{ env.GOPATH }}
52 |
53 | changie:
54 | runs-on: ubuntu-latest
55 | needs: test
56 | if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request'
57 | permissions:
58 | contents: write
59 | pull-requests: write
60 | actions: write
61 | steps:
62 | - uses: actions/checkout@v4
63 | with:
64 | fetch-depth: 0
65 |
66 | - name: Prepare release
67 | uses: labd/changie-release-action@v0.5.0
68 | with:
69 | github-token: ${{ secrets.GITHUB_TOKEN }}
70 | release-workflow: 'release.yaml'
71 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_associate_role/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_type" "my-type" {
2 | key = "my-type"
3 | name = {
4 | en = "My type"
5 | nl = "Mijn type"
6 | }
7 |
8 | resource_type_ids = ["associate-role"]
9 |
10 | field {
11 | name = "my-field"
12 | label = {
13 | en = "My field"
14 | nl = "Mijn veld"
15 | }
16 | type {
17 | name = "String"
18 | }
19 | }
20 | }
21 |
22 | resource "commercetools_associate_role" "my-role" {
23 | key = "my-role"
24 | buyer_assignable = false
25 | name = "My Role"
26 | permissions = [
27 | "AddChildUnits",
28 | "UpdateAssociates",
29 | "UpdateBusinessUnitDetails",
30 | "UpdateParentUnit",
31 | "ViewMyCarts",
32 | "ViewOthersCarts",
33 | "UpdateMyCarts",
34 | "UpdateOthersCarts",
35 | "CreateMyCarts",
36 | "CreateOthersCarts",
37 | "DeleteMyCarts",
38 | "DeleteOthersCarts",
39 | "ViewMyOrders",
40 | "ViewOthersOrders",
41 | "UpdateMyOrders",
42 | "UpdateOthersOrders",
43 | "CreateMyOrdersFromMyCarts",
44 | "CreateMyOrdersFromMyQuotes",
45 | "CreateOrdersFromOthersCarts",
46 | "CreateOrdersFromOthersQuotes",
47 | "ViewMyQuotes",
48 | "ViewOthersQuotes",
49 | "AcceptMyQuotes",
50 | "AcceptOthersQuotes",
51 | "DeclineMyQuotes",
52 | "DeclineOthersQuotes",
53 | "RenegotiateMyQuotes",
54 | "RenegotiateOthersQuotes",
55 | "ReassignMyQuotes",
56 | "ReassignOthersQuotes",
57 | "ViewMyQuoteRequests",
58 | "ViewOthersQuoteRequests",
59 | "UpdateMyQuoteRequests",
60 | "UpdateOthersQuoteRequests",
61 | "CreateMyQuoteRequestsFromMyCarts",
62 | "CreateQuoteRequestsFromOthersCarts",
63 | "CreateApprovalRules",
64 | "UpdateApprovalRules",
65 | "UpdateApprovalFlows",
66 | ]
67 |
68 | custom {
69 | type_id = commercetools_type.my-type.id
70 | fields = {
71 | my_field = "My value"
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/internal/custommodifiers/emptylist.go:
--------------------------------------------------------------------------------
1 | package custommodifiers
2 |
3 | // From https://developer.hashicorp.com/terraform/plugin/framework/resources/plan-modification#creating-attribute-plan-modifiers
4 |
5 | import (
6 | "context"
7 |
8 | "github.com/hashicorp/terraform-plugin-framework/attr"
9 | "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
10 | "github.com/hashicorp/terraform-plugin-framework/types"
11 | "github.com/hashicorp/terraform-plugin-framework/types/basetypes"
12 | )
13 |
14 | // stringDefaultModifier is a plan modifier that sets a default value for a
15 | // types.StringType attribute when it is not configured. The attribute must be
16 | // marked as Optional and Computed. When setting the state during the resource
17 | // Create, Read, or Update methods, this default value must also be included or
18 | // the Terraform CLI will generate an error.
19 | type listEmptyListModifier struct{}
20 |
21 | // Description returns a plain text description of the validator's behavior, suitable for a practitioner to understand its impact.
22 | func (m listEmptyListModifier) Description(ctx context.Context) string {
23 | return "If value is not configured, defaults to empty list"
24 | }
25 |
26 | // MarkdownDescription returns a markdown formatted description of the validator's behavior, suitable for a practitioner to understand its impact.
27 | func (m listEmptyListModifier) MarkdownDescription(ctx context.Context) string {
28 | return "If value is not configured, defaults to empty list"
29 | }
30 |
31 | func (m listEmptyListModifier) PlanModifyList(ctx context.Context, req planmodifier.ListRequest, resp *planmodifier.ListResponse) {
32 | if resp.PlanValue.IsNull() {
33 | val, diags := basetypes.NewListValue(types.StringType, []attr.Value{})
34 | resp.Diagnostics = append(resp.Diagnostics, diags...)
35 | if diags.HasError() {
36 | return
37 | }
38 | resp.PlanValue = val
39 | }
40 | }
41 |
42 | func EmptyList() planmodifier.List {
43 | return listEmptyListModifier{}
44 | }
45 |
--------------------------------------------------------------------------------
/docs/resources/api_client.md:
--------------------------------------------------------------------------------
1 | ---
2 | # generated by https://github.com/hashicorp/terraform-plugin-docs
3 | page_title: "commercetools_api_client Resource - terraform-provider-commercetools"
4 | subcategory: ""
5 | description: |-
6 | Create a new API client. Note that Commercetools might return slightly different scopes, resulting in a new API client being created everytime Terraform is run. In this case, fix your scopes accordingly to match what is returned by Commercetools.
7 | Also see the API client HTTP API documentation https://docs.commercetools.com/api/projects/api-clients.
8 | ---
9 |
10 | # commercetools_api_client (Resource)
11 |
12 | Create a new API client. Note that Commercetools might return slightly different scopes, resulting in a new API client being created everytime Terraform is run. In this case, fix your scopes accordingly to match what is returned by Commercetools.
13 |
14 | Also see the [API client HTTP API documentation](https://docs.commercetools.com/api/projects/api-clients).
15 |
16 | ## Example Usage
17 |
18 | ```terraform
19 | resource "commercetools_api_client" "my-api-client" {
20 | name = "My API Client"
21 | scope = ["manage_orders:my-ct-project-key", "manage_payments:my-ct-project-key"]
22 | }
23 | ```
24 |
25 |
26 | ## Schema
27 |
28 | ### Required
29 |
30 | - `name` (String) Name of the API client
31 | - `scope` (Set of String) A list of the [OAuth scopes](https://docs.commercetools.com/api/scopes)
32 |
33 | ### Optional
34 |
35 | - `access_token_validity_seconds` (Number) Expiration time in seconds for each access token obtained by the APIClient. Only present when set with the APIClientDraft. If not present the default value applies.
36 | - `refresh_token_validity_seconds` (Number) Inactivity expiration time in seconds for each refresh token obtained by the APIClient. Only present when set with the APIClientDraft. If not present the default value applies.
37 |
38 | ### Read-Only
39 |
40 | - `id` (String) The ID of this resource.
41 | - `secret` (String, Sensitive)
42 |
--------------------------------------------------------------------------------
/commercetools/resource_cart_discount_giftlineitem_test.go:
--------------------------------------------------------------------------------
1 | package commercetools
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
7 | )
8 |
9 | func TestAccCartDiscountGiftLineItem(t *testing.T) {
10 | identifier := "gift_line_item"
11 | resourceName := "commercetools_cart_discount.gift_line_item"
12 |
13 | resource.Test(t, resource.TestCase{
14 | PreCheck: func() { testAccPreCheck(t) },
15 | ProviderFactories: testAccProviders,
16 | CheckDestroy: testAccCheckCartDiscountDestroy,
17 | Steps: []resource.TestStep{
18 | {
19 | Config: testAccCartDiscountGiftLineItemConfig(identifier),
20 | Check: resource.ComposeTestCheckFunc(
21 | resource.TestCheckResourceAttr(resourceName, "name.en", "giftLineItem name"),
22 | resource.TestCheckResourceAttr(resourceName, "value.0.type", "giftLineItem"),
23 | resource.TestCheckResourceAttr(resourceName, "value.0.product_id", "product-id"),
24 | resource.TestCheckResourceAttr(resourceName, "value.0.variant_id", "1"),
25 | resource.TestCheckResourceAttr(resourceName, "value.0.supply_channel_id", "supply-channel-id"),
26 | resource.TestCheckResourceAttr(resourceName, "value.0.distribution_channel_id", "distribution-channel-id"),
27 | resource.TestCheckResourceAttr(resourceName, "target.#", "0"),
28 | ),
29 | },
30 | },
31 | })
32 | }
33 |
34 | func testAccCartDiscountGiftLineItemConfig(identifier string) string {
35 | return hclTemplate(`
36 | resource "commercetools_cart_discount" "{{ .identifier }}" {
37 | name = {
38 | en = "giftLineItem name"
39 | }
40 | sort_order = "0.9"
41 | predicate = "1=1"
42 |
43 | value {
44 | type = "giftLineItem"
45 | product_id = "product-id"
46 | variant_id = 1
47 | supply_channel_id = "supply-channel-id"
48 | distribution_channel_id = "distribution-channel-id"
49 | }
50 | }
51 | `, map[string]any{
52 | "identifier": identifier,
53 | })
54 | }
55 |
--------------------------------------------------------------------------------
/commercetools/resource_cart_discount_totalprice_test.go:
--------------------------------------------------------------------------------
1 | package commercetools
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
7 | )
8 |
9 | func TestAccCartDiscountTotalPrice(t *testing.T) {
10 | identifier := "totalPrice"
11 | resourceName := "commercetools_cart_discount.totalPrice"
12 |
13 | resource.Test(t, resource.TestCase{
14 | PreCheck: func() { testAccPreCheck(t) },
15 | ProviderFactories: testAccProviders,
16 | CheckDestroy: testAccCheckCartDiscountDestroy,
17 | Steps: []resource.TestStep{
18 | {
19 | Config: testAccCartDiscountTotalPriceConfig(identifier),
20 | Check: resource.ComposeTestCheckFunc(
21 | resource.TestCheckResourceAttr(resourceName, "name.en", "absolute name"),
22 | resource.TestCheckResourceAttr(resourceName, "value.0.type", "absolute"),
23 | resource.TestCheckResourceAttr(resourceName, "value.0.money.0.currency_code", "USD"),
24 | resource.TestCheckResourceAttr(resourceName, "value.0.money.0.cent_amount", "1000"),
25 | resource.TestCheckResourceAttr(resourceName, "value.0.money.1.currency_code", "EUR"),
26 | resource.TestCheckResourceAttr(resourceName, "value.0.money.1.cent_amount", "2000"),
27 | resource.TestCheckResourceAttr(resourceName, "target.0.type", "totalPrice"),
28 | ),
29 | },
30 | },
31 | })
32 | }
33 |
34 | func testAccCartDiscountTotalPriceConfig(identifier string) string {
35 | return hclTemplate(`
36 | resource "commercetools_cart_discount" "{{ .identifier }}" {
37 | name = {
38 | en = "absolute name"
39 | }
40 | sort_order = "0.9"
41 | predicate = "1=1"
42 |
43 | target {
44 | type = "totalPrice"
45 | }
46 |
47 | value {
48 | type = "absolute"
49 | money {
50 | currency_code = "USD"
51 | cent_amount = 1000
52 | }
53 | money {
54 | currency_code = "EUR"
55 | cent_amount = 2000
56 | }
57 | }
58 | }
59 | `, map[string]any{
60 | "identifier": identifier,
61 | })
62 | }
63 |
--------------------------------------------------------------------------------
/Taskfile.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 |
3 | tasks:
4 | build-local:
5 | cmds:
6 | - go build -o terraform-provider-{{ .NAME }}_{{ .VERSION }}
7 | - mkdir -p ~/.terraform.d/plugins/registry.terraform.io/labd/{{ .NAME }}/{{ .VERSION }}/{{ .PLATFORM }}/
8 | - mv terraform-provider-{{ .NAME }}_{{ .VERSION }} ~/.terraform.d/plugins/registry.terraform.io/labd/{{ .NAME }}/{{ .VERSION }}/{{ .PLATFORM }}/terraform-provider-{{ .NAME }}_v{{ .VERSION }}
9 | - cmd: codesign --deep --force -s - ~/.terraform.d/plugins/registry.terraform.io/labd/{{ .NAME }}/{{ .VERSION }}/{{ .PLATFORM }}/terraform-provider-{{ .NAME }}_v{{ .VERSION }}
10 | platforms: [darwin]
11 | vars:
12 | VERSION: 99.0.0
13 | NAME: commercetools
14 | PLATFORM:
15 | sh: echo "$(go env GOOS)_$(go env GOARCH)"
16 |
17 | build:
18 | env:
19 | GORELEASER_CURRENT_TAG: "v0.0.0"
20 | cmd: goreleaser build --snapshot --clean --single-target --output mach-composer
21 |
22 | format:
23 | cmds:
24 | - go fmt ./...
25 |
26 | test:
27 | cmds:
28 | - go test -v ./...
29 |
30 | docs:
31 | cmds:
32 | - go generate
33 |
34 | coverage-html:
35 | cmds:
36 | - go test -race -coverprofile=coverage.txt -covermode=atomic -coverpkg=./... ./...
37 | - go tool cover -html=coverage.txt
38 |
39 | coverage:
40 | cmds:
41 | - go test -race -coverprofile=coverage.txt -covermode=atomic -coverpkg=./... ./...
42 | - go tool cover -func=coverage.txt
43 |
44 | testacc:
45 | cmds:
46 | - TF_ACC=1 go test -v ./...
47 |
48 | testacct:
49 | cmds:
50 | - TF_ACC=1 go test -race -coverprofile=coverage.txt -covermode=atomic -coverpkg=./... -v ./...
51 |
52 | mockacc:
53 | cmds:
54 | - go test -count=1 -v ./...
55 | env:
56 | TF_ACC: 1
57 | CTP_CLIENT_ID: unittest
58 | CTP_CLIENT_SECRET: x
59 | CTP_PROJECT_KEY: unittest
60 | CTP_SCOPES: manage_project:projectkey
61 | CTP_API_URL: http://localhost:8989
62 | CTP_AUTH_URL: http://localhost:8989
63 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_business_unit_company/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_store" "my-store" {
2 | key = "my-store"
3 | name = {
4 | en-US = "My store"
5 | }
6 | countries = ["NL", "BE"]
7 | languages = ["en-GB"]
8 | }
9 |
10 | resource "commercetools_type" "my-type" {
11 | key = "my-type"
12 | name = {
13 | en = "My type"
14 | nl = "Mijn type"
15 | }
16 |
17 | resource_type_ids = ["business-unit"]
18 |
19 | field {
20 | name = "my-field"
21 | label = {
22 | en = "My field"
23 | nl = "Mijn veld"
24 | }
25 | type {
26 | name = "String"
27 | }
28 | }
29 | }
30 |
31 | resource "commercetools_business_unit_company" "my-company" {
32 | key = "my-company"
33 | name = "My company"
34 | contact_email = "main@my-company.com"
35 |
36 | address {
37 | key = "my-company-address-1"
38 | country = "NL"
39 | state = "Noord-Holland"
40 | city = "Amsterdam"
41 | street_name = "Keizersgracht"
42 | street_number = "3"
43 | additional_street_info = "4th floor"
44 | postal_code = "1015 CJ"
45 | }
46 |
47 | address {
48 | key = "my-company-address-2"
49 | country = "NL"
50 | state = "Utrecht"
51 | city = "Utrecht"
52 | street_name = "Oudegracht"
53 | street_number = "1"
54 | postal_code = "3511 AA"
55 | additional_street_info = "Main floor"
56 | }
57 |
58 | store {
59 | key = commercetools_store.my-store.key
60 | }
61 |
62 | billing_address_keys = ["my-company-address-1"]
63 | shipping_address_keys = ["my-company-address-1", "my-company-address-2"]
64 | default_billing_address_key = "my-company-address-1"
65 | default_shipping_address_key = "my-company-address-1"
66 |
67 | custom {
68 | type_id = commercetools_type.my-type.id
69 | fields = {
70 | my_field = "My value"
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/commercetools/resource_api_extension_migrate.go:
--------------------------------------------------------------------------------
1 | package commercetools
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
7 | )
8 |
9 | func resourceAPIExtensionResourceV0() *schema.Resource {
10 | return &schema.Resource{
11 | Schema: map[string]*schema.Schema{
12 | "key": {
13 | Description: "User-specific unique identifier for the extension",
14 | Type: schema.TypeString,
15 | Optional: true,
16 | },
17 | "destination": {
18 | Description: "[Destination](https://docs.commercetools.com/api/projects/api-extensions#destination) " +
19 | "Details where the extension can be reached",
20 | Type: schema.TypeSet,
21 | MaxItems: 1,
22 | Required: true,
23 | Elem: &schema.Schema{
24 | Type: schema.TypeString,
25 | },
26 | },
27 | "trigger": {
28 | Description: "Array of [Trigger](https://docs.commercetools.com/api/projects/api-extensions#trigger) " +
29 | "Describes what triggers the extension",
30 | Type: schema.TypeList,
31 | Required: true,
32 | Elem: &schema.Resource{
33 | Schema: map[string]*schema.Schema{
34 | "resource_type_id": {
35 | Description: "Currently, cart, order, payment, customer, quote-request, staged-quote, quote and business-unit are supported",
36 | Type: schema.TypeString,
37 | Required: true,
38 | },
39 | "actions": {
40 | Description: "Currently, Create and Update are supported",
41 | Type: schema.TypeList,
42 | Required: true,
43 | Elem: &schema.Schema{Type: schema.TypeString},
44 | },
45 | },
46 | },
47 | },
48 | "timeout_in_ms": {
49 | Description: "Extension timeout in milliseconds",
50 | Type: schema.TypeInt,
51 | Optional: true,
52 | },
53 | "version": {
54 | Type: schema.TypeInt,
55 | Computed: true,
56 | },
57 | },
58 | }
59 | }
60 |
61 | func migrateAPIExtensionStateV0toV1(_ context.Context, rawState map[string]any, _ any) (map[string]any, error) {
62 | transformToList(rawState, "destination")
63 | return rawState, nil
64 | }
65 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "flag"
6 | "fmt"
7 | "log"
8 |
9 | "github.com/hashicorp/terraform-plugin-framework/providerserver"
10 | "github.com/hashicorp/terraform-plugin-go/tfprotov5"
11 | "github.com/hashicorp/terraform-plugin-go/tfprotov5/tf5server"
12 | "github.com/hashicorp/terraform-plugin-mux/tf5muxserver"
13 |
14 | "github.com/labd/terraform-provider-commercetools/commercetools"
15 | "github.com/labd/terraform-provider-commercetools/internal/provider"
16 | )
17 |
18 | // Run "go generate" to format example terraform files and generate the docs for the registry/website
19 |
20 | // If you do not have terraform installed, you can remove the formatting command, but its suggested to
21 | // ensure the documentation is formatted properly.
22 | //go:generate terraform fmt -recursive ./examples/
23 |
24 | // Run the docs generation tool, check its repository for more information on how it works and how docs
25 | // can be customized.
26 | //go:generate go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs
27 |
28 | var (
29 | // these will be set by the goreleaser configuration
30 | // to appropriate values for the compiled binary
31 | version string = "dev"
32 | commit string = "snapshot"
33 | )
34 |
35 | func main() {
36 | debugFlag := flag.Bool("debug", false, "Start provider in debug mode.")
37 | flag.Parse()
38 |
39 | fullVersion := fmt.Sprintf("%s (%s)", version, commit)
40 |
41 | sdkProvider := commercetools.New(fullVersion)
42 |
43 | ctx := context.Background()
44 | providers := []func() tfprotov5.ProviderServer{
45 | providerserver.NewProtocol5(provider.New(fullVersion)),
46 | sdkProvider().GRPCProvider,
47 | }
48 |
49 | muxServer, err := tf5muxserver.NewMuxServer(ctx, providers...)
50 | if err != nil {
51 | log.Fatal(err)
52 | }
53 |
54 | var serveOpts []tf5server.ServeOpt
55 | if *debugFlag {
56 | serveOpts = append(serveOpts, tf5server.WithManagedDebug())
57 | }
58 |
59 | err = tf5server.Serve(
60 | "registry.terraform.io/labd/commercetools",
61 | muxServer.ProviderServer,
62 | serveOpts...,
63 | )
64 | if err != nil {
65 | log.Fatal(err)
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/commercetools/resource_cart_discount_absolute_test.go:
--------------------------------------------------------------------------------
1 | package commercetools
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
7 | )
8 |
9 | func TestAccCartDiscountAbsolute(t *testing.T) {
10 | identifier := "absolute"
11 | resourceName := "commercetools_cart_discount.absolute"
12 |
13 | resource.Test(t, resource.TestCase{
14 | PreCheck: func() { testAccPreCheck(t) },
15 | ProviderFactories: testAccProviders,
16 | CheckDestroy: testAccCheckCartDiscountDestroy,
17 | Steps: []resource.TestStep{
18 | {
19 | Config: testAccCartDiscountAbsoluteConfig(identifier),
20 | Check: resource.ComposeTestCheckFunc(
21 | resource.TestCheckResourceAttr(resourceName, "name.en", "absolute name"),
22 | resource.TestCheckResourceAttr(resourceName, "value.0.type", "absolute"),
23 | resource.TestCheckResourceAttr(resourceName, "value.0.money.0.currency_code", "USD"),
24 | resource.TestCheckResourceAttr(resourceName, "value.0.money.0.cent_amount", "1000"),
25 | resource.TestCheckResourceAttr(resourceName, "value.0.money.1.currency_code", "EUR"),
26 | resource.TestCheckResourceAttr(resourceName, "value.0.money.1.cent_amount", "2000"),
27 | resource.TestCheckResourceAttr(resourceName, "target.0.type", "customLineItems"),
28 | resource.TestCheckResourceAttr(resourceName, "target.0.predicate", "1=1"),
29 | ),
30 | },
31 | },
32 | })
33 | }
34 |
35 | func testAccCartDiscountAbsoluteConfig(identifier string) string {
36 | return hclTemplate(`
37 | resource "commercetools_cart_discount" "{{ .identifier }}" {
38 | name = {
39 | en = "absolute name"
40 | }
41 | sort_order = "0.9"
42 | predicate = "1=1"
43 |
44 | target {
45 | type = "customLineItems"
46 | predicate = "1=1"
47 | }
48 |
49 | value {
50 | type = "absolute"
51 | money {
52 | currency_code = "USD"
53 | cent_amount = 1000
54 | }
55 | money {
56 | currency_code = "EUR"
57 | cent_amount = 2000
58 | }
59 | }
60 | }
61 | `, map[string]any{
62 | "identifier": identifier,
63 | })
64 | }
65 |
--------------------------------------------------------------------------------
/internal/utils/fields.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "github.com/hashicorp/terraform-plugin-framework/attr"
5 | "github.com/hashicorp/terraform-plugin-framework/types"
6 | "github.com/hashicorp/terraform-plugin-framework/types/basetypes"
7 | "github.com/labd/commercetools-go-sdk/platform"
8 |
9 | "github.com/labd/terraform-provider-commercetools/internal/customtypes"
10 | )
11 |
12 | func OptionalString(value types.String) *string {
13 | if value.IsUnknown() || value.IsNull() {
14 | return nil
15 | }
16 |
17 | val := value.ValueString()
18 | return &val
19 | }
20 |
21 | func OptionalInt(value types.Int64) *int {
22 | if value.IsUnknown() || value.IsNull() {
23 | return nil
24 | }
25 |
26 | val := int(value.ValueInt64())
27 | return &val
28 | }
29 |
30 | func FromOptionalString(value *string) basetypes.StringValue {
31 | if value == nil {
32 | return types.StringNull()
33 | }
34 | return types.StringValue(*value)
35 |
36 | }
37 | func FromOptionalLocalizedString(value *platform.LocalizedString) customtypes.LocalizedStringValue {
38 | if value == nil {
39 | return customtypes.NewLocalizedStringNull()
40 | }
41 |
42 | return FromLocalizedString(*value)
43 | }
44 |
45 | func FromOptionalInt(value *int) basetypes.Int64Value {
46 | if value == nil {
47 | return types.Int64Null()
48 | }
49 | return types.Int64Value(int64(*value))
50 | }
51 |
52 | func FromOptionalBool(value *bool) basetypes.BoolValue {
53 | if value == nil {
54 | return types.BoolNull()
55 | }
56 | return types.BoolValue(*value)
57 | }
58 |
59 | func FromLocalizedString(value platform.LocalizedString) customtypes.LocalizedStringValue {
60 | result := make(map[string]attr.Value, len(value))
61 | for k, v := range value {
62 | result[k] = types.StringValue(v)
63 | }
64 | return customtypes.NewLocalizedStringValue(result)
65 | }
66 |
67 | func StringRef(value any) *string {
68 | if value == nil {
69 | return nil
70 | }
71 | result := value.(string)
72 | return &result
73 | }
74 |
75 | func IntRef(value any) *int {
76 | result := value.(int)
77 | return &result
78 | }
79 |
80 | func BoolRef(value any) *bool {
81 | result := value.(bool)
82 | return &result
83 | }
84 |
85 | func Ref[T comparable](value T) *T {
86 | return &value
87 | }
88 |
--------------------------------------------------------------------------------
/docs/resources/attribute_group.md:
--------------------------------------------------------------------------------
1 | ---
2 | # generated by https://github.com/hashicorp/terraform-plugin-docs
3 | page_title: "commercetools_attribute_group Resource - terraform-provider-commercetools"
4 | subcategory: ""
5 | description: |-
6 | Attribute Groups allow you to define a set of referenced Attribute Definitions for the purpose of giving one or more dedicated teams access to edit Attribute values in Product Variants for those Attributes in the Merchant Center. Depending on the use case, editing permission can be granted to all Attributes, to Attributes that are ungrouped, or none.
7 | ---
8 |
9 | # commercetools_attribute_group (Resource)
10 |
11 | Attribute Groups allow you to define a set of referenced Attribute Definitions for the purpose of giving one or more dedicated teams access to edit Attribute values in Product Variants for those Attributes in the Merchant Center. Depending on the use case, editing permission can be granted to all Attributes, to Attributes that are ungrouped, or none.
12 |
13 | ## Example Usage
14 |
15 | ```terraform
16 | resource "commercetools_attribute_group" "my-attribute-group" {
17 | key = "my-attribute-group-key"
18 | name = {
19 | en = "my-attribute-group-name"
20 | }
21 | description = {
22 | en = "my-attribute-group-description"
23 | }
24 |
25 | attribute {
26 | key = "attribute-key-1"
27 | }
28 |
29 | attribute {
30 | key = "attribute-key-2"
31 | }
32 | }
33 | ```
34 |
35 |
36 | ## Schema
37 |
38 | ### Required
39 |
40 | - `name` (Map of String) Name of the State as localized string.
41 |
42 | ### Optional
43 |
44 | - `attribute` (Block List) Attributes with unique values. (see [below for nested schema](#nestedblock--attribute))
45 | - `description` (Map of String) Description of the State as localized string.
46 | - `key` (String) User-defined unique identifier of the AttributeGroup.
47 |
48 | ### Read-Only
49 |
50 | - `id` (String) Platform-generated unique identifier of the AttributeGroup.
51 | - `version` (Number) Current version of the AttributeGroup.
52 |
53 |
54 | ### Nested Schema for `attribute`
55 |
56 | Required:
57 |
58 | - `key` (String) The Attribute's name as given in its AttributeDefinition.
59 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_business_unit_division/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_store" "my-store" {
2 | key = "my-store"
3 | name = {
4 | en-US = "My store"
5 | }
6 | countries = ["NL", "BE"]
7 | languages = ["en-GB"]
8 | }
9 |
10 | resource "commercetools_type" "my-type" {
11 | key = "my-type"
12 | name = {
13 | en = "My type"
14 | nl = "Mijn type"
15 | }
16 |
17 | resource_type_ids = ["business-unit"]
18 |
19 | field {
20 | name = "my-field"
21 | label = {
22 | en = "My field"
23 | nl = "Mijn veld"
24 | }
25 | type {
26 | name = "String"
27 | }
28 | }
29 | }
30 |
31 | resource "commercetools_business_unit_company" "my-company" {
32 | key = "my-company"
33 | name = "My company"
34 | contact_email = "main@my-company.com"
35 | }
36 |
37 | resource "commercetools_business_unit_division" "my-division" {
38 | key = "my-division"
39 | name = "My division"
40 | contact_email = "my-division@my-company.com"
41 | store_mode = "Explicit"
42 | status = "Active"
43 | associate_mode = "Explicit"
44 | approval_rule_mode = "Explicit"
45 |
46 | parent_unit {
47 | key = commercetools_business_unit_company.my-company.key
48 | }
49 |
50 | store {
51 | key = commercetools_store.my-store.key
52 | }
53 |
54 | address {
55 | key = "my-div-address-1"
56 | country = "NL"
57 | state = "Utrecht"
58 | city = "Utrecht"
59 | street_name = "Oudegracht"
60 | street_number = "1"
61 | postal_code = "3511 AA"
62 | additional_street_info = "Main floor"
63 | }
64 |
65 | address {
66 | key = "my-div-address-2"
67 | country = "NL"
68 | state = "Zuid-Holland"
69 | city = "Leiden"
70 | street_name = "Breestraat"
71 | street_number = "1"
72 | postal_code = "2311 CH"
73 | }
74 | billing_address_keys = ["my-div-address-1"]
75 | shipping_address_keys = ["my-div-address-1", "my-div-address-2"]
76 | default_billing_address_key = "my-div-address-1"
77 | default_shipping_address_key = "my-div-address-1"
78 |
79 | custom {
80 | type_id = commercetools_type.my-type.id
81 | fields = {
82 | my_field = "My value"
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/docs/resources/tax_category_rate.md:
--------------------------------------------------------------------------------
1 | ---
2 | # generated by https://github.com/hashicorp/terraform-plugin-docs
3 | page_title: "commercetools_tax_category_rate Resource - terraform-provider-commercetools"
4 | subcategory: ""
5 | description: |-
6 | Tax rate for Tax Category.
7 | See also Tax Rate API Documentation https://docs.commercetools.com/api/projects/taxCategories#taxrate
8 | ---
9 |
10 | # commercetools_tax_category_rate (Resource)
11 |
12 | Tax rate for Tax Category.
13 |
14 | See also [Tax Rate API Documentation](https://docs.commercetools.com/api/projects/taxCategories#taxrate)
15 |
16 | ## Example Usage
17 |
18 | ```terraform
19 | resource "commercetools_tax_category" "my-tax-category" {
20 | name = "Standard tax category"
21 | description = "Example category"
22 | }
23 |
24 | resource "commercetools_tax_category_rate" "standard-tax-category-DE" {
25 | tax_category_id = commercetools_tax_category.my-tax-category.id
26 | name = "19% MwSt"
27 | amount = 0.19
28 | included_in_price = false
29 | country = "DE"
30 | sub_rate {
31 | name = "example"
32 | amount = 0.19
33 | }
34 | }
35 |
36 | resource "commercetools_tax_category_rate" "standard-tax-category-NL" {
37 | tax_category_id = commercetools_tax_category.my-tax-category.id
38 | name = "21% BTW"
39 | amount = 0.21
40 | included_in_price = true
41 | country = "NL"
42 | }
43 | ```
44 |
45 |
46 | ## Schema
47 |
48 | ### Required
49 |
50 | - `country` (String) A two-digit country code as per [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)
51 | - `included_in_price` (Boolean)
52 | - `name` (String)
53 | - `tax_category_id` (String)
54 |
55 | ### Optional
56 |
57 | - `amount` (Number) Number Percentage in the range of [0..1]. The sum of the amounts of all subRates, if there are any
58 | - `state` (String) The state in the country
59 | - `sub_rate` (Block List) For countries (for example the US) where the total tax is a combination of multiple taxes (for example state and local taxes) (see [below for nested schema](#nestedblock--sub_rate))
60 |
61 | ### Read-Only
62 |
63 | - `id` (String) The ID of this resource.
64 |
65 |
66 | ### Nested Schema for `sub_rate`
67 |
68 | Required:
69 |
70 | - `amount` (Number) Number Percentage in the range of [0..1]
71 | - `name` (String)
72 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_api_extension/resource.tf:
--------------------------------------------------------------------------------
1 | # HTTP api extension
2 | resource "commercetools_api_extension" "my-http-extension" {
3 | key = "my-http-extension-key"
4 |
5 | destination {
6 | type = "HTTP"
7 | url = "https://example.com"
8 | authorization_header = "Basic 12345"
9 | }
10 |
11 | trigger {
12 | resource_type_id = "customer"
13 | actions = ["Create", "Update"]
14 | }
15 | }
16 |
17 | # AWS Lambda api extension
18 | resource "commercetools_api_extension" "my-awslambda-extension" {
19 | key = "my-awslambda-extension-key"
20 |
21 | destination {
22 | type = "awslambda"
23 | arn = "us-east-1:123456789012:mylambda"
24 | access_key = "mykey"
25 | access_secret = "mysecret"
26 | }
27 |
28 | trigger {
29 | resource_type_id = "customer"
30 | actions = ["Create", "Update"]
31 | }
32 | }
33 |
34 | # Google Cloud Function api extension
35 | resource "commercetools_api_extension" "my-googlecloudfunction-extension" {
36 | key = "my-googlecloudfunction-extension-key"
37 |
38 | destination {
39 | type = "googlecloudfunction"
40 | url = "https://example.com"
41 | }
42 |
43 | trigger {
44 | resource_type_id = "customer"
45 | actions = ["Create", "Update"]
46 | }
47 | }
48 |
49 | resource "google_cloudfunctions_function" "my_cloud_function" {
50 | name = "function-test"
51 | description = "My function"
52 | runtime = "nodejs16"
53 |
54 | # See https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/cloudfunctions_function for any
55 | # further settings
56 | }
57 |
58 | resource "google_cloudfunctions_function_iam_member" "invoker" {
59 | # For GoogleCloudFunction destinations, you need to grant permissions to the
60 | # service account to invoke your function.
61 | project = "my-project"
62 | region = "europe-central2"
63 | cloud_function = google_cloudfunctions_function.my_cloud_function.name
64 |
65 | # If your function's version is 1st gen, grant the service account the IAM role Cloud Functions Invoker
66 | role = "roles/cloudfunctions.invoker"
67 | # For version 2nd gen, assign the IAM role Cloud Run Invoker
68 | # role = "roles/run.invoker"
69 | member = "serviceAccount:extensions@commercetools-platform.iam.gserviceaccount.com"
70 | }
71 |
--------------------------------------------------------------------------------
/internal/datasource/state/resource_test.go:
--------------------------------------------------------------------------------
1 | package custom_type_test
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "testing"
7 |
8 | acctest "github.com/labd/terraform-provider-commercetools/internal/acctest"
9 | "github.com/labd/terraform-provider-commercetools/internal/utils"
10 |
11 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
12 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
13 | "github.com/stretchr/testify/assert"
14 | )
15 |
16 | func TestAccState(t *testing.T) {
17 | resource.Test(t, resource.TestCase{
18 | PreCheck: func() { acctest.TestAccPreCheck(t) },
19 | ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
20 | CheckDestroy: testAccCheckDestroy,
21 | Steps: []resource.TestStep{
22 | {
23 | Config: testAccConfigLoadState(),
24 | Check: resource.ComposeTestCheckFunc(
25 | func(s *terraform.State) error {
26 | client, err := acctest.GetClient()
27 | if err != nil {
28 | return nil
29 | }
30 | result, err := client.States().WithKey("test").Get().Execute(context.Background())
31 | if err != nil {
32 | return nil
33 | }
34 | assert.NotNil(t, result)
35 | assert.Equal(t, result.Key, "test")
36 | return nil
37 | },
38 | ),
39 | },
40 | },
41 | })
42 | }
43 |
44 | func testAccCheckDestroy(s *terraform.State) error {
45 | client, err := acctest.GetClient()
46 | if err != nil {
47 | return err
48 | }
49 |
50 | for _, rs := range s.RootModule().Resources {
51 | if rs.Type != "commercetools_state" {
52 | continue
53 | }
54 | response, err := client.States().WithId(rs.Primary.ID).Get().Execute(context.Background())
55 | if err == nil {
56 | if response != nil && response.ID == rs.Primary.ID {
57 | return fmt.Errorf("state (%s) still exists", rs.Primary.ID)
58 | }
59 | return nil
60 | }
61 | if newErr := acctest.CheckApiResult(err); newErr != nil {
62 | return newErr
63 | }
64 | }
65 | return nil
66 | }
67 |
68 | func testAccConfigLoadState() string {
69 | return utils.HCLTemplate(`
70 | resource "commercetools_state" "test" {
71 | key = "test"
72 | type = "ReviewState"
73 | name = {
74 | en = "Unreviewed"
75 | }
76 | description = {
77 | en = "Not reviewed yet"
78 | }
79 | initial = true
80 | }
81 |
82 | data "commercetools_state" "test" {
83 | key = "test"
84 |
85 | depends_on = [
86 | commercetools_state.test
87 | ]
88 | }
89 | `, map[string]any{})
90 | }
91 |
--------------------------------------------------------------------------------
/docs/guides/extensions.md:
--------------------------------------------------------------------------------
1 | ---
2 | subcategory: ""
3 | page_title: "API Extensions"
4 | description: |-
5 | Using AWS Lambda, Google Cloud Functions for API Extensions
6 | ---
7 |
8 | ## Example
9 |
10 | ```hcl
11 | locals {
12 | project = ""
13 | region = "europe-west1"
14 | }
15 |
16 | provider "commercetools" {
17 | client_id = "foo"
18 | client_secret = "bar"
19 | project_key = "some-project"
20 | scopes = "manage_project:some-project"
21 | token_url = "https://auth.sphere.io"
22 | api_url = "https://api.sphere.io"
23 | }
24 |
25 | provider "google" {
26 | project = local.project
27 | region = local.region
28 | }
29 |
30 |
31 | # Create the artifact
32 | data "archive_file" "source" {
33 | type = "zip"
34 | source_dir = "src"
35 | output_path = "functions-source.zip"
36 | }
37 |
38 | resource "google_storage_bucket" "bucket" {
39 | name = "${local.project}-gcf-source"
40 | location = "EU"
41 | uniform_bucket_level_access = true
42 | }
43 |
44 | resource "google_storage_bucket_object" "object" {
45 | name = "function-source-${data.archive_file.source.output_md5}.zip"
46 | bucket = google_storage_bucket.bucket.name
47 | source = "function-source.zip"
48 | }
49 |
50 | resource "google_cloudfunctions_function" "function" {
51 | name = "my-cart-extension"
52 | region = local.region
53 | description = "Extension for cart create / update"
54 |
55 | runtime = "nodejs16"
56 | trigger_http = true
57 | entry_point = "cartHandler"
58 |
59 | source_archive_bucket = google_storage_bucket.bucket.name
60 | source_archive_object = google_storage_bucket_object.object.name
61 | }
62 |
63 |
64 | # Allow everyone to access this function. Commercetools doesn't support auth
65 | # yet for cloud functions, so this is needed.
66 | resource "google_cloudfunctions_function_iam_member" "invoker" {
67 | project = google_cloudfunctions_function.function.project
68 | region = google_cloudfunctions_function.function.region
69 | cloud_function = google_cloudfunctions_function.function.name
70 |
71 | role = "roles/cloudfunctions.invoker"
72 | member = "allUsers"
73 | }
74 |
75 | resource "commercetools_api_extension" "cart_extension" {
76 | key = "my-cart-extension"
77 |
78 | destination {
79 | type = "HTTP"
80 | url = google_cloudfunctions_function.function.https_trigger_url
81 | }
82 |
83 | trigger {
84 | resource_type_id = "cart"
85 | actions = ["Create", "Update"]
86 | }
87 | }
88 | ```
89 |
--------------------------------------------------------------------------------
/templates/index.md.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "commercetools provider"
3 | subcategory: ""
4 | description: |-
5 | The commercetools provider provides resources to interact with the commercetools API
6 |
7 | ---
8 |
9 | # commercetools provider
10 |
11 | ## Commercial support
12 | Need support implementing this terraform module in your organization? We are
13 | able to offer support. Please contact us at
14 | [opensource@labdigital.nl](opensource@labdigital.nl)!
15 |
16 | ## Installation
17 | Terraform automatically downloads providers from the terraform registry. Add the
18 | following to your terraform project
19 |
20 |
21 | ```hcl
22 | terraform {
23 | required_providers {
24 | commercetools = {
25 | source = "labd/commercetools"
26 | }
27 | }
28 | }
29 | ```
30 |
31 | Packages of the releases are available at [the GitHub Repo](https://github.com/labd/terraform-provider-commercetools/releases).
32 | See the [terraform documentation](https://www.terraform.io/docs/configuration/providers.html#third-party-plugins)
33 | for more information about installing third-party providers.
34 |
35 |
36 | ## Using the provider
37 | The provider attempts to read the required values from environment variables:
38 | - `CTP_CLIENT_ID`
39 | - `CTP_CLIENT_SECRET`
40 | - `CTP_PROJECT_KEY`
41 | - `CTP_SCOPES`
42 | - `CTP_API_URL`
43 | - `CTP_AUTH_URL`
44 |
45 | Alternatively, you can set it up directly in the terraform file:
46 |
47 | ```hcl
48 | provider "commercetools" {
49 | client_id = ""
50 | client_secret = ""
51 | project_key = ""
52 | scopes = ""
53 | api_url = ""
54 | token_url = ""
55 | }
56 | ```
57 |
58 | {{ .SchemaMarkdown | trimspace }}
59 |
60 | ## Using with docker
61 |
62 | The included `Dockerfile` bundles the official [`hashicorp/terraform:light`](https://hub.docker.com/r/hashicorp/terraform/) docker image with
63 | our `terraform-provider-commercetools`.
64 |
65 | To build the docker image file locally, use:
66 | ```sh
67 | docker build . -t terraform-with-provider-commercetools:latest
68 | ```
69 | Then you can run a terraform command on files in the current directory with:
70 | ```sh
71 | docker run -v "${pwd}:/config" terraform-with-provider-commercetools:latest
72 | ```
73 |
74 | ## Authors
75 | This project is developed by [Lab Digital](https://www.labdigital.nl). We
76 | welcome additional contributors. Please see our
77 | [GitHub repository](https://github.com/labd/terraform-provider-commercetools)
78 | for more information.
79 |
--------------------------------------------------------------------------------
/templates/guides/extensions.md.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | subcategory: ""
3 | page_title: "API Extensions"
4 | description: |-
5 | Using AWS Lambda, Google Cloud Functions for API Extensions
6 | ---
7 |
8 | ## Example
9 |
10 | ```hcl
11 | locals {
12 | project = ""
13 | region = "europe-west1"
14 | }
15 |
16 | provider "commercetools" {
17 | client_id = "foo"
18 | client_secret = "bar"
19 | project_key = "some-project"
20 | scopes = "manage_project:some-project"
21 | token_url = "https://auth.sphere.io"
22 | api_url = "https://api.sphere.io"
23 | }
24 |
25 | provider "google" {
26 | project = local.project
27 | region = local.region
28 | }
29 |
30 |
31 | # Create the artifact
32 | data "archive_file" "source" {
33 | type = "zip"
34 | source_dir = "src"
35 | output_path = "functions-source.zip"
36 | }
37 |
38 | resource "google_storage_bucket" "bucket" {
39 | name = "${local.project}-gcf-source"
40 | location = "EU"
41 | uniform_bucket_level_access = true
42 | }
43 |
44 | resource "google_storage_bucket_object" "object" {
45 | name = "function-source-${data.archive_file.source.output_md5}.zip"
46 | bucket = google_storage_bucket.bucket.name
47 | source = "function-source.zip"
48 | }
49 |
50 | resource "google_cloudfunctions_function" "function" {
51 | name = "my-cart-extension"
52 | region = local.region
53 | description = "Extension for cart create / update"
54 |
55 | runtime = "nodejs16"
56 | trigger_http = true
57 | entry_point = "cartHandler"
58 |
59 | source_archive_bucket = google_storage_bucket.bucket.name
60 | source_archive_object = google_storage_bucket_object.object.name
61 | }
62 |
63 |
64 | # Allow everyone to access this function. Commercetools doesn't support auth
65 | # yet for cloud functions, so this is needed.
66 | resource "google_cloudfunctions_function_iam_member" "invoker" {
67 | project = google_cloudfunctions_function.function.project
68 | region = google_cloudfunctions_function.function.region
69 | cloud_function = google_cloudfunctions_function.function.name
70 |
71 | role = "roles/cloudfunctions.invoker"
72 | member = "allUsers"
73 | }
74 |
75 | resource "commercetools_api_extension" "cart_extension" {
76 | key = "my-cart-extension"
77 |
78 | destination {
79 | type = "HTTP"
80 | url = google_cloudfunctions_function.function.https_trigger_url
81 | }
82 |
83 | trigger {
84 | resource_type_id = "cart"
85 | actions = ["Create", "Update"]
86 | }
87 | }
88 | ```
89 |
--------------------------------------------------------------------------------
/docs/resources/state.md:
--------------------------------------------------------------------------------
1 | ---
2 | # generated by https://github.com/hashicorp/terraform-plugin-docs
3 | page_title: "commercetools_state Resource - terraform-provider-commercetools"
4 | subcategory: ""
5 | description: |-
6 | The commercetools platform allows you to model states of certain objects, such as orders, line items, products, reviews, and payments to define finite state machines reflecting the business logic you'd like to implement.
7 | See also the State API Documentation https://docs.commercetools.com/api/projects/states
8 | ---
9 |
10 | # commercetools_state (Resource)
11 |
12 | The commercetools platform allows you to model states of certain objects, such as orders, line items, products, reviews, and payments to define finite state machines reflecting the business logic you'd like to implement.
13 |
14 | See also the [State API Documentation](https://docs.commercetools.com/api/projects/states)
15 |
16 | ## Example Usage
17 |
18 | ```terraform
19 | resource "commercetools_state" "review_unreviewed" {
20 | key = "review-unreviewed"
21 | type = "ReviewState"
22 | name = {
23 | en = "Unreviewed"
24 | }
25 | description = {
26 | en = "Not reviewed yet"
27 | }
28 | initial = true
29 | roles = ["ReviewIncludedInStatistics"]
30 | }
31 |
32 | resource "commercetools_state" "product_for_sale" {
33 | key = "product-for-sale"
34 | type = "ProductState"
35 | name = {
36 | en = "For Sale"
37 | }
38 | description = {
39 | en = "Regularly stocked product."
40 | }
41 | initial = true
42 | }
43 |
44 | resource "commercetools_state" "product_clearance" {
45 | key = "product-clearance"
46 | type = "ProductState"
47 | name = {
48 | en = "On Clearance"
49 | }
50 | description = {
51 | en = "The product line will not be ordered again."
52 | }
53 | }
54 | ```
55 |
56 |
57 | ## Schema
58 |
59 | ### Required
60 |
61 | - `type` (String) [StateType](https://docs.commercetools.com/api/projects/states#statetype)
62 |
63 | ### Optional
64 |
65 | - `description` (Map of String) Description of the State as localized string.
66 | - `initial` (Boolean) A state can be declared as an initial state for any state machine. When a workflow starts, this first state must be an initial state
67 | - `key` (String) Timestamp of the last Terraform update of the order.
68 | - `name` (Map of String) Name of the State as localized string.
69 | - `roles` (List of String) [State Role](https://docs.commercetools.com/api/projects/states#staterole)
70 |
71 | ### Read-Only
72 |
73 | - `id` (String) The ID of this resource.
74 | - `version` (Number)
75 |
--------------------------------------------------------------------------------
/docs/resources/product_selection.md:
--------------------------------------------------------------------------------
1 | ---
2 | # generated by https://github.com/hashicorp/terraform-plugin-docs
3 | page_title: "commercetools_product_selection Resource - terraform-provider-commercetools"
4 | subcategory: ""
5 | description: |-
6 | Product Selections can be used to manage individual assortments for different sales channels.See also the Product Selections API Documentation https://docs.commercetools.com/api/projects/product-selections
7 | ---
8 |
9 | # commercetools_product_selection (Resource)
10 |
11 | Product Selections can be used to manage individual assortments for different sales channels.See also the [Product Selections API Documentation](https://docs.commercetools.com/api/projects/product-selections)
12 |
13 | ## Example Usage
14 |
15 | ```terraform
16 | resource "commercetools_type" "my-type" {
17 | key = "my-type"
18 | name = {
19 | en = "My type"
20 | nl = "Mijn type"
21 | }
22 |
23 | resource_type_ids = ["product-selection"]
24 |
25 | field {
26 | name = "my-field"
27 | label = {
28 | en = "My field"
29 | nl = "Mijn veld"
30 | }
31 | type {
32 | name = "String"
33 | }
34 | }
35 | }
36 |
37 | resource "commercetools_product_selection" "product-selection-us" {
38 | key = "product-selection-us"
39 | name = {
40 | en = "US Product Selection"
41 | }
42 | mode = "Individual"
43 |
44 | custom {
45 | type_id = commercetools_type.my-type.id
46 | fields = {
47 | my-field = "my-value"
48 | }
49 | }
50 | }
51 | ```
52 |
53 |
54 | ## Schema
55 |
56 | ### Required
57 |
58 | - `name` (Map of String) Name of the ProductSelection.
59 |
60 | ### Optional
61 |
62 | - `custom` (Block, Optional) Custom fields for this resource. (see [below for nested schema](#nestedblock--custom))
63 | - `key` (String) User-defined unique identifier of the ProductSelection.
64 | - `mode` (String) Specifies in which way the Products are assigned to the ProductSelection.Currently, the only way of doing this is to specify each Product individually, either by including or excluding them explicitly.Default: Individual
65 |
66 | ### Read-Only
67 |
68 | - `id` (String) Unique identifier of the ProductSelection.
69 | - `version` (Number) Current version of the ProductSelection.
70 |
71 |
72 | ### Nested Schema for `custom`
73 |
74 | Optional:
75 |
76 | - `fields` (Map of String) CustomValue fields for this resource. Note that the values need to be provided as JSON encoded strings: `my-value = jsonencode({"key": "value"})`
77 | - `type_id` (String) The ID of the custom type to use for this resource.
78 |
--------------------------------------------------------------------------------
/internal/resources/state/resource_test.go:
--------------------------------------------------------------------------------
1 | package state_test
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "testing"
7 |
8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
10 |
11 | "github.com/labd/terraform-provider-commercetools/internal/acctest"
12 | "github.com/labd/terraform-provider-commercetools/internal/utils"
13 | )
14 |
15 | func TestAccState_createAndUpdateWithID(t *testing.T) {
16 | name := "test state"
17 | key := "test-state"
18 | resourceName := "commercetools_state.acctest-state"
19 |
20 | newName := "new test state name"
21 |
22 | resource.Test(t, resource.TestCase{
23 | PreCheck: func() { acctest.TestAccPreCheck(t) },
24 | ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
25 | CheckDestroy: testAccCheckStateDestroy,
26 | Steps: []resource.TestStep{
27 | {
28 | Config: testAccStateConfig(t, name, key, false),
29 | Check: resource.ComposeTestCheckFunc(
30 | resource.TestCheckResourceAttr(resourceName, "name.en", name),
31 | resource.TestCheckResourceAttr(resourceName, "key", key),
32 | ),
33 | },
34 | {
35 | Config: testAccStateConfig(t, newName, key, true),
36 | Check: resource.ComposeTestCheckFunc(
37 | resource.TestCheckResourceAttr(resourceName, "name.en", newName),
38 | resource.TestCheckResourceAttr(resourceName, "key", key),
39 | ),
40 | },
41 | },
42 | })
43 | }
44 |
45 | func testAccStateConfig(t *testing.T, name string, key string, addRole bool) string {
46 | return utils.HCLTemplate(`
47 | resource "commercetools_state" "acctest-state" {
48 | key = "{{ .key }}"
49 | type = "ReviewState"
50 | name = {
51 | en = "{{ .name }}"
52 | nl = "{{ .name }}"
53 | }
54 |
55 | {{ if .addRole }}
56 | roles = ["ReviewIncludedInStatistics"]
57 | {{ end }}
58 | }
59 | `,
60 | map[string]any{
61 | "key": key,
62 | "name": name,
63 | "addRole": addRole,
64 | })
65 | }
66 |
67 | func testAccCheckStateDestroy(s *terraform.State) error {
68 | client, err := acctest.GetClient()
69 | if err != nil {
70 | return err
71 | }
72 |
73 | for _, rs := range s.RootModule().Resources {
74 | if rs.Type != "commercetools_state" {
75 | continue
76 | }
77 | response, err := client.States().WithId(rs.Primary.ID).Get().Execute(context.Background())
78 | if err == nil {
79 | if response != nil && response.ID == rs.Primary.ID {
80 | return fmt.Errorf("state (%s) still exists", rs.Primary.ID)
81 | }
82 | return nil
83 | }
84 | if newErr := acctest.CheckApiResult(err); newErr != nil {
85 | return newErr
86 | }
87 | }
88 | return nil
89 | }
90 |
--------------------------------------------------------------------------------
/commercetools/resource_tax_category_test.go:
--------------------------------------------------------------------------------
1 | package commercetools
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "testing"
7 |
8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
10 | )
11 |
12 | func TestAccTaxCategory_createAndUpdateWithID(t *testing.T) {
13 | resourceName := "commercetools_tax_category.standard"
14 | name := "test category"
15 | key := "test-category"
16 | description := "test category description"
17 |
18 | newName := "new test category"
19 | newKey := "new-test-category"
20 | newDescription := "new test category description"
21 |
22 | resource.Test(t, resource.TestCase{
23 | PreCheck: func() { testAccPreCheck(t) },
24 | ProviderFactories: testAccProviders,
25 | CheckDestroy: testAccCheckTaxCategoryDestroy,
26 | Steps: []resource.TestStep{
27 | {
28 | Config: testAccTaxCategoryConfig(name, key, description),
29 | Check: resource.ComposeTestCheckFunc(
30 | resource.TestCheckResourceAttr(resourceName, "name", name),
31 | resource.TestCheckResourceAttr(resourceName, "key", key),
32 | resource.TestCheckResourceAttr(resourceName, "description", description),
33 | ),
34 | },
35 | {
36 | Config: testAccTaxCategoryConfig(newName, newKey, newDescription),
37 | Check: resource.ComposeTestCheckFunc(
38 | resource.TestCheckResourceAttr(resourceName, "name", newName),
39 | resource.TestCheckResourceAttr(resourceName, "key", newKey),
40 | resource.TestCheckResourceAttr(resourceName, "description", newDescription),
41 | ),
42 | },
43 | },
44 | })
45 | }
46 |
47 | func testAccTaxCategoryConfig(name, key, description string) string {
48 | return hclTemplate(`
49 | resource "commercetools_tax_category" "standard" {
50 | name = "{{ .name }}"
51 | key = "{{ .key }}"
52 | description = "{{ .description }}"
53 | }
54 | `, map[string]any{
55 | "key": key,
56 | "name": name,
57 | "description": description,
58 | })
59 |
60 | }
61 |
62 | func testAccCheckTaxCategoryDestroy(s *terraform.State) error {
63 | client := getClient(testAccProvider.Meta())
64 |
65 | for _, rs := range s.RootModule().Resources {
66 | if rs.Type != "commercetools_tax_category" {
67 | continue
68 | }
69 | response, err := client.TaxCategories().WithId(rs.Primary.ID).Get().Execute(context.Background())
70 | if err == nil {
71 | if response != nil && response.ID == rs.Primary.ID {
72 | return fmt.Errorf("tax category (%s) still exists", rs.Primary.ID)
73 | }
74 | return nil
75 | }
76 | if newErr := checkApiResult(err); newErr != nil {
77 | return newErr
78 | }
79 | }
80 | return nil
81 | }
82 |
--------------------------------------------------------------------------------
/commercetools/resource_cart_discount_stores_test.go:
--------------------------------------------------------------------------------
1 | package commercetools
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
7 | )
8 |
9 | func TestAccCartDiscountStores(t *testing.T) {
10 | identifier := "stores"
11 | resourceName := "commercetools_cart_discount.stores"
12 |
13 | resource.Test(t, resource.TestCase{
14 | PreCheck: func() { testAccPreCheck(t) },
15 | ProviderFactories: testAccProviders,
16 | CheckDestroy: testAccCheckCartDiscountDestroy,
17 | Steps: []resource.TestStep{
18 | {
19 | Config: testAccCartDiscountWithoutStores(identifier),
20 | Check: resource.ComposeTestCheckFunc(
21 | resource.TestCheckResourceAttr(resourceName, "stores.#", "0"),
22 | ),
23 | },
24 | {
25 | Config: testAccCartDiscountWithStores(identifier),
26 | Check: resource.ComposeTestCheckFunc(
27 | resource.TestCheckTypeSetElemAttr(resourceName, "stores.*", "my-store"),
28 | ),
29 | },
30 | {
31 | Config: testAccCartDiscountWithoutStores(identifier),
32 | Check: resource.ComposeTestCheckFunc(
33 | resource.TestCheckResourceAttr(resourceName, "stores.#", "0"),
34 | ),
35 | },
36 | },
37 | })
38 | }
39 |
40 | func testAccCartDiscountWithoutStores(identifier string) string {
41 | return hclTemplate(`
42 | resource "commercetools_cart_discount" "{{ .identifier }}" {
43 | name = {
44 | en = "fixed name"
45 | }
46 | sort_order = "0.9"
47 | predicate = "1=1"
48 |
49 | target {
50 | type = "shipping"
51 | }
52 |
53 | value {
54 | type = "fixed"
55 | money {
56 | currency_code = "USD"
57 | cent_amount = 1000
58 | }
59 | }
60 | }
61 | `, map[string]any{
62 | "identifier": identifier,
63 | })
64 | }
65 |
66 | func testAccCartDiscountWithStores(identifier string) string {
67 | return hclTemplate(`
68 | resource "commercetools_store" "my-store-{{ .identifier }}" {
69 | key = "my-store"
70 | name = {
71 | en-US = "My store"
72 | }
73 | countries = ["NL", "BE"]
74 | languages = ["nl-NL"]
75 | }
76 |
77 | resource "commercetools_cart_discount" "{{ .identifier }}" {
78 | name = {
79 | en = "fixed name"
80 | }
81 | stores = [commercetools_store.my-store-{{ .identifier }}.key]
82 | sort_order = "0.9"
83 | predicate = "1=1"
84 |
85 | target {
86 | type = "shipping"
87 | }
88 |
89 | value {
90 | type = "fixed"
91 | money {
92 | currency_code = "USD"
93 | cent_amount = 1000
94 | }
95 | }
96 | }
97 | `, map[string]any{
98 | "identifier": identifier,
99 | })
100 | }
101 |
--------------------------------------------------------------------------------
/internal/resources/product_selection/model_test.go:
--------------------------------------------------------------------------------
1 | package product_selection
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/hashicorp/terraform-plugin-framework/attr"
7 | "github.com/hashicorp/terraform-plugin-framework/types"
8 | "github.com/labd/commercetools-go-sdk/platform"
9 | "github.com/labd/terraform-provider-commercetools/internal/customtypes"
10 | "github.com/labd/terraform-provider-commercetools/internal/utils"
11 | "github.com/stretchr/testify/assert"
12 | )
13 |
14 | func TestProductSelection_UpdateActions(t *testing.T) {
15 | cases := []struct {
16 | name string
17 | state ProductSelection
18 | plan ProductSelection
19 | expected platform.ProductSelectionUpdate
20 | }{
21 | {
22 | "product selection update name",
23 | ProductSelection{
24 | Name: customtypes.NewLocalizedStringValue(map[string]attr.Value{
25 | "en-US": types.StringValue("Example product selection"),
26 | }),
27 | },
28 | ProductSelection{
29 | Name: customtypes.NewLocalizedStringValue(map[string]attr.Value{
30 | "en-US": types.StringValue("Example other product selection"),
31 | }),
32 | },
33 | platform.ProductSelectionUpdate{
34 | Actions: []platform.ProductSelectionUpdateAction{
35 | platform.ProductSelectionChangeNameAction{
36 | Name: map[string]string{"en-US": "Example other product selection"},
37 | },
38 | },
39 | },
40 | },
41 | }
42 |
43 | for _, c := range cases {
44 | t.Run(c.name, func(t *testing.T) {
45 | result, err := c.state.updateActions(nil, c.plan)
46 | assert.NoError(t, err)
47 | assert.EqualValues(t, c.expected, result)
48 | })
49 | }
50 | }
51 |
52 | func TestNewProductSelectionFromNative(t *testing.T) {
53 | cases := []struct {
54 | name string
55 | res *platform.ProductSelection
56 | expect ProductSelection
57 | }{
58 | {
59 | "decode remote product selection representation into local resource",
60 | &platform.ProductSelection{
61 | ID: "rand-uuid-or-other-string",
62 | Version: 1,
63 | Key: utils.StringRef("ps-1"),
64 | Name: map[string]string{"en-US": "the selection"},
65 | Mode: platform.ProductSelectionModeIndividual,
66 | },
67 | ProductSelection{
68 | ID: types.StringValue("rand-uuid-or-other-string"),
69 | Key: types.StringValue("ps-1"),
70 | Version: types.Int64Value(1),
71 | Name: customtypes.NewLocalizedStringValue(map[string]attr.Value{
72 | "en-US": types.StringValue("the selection"),
73 | }),
74 | Mode: types.StringValue("Individual"),
75 | },
76 | },
77 | }
78 |
79 | for _, c := range cases {
80 | t.Run(c.name, func(t *testing.T) {
81 | got, err := NewProductSelectionFromNative(c.res)
82 | assert.NoError(t, err)
83 | assert.EqualValues(t, got, c.expect)
84 | })
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/internal/customvalidator/requires.go:
--------------------------------------------------------------------------------
1 | package customvalidator
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | "github.com/hashicorp/terraform-plugin-framework-validators/helpers/validatordiag"
8 | "github.com/hashicorp/terraform-plugin-framework/attr"
9 | "github.com/hashicorp/terraform-plugin-framework/path"
10 | "github.com/hashicorp/terraform-plugin-framework/schema/validator"
11 | "github.com/hashicorp/terraform-plugin-framework/types/basetypes"
12 | )
13 |
14 | func RequireValueValidator(value string, expressions ...path.Expression) validator.List {
15 | return requireValueValidator{
16 | value: value,
17 | pathExpressions: expressions,
18 | }
19 | }
20 |
21 | var _ validator.List = requireValueValidator{}
22 |
23 | // anyValidator implements the validator.
24 | type requireValueValidator struct {
25 | value string
26 | pathExpressions path.Expressions
27 | }
28 |
29 | // Description describes the validation in plain text formatting.
30 | func (v requireValueValidator) Description(ctx context.Context) string {
31 | return fmt.Sprintf("Magic")
32 | }
33 |
34 | // MarkdownDescription describes the validation in Markdown formatting.
35 | func (v requireValueValidator) MarkdownDescription(ctx context.Context) string {
36 | return v.Description(ctx)
37 | }
38 |
39 | // ValidateString performs the validation.
40 | func (v requireValueValidator) ValidateList(ctx context.Context, req validator.ListRequest, resp *validator.ListResponse) {
41 |
42 | expressions := req.PathExpression.MergeExpressions(v.pathExpressions...)
43 |
44 | for _, expression := range expressions {
45 | matchedPaths, diags := req.Config.PathMatches(ctx, expression)
46 | resp.Diagnostics.Append(diags...)
47 |
48 | // Collect all errors
49 | if diags.HasError() {
50 | continue
51 | }
52 |
53 | for _, mp := range matchedPaths {
54 | // If the user specifies the same attribute this validator is applied to,
55 | // also as part of the input, skip it
56 | if mp.Equal(req.Path) {
57 | continue
58 | }
59 |
60 | var mpVal attr.Value
61 | diags := req.Config.GetAttribute(ctx, mp, &mpVal)
62 | resp.Diagnostics.Append(diags...)
63 |
64 | // Collect all errors
65 | if diags.HasError() {
66 | continue
67 | }
68 |
69 | val, ok := mpVal.(basetypes.StringValue)
70 | if !ok {
71 | resp.Diagnostics.Append(validatordiag.BugInProviderDiagnostic(
72 | fmt.Sprintf("Expression %q must resolve to a string", mp),
73 | ))
74 | }
75 |
76 | if len(req.ConfigValue.Elements()) == 0 {
77 | continue
78 | }
79 |
80 | if val.ValueString() != v.value {
81 | resp.Diagnostics.Append(validatordiag.InvalidAttributeCombinationDiagnostic(
82 | req.Path,
83 | fmt.Sprintf("Block %q can only be specified when %q is %q", req.Path, mp, v.value),
84 | ))
85 | }
86 | }
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/docs/resources/shipping_method.md:
--------------------------------------------------------------------------------
1 | ---
2 | # generated by https://github.com/hashicorp/terraform-plugin-docs
3 | page_title: "commercetools_shipping_method Resource - terraform-provider-commercetools"
4 | subcategory: ""
5 | description: |-
6 | With Shipping Methods you can specify which shipping services you want to provide to your customers for deliveries to different areas of the world at rates you can define.
7 | See also the Shipping Methods API Documentation https://docs.commercetools.com/api/projects/shippingMethods
8 | ---
9 |
10 | # commercetools_shipping_method (Resource)
11 |
12 | With Shipping Methods you can specify which shipping services you want to provide to your customers for deliveries to different areas of the world at rates you can define.
13 |
14 | See also the [Shipping Methods API Documentation](https://docs.commercetools.com/api/projects/shippingMethods)
15 |
16 | ## Example Usage
17 |
18 | ```terraform
19 | resource "commercetools_tax_category" "some-tax-category" {
20 | key = "some-tax-category-key"
21 | name = "some test cateogry"
22 | description = "test category"
23 | }
24 |
25 | resource "commercetools_shipping_method" "standard" {
26 | key = "standard-key"
27 | name = "Standard tax category"
28 | description = "Standard tax category"
29 | is_default = true
30 | tax_category_id = commercetools_tax_category.some-tax-category.id
31 | predicate = "1 = 1"
32 | }
33 | ```
34 |
35 |
36 | ## Schema
37 |
38 | ### Required
39 |
40 | - `name` (String)
41 | - `tax_category_id` (String) ID of a [Tax Category](https://docs.commercetools.com/api/projects/taxCategories#taxcategory)
42 |
43 | ### Optional
44 |
45 | - `active` (Boolean) Activate or deactivate a shipping method. Default is active.
46 | - `custom` (Block List, Max: 1) (see [below for nested schema](#nestedblock--custom))
47 | - `description` (String)
48 | - `is_default` (Boolean) One shipping method in a project can be default
49 | - `key` (String) User-specific unique identifier for the shipping method
50 | - `localized_description` (Map of String) [LocalizedString](https://docs.commercetools.com/api/types#localizedstring)
51 | - `localized_name` (Map of String) [LocalizedString](https://docs.commercetools.com/api/types#localizedstring)
52 | - `predicate` (String) A Cart predicate which can be used to more precisely select a shipping method for a cart
53 |
54 | ### Read-Only
55 |
56 | - `id` (String) The ID of this resource.
57 | - `version` (Number)
58 |
59 |
60 | ### Nested Schema for `custom`
61 |
62 | Required:
63 |
64 | - `type_id` (String)
65 |
66 | Optional:
67 |
68 | - `fields` (Map of String) Custom fields for this resource. Note that the values need to be provided as JSON encoded strings: `my-value = jsonencode({"key": "value"})`
69 |
--------------------------------------------------------------------------------
/commercetools/marshalling.go:
--------------------------------------------------------------------------------
1 | package commercetools
2 |
3 | import (
4 | "time"
5 |
6 | "fmt"
7 | "github.com/labd/commercetools-go-sdk/platform"
8 | )
9 |
10 | func flattenTime(val *time.Time) string {
11 | if val == nil {
12 | return ""
13 | }
14 | return val.Format(time.RFC3339)
15 | }
16 |
17 | func expandTime(input string) (time.Time, error) {
18 | return time.Parse(time.RFC3339, input)
19 | }
20 |
21 | func flattenTypedMoney(val platform.TypedMoney) map[string]any {
22 | switch v := val.(type) {
23 | case platform.HighPrecisionMoney:
24 | return map[string]any{
25 | "currency_code": v.CurrencyCode,
26 | "cent_amount": v.CentAmount,
27 | }
28 | case platform.Money:
29 | return map[string]any{
30 | "currency_code": v.CurrencyCode,
31 | "cent_amount": v.CentAmount,
32 | }
33 | case platform.CentPrecisionMoney:
34 | return map[string]any{
35 | "currency_code": v.CurrencyCode,
36 | "cent_amount": v.CentAmount,
37 | }
38 | }
39 | panic(fmt.Sprintf("Unknown money type: %T", val))
40 | }
41 |
42 | func expandTypedMoney(d map[string]any) []platform.Money {
43 | input := d["money"].([]any)
44 | var result []platform.Money
45 |
46 | for _, raw := range input {
47 | i := raw.(map[string]any)
48 | priceCurrencyCode := i["currency_code"].(string)
49 |
50 | result = append(result, platform.Money{
51 | CurrencyCode: priceCurrencyCode,
52 | CentAmount: i["cent_amount"].(int),
53 | })
54 | }
55 |
56 | return result
57 | }
58 |
59 | func expandTypedMoneyDraft(d map[string]any) []platform.TypedMoneyDraft {
60 | input := d["money"].([]any)
61 | var result []platform.TypedMoneyDraft
62 |
63 | for _, raw := range input {
64 | i := raw.(map[string]any)
65 | priceCurrencyCode := i["currency_code"].(string)
66 |
67 | result = append(result, platform.Money{
68 | CurrencyCode: priceCurrencyCode,
69 | CentAmount: i["cent_amount"].(int),
70 | })
71 | }
72 |
73 | return result
74 | }
75 |
76 | func expandLocalizedString(val any) platform.LocalizedString {
77 | values, ok := val.(map[string]any)
78 | if !ok {
79 | return platform.LocalizedString{}
80 | }
81 |
82 | result := make(platform.LocalizedString, len(values))
83 | for k := range values {
84 | result[k] = values[k].(string)
85 | }
86 | return result
87 | }
88 |
89 | func expandMoneyDraft(d map[string]any) []platform.Money {
90 | input := d["money"].([]any)
91 | var result []platform.Money
92 | for _, raw := range input {
93 | data := raw.(map[string]any)
94 | item := platform.Money{}
95 | if currencyCode, ok := data["currency_code"].(string); ok {
96 | item.CurrencyCode = currencyCode
97 | }
98 | if centAmount, ok := data["cent_amount"].(int); ok {
99 | item.CentAmount = centAmount
100 | }
101 | result = append(result, item)
102 | }
103 | return result
104 | }
105 |
--------------------------------------------------------------------------------
/internal/utils/errors.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "encoding/json"
5 | "errors"
6 | "fmt"
7 | "reflect"
8 |
9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
10 | "github.com/labd/commercetools-go-sdk/platform"
11 | )
12 |
13 | func ProcessRemoteError(err error) *resource.RetryError {
14 | if err == nil {
15 | return nil
16 | }
17 |
18 | switch e := err.(type) {
19 | case platform.ErrorResponse:
20 | if err := extractDetailedError(e); err != nil {
21 | return resource.NonRetryableError(err)
22 | }
23 | return resource.NonRetryableError(e)
24 |
25 | case platform.GenericRequestError:
26 | {
27 | if err := extractRawDetailedError(e.Content); err != nil {
28 | return resource.NonRetryableError(err)
29 | }
30 | return resource.NonRetryableError(e)
31 | }
32 | }
33 |
34 | return resource.RetryableError(err)
35 | }
36 |
37 | func extractDetailedError(e platform.ErrorResponse) error {
38 | for i := range e.Errors {
39 | item := e.Errors[i]
40 |
41 | metaValue := reflect.ValueOf(item)
42 | message := metaValue.FieldByName("Message")
43 | values := metaValue.FieldByName("ExtraValues")
44 |
45 | if message.IsValid() && values.IsValid() {
46 | data := values.Interface().(map[string]any)
47 | if msg, ok := data["detailedErrorMessage"]; ok {
48 | return fmt.Errorf("%s %s", message.String(), msg)
49 | }
50 | }
51 | }
52 | return e
53 | }
54 |
55 | func extractRawDetailedError(content []byte) error {
56 | data := map[string]any{}
57 | if err := json.Unmarshal(content, &data); err != nil {
58 | return nil
59 | }
60 |
61 | // Iterate over the errors. This is a list of objects containing the
62 | // code, message and detailedErrorMessage values.
63 | if val, ok := data["errors"].([]any); ok {
64 | for i := range val {
65 | if error, ok := val[i].(map[string]any); ok {
66 | var message string
67 |
68 | if detail, ok := error["message"].(string); ok {
69 | message = detail
70 | }
71 |
72 | if detail, ok := error["detailedErrorMessage"].(string); ok {
73 | if message != "" {
74 | return fmt.Errorf("%s %s", message, detail)
75 | }
76 | return errors.New(detail)
77 | }
78 | }
79 | }
80 | }
81 |
82 | // Fallback to the generic error message
83 | if val, ok := data["message"].(string); ok {
84 | return errors.New(val)
85 | }
86 |
87 | return nil
88 | }
89 |
90 | // IsResourceNotFoundError returns true if commercetools returned a 404 error
91 | func IsResourceNotFoundError(err error) bool {
92 | //Occasionally the SDK returns a sentinel value instead of the parsed error response for 404.
93 | //This is a workaround to handle that case.
94 | if errors.Is(err, platform.ErrNotFound) {
95 | return true
96 | }
97 |
98 | switch e := err.(type) {
99 | case platform.ResourceNotFoundError:
100 | return true
101 |
102 | case platform.ErrorResponse:
103 | return e.StatusCode == 404
104 |
105 | case platform.GenericRequestError:
106 | return e.StatusCode == 404
107 | }
108 | return false
109 | }
110 |
--------------------------------------------------------------------------------
/examples/resources/commercetools_product_type/resource.tf:
--------------------------------------------------------------------------------
1 | resource "commercetools_product_type" "some-generic-properties-product-type" {
2 | key = "some-key"
3 | name = "Some generic product properties"
4 | description = "All the generic product properties"
5 | attribute {
6 | name = "perishable"
7 | label = {
8 | en = "Is perishable"
9 | nl = "Is perishable"
10 | }
11 | required = true
12 | type {
13 | name = "boolean"
14 | }
15 | }
16 | }
17 |
18 | resource "commercetools_product_type" "my-product-type" {
19 | key = "my-product-type-key"
20 | name = "Lens specification"
21 | description = "All the specific info concerning the lens"
22 |
23 | attribute {
24 | name = "autofocus"
25 | label = {
26 | en = "Has autofocus"
27 | nl = "Heeft autofocus"
28 | }
29 | required = true
30 | type {
31 | name = "boolean"
32 | }
33 | }
34 |
35 | attribute {
36 | name = "lens_product_no"
37 | label = {
38 | en = "Lens product number"
39 | nl = "Objectief productnummer"
40 | }
41 | required = true
42 | type {
43 | name = "text"
44 | }
45 | constraint = "Unique"
46 | input_tip = {
47 | en = "Enter the product code"
48 | nl = "Voer de product code in"
49 | }
50 | searchable = true
51 | }
52 |
53 | attribute {
54 | name = "previous_model"
55 | label = {
56 | en = "Previous model"
57 | nl = "Vorig model"
58 | }
59 | type {
60 | name = "reference"
61 | reference_type_id = "product"
62 | }
63 | }
64 |
65 | attribute {
66 | name = "product_properties"
67 | label = {
68 | en = "Product properties"
69 | nl = "Product eigenschappen"
70 | }
71 | required = false
72 | type {
73 | name = "nested"
74 | type_reference = commercetools_product_type.some-generic-properties-product-type.id
75 | }
76 | }
77 |
78 | attribute {
79 | name = "some-flag"
80 | label = {
81 | en = "Some flag"
82 | nl = "Een vlag"
83 | }
84 | required = false
85 | type {
86 | name = "enum"
87 | value {
88 | key = "FLAG-1"
89 | label = "Flag 1"
90 | }
91 | value {
92 | key = "FLAG-2"
93 | label = "FLAG-2"
94 | }
95 | }
96 | }
97 |
98 | attribute {
99 | name = "origin"
100 | label = {
101 | en = "Origin country"
102 | nl = "Land van herkomst"
103 | }
104 | required = false
105 | type {
106 | name = "set"
107 | element_type {
108 | name = "lenum"
109 | localized_value {
110 | key = "NL"
111 | label = {
112 | en = "Netherlands"
113 | nl = "Nederland"
114 | }
115 | }
116 | localized_value {
117 | key = "DE"
118 | label = {
119 | en = "Germany"
120 | nl = "Duitsland"
121 | }
122 | }
123 | }
124 | }
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/internal/customvalidator/field.go:
--------------------------------------------------------------------------------
1 | package customvalidator
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | "github.com/hashicorp/terraform-plugin-framework-validators/helpers/validatordiag"
8 | "github.com/hashicorp/terraform-plugin-framework/attr"
9 | "github.com/hashicorp/terraform-plugin-framework/path"
10 | "github.com/hashicorp/terraform-plugin-framework/schema/validator"
11 | )
12 |
13 | func DependencyValidator(value string, expressions ...path.Expression) validator.String {
14 | return dependencyValidator{
15 | value: value,
16 | pathExpressions: expressions,
17 | }
18 | }
19 |
20 | var _ validator.String = dependencyValidator{}
21 |
22 | // anyValidator implements the validator.
23 | type dependencyValidator struct {
24 | value string
25 | pathExpressions path.Expressions
26 | }
27 |
28 | // Description describes the validation in plain text formatting.
29 | func (v dependencyValidator) Description(ctx context.Context) string {
30 | return "Validate the existence of specific attributes when the attribute has the given value"
31 | }
32 |
33 | // MarkdownDescription describes the validation in Markdown formatting.
34 | func (v dependencyValidator) MarkdownDescription(ctx context.Context) string {
35 | return v.Description(ctx)
36 | }
37 |
38 | // ValidateString performs the validation.
39 | func (v dependencyValidator) ValidateString(ctx context.Context, req validator.StringRequest, resp *validator.StringResponse) {
40 | sourceVal := req.ConfigValue.ValueString()
41 | if sourceVal != v.value {
42 | return
43 | }
44 |
45 | expressions := req.PathExpression.MergeExpressions(v.pathExpressions...)
46 |
47 | for _, expression := range expressions {
48 | matchedPaths, diags := req.Config.PathMatches(ctx, expression)
49 |
50 | if diags.HasError() {
51 | if diags.Errors()[0].Summary() == "Invalid Path Expression for Schema Data" {
52 | _, steps := expression.Steps().LastStep()
53 | resp.Diagnostics.Append(validatordiag.InvalidAttributeCombinationDiagnostic(
54 | req.Path.ParentPath(),
55 | fmt.Sprintf("Block %q must be specified when %q is %q", steps, req.Path, sourceVal),
56 | ))
57 | continue
58 | }
59 | }
60 | resp.Diagnostics.Append(diags...)
61 |
62 | // Collect all errors
63 | if diags.HasError() {
64 | continue
65 | }
66 |
67 | for _, mp := range matchedPaths {
68 | // If the user specifies the same attribute this validator is applied to,
69 | // also as part of the input, skip it
70 | if mp.Equal(req.Path) {
71 | continue
72 | }
73 |
74 | var mpVal attr.Value
75 | diags := req.Config.GetAttribute(ctx, mp, &mpVal)
76 | resp.Diagnostics.Append(diags...)
77 |
78 | // Collect all errors
79 | if diags.HasError() {
80 | continue
81 | }
82 |
83 | // Delay validation until all involved attribute have a known value
84 | if mpVal.IsUnknown() {
85 | return
86 | }
87 |
88 | if mpVal.IsNull() {
89 | resp.Diagnostics.Append(validatordiag.InvalidAttributeCombinationDiagnostic(
90 | req.Path,
91 | fmt.Sprintf("Attribute %q must be specified when %q is %q", mp, req.Path, sourceVal),
92 | ))
93 | }
94 | }
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/docs/guides/custom-fields.md:
--------------------------------------------------------------------------------
1 | ---
2 | subcategory: ""
3 | page_title: "Custom Fields"
4 | ---
5 |
6 | ## Creating a custom type
7 |
8 | To extend the commercetools platform with custom fields, you can create custom
9 | types that can be attached to resources. The following example shows how to
10 | create a custom type that can be attached to categories.
11 |
12 | For more information see
13 | the [commercetools documentation](https://docs.commercetools.com/api/projects/types).
14 |
15 | ```hcl
16 | resource "commercetools_type" "my-category" {
17 | key = "my-category"
18 |
19 | resource_type_ids = ["category"]
20 |
21 | name = {
22 | en = "myCategory"
23 | }
24 |
25 | description = {
26 | en = "My Category"
27 | }
28 |
29 | field {
30 | name = "myBoolean"
31 | label = {
32 | en = "myBoolean"
33 | }
34 | required = false
35 | type {
36 | name = "Boolean"
37 | }
38 | input_hint = "SingleLine"
39 | }
40 |
41 | field {
42 | name = "myNumber"
43 | label = {
44 | en = "myNumber"
45 | }
46 | required = false
47 | type {
48 | name = "Number"
49 | }
50 | input_hint = "SingleLine"
51 | }
52 |
53 | field {
54 | name = "mySet"
55 |
56 | label = {
57 | en = "mySet"
58 | }
59 |
60 | type {
61 | name = "Set"
62 | element_type {
63 | name = "String"
64 | }
65 | }
66 | }
67 |
68 | field {
69 | name = "myLocalizedString"
70 | label = {
71 | en = "myLocalizedString"
72 | }
73 | required = false
74 | type {
75 | name = "LocalizedString"
76 | }
77 | input_hint = "SingleLine"
78 | }
79 |
80 | field {
81 | name = "mySetOfLocalizedStrings"
82 | label = {
83 | en = "mySetOfLocalizedStrings"
84 | }
85 | required = false
86 | type {
87 | name = "Set"
88 | element_type {
89 | name = "LocalizedString"
90 | }
91 | }
92 | input_hint = "SingleLine"
93 | }
94 | }
95 | ```
96 |
97 | ## Setting custom fields
98 |
99 | Due to constrains within the old terraform provider framework, the custom fields
100 | are set in terraform state as a map of strings. This means that the actual
101 | values need to be serialized to JSON before they can be set. The following
102 | example shows how to set the custom fields for a category with the custom type
103 | given above.
104 |
105 | ```hcl
106 | resource "commercetools_category" "my-category" {
107 | name = {
108 | en = "My category"
109 | }
110 | slug = {
111 | en = "my-category"
112 | }
113 |
114 | custom {
115 | type_id = commercetools_type.my-category.id
116 | fields = {
117 | myBoolean = jsonencode(true)
118 | myNumber = jsonencode(123)
119 | mySet = jsonencode(["a", "b", "c"])
120 | myLocalizedString = jsonencode({
121 | en = "English"
122 | })
123 | mySetOfLocalizedStrings = jsonencode([
124 | { en = "English 1" },
125 | { en = "English 2" }
126 | ])
127 | }
128 | }
129 | }
130 | ```
131 |
--------------------------------------------------------------------------------
/internal/datasource/type/resource.go:
--------------------------------------------------------------------------------
1 | package custom_type
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/hashicorp/terraform-plugin-framework/datasource"
7 | "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
8 | "github.com/hashicorp/terraform-plugin-framework/types"
9 | "github.com/labd/commercetools-go-sdk/platform"
10 |
11 | "github.com/labd/terraform-provider-commercetools/internal/utils"
12 | )
13 |
14 | // Ensure the implementation satisfies the expected interfaces.
15 | var (
16 | _ datasource.DataSource = &CustomTypeSource{}
17 | _ datasource.DataSourceWithConfigure = &CustomTypeSource{}
18 | )
19 |
20 | // NewDataSource is a helper function to simplify the provider implementation.
21 | func NewDataSource() datasource.DataSource {
22 | return &CustomTypeSource{}
23 | }
24 |
25 | // CustomTypeSource is the data source implementation.
26 | type CustomTypeSource struct {
27 | client *platform.ByProjectKeyRequestBuilder
28 | mutex *utils.MutexKV
29 | }
30 |
31 | // CustomTypeSourceModel maps the data source schema data.
32 | type CustomTypeSourceModel struct {
33 | ID types.String `tfsdk:"id"`
34 | Key types.String `tfsdk:"key"`
35 | }
36 |
37 | // Metadata returns the data source type name.
38 | func (d *CustomTypeSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
39 | resp.TypeName = req.ProviderTypeName + "_type"
40 | }
41 |
42 | // Schema defines the schema for the data source.
43 | func (d *CustomTypeSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
44 | resp.Schema = schema.Schema{
45 | Description: "Fetches type information",
46 | Attributes: map[string]schema.Attribute{
47 | "id": schema.StringAttribute{
48 | Description: "ID of the custom type",
49 | Computed: true,
50 | },
51 | "key": schema.StringAttribute{
52 | Description: "Key of the custom type",
53 | Required: true,
54 | },
55 | },
56 | }
57 | }
58 |
59 | // Configure adds the provider configured client to the data source.
60 | func (d *CustomTypeSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) {
61 | if req.ProviderData == nil {
62 | return
63 | }
64 | data := req.ProviderData.(*utils.ProviderData)
65 | d.client = data.Client
66 | d.mutex = data.Mutex
67 | }
68 |
69 | // Read refreshes the Terraform state with the latest data.
70 | func (d *CustomTypeSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
71 | var state CustomTypeSourceModel
72 |
73 | diags := req.Config.Get(ctx, &state)
74 | resp.Diagnostics.Append(diags...)
75 | if resp.Diagnostics.HasError() {
76 | return
77 | }
78 |
79 | resource, err := d.client.Types().WithKey(state.Key.ValueString()).Get().Execute(ctx)
80 | if err != nil {
81 | resp.Diagnostics.AddError(
82 | "Unable to Read Type",
83 | err.Error(),
84 | )
85 | return
86 | }
87 |
88 | state.ID = types.StringValue(resource.ID)
89 |
90 | // Set state
91 | diags = resp.State.Set(ctx, &state)
92 | resp.Diagnostics.Append(diags...)
93 | if resp.Diagnostics.HasError() {
94 | return
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/templates/guides/custom-fields.md.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | subcategory: ""
3 | page_title: "Custom Fields"
4 | ---
5 |
6 | ## Creating a custom type
7 |
8 | To extend the commercetools platform with custom fields, you can create custom
9 | types that can be attached to resources. The following example shows how to
10 | create a custom type that can be attached to categories.
11 |
12 | For more information see
13 | the [commercetools documentation](https://docs.commercetools.com/api/projects/types).
14 |
15 | ```hcl
16 | resource "commercetools_type" "my-category" {
17 | key = "my-category"
18 |
19 | resource_type_ids = ["category"]
20 |
21 | name = {
22 | en = "myCategory"
23 | }
24 |
25 | description = {
26 | en = "My Category"
27 | }
28 |
29 | field {
30 | name = "myBoolean"
31 | label = {
32 | en = "myBoolean"
33 | }
34 | required = false
35 | type {
36 | name = "Boolean"
37 | }
38 | input_hint = "SingleLine"
39 | }
40 |
41 | field {
42 | name = "myNumber"
43 | label = {
44 | en = "myNumber"
45 | }
46 | required = false
47 | type {
48 | name = "Number"
49 | }
50 | input_hint = "SingleLine"
51 | }
52 |
53 | field {
54 | name = "mySet"
55 |
56 | label = {
57 | en = "mySet"
58 | }
59 |
60 | type {
61 | name = "Set"
62 | element_type {
63 | name = "String"
64 | }
65 | }
66 | }
67 |
68 | field {
69 | name = "myLocalizedString"
70 | label = {
71 | en = "myLocalizedString"
72 | }
73 | required = false
74 | type {
75 | name = "LocalizedString"
76 | }
77 | input_hint = "SingleLine"
78 | }
79 |
80 | field {
81 | name = "mySetOfLocalizedStrings"
82 | label = {
83 | en = "mySetOfLocalizedStrings"
84 | }
85 | required = false
86 | type {
87 | name = "Set"
88 | element_type {
89 | name = "LocalizedString"
90 | }
91 | }
92 | input_hint = "SingleLine"
93 | }
94 | }
95 | ```
96 |
97 | ## Setting custom fields
98 |
99 | Due to constrains within the old terraform provider framework, the custom fields
100 | are set in terraform state as a map of strings. This means that the actual
101 | values need to be serialized to JSON before they can be set. The following
102 | example shows how to set the custom fields for a category with the custom type
103 | given above.
104 |
105 | ```hcl
106 | resource "commercetools_category" "my-category" {
107 | name = {
108 | en = "My category"
109 | }
110 | slug = {
111 | en = "my-category"
112 | }
113 |
114 | custom {
115 | type_id = commercetools_type.my-category.id
116 | fields = {
117 | myBoolean = jsonencode(true)
118 | myNumber = jsonencode(123)
119 | mySet = jsonencode(["a", "b", "c"])
120 | myLocalizedString = jsonencode({
121 | en = "English"
122 | })
123 | mySetOfLocalizedStrings = jsonencode([
124 | { en = "English 1" },
125 | { en = "English 2" }
126 | ])
127 | }
128 | }
129 | }
130 | ```
131 |
--------------------------------------------------------------------------------
/internal/datasource/state/resource.go:
--------------------------------------------------------------------------------
1 | package custom_type
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/hashicorp/terraform-plugin-framework/datasource"
7 | "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
8 | "github.com/hashicorp/terraform-plugin-framework/types"
9 | "github.com/labd/commercetools-go-sdk/platform"
10 |
11 | "github.com/labd/terraform-provider-commercetools/internal/utils"
12 | )
13 |
14 | // Ensure the implementation satisfies the expected interfaces.
15 | var (
16 | _ datasource.DataSource = &StateSource{}
17 | _ datasource.DataSourceWithConfigure = &StateSource{}
18 | )
19 |
20 | // NewDataSource is a helper function to simplify the data source implementation.
21 | func NewDataSource() datasource.DataSource {
22 | return &StateSource{}
23 | }
24 |
25 | // StateSource is the data source implementation.
26 | type StateSource struct {
27 | client *platform.ByProjectKeyRequestBuilder
28 | mutex *utils.MutexKV
29 | }
30 |
31 | // StateModel maps the data source schema data.
32 | type StateModel struct {
33 | ID types.String `tfsdk:"id"`
34 | Key types.String `tfsdk:"key"`
35 | }
36 |
37 | // Metadata returns the data source type name.
38 | func (d *StateSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
39 | resp.TypeName = req.ProviderTypeName + "_state"
40 | }
41 |
42 | // Schema defines the schema for the data source.
43 | func (d *StateSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
44 | resp.Schema = schema.Schema{
45 | Description: "Fetches state information for the given key. " +
46 | "This is an easy way to import the id of an existing state for a given key.",
47 | Attributes: map[string]schema.Attribute{
48 | "id": schema.StringAttribute{
49 | Description: "ID of the state",
50 | Computed: true,
51 | },
52 | "key": schema.StringAttribute{
53 | Description: "Key of the state",
54 | Required: true,
55 | },
56 | },
57 | }
58 | }
59 |
60 | // Configure adds the provider configured client to the data source.
61 | func (d *StateSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) {
62 | if req.ProviderData == nil {
63 | return
64 | }
65 | data := req.ProviderData.(*utils.ProviderData)
66 | d.client = data.Client
67 | d.mutex = data.Mutex
68 | }
69 |
70 | // Read refreshes the Terraform state with the latest data.
71 | func (d *StateSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
72 | var state StateModel
73 |
74 | diags := req.Config.Get(ctx, &state)
75 | resp.Diagnostics.Append(diags...)
76 | if resp.Diagnostics.HasError() {
77 | return
78 | }
79 |
80 | resource, err := d.client.States().WithKey(state.Key.ValueString()).Get().Execute(ctx)
81 | if err != nil {
82 | resp.Diagnostics.AddError(
83 | "Unable to read state",
84 | err.Error(),
85 | )
86 | return
87 | }
88 |
89 | state.ID = types.StringValue(resource.ID)
90 |
91 | // Set state
92 | diags = resp.State.Set(ctx, &state)
93 | resp.Diagnostics.Append(diags...)
94 | if resp.Diagnostics.HasError() {
95 | return
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/internal/resources/product_selection/model.go:
--------------------------------------------------------------------------------
1 | package product_selection
2 |
3 | import (
4 | "github.com/labd/terraform-provider-commercetools/internal/sharedtypes"
5 | "reflect"
6 |
7 | "github.com/hashicorp/terraform-plugin-framework/types"
8 | "github.com/labd/commercetools-go-sdk/platform"
9 | "github.com/labd/terraform-provider-commercetools/internal/customtypes"
10 | "github.com/labd/terraform-provider-commercetools/internal/utils"
11 | )
12 |
13 | // ProductSelection represents the main schema data.
14 | type ProductSelection struct {
15 | ID types.String `tfsdk:"id"`
16 | Key types.String `tfsdk:"key"`
17 | Version types.Int64 `tfsdk:"version"`
18 | Name customtypes.LocalizedStringValue `tfsdk:"name"`
19 | Mode types.String `tfsdk:"mode"`
20 | Custom *sharedtypes.Custom `tfsdk:"custom"`
21 | }
22 |
23 | func NewProductSelectionFromNative(ps *platform.ProductSelection) (ProductSelection, error) {
24 | custom, err := sharedtypes.NewCustomFromNative(ps.Custom)
25 | if err != nil {
26 | return ProductSelection{}, err
27 | }
28 |
29 | return ProductSelection{
30 | ID: types.StringValue(ps.ID),
31 | Version: types.Int64Value(int64(ps.Version)),
32 | Name: utils.FromLocalizedString(ps.Name),
33 | Key: utils.FromOptionalString(ps.Key),
34 | Mode: types.StringValue(string(ps.Mode)),
35 | Custom: custom,
36 | }, err
37 | }
38 |
39 | func (ps ProductSelection) draft(t *platform.Type) (platform.ProductSelectionDraft, error) {
40 | custom, err := ps.Custom.Draft(t)
41 | if err != nil {
42 | return platform.ProductSelectionDraft{}, err
43 | }
44 |
45 | return platform.ProductSelectionDraft{
46 | Key: ps.Key.ValueStringPointer(),
47 | Name: ps.Name.ValueLocalizedString(),
48 | Mode: (*platform.ProductSelectionMode)(ps.Mode.ValueStringPointer()),
49 | Custom: custom,
50 | }, nil
51 | }
52 |
53 | func (ps ProductSelection) updateActions(t *platform.Type, plan ProductSelection) (platform.ProductSelectionUpdate, error) {
54 | result := platform.ProductSelectionUpdate{
55 | Version: int(ps.Version.ValueInt64()),
56 | Actions: []platform.ProductSelectionUpdateAction{},
57 | }
58 |
59 | // setName
60 | if !reflect.DeepEqual(ps.Name, plan.Name) {
61 | result.Actions = append(
62 | result.Actions,
63 | platform.ProductSelectionChangeNameAction{
64 | Name: plan.Name.ValueLocalizedString(),
65 | })
66 | }
67 |
68 | // changeKey
69 | if ps.Key != plan.Key {
70 | result.Actions = append(
71 | result.Actions,
72 | platform.ProductSelectionSetKeyAction{Key: plan.Key.ValueStringPointer()})
73 | }
74 |
75 | // setCustomFields
76 | if !reflect.DeepEqual(ps.Custom, plan.Custom) {
77 | actions, err := sharedtypes.CustomFieldUpdateActions[
78 | platform.ProductSelectionSetCustomTypeAction,
79 | platform.ProductSelectionSetCustomFieldAction,
80 | ](t, ps.Custom, plan.Custom)
81 | if err != nil {
82 | return platform.ProductSelectionUpdate{}, err
83 | }
84 |
85 | for i := range actions {
86 | result.Actions = append(result.Actions, actions[i].(platform.AssociateRoleUpdateAction))
87 | }
88 | }
89 |
90 | return result, nil
91 | }
92 |
--------------------------------------------------------------------------------
/commercetools/utils_test.go:
--------------------------------------------------------------------------------
1 | package commercetools
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "github.com/stretchr/testify/assert"
7 | "testing"
8 |
9 | "github.com/labd/commercetools-go-sdk/platform"
10 | )
11 |
12 | func TestCreateLookup(t *testing.T) {
13 | input := []any{
14 | map[string]any{
15 | "name": "name1",
16 | "value": "Value 1",
17 | },
18 | map[string]any{
19 | "name": "name2",
20 | "value": "Value 2",
21 | },
22 | }
23 | result := createLookup(input, "name")
24 | if _, ok := result["name1"]; !ok {
25 | t.Error("Could not lookup name1")
26 | }
27 | if _, ok := result["name2"]; !ok {
28 | t.Error("Could not lookup name1")
29 | }
30 | }
31 |
32 | func TestCompareDateString(t *testing.T) {
33 | type testCase struct {
34 | a string
35 | b string
36 | expected bool
37 | }
38 |
39 | testCases := []testCase{
40 | {"2018-01-02T15:04:05.000Z", "2018-01-02T15:04:05.000Z", true},
41 | {"2017-03-04T10:01:02.000Z", "2018-01-02T15:04:05.000Z", false},
42 | {"2018-01-02T15:04:05.000Z", "2018-01-02T15:04:05Z", true},
43 | {"2018-01-02T15:04:05Z", "2018-01-02T15:04:05Z", true},
44 | {"2018-01-02T15:04:05Z", "2018-01-02T15:04:05.999Z", true},
45 | {"2018-01-02T15:04:04Z", "2018-01-02T15:04:05Z", false},
46 | {"2018-01-02T15:06:04Z", "2018-01-02T15:04:05.999Z", false},
47 | {"", "2018-01-02T15:04:05.999Z", false},
48 | {"", "xxx", false},
49 | {"", "", true},
50 | }
51 |
52 | var res bool
53 | for _, tt := range testCases {
54 | res = compareDateString(tt.a, tt.b)
55 | if res != tt.expected {
56 | t.Errorf("failures %v, got %v", tt.expected, res)
57 | }
58 | }
59 |
60 | }
61 |
62 | func checkApiResult(err error) error {
63 | if errors.Is(err, platform.ErrNotFound) {
64 | return nil
65 | }
66 |
67 | switch v := err.(type) {
68 | case platform.GenericRequestError:
69 | if v.StatusCode == 404 {
70 | return nil
71 | }
72 | return fmt.Errorf("unhandled error generic error returned (%d)", v.StatusCode)
73 | case platform.ResourceNotFoundError:
74 | return nil
75 | default:
76 | return fmt.Errorf("unexpected result returned")
77 | }
78 | }
79 |
80 | func TestIntNilIfEmpty(t *testing.T) {
81 | testCases := []struct {
82 | input *int
83 | expected *int
84 | }{
85 | {nil, nil},
86 | {intRef(0), nil},
87 | {intRef(1), intRef(1)},
88 | }
89 |
90 | for _, tt := range testCases {
91 | v := intNilIfEmpty(tt.input)
92 | assert.Equal(t, tt.expected, v)
93 | }
94 | }
95 |
96 | func TestValidateLocalizedStringKey(t *testing.T) {
97 | testCases := []struct {
98 | input interface{}
99 | failures int
100 | }{
101 | {map[string]any{"en": "English"}, 0},
102 | {map[string]any{"en-US": "English (United States)"}, 0},
103 | {map[string]any{"es-419": "Spanish (Latin America)"}, 0},
104 | {map[string]any{"rm-sursilv": "Romansh Sursilvan"}, 0},
105 | {map[string]any{"sr-Cyrl": "Serbian in Cyrillic"}, 0},
106 | {map[string]any{"foobar": "Fail"}, 1},
107 | {"foobar", 1},
108 | {1, 1},
109 | {map[string]any{"es-409": "Spanish (Latin America)"}, 1},
110 | }
111 |
112 | for _, tt := range testCases {
113 | diag := validateLocalizedStringKey(tt.input, nil)
114 | assert.Equal(t, tt.failures, len(diag), fmt.Sprintf("%+v", diag))
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/docs/resources/channel.md:
--------------------------------------------------------------------------------
1 | ---
2 | # generated by https://github.com/hashicorp/terraform-plugin-docs
3 | page_title: "commercetools_channel Resource - terraform-provider-commercetools"
4 | subcategory: ""
5 | description: |-
6 | Channels represent a source or destination of different entities. They can be used to model warehouses or stores.
7 | See also the Channels API Documentation https://docs.commercetools.com/api/projects/channels
8 | ---
9 |
10 | # commercetools_channel (Resource)
11 |
12 | Channels represent a source or destination of different entities. They can be used to model warehouses or stores.
13 |
14 | See also the [Channels API Documentation](https://docs.commercetools.com/api/projects/channels)
15 |
16 | ## Example Usage
17 |
18 | ```terraform
19 | resource "commercetools_channel" "my-channel" {
20 | key = "my-channel-key"
21 | roles = ["ProductDistribution"]
22 | name = {
23 | nl-NL = "Channel"
24 | }
25 | description = {
26 | nl-NL = "Channel"
27 | }
28 | }
29 | ```
30 |
31 |
32 | ## Schema
33 |
34 | ### Required
35 |
36 | - `key` (String) Any arbitrary string key that uniquely identifies this channel within the project
37 | - `roles` (List of String) The [roles](https://docs.commercetools.com/api/projects/channels#channelroleenum) of this channel. Each channel must have at least one role
38 |
39 | ### Optional
40 |
41 | - `address` (Block List, Max: 1) (see [below for nested schema](#nestedblock--address))
42 | - `custom` (Block List, Max: 1) (see [below for nested schema](#nestedblock--custom))
43 | - `description` (Map of String) [LocalizedString](https://docs.commercetools.com/api/types#localizedstring)
44 | - `geolocation` (Block List, Max: 1) (see [below for nested schema](#nestedblock--geolocation))
45 | - `name` (Map of String) [LocalizedString](https://docs.commercetools.com/api/types#localizedstring)
46 |
47 | ### Read-Only
48 |
49 | - `id` (String) The ID of this resource.
50 | - `version` (Number)
51 |
52 |
53 | ### Nested Schema for `address`
54 |
55 | Required:
56 |
57 | - `country` (String)
58 |
59 | Optional:
60 |
61 | - `additional_address_info` (String)
62 | - `additional_street_info` (String)
63 | - `apartment` (String)
64 | - `building` (String)
65 | - `city` (String)
66 | - `company` (String)
67 | - `department` (String)
68 | - `email` (String)
69 | - `external_id` (String)
70 | - `fax` (String)
71 | - `first_name` (String)
72 | - `key` (String)
73 | - `last_name` (String)
74 | - `mobile` (String)
75 | - `phone` (String)
76 | - `po_box` (String)
77 | - `postal_code` (String)
78 | - `region` (String)
79 | - `salutation` (String)
80 | - `state` (String)
81 | - `street_name` (String)
82 | - `street_number` (String)
83 | - `title` (String)
84 |
85 | Read-Only:
86 |
87 | - `id` (String)
88 |
89 |
90 |
91 | ### Nested Schema for `custom`
92 |
93 | Required:
94 |
95 | - `type_id` (String)
96 |
97 | Optional:
98 |
99 | - `fields` (Map of String) Custom fields for this resource. Note that the values need to be provided as JSON encoded strings: `my-value = jsonencode({"key": "value"})`
100 |
101 |
102 |
103 | ### Nested Schema for `geolocation`
104 |
105 | Required:
106 |
107 | - `coordinates` (List of Number)
108 |
--------------------------------------------------------------------------------
/docs/resources/state_transitions.md:
--------------------------------------------------------------------------------
1 | ---
2 | # generated by https://github.com/hashicorp/terraform-plugin-docs
3 | page_title: "commercetools_state_transitions Resource - terraform-provider-commercetools"
4 | subcategory: ""
5 | description: |-
6 | Transitions are a way to describe possible transformations of the current state to other states of the same type (for example: Initial -> Shipped). When performing a transitionState update action and transitions is set, the currently referenced state must have a transition to the new state.
7 | If transitions is an empty list, it means the current state is a final state and no further transitions are allowed.
8 | If transitions is not set, the validation is turned off. When performing a transitionState update action, any other state of the same type can be transitioned to.
9 | Note: Only one resource can be created for each state
10 | ---
11 |
12 | # commercetools_state_transitions (Resource)
13 |
14 | Transitions are a way to describe possible transformations of the current state to other states of the same type (for example: Initial -> Shipped). When performing a transitionState update action and transitions is set, the currently referenced state must have a transition to the new state.
15 | If transitions is an empty list, it means the current state is a final state and no further transitions are allowed.
16 | If transitions is not set, the validation is turned off. When performing a transitionState update action, any other state of the same type can be transitioned to.
17 |
18 | Note: Only one resource can be created for each state
19 |
20 | ## Example Usage
21 |
22 | ```terraform
23 | resource "commercetools_state" "product_for_sale" {
24 | key = "product-for-sale"
25 | type = "ProductState"
26 | name = {
27 | en = "For Sale"
28 | }
29 | description = {
30 | en = "Regularly stocked product."
31 | }
32 | initial = true
33 | }
34 |
35 | resource "commercetools_state" "product_clearance" {
36 | key = "product-clearance"
37 | type = "ProductState"
38 | name = {
39 | en = "On Clearance"
40 | }
41 | description = {
42 | en = "The product line will not be ordered again."
43 | }
44 | }
45 |
46 |
47 | // Only allow transition from sale to clearance
48 | resource "commercetools_state_transitions" "transition_1" {
49 | from = commercetools_state.product_for_sale.id
50 | to = [
51 | commercetools_state.product_clearance.id,
52 | ]
53 | }
54 |
55 | // Disable transitions from product clearance to other
56 | resource "commercetools_state_transitions" "transition_2" {
57 | from = commercetools_state.product_clearance.id
58 | to = []
59 | }
60 | ```
61 |
62 |
63 | ## Schema
64 |
65 | ### Required
66 |
67 | - `from` (String) ID of the state to transition from
68 | - `to` (Set of String) Transitions are a way to describe possible transformations of the current state to other states of the same type (for example: Initial -> Shipped). When performing a transitionState update action and transitions is set, the currently referenced state must have a transition to the new state.
69 | If transitions is an empty list, it means the current state is a final state and no further transitions are allowed.
70 | If transitions is not set, the validation is turned off. When performing a transitionState update action, any other state of the same type can be transitioned to
71 |
72 | ### Read-Only
73 |
74 | - `id` (String) ID of the state to transition from
75 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_title: "commercetools provider"
3 | subcategory: ""
4 | description: |-
5 | The commercetools provider provides resources to interact with the commercetools API
6 |
7 | ---
8 |
9 | # commercetools provider
10 |
11 | ## Commercial support
12 | Need support implementing this terraform module in your organization? We are
13 | able to offer support. Please contact us at
14 | [opensource@labdigital.nl](opensource@labdigital.nl)!
15 |
16 | ## Installation
17 | Terraform automatically downloads providers from the terraform registry. Add the
18 | following to your terraform project
19 |
20 |
21 | ```hcl
22 | terraform {
23 | required_providers {
24 | commercetools = {
25 | source = "labd/commercetools"
26 | }
27 | }
28 | }
29 | ```
30 |
31 | Packages of the releases are available at [the GitHub Repo](https://github.com/labd/terraform-provider-commercetools/releases).
32 | See the [terraform documentation](https://www.terraform.io/docs/configuration/providers.html#third-party-plugins)
33 | for more information about installing third-party providers.
34 |
35 |
36 | ## Using the provider
37 | The provider attempts to read the required values from environment variables:
38 | - `CTP_CLIENT_ID`
39 | - `CTP_CLIENT_SECRET`
40 | - `CTP_PROJECT_KEY`
41 | - `CTP_SCOPES`
42 | - `CTP_API_URL`
43 | - `CTP_AUTH_URL`
44 |
45 | Alternatively, you can set it up directly in the terraform file:
46 |
47 | ```hcl
48 | provider "commercetools" {
49 | client_id = ""
50 | client_secret = ""
51 | project_key = ""
52 | scopes = ""
53 | api_url = ""
54 | token_url = ""
55 | }
56 | ```
57 |
58 |
59 | ## Schema
60 |
61 | ### Optional
62 |
63 | - `api_url` (String) The API URL of the commercetools platform. https://docs.commercetools.com/api/general-concepts#hosts
64 | - `client_id` (String, Sensitive) The OAuth Client ID for a commercetools platform project. https://docs.commercetools.com/api/authorization
65 | - `client_secret` (String, Sensitive) The OAuth Client Secret for a commercetools platform project. https://docs.commercetools.com/api/authorization
66 | - `project_key` (String, Sensitive) The project key of commercetools platform project. https://docs.commercetools.com/getting-started
67 | - `scopes` (String) A list as string of OAuth scopes assigned to a project key, to access resources in a commercetools platform project. https://docs.commercetools.com/api/authorization
68 | - `token_url` (String) The authentication URL of the commercetools platform. https://docs.commercetools.com/api/authorization
69 |
70 | ## Using with docker
71 |
72 | The included `Dockerfile` bundles the official [`hashicorp/terraform:light`](https://hub.docker.com/r/hashicorp/terraform/) docker image with
73 | our `terraform-provider-commercetools`.
74 |
75 | To build the docker image file locally, use:
76 | ```sh
77 | docker build . -t terraform-with-provider-commercetools:latest
78 | ```
79 | Then you can run a terraform command on files in the current directory with:
80 | ```sh
81 | docker run -v "${pwd}:/config" terraform-with-provider-commercetools:latest
82 | ```
83 |
84 | ## Authors
85 | This project is developed by [Lab Digital](https://www.labdigital.nl). We
86 | welcome additional contributors. Please see our
87 | [GitHub repository](https://github.com/labd/terraform-provider-commercetools)
88 | for more information.
89 |
--------------------------------------------------------------------------------
/internal/resources/subscription/downgrade_v2.go:
--------------------------------------------------------------------------------
1 | package subscription
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/hashicorp/terraform-plugin-framework/resource"
7 | "github.com/hashicorp/terraform-plugin-go/tfprotov6"
8 | "github.com/hashicorp/terraform-plugin-go/tftypes"
9 | )
10 |
11 | var SubscriptionResourceV2 = tftypes.Object{
12 | AttributeTypes: map[string]tftypes.Type{
13 | "id": tftypes.String,
14 | "key": tftypes.String,
15 | "version": tftypes.Number,
16 |
17 | "changes": tftypes.Set{
18 | ElementType: tftypes.Object{
19 | AttributeTypes: map[string]tftypes.Type{
20 | "resource_type_ids": tftypes.List{
21 | ElementType: tftypes.String,
22 | },
23 | },
24 | },
25 | },
26 | "destination": tftypes.Object{
27 | AttributeTypes: map[string]tftypes.Type{
28 | "type": tftypes.String,
29 | "topic_arn": tftypes.String,
30 | "queue_url": tftypes.String,
31 | "region": tftypes.String,
32 | "account_id": tftypes.String,
33 | "access_key": tftypes.String,
34 | "access_secret": tftypes.String,
35 | "uri": tftypes.String,
36 | "connection_string": tftypes.String,
37 | "project_id": tftypes.String,
38 | "topic": tftypes.String,
39 | },
40 | },
41 | "format": tftypes.Object{
42 | AttributeTypes: map[string]tftypes.Type{
43 | "type": tftypes.String,
44 | "cloud_events_version": tftypes.String,
45 | },
46 | },
47 | "message": tftypes.Set{
48 | ElementType: tftypes.Object{
49 | AttributeTypes: map[string]tftypes.Type{
50 | "resource_type_id": tftypes.String,
51 | "types": tftypes.List{
52 | ElementType: tftypes.String,
53 | },
54 | },
55 | },
56 | },
57 | },
58 | }
59 |
60 | // Schema version 1 used a list for destination and format since
61 | // that single nested blocks were not supported in sdk v2 (it was in sdk v1)
62 | // Schema version 2 moves us to Single nested blocks, but it turned out to be
63 | // not working correctly in terraform for now. So we moved back to the v1
64 | // approach
65 | func downgradeStateV2(_ context.Context, req resource.UpgradeStateRequest, resp *resource.UpgradeStateResponse) {
66 | rawStateValue, err := req.RawState.Unmarshal(SubscriptionResourceV2)
67 | if err != nil {
68 | resp.Diagnostics.AddError(
69 | "Unable to Unmarshal Prior State",
70 | err.Error(),
71 | )
72 | return
73 | }
74 |
75 | var rawState map[string]tftypes.Value
76 | if err := rawStateValue.As(&rawState); err != nil {
77 | resp.Diagnostics.AddError(
78 | "Unable to Convert Prior State",
79 | err.Error(),
80 | )
81 | return
82 | }
83 |
84 | dynamicValue, err := tfprotov6.NewDynamicValue(
85 | SubscriptionResourceV1,
86 | tftypes.NewValue(SubscriptionResourceV1, map[string]tftypes.Value{
87 | "id": rawState["id"],
88 | "key": rawState["key"],
89 | "version": rawState["version"],
90 | "changes": rawState["changes"],
91 | "destination": valueDestinationV1(rawState, "destination"),
92 | "format": valueToFormatV1(rawState, "format"),
93 | "message": rawState["message"],
94 | }),
95 | )
96 | if err != nil {
97 | resp.Diagnostics.AddError(
98 | "Unable to Convert Upgraded State",
99 | err.Error(),
100 | )
101 | return
102 | }
103 |
104 | resp.DynamicValue = &dynamicValue
105 | }
106 |
--------------------------------------------------------------------------------
/internal/resources/attribute_group/model.go:
--------------------------------------------------------------------------------
1 | package attribute_group
2 |
3 | import (
4 | "github.com/hashicorp/terraform-plugin-framework/types"
5 | "github.com/labd/commercetools-go-sdk/platform"
6 | "github.com/labd/terraform-provider-commercetools/internal/customtypes"
7 | "github.com/labd/terraform-provider-commercetools/internal/utils"
8 | "reflect"
9 | )
10 |
11 | // AttributeGroup is the main resource schema data
12 | type AttributeGroup struct {
13 | ID types.String `tfsdk:"id"`
14 | Version types.Int64 `tfsdk:"version"`
15 | Key types.String `tfsdk:"key"`
16 | Name customtypes.LocalizedStringValue `tfsdk:"name"`
17 | Description customtypes.LocalizedStringValue `tfsdk:"description"`
18 | Attributes []AttributeReference `tfsdk:"attribute"`
19 | }
20 |
21 | type AttributeReference struct {
22 | Key types.String `tfsdk:"key"`
23 | }
24 |
25 | func toDraft(g *AttributeGroup) platform.AttributeGroupDraft {
26 | var attributes []platform.AttributeReference
27 | for _, v := range g.Attributes {
28 | attributes = append(attributes, platform.AttributeReference{
29 | Key: v.Key.ValueString(),
30 | })
31 | }
32 |
33 | return platform.AttributeGroupDraft{
34 | Name: g.Name.ValueLocalizedString(),
35 | Description: g.Description.ValueLocalizedStringRef(),
36 | Key: g.Key.ValueStringPointer(),
37 | Attributes: attributes,
38 | }
39 | }
40 |
41 | func fromNative(n *platform.AttributeGroup) AttributeGroup {
42 | var attributes []AttributeReference
43 | for _, v := range n.Attributes {
44 | attributes = append(attributes, AttributeReference{
45 | Key: types.StringValue(v.Key),
46 | })
47 | }
48 |
49 | return AttributeGroup{
50 | ID: types.StringValue(n.ID),
51 | Version: types.Int64Value(int64(n.Version)),
52 | Key: types.StringPointerValue(n.Key),
53 | Name: utils.FromLocalizedString(n.Name),
54 | Description: utils.FromOptionalLocalizedString(n.Description),
55 | Attributes: attributes,
56 | }
57 | }
58 |
59 | func toUpdateActions(state *AttributeGroup, plan *AttributeGroup) platform.AttributeGroupUpdate {
60 | update := platform.AttributeGroupUpdate{
61 | Version: int(state.Version.ValueInt64()),
62 | Actions: []platform.AttributeGroupUpdateAction{},
63 | }
64 |
65 | if !reflect.DeepEqual(state.Name, plan.Name) {
66 | update.Actions = append(
67 | update.Actions,
68 | platform.AttributeGroupChangeNameAction{
69 | Name: plan.Name.ValueLocalizedString(),
70 | },
71 | )
72 | }
73 |
74 | if !reflect.DeepEqual(state.Description, plan.Description) {
75 | update.Actions = append(
76 | update.Actions,
77 | platform.AttributeGroupSetDescriptionAction{
78 | Description: plan.Description.ValueLocalizedStringRef(),
79 | },
80 | )
81 | }
82 |
83 | if !reflect.DeepEqual(state.Key, plan.Key) {
84 | update.Actions = append(
85 | update.Actions,
86 | platform.AttributeGroupSetKeyAction{
87 | Key: utils.StringRef(plan.Key.ValueString()),
88 | },
89 | )
90 | }
91 |
92 | if !reflect.DeepEqual(state.Attributes, plan.Attributes) {
93 | var attributes []platform.AttributeReference
94 | for _, v := range plan.Attributes {
95 | attributes = append(attributes, platform.AttributeReference{
96 | Key: v.Key.ValueString(),
97 | })
98 | }
99 |
100 | update.Actions = append(
101 | update.Actions,
102 | platform.AttributeGroupSetAttributesAction{
103 | Attributes: attributes,
104 | },
105 | )
106 | }
107 |
108 | return update
109 | }
110 |
--------------------------------------------------------------------------------