diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 48aaab45..58efb758 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,6 +26,8 @@ jobs: with: # Allow goreleaser to access older tag information. fetch-depth: 0 + - name: Set release VERSION + run: echo "VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - name: Set up Go uses: actions/setup-go@v5 with: @@ -44,5 +46,6 @@ jobs: args: release --clean env: GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} + VERSION: ${{ env.VERSION }} # GitHub sets this automatically GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.goreleaser.yml b/.goreleaser.yml index 77d63556..c7638dc1 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -14,7 +14,7 @@ builds: flags: - -trimpath ldflags: - - '-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}' + - '-s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/dbt_cloud.versionString={{.Env.VERSION}}"' goos: - freebsd - windows @@ -47,7 +47,7 @@ signs: - "${signature}" - "--detach-sign" - "${artifact}" -release: +# release: # If you want to manually examine the release before its live, uncomment this line: # draft: true changelog: diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c3e86f4..4cdcaa9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,37 +2,56 @@ All notable changes to this project will be documented in this file. -## [Unreleased](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.3.4...HEAD) +## [Unreleased](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.3.5...HEAD) + +## [0.3.5](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.3.4...v0.3.5) + +### Changes + +- add a `dbtcloud_partial_notification` resource to allow different resources to add/remove job notifications for the same Slack channel/email/user + +### Fixes + +- [#257](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/257) - Force new resource when the `project_id` changes for a `dbtcloud_job`. +- Creating connection for adapters (e.g. Databricks and Fabric) was failing when using Service Tokens following changes in the dbt Cloud APIs + +### Behind the scenes + +- change the User Agent to report what provider version is being used + +### Documentation + +- add import block example for the resources in addition to the import command ## [0.3.4](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.3.3...v0.3.4) -## Changes +### Changes - [#255](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/255) - Add new datasource `dbtcloud_environments` to return all environments across an account, or all environments for a give project ID -## Behind the scenes +### Behind the scenes - Move the `dbtcloud_environment` datasource to the Terraform Plugin Framework ## [0.3.3](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.3.2...v0.3.3) -## Changes +### Changes - [#250](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/250) - [Experimental] Create a new resource called `dbtcloud_group_partial_permissions` to manage permissions of a single group from different resources which can be set across different Terraform projects/workspaces. The dbt Cloud API doesn't provide endpoints for adding/removing single permissions, so the logic in the provider is more complex than other resources. If the resource works as expected for the provider users we could create similar ones for "partial" notifications and "partial" license mappings. ## [0.3.2](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.3.0...v0.3.2) -## Changes +### Changes - Add `on_merge` trigger for jobs. The trigger is optional for now but will be required in the future. -## Documentation +### Documentation - Remove mention of `dbt_cloud_xxx` resources in the docs ## [0.3.0](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.25...v0.3.0) -## Changes +### Changes - Implements muxing to allow both SDKv2 and Plugin Framework resources to work at the same time. This change a bit the internals but shouldn't have any regression. - Move some resources / datasources to the plugin Framework @@ -40,201 +59,201 @@ All notable changes to this project will be documented in this file. ## [0.2.25](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.24...v0.2.25) -## Changes +### Changes - Enable OAuth configuration for Databricks connections + update docs accordingly ## [0.2.24](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.23...v0.2.24) -## Fixes +### Fixes - [#247](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/247) Segfault when the env var for the token is empty - [Internal] Issue with `job_ids` required to be set going forward, even if it is empty ## [0.2.23](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.22...v0.2.23) -## Changes +### Changes - [#244](https://github.com/dbt-labs/terraform-provider-dbtcloud/pull/244) Better error handling when GitLab repositories are created with a User Token -## Fixes +### Fixes - [#245](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/245) Issues on `dbtcloud_job` when modifying an existing job schedule ## [0.2.22](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.21...v0.2.22) -## Changes +### Changes - [#240](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/240) Add notice of deprecation for `triggers.custom_branch_only` for jobs and update logic to make it work even though people have it to true or false in their config. We might raise an error if the field is still there in the future. - Update diff calculation for Extended Attributes, allowing strings which are not set with `jsonencode()` - [#241](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/241) Force recreation of env vars when values change to work with the recent changes in the dbt Cloud API -## Documentation +### Documentation - Add list of permission names and permission codes in the docs of the `service_token` and `group` - Add info in `dbtcloud_repository` about the need to also create a `dbtcloud_project_repository` ## [0.2.21](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.20...v0.2.21) -## Changes +### Changes - Flag `fetch_deploy_key` as deprecated for `dbtcloud_repository`. The key is always fetched for the genetic git clone approach -## Documentations +### Documentations - Add info about `versionless` dbt environment (Private Beta) - [#235](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/235) Fix docs on the examples for Fabric credentials ## [0.2.20](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.19...v0.2.20) -## Changes +### Changes - Add support for job chaining and `job_completion_trigger_condition` (feature is in closed Beta in dbt Cloud as of 5 FEB 2024) -## Documentations +### Documentations - Improve docs for jobs ## [0.2.19](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.18...v0.2.19) -## Changes +### Changes - Update permissions allowed for groups and token to include `job_runner` -## Documentations +### Documentations - Add guide on `dbtcloud-terraforming` to import existing resources ## [0.2.18](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.17...v0.2.18) -## Changes +### Changes - #229 - fix logic for secret environment variables -## Documentations +### Documentations - #228 - update docs to replace the non existing `dbtcloud_user` resource by the existing `data.dbtcloud_user` data source -## Behind the scenes +### Behind the scenes - update third party module version following security report ## [0.2.17](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.16...v0.2.17) -## Changes +### Changes - #224 - add the resources `dbtcloud_fabric_connection` and `dbtcloud_fabric_credential` to allow using dbt Cloud along with Microsoft Fabric - #222 - allow users to set Slack notifications from Terraform -## Behind the scenes +### Behind the scenes - Refactor some of the shared code for Adapters and connections ## [0.2.16](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.15...v0.2.16) -## Changes +### Changes - #99 - add the resource `environment_variable_job_override` to allow environment variable override in jobs - Update the go version and packages versions -## Fixes +### Fixes - #221 - removing the value for an env var scope was not removing it in dbt Cloud - add better messages and error handling for jobs ## [0.2.15](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.14...v0.2.15) -## Changes +### Changes - Update list of permissions for groups and service tokens ## [0.2.14](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.13...v0.2.14) -## Changes +### Changes - Fix issues with the repositories connected via GitLab native integration - Add ability to configure repositories using the native ADO integration - Add data sources for retrieving ADO projects and repositories ID and information -## Documentation +### Documentation - Show in the main page that provider parameters can be set with env vars - Update examples and field descriptions for the repositories ## [0.2.13](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.11...v0.2.13) -## Changes +### Changes - Update connections to force new one when the project changes - Add support for the Datasource dbtcloud_group_users to get the list of users assigned to a given project -## Documentation +### Documentation - Use d2 for showing the different resources - Update examples in docs ## [0.2.11](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.10...v0.2.11) -## Changes +### Changes - Update docs and examples for jobs and add the ability to set/unset running CI jobs on Draft PRs ## [0.2.10](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.9...v0.2.10) -## Fix +### Fix - [#197](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/197) - Community contribution to handle cases where more than 100 groups are created in dbt Cloud - [#199](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/199) - Update logic to allow finding users by their email addresses in a cases insensitive way - [#198](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/198) - Update some internal logic to call endpoints by their unique IDs instead of looping through answers to avoid issues like #199 and paginate through results for endpoints where we can't query the ID directly -## Changes +### Changes - [#189](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/189) - Allow users to retrieve project data sources by providing project names instead of project IDs. This will return an error if more than 1 project has the given name and takes care of the pagination required for handling more than 100 projects ## [0.2.9](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.8...v0.2.9) -## Changes +### Changes - Add support for extended attributes for environments [(docs)](https://docs.getdbt.com/docs/dbt-cloud-environments#extended-attributes-beta), allowing people to add connection attributes available in dbt-core but not in the dbt Cloud interface - [#191](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/191) - Allow setting a description for jobs ## [0.2.8](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.7...v0.2.8) -## Fix +### Fix - [#190](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/190) - Allow setting deferral for jobs at the environment level rather than at the job level. This is due to changes in CI in dbt Cloud. Add docs about those changes on the dbtcloud_job resource page ## [0.2.7](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.6...v0.2.7) -## Fix +### Fix - [#184](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/184) - Fix issue when updating SSO groups for a given RBAC group ## [0.2.6](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.5...v0.2.6) -## Changes +### Changes - [#178](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/178) and [#179](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/179): Add support for [dbtcloud_license_map](https://registry.terraform.io/providers/dbt-labs/dbtcloud/latest/docs/resources/license_map), allowing the assignment of SSO groups to different dbt Cloud license types ## [0.2.5](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.4...v0.2.5) -## Fixes +### Fixes - [#172](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/172): Fix issue when changing the schedule of jobs from a list of hours to an interval in a [dbtcloud_job](https://registry.terraform.io/providers/dbt-labs/dbtcloud/latest/docs/resources/job) - [#175](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/175): Fix issue when modifying the `environment_id` of an existing [dbtcloud_job](https://registry.terraform.io/providers/dbt-labs/dbtcloud/latest/docs/resources/job) - [#154](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/154): Allow the creation of [Databricks connections](https://registry.terraform.io/providers/dbt-labs/dbtcloud/latest/docs/resources/connection) using Service Tokens when it was only possible with User Tokens before -## Changes +### Changes - Use the `v2/users/` endpoint to get the groups of a user ## [0.2.4](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.3...v0.2.4) -## Fixes +### Fixes - More update to docs -## Changes +### Changes - [#171](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/171) Add the ability to define which [environment](https://registry.terraform.io/providers/dbt-labs/dbtcloud/latest/docs/resources/environment) is the production one (to be used with cross project references in dbt Cloud) - Add [guide](https://registry.terraform.io/providers/dbt-labs/dbtcloud/latest/docs/guides/2_leveraging_http_provider) on how to use the Hashicorp HTTP provider @@ -242,24 +261,24 @@ All notable changes to this project will be documented in this file. ## [0.2.3](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.2...v0.2.3) -## Fixes +### Fixes - Update CI to avoid Node version warnings - Fixes to the docs -## Changes +### Changes - [164](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/164) Add the ability to define `priority` and `execution_project` for [BigQuery connections](https://registry.terraform.io/providers/dbt-labs/dbtcloud/latest/docs/resources/bigquery_connection) - [168](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/168) Add the ability to set up [email notifications](https://registry.terraform.io/providers/dbt-labs/dbtcloud/latest/docs/resources/notification) (to internal users and external email addresses) based on jobs results ## [0.2.2](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.1...v0.2.2) -## Fixes +### Fixes - [#156](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/156) Fix the `dbtcloud_connection` for Databricks when updating the `http_path` or `catalog` + add integration test - [#157](https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/157) Fix updating an environment with credentials already set + add integration test -## Changes +### Changes - Add [guide](https://registry.terraform.io/providers/dbt-labs/dbtcloud/latest/docs/guides/1_getting_started) to get started with the provider - Add missing import and fix more docs @@ -267,19 +286,19 @@ All notable changes to this project will be documented in this file. ## [0.2.1](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.2.0...v0.2.1) -## Changes +### Changes - Resources deleted from dbt Cloud won't crash the provider and we now consider the resource as deleted, removing it from the state. This is the expected behavior of a provider. - Add examples in the docs to resources that didn't have any so far ## [0.2.0](https://github.com/dbt-labs/terraform-provider-dbtcloud/compare/v0.1.12...v0.2.0) -## Important changes +### Important changes - The resources and data sources are now available as `dbtcloud_xxx` (following the terraform convention) in addition to `dbt_cloud_xxx` (legacy). The legacy version will be removed from v0.3.0 onwards. Instructions on how to use the new resources are available on [the main page of the Provider](https://registry.terraform.io/providers/dbt-labs/dbtcloud/latest/docs). ## 0.1.12 -## Changes +### Changes - The provider is now published under the dbt-labs org: https://registry.terraform.io/providers/dbt-labs/dbtcloud/latest diff --git a/docs/resources/bigquery_connection.md b/docs/resources/bigquery_connection.md index c3b9b051..99985b63 100644 --- a/docs/resources/bigquery_connection.md +++ b/docs/resources/bigquery_connection.md @@ -97,6 +97,18 @@ resource "dbtcloud_bigquery_connection" "my_connection_with_oauth" { Import is supported using the following syntax: ```shell +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_bigquery_connection.my_connection + id = "project_id:connection_id" +} + +import { + to = dbtcloud_bigquery_connection.my_connection + id = "12345:6789" +} + +# using the older import command terraform import dbtcloud_bigquery_connection.my_connection "project_id:connection_id" terraform import dbtcloud_bigquery_connection.my_connection 12345:6789 ``` diff --git a/docs/resources/bigquery_credential.md b/docs/resources/bigquery_credential.md index 9efbef38..a73acc99 100644 --- a/docs/resources/bigquery_credential.md +++ b/docs/resources/bigquery_credential.md @@ -43,6 +43,18 @@ resource "dbtcloud_bigquery_credential" "my_credential" { Import is supported using the following syntax: ```shell +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_bigquery_credential.my_credential + id = "project_id:credential_id" +} + +import { + to = dbtcloud_bigquery_credential.my_credential + id = "12345:5678" +} + +# using the older import command terraform import dbtcloud_bigquery_credential.my_credential "project_id:credential_id" terraform import dbtcloud_bigquery_credential.my_credential 12345:5678 ``` diff --git a/docs/resources/connection.md b/docs/resources/connection.md index 1808d447..6d2d80bf 100644 --- a/docs/resources/connection.md +++ b/docs/resources/connection.md @@ -93,7 +93,18 @@ resource "dbtcloud_connection" "snowflake" { Import is supported using the following syntax: ```shell -# Import using a project ID and connection ID found in the URL or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_connection.test_connection + id = "project_id:connection_id" +} + +import { + to = dbtcloud_connection.test_connection + id = "12345:6789" +} + +# using the older import command terraform import dbtcloud_connection.test_connection "project_id:connection_id" terraform import dbtcloud_connection.test_connection 12345:6789 ``` diff --git a/docs/resources/databricks_credential.md b/docs/resources/databricks_credential.md index 563e4a81..88960288 100644 --- a/docs/resources/databricks_credential.md +++ b/docs/resources/databricks_credential.md @@ -60,7 +60,18 @@ resource "dbtcloud_databricks_credential" "my_spark_cred" { Import is supported using the following syntax: ```shell -# Import using a project ID and credential ID found in the URL or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_databricks_credential.my_databricks_credential + id = "project_id:credential_id" +} + +import { + to = dbtcloud_databricks_credential.my_databricks_credential + id = "12345:6789" +} + +# using the older import command terraform import dbtcloud_databricks_credential.my_databricks_credential "project_id:credential_id" terraform import dbtcloud_databricks_credential.my_databricks_credential 12345:6789 ``` diff --git a/docs/resources/environment.md b/docs/resources/environment.md index ddb7fcfe..b156b13d 100644 --- a/docs/resources/environment.md +++ b/docs/resources/environment.md @@ -70,7 +70,18 @@ resource "dbtcloud_environment" "dev_environment" { Import is supported using the following syntax: ```shell -# Import using a project ID and environment ID found in the URL or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_environment.prod_environment + id = "project_id:environment_id" +} + +import { + to = dbtcloud_environment.prod_environment + id = "12345:6789" +} + +# using the older import command terraform import dbtcloud_environment.prod_environment "project_id:environment_id" terraform import dbtcloud_environment.prod_environment 12345:6789 ``` diff --git a/docs/resources/environment_variable.md b/docs/resources/environment_variable.md index b90a6f8c..5593d203 100644 --- a/docs/resources/environment_variable.md +++ b/docs/resources/environment_variable.md @@ -49,7 +49,18 @@ resource "dbtcloud_environment_variable" "dbt_my_env_var" { Import is supported using the following syntax: ```shell -# Import using a project ID and environment variable name found in the URL and UI or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_environment_variable.test_environment_variable + id = "project_id:environment_variable_name" +} + +import { + to = dbtcloud_environment_variable.test_environment_variable + id = "12345:DBT_ENV_VAR" +} + +# using the older import command terraform import dbtcloud_environment_variable.test_environment_variable "project_id:environment_variable_name" terraform import dbtcloud_environment_variable.test_environment_variable 12345:DBT_ENV_VAR ``` \ No newline at end of file diff --git a/docs/resources/environment_variable_job_override.md b/docs/resources/environment_variable_job_override.md index ec18ffa1..d537f443 100644 --- a/docs/resources/environment_variable_job_override.md +++ b/docs/resources/environment_variable_job_override.md @@ -41,7 +41,18 @@ resource "dbtcloud_environment_variable_job_override" "my_env_var_job_override" Import is supported using the following syntax: ```shell -# Import using a project ID, a job ID and the environment variable override ID +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_environment_variable_job_override.test_environment_variable_job_override + id = "project_id:job_id:environment_variable_override_id" +} + +import { + to = dbtcloud_environment_variable_job_override.test_environment_variable_job_override + id = "12345:678:123456" +} + +# using the older import command terraform import dbtcloud_environment_variable_job_override.test_environment_variable_job_override "project_id:job_id:environment_variable_override_id" terraform import dbtcloud_environment_variable_job_override.test_environment_variable_job_override 12345:678:123456 ``` diff --git a/docs/resources/extended_attributes.md b/docs/resources/extended_attributes.md index ddc22b6e..9b5b4590 100644 --- a/docs/resources/extended_attributes.md +++ b/docs/resources/extended_attributes.md @@ -63,7 +63,18 @@ resource "dbtcloud_environment" "issue_depl" { Import is supported using the following syntax: ```shell -# Import using a project ID and extended attribute ID found in the URL or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_extended_attributes.test_extended_attributes + id = "project_id_id:extended_attributes_id" +} + +import { + to = dbtcloud_extended_attributes.test_extended_attributes + id = "12345:6789" +} + +# using the older import command terraform import dbtcloud_extended_attributes.test_extended_attributes "project_id_id:extended_attributes_id" terraform import dbtcloud_extended_attributes.test_extended_attributes 12345:6789 ``` diff --git a/docs/resources/fabric_connection.md b/docs/resources/fabric_connection.md index d5645c92..dbd644bf 100644 --- a/docs/resources/fabric_connection.md +++ b/docs/resources/fabric_connection.md @@ -51,6 +51,18 @@ resource "dbtcloud_fabric_connection" "my_fabric_connection" { Import is supported using the following syntax: ```shell +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_fabric_connection.my_connection + id = "project_id:connection_id" +} + +import { + to = dbtcloud_fabric_connection.my_connection + id = "12345:6789" +} + +# using the older import command terraform import dbtcloud_fabric_connection.my_connection "project_id:connection_id" terraform import dbtcloud_fabric_connection.my_connection 12345:6789 ``` diff --git a/docs/resources/fabric_credential.md b/docs/resources/fabric_credential.md index 0a5b9b90..c47033a3 100644 --- a/docs/resources/fabric_credential.md +++ b/docs/resources/fabric_credential.md @@ -63,7 +63,18 @@ resource "dbtcloud_fabric_credential" "my_fabric_cred_serv_princ" { Import is supported using the following syntax: ```shell -# Import using a project ID and credential ID found in the URL or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_fabric_credential.my_fabric_credential + id = "project_id:credential_id" +} + +import { + to = dbtcloud_fabric_credential.my_fabric_credential + id = "12345:6789" +} + +# using the older import command terraform import dbtcloud_fabric_credential.my_fabric_credential "project_id:credential_id" terraform import dbtcloud_fabric_credential.my_fabric_credential 12345:6789 ``` diff --git a/docs/resources/group.md b/docs/resources/group.md index 8a518f88..17379c2b 100644 --- a/docs/resources/group.md +++ b/docs/resources/group.md @@ -88,7 +88,18 @@ Optional: Import is supported using the following syntax: ```shell -# Import using a group ID found in the URL or via the API. -terraform import dbtcloud_group.test_group "group_id" -terraform import dbtcloud_group.test_group 12345 +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_group.my_group + id = "group_id" +} + +import { + to = dbtcloud_group.my_group + id = "12345" +} + +# using the older import command +terraform import dbtcloud_group.my_group "group_id" +terraform import dbtcloud_group.my_group 12345 ``` diff --git a/docs/resources/group_partial_permissions.md b/docs/resources/group_partial_permissions.md index 767607dd..154ed6aa 100644 --- a/docs/resources/group_partial_permissions.md +++ b/docs/resources/group_partial_permissions.md @@ -5,9 +5,9 @@ description: |- Provide a partial set of permissions for a group. This is different from dbt_cloud_group as it allows to have multiple resources updating the same dbt Cloud group and is useful for companies managing a single dbt Cloud Account configuration from different Terraform projects/workspaces. If a company uses only one Terraform project/workspace to manage all their dbt Cloud Account config, it is recommended to use dbt_cloud_group instead of dbt_cloud_group_partial_permissions. ~> This is currently an experimental resource and any feedback is welcome in the GitHub repository. + The resource currently requires a Service Token with Account Admin access. The current behavior of the resource is the following: when using dbt_cloud_group_partial_permissions, don't use dbt_cloud_group for the same group in any other project/workspace. Otherwise, the behavior is undefined and partial permissions might be removed.when defining a new dbt_cloud_group_partial_permissions - if the group doesn't exist with the given name, it will be createdif a group exists with the given name, permissions will be added in the dbt Cloud group if they are not present yetin a given Terraform project/workspace, avoid having different dbt_cloud_group_partial_permissions for the same group name to prevent sync issues. Add all the permissions in the same resource.all resources for the same group name need to have the same values for assign_by_default and sso_mapping_groups. Those fields are not considered "partial". (Please raise feedback in GitHub if you think that sso_mapping_groups should be "partial" as well)when a resource is updated, the dbt Cloud group will be updated accordingly, removing and adding permissionswhen the resource is deleted/destroyed, if the resulting permission sets is empty, the group will be deleted ; otherwise, the group will be updated, removing the permissions from the deleted resource --- @@ -20,6 +20,8 @@ If a company uses only one Terraform project/workspace to manage all their dbt C ~> This is currently an experimental resource and any feedback is welcome in the GitHub repository. +The resource currently requires a Service Token with Account Admin access. + The current behavior of the resource is the following: - when using `dbt_cloud_group_partial_permissions`, don't use `dbt_cloud_group` for the same group in any other project/workspace. Otherwise, the behavior is undefined and partial permissions might be removed. diff --git a/docs/resources/job.md b/docs/resources/job.md index b3019c51..cfd5df6e 100644 --- a/docs/resources/job.md +++ b/docs/resources/job.md @@ -151,7 +151,18 @@ Required: Import is supported using the following syntax: ```shell -# Import using a job ID found in the URL or via the API. -terraform import dbtcloud_job.test_job "job_id" -terraform import dbtcloud_job.test_job 12345 +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_job.my_job + id = "job_id" +} + +import { + to = dbtcloud_job.my_job + id = "12345" +} + +# using the older import command +terraform import dbtcloud_job.my_job "job_id" +terraform import dbtcloud_job.my_job 12345 ``` \ No newline at end of file diff --git a/docs/resources/license_map.md b/docs/resources/license_map.md index 23dd798b..473ffb93 100644 --- a/docs/resources/license_map.md +++ b/docs/resources/license_map.md @@ -52,7 +52,18 @@ resource "dbtcloud_license_map" "it_license_map" { Import is supported using the following syntax: ```shell -# Import using a license map ID found in the URL or via the API. -terraform import dbtcloud_license_map.test_license_map "license_map_id" -terraform import dbtcloud_license_map.test_license_map 12345 +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_license_map.my_license_map + id = "license_map_id" +} + +import { + to = dbtcloud_license_map.my_license_map + id = "12345" +} + +# using the older import command +terraform import dbtcloud_license_map.my_license_map "license_map_id" +terraform import dbtcloud_license_map.my_license_map 12345 ``` diff --git a/docs/resources/notification.md b/docs/resources/notification.md index 57499161..f96ed95e 100644 --- a/docs/resources/notification.md +++ b/docs/resources/notification.md @@ -84,7 +84,18 @@ resource "dbtcloud_notification" "prod_job_slack_notifications" { Import is supported using the following syntax: ```shell -# Import using a notification ID +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_notification.my_notification + id = "notification_id" +} + +import { + to = dbtcloud_notification.my_notification + id = "12345" +} + +# using the older import command terraform import dbtcloud_notification.my_notification "notification_id" terraform import dbtcloud_notification.my_notification 12345 ``` diff --git a/docs/resources/partial_notification.md b/docs/resources/partial_notification.md new file mode 100644 index 00000000..99ec0092 --- /dev/null +++ b/docs/resources/partial_notification.md @@ -0,0 +1,95 @@ +--- +page_title: "dbtcloud_partial_notification Resource - dbtcloud" +subcategory: "" +description: |- + Setup partial notifications on jobs success/failure to internal users, external email addresses or Slack channels. This is different from dbt_cloud_notification as it allows to have multiple resources updating the same notification recipient (email, user or Slack channel) and is useful for companies managing a single dbt Cloud Account configuration from different Terraform projects/workspaces. + If a company uses only one Terraform project/workspace to manage all their dbt Cloud Account config, it is recommended to use dbt_cloud_notification instead of dbt_cloud_partial_notification. + ~> This is a new resource. Feedback is welcome. + The resource currently requires a Service Token with Account Admin access. + The current behavior of the resource is the following: + when using dbt_cloud_partial_notification, don't use dbt_cloud_notification for the same notification recipient in any other project/workspace. Otherwise, the behavior is undefined and partial notifications might be removed.when defining a new dbt_cloud_partial_notification + if the notification recipient doesn't exist, it will be createdif a notification config exists for the current recipient, Job IDs will be added in the list of jobs to trigger the notificationsin a given Terraform project/workspace, avoid having different dbt_cloud_partial_notification for the same recipient to prevent sync issues. Add all the jobs in the same resource.all resources for the same notification recipient need to have the same values for state and user_id. Those fields are not considered "partial".when a resource is updated, the dbt Cloud notification recipient will be updated accordingly, removing and adding job ids in the list of jobs triggering notificationswhen the resource is deleted/destroyed, if the resulting notification recipient list of jobs is empty, the notification will be deleted ; otherwise, the notification will be updated, removing the job ids from the deleted resource +--- + +# dbtcloud_partial_notification (Resource) + + +Setup partial notifications on jobs success/failure to internal users, external email addresses or Slack channels. This is different from `dbt_cloud_notification` as it allows to have multiple resources updating the same notification recipient (email, user or Slack channel) and is useful for companies managing a single dbt Cloud Account configuration from different Terraform projects/workspaces. + +If a company uses only one Terraform project/workspace to manage all their dbt Cloud Account config, it is recommended to use `dbt_cloud_notification` instead of `dbt_cloud_partial_notification`. + +~> This is a new resource. Feedback is welcome. + +The resource currently requires a Service Token with Account Admin access. + +The current behavior of the resource is the following: + +- when using `dbt_cloud_partial_notification`, don't use `dbt_cloud_notification` for the same notification recipient in any other project/workspace. Otherwise, the behavior is undefined and partial notifications might be removed. +- when defining a new `dbt_cloud_partial_notification` + - if the notification recipient doesn't exist, it will be created + - if a notification config exists for the current recipient, Job IDs will be added in the list of jobs to trigger the notifications +- in a given Terraform project/workspace, avoid having different `dbt_cloud_partial_notification` for the same recipient to prevent sync issues. Add all the jobs in the same resource. +- all resources for the same notification recipient need to have the same values for `state` and `user_id`. Those fields are not considered "partial". +- when a resource is updated, the dbt Cloud notification recipient will be updated accordingly, removing and adding job ids in the list of jobs triggering notifications +- when the resource is deleted/destroyed, if the resulting notification recipient list of jobs is empty, the notification will be deleted ; otherwise, the notification will be updated, removing the job ids from the deleted resource + +## Example Usage + +```terraform +// the config is the same as for `dbtcloud_notification` + +resource "dbtcloud_partial_notification" "prod_job_internal_notification" { + // user_id is the internal ID of a given user in dbt Cloud + user_id = 100 + on_success = [dbtcloud_job.prod_job.id] + on_failure = [12345] + // the Type 1 is used for internal notifications + notification_type = 1 +} + +// we can also send "external" email notifications to emails to related to dbt Cloud users +resource "dbtcloud_partial_notification" "prod_job_external_notification" { + // we still need the ID of a user in dbt Cloud even though it is not used for sending notifications + user_id = 100 + on_failure = [23456, 56788] + on_cancel = [dbtcloud_job.prod_job.id] + // the Type 4 is used for external notifications + notification_type = 4 + // the external_email is the email address that will receive the notification + external_email = "my_email@mail.com" +} + +// and finally, we can set up Slack notifications +resource "dbtcloud_partial_notification" "prod_job_slack_notifications" { + // we still need the ID of a user in dbt Cloud even though it is not used for sending notifications + user_id = 100 + on_failure = [23456, 56788] + on_cancel = [dbtcloud_job.prod_job.id] + // the Type 2 is used for Slack notifications + notification_type = 2 + slack_channel_id = "C12345ABCDE" + slack_channel_name = "#my-awesome-channel" +} +``` + + +## Schema + +### Required + +- `user_id` (Number) Internal dbt Cloud User ID. Must be the user_id for an existing user even if the notification is an external one [global] + +### Optional + +- `external_email` (String) The external email to receive the notification [global, used as identifier] +- `notification_type` (Number) Type of notification (1 = dbt Cloud user email (default): does not require an external_email ; 2 = Slack channel: requires `slack_channel_id` and `slack_channel_name` ; 4 = external email: requires setting an `external_email`) [global, used as identifier] +- `on_cancel` (Set of Number) List of job IDs to trigger the webhook on cancel. Those will be added/removed when config is added/removed. +- `on_failure` (Set of Number) List of job IDs to trigger the webhook on failure Those will be added/removed when config is added/removed. +- `on_success` (Set of Number) List of job IDs to trigger the webhook on success Those will be added/removed when config is added/removed. +- `slack_channel_id` (String) The ID of the Slack channel to receive the notification. It can be found at the bottom of the Slack channel settings [global, used as identifier] +- `slack_channel_name` (String) The name of the slack channel [global, used as identifier] +- `state` (Number) State of the notification (1 = active (default), 2 = inactive) [global] + +### Read-Only + +- `id` (String) The ID of the notification diff --git a/docs/resources/postgres_credential.md b/docs/resources/postgres_credential.md index 8bd89aea..334beb25 100644 --- a/docs/resources/postgres_credential.md +++ b/docs/resources/postgres_credential.md @@ -51,7 +51,18 @@ resource "dbtcloud_postgres_credential" "postgres_prod_credential" { Import is supported using the following syntax: ```shell -# Import using a project ID and credential ID found in the URL or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_postgres_credential.my_credential + id = "project_id:credential_id" +} + +import { + to = dbtcloud_postgres_credential.my_credential + id = "12345:6789" +} + +# using the older import command terraform import dbtcloud_postgres_credential.my_credential "project_id:credential_id" terraform import dbtcloud_postgres_credential.my_credential 12345:6789 ``` diff --git a/docs/resources/project.md b/docs/resources/project.md index 12967b8a..a13b8d7b 100644 --- a/docs/resources/project.md +++ b/docs/resources/project.md @@ -43,7 +43,18 @@ resource "dbtcloud_project" "dbt_project_with_subdir" { Import is supported using the following syntax: ```shell -# Import using a project ID found in the URL or via the API. -terraform import dbtcloud_project.test_project "project_id" -terraform import dbtcloud_project.test_project 12345 +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_project.my_project + id = "project_id" +} + +import { + to = dbtcloud_project.my_project + id = "12345" +} + +# using the older import command +terraform import dbtcloud_project.my_project "project_id" +terraform import dbtcloud_project.my_project 12345 ``` diff --git a/docs/resources/project_artefacts.md b/docs/resources/project_artefacts.md index 3ce67286..aee215dc 100644 --- a/docs/resources/project_artefacts.md +++ b/docs/resources/project_artefacts.md @@ -41,7 +41,18 @@ resource "dbtcloud_project_artefacts" "my_project_artefacts" { Import is supported using the following syntax: ```shell -# Import using a project ID found in the URL or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_project_artefacts.my_artefacts + id = "project_id" +} + +import { + to = dbtcloud_project_artefacts.my_artefacts + id = "12345" +} + +# using the older import command terraform import dbtcloud_project_artefacts.my_artefacts "project_id" terraform import dbtcloud_project_artefacts.my_artefacts 12345 ``` diff --git a/docs/resources/project_connection.md b/docs/resources/project_connection.md index d832f7f6..fc149b60 100644 --- a/docs/resources/project_connection.md +++ b/docs/resources/project_connection.md @@ -36,7 +36,18 @@ resource "dbtcloud_project_connection" "dbt_project_connection" { Import is supported using the following syntax: ```shell -# Import using a project ID and Connection ID found in the URL or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_project_connection.my_project + id = "project_id:connection_id" +} + +import { + to = dbtcloud_project_connection.my_project + id = "12345:5678" +} + +# using the older import command terraform import dbtcloud_project_connection.my_project "project_id:connection_id" terraform import dbtcloud_project_connection.my_project 12345:5678 ``` diff --git a/docs/resources/project_repository.md b/docs/resources/project_repository.md index 503b5a8d..6605b0a5 100644 --- a/docs/resources/project_repository.md +++ b/docs/resources/project_repository.md @@ -36,7 +36,18 @@ resource "dbtcloud_project_repository" "dbt_project_repository" { Import is supported using the following syntax: ```shell -# Import using a project ID and Connection ID found in the URL or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_project_repository.my_project + id = "project_id:repository_id" +} + +import { + to = dbtcloud_project_repository.my_project + id = "12345:5678" +} + +# using the older import command terraform import dbtcloud_project_repository.my_project "project_id:repository_id" terraform import dbtcloud_project_repository.my_project 12345:5678 ``` diff --git a/docs/resources/repository.md b/docs/resources/repository.md index 0c0c7169..248f9427 100644 --- a/docs/resources/repository.md +++ b/docs/resources/repository.md @@ -121,7 +121,18 @@ resource "dbtcloud_repository" "ado_repo" { Import is supported using the following syntax: ```shell -# Import using a project ID and repository ID found in the URL or via the API. -terraform import dbtcloud_repository.test_repository "project_id:repository_id" -terraform import dbtcloud_repository.test_repository 12345:6789 +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_repository.my_repository + id = "project_id:repository_id" +} + +import { + to = dbtcloud_repository.my_repository + id = "12345:6789" +} + +# using the older import command +terraform import dbtcloud_repository.my_repository "project_id:repository_id" +terraform import dbtcloud_repository.my_repository 12345:6789 ``` diff --git a/docs/resources/service_token.md b/docs/resources/service_token.md index 0b972ea3..a8eb4de2 100644 --- a/docs/resources/service_token.md +++ b/docs/resources/service_token.md @@ -88,7 +88,18 @@ Optional: Import is supported using the following syntax: ```shell -# Import using a group ID found in the URL or via the API. -terraform import dbtcloud_group.test_service_token "service_token_id" -terraform import dbtcloud_group.test_service_token 12345 +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_group.my_service_token + id = "service_token_id" +} + +import { + to = dbtcloud_group.my_service_token + id = "12345" +} + +# using the older import command +terraform import dbtcloud_group.my_service_token "service_token_id" +terraform import dbtcloud_group.my_service_token 12345 ``` diff --git a/docs/resources/snowflake_credential.md b/docs/resources/snowflake_credential.md index a234164a..ee5efe47 100644 --- a/docs/resources/snowflake_credential.md +++ b/docs/resources/snowflake_credential.md @@ -54,7 +54,18 @@ resource "dbtcloud_snowflake_credential" "prod_credential" { Import is supported using the following syntax: ```shell -# Import using a project ID and credential ID found in the URL or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_snowflake_credential.prod_snowflake_credential + id = "project_id:credential_id" +} + +import { + to = dbtcloud_snowflake_credential.prod_snowflake_credential + id = "12345:6789" +} + +# using the older import command terraform import dbtcloud_snowflake_credential.prod_snowflake_credential "project_id:credential_id" terraform import dbtcloud_snowflake_credential.prod_snowflake_credential 12345:6789 ``` diff --git a/docs/resources/user_groups.md b/docs/resources/user_groups.md index 5a40ac20..852c1c5a 100644 --- a/docs/resources/user_groups.md +++ b/docs/resources/user_groups.md @@ -61,7 +61,18 @@ Import is supported using the following syntax: ```shell # Import using the User ID -# The User ID can be retrieved from the dbt Cloud UI or with the data source dbtcloud_user +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_user_groups.my_user_groups + id = "user_id" +} + +import { + to = dbtcloud_user_groups.my_user_groups + id = "123456" +} + +# using the older import command terraform import dbtcloud_user_groups.my_user_groups "user_id" terraform import dbtcloud_user_groups.my_user_groups 123456 ``` diff --git a/docs/resources/webhook.md b/docs/resources/webhook.md index bf239fe5..cd7a236c 100644 --- a/docs/resources/webhook.md +++ b/docs/resources/webhook.md @@ -56,7 +56,18 @@ resource "dbtcloud_webhook" "test_webhook" { Import is supported using the following syntax: ```shell -# Import using a job ID found in the URL or via the API. -terraform import dbtcloud_webhook.test_webhook "job_id" -terraform import dbtcloud_webhook.test_webhook wsu_abcdefg +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_webhook.my_webhook + id = "webhook_id" +} + +import { + to = dbtcloud_webhook.my_webhook + id = "wsu_abcdefg" +} + +# using the older import command +terraform import dbtcloud_webhook.my_webhook "webhook_id" +terraform import dbtcloud_webhook.my_webhook wsu_abcdefg ``` diff --git a/examples/resources/dbtcloud_bigquery_connection/import.sh b/examples/resources/dbtcloud_bigquery_connection/import.sh index 3c1f55fb..b294ad0b 100644 --- a/examples/resources/dbtcloud_bigquery_connection/import.sh +++ b/examples/resources/dbtcloud_bigquery_connection/import.sh @@ -1,2 +1,14 @@ +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_bigquery_connection.my_connection + id = "project_id:connection_id" +} + +import { + to = dbtcloud_bigquery_connection.my_connection + id = "12345:6789" +} + +# using the older import command terraform import dbtcloud_bigquery_connection.my_connection "project_id:connection_id" -terraform import dbtcloud_bigquery_connection.my_connection 12345:6789 +terraform import dbtcloud_bigquery_connection.my_connection 12345:6789 \ No newline at end of file diff --git a/examples/resources/dbtcloud_bigquery_credential/import.sh b/examples/resources/dbtcloud_bigquery_credential/import.sh index 272c1e2c..d6fd3005 100644 --- a/examples/resources/dbtcloud_bigquery_credential/import.sh +++ b/examples/resources/dbtcloud_bigquery_credential/import.sh @@ -1,2 +1,14 @@ +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_bigquery_credential.my_credential + id = "project_id:credential_id" +} + +import { + to = dbtcloud_bigquery_credential.my_credential + id = "12345:5678" +} + +# using the older import command terraform import dbtcloud_bigquery_credential.my_credential "project_id:credential_id" terraform import dbtcloud_bigquery_credential.my_credential 12345:5678 diff --git a/examples/resources/dbtcloud_connection/import.sh b/examples/resources/dbtcloud_connection/import.sh index 6086cbf0..dd1e85ef 100644 --- a/examples/resources/dbtcloud_connection/import.sh +++ b/examples/resources/dbtcloud_connection/import.sh @@ -1,3 +1,14 @@ -# Import using a project ID and connection ID found in the URL or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_connection.test_connection + id = "project_id:connection_id" +} + +import { + to = dbtcloud_connection.test_connection + id = "12345:6789" +} + +# using the older import command terraform import dbtcloud_connection.test_connection "project_id:connection_id" terraform import dbtcloud_connection.test_connection 12345:6789 diff --git a/examples/resources/dbtcloud_databricks_credential/import.sh b/examples/resources/dbtcloud_databricks_credential/import.sh index 6802c631..7ede7f4f 100644 --- a/examples/resources/dbtcloud_databricks_credential/import.sh +++ b/examples/resources/dbtcloud_databricks_credential/import.sh @@ -1,3 +1,14 @@ -# Import using a project ID and credential ID found in the URL or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_databricks_credential.my_databricks_credential + id = "project_id:credential_id" +} + +import { + to = dbtcloud_databricks_credential.my_databricks_credential + id = "12345:6789" +} + +# using the older import command terraform import dbtcloud_databricks_credential.my_databricks_credential "project_id:credential_id" terraform import dbtcloud_databricks_credential.my_databricks_credential 12345:6789 diff --git a/examples/resources/dbtcloud_environment/import.sh b/examples/resources/dbtcloud_environment/import.sh index 1dcd8dd1..649d8fef 100644 --- a/examples/resources/dbtcloud_environment/import.sh +++ b/examples/resources/dbtcloud_environment/import.sh @@ -1,3 +1,14 @@ -# Import using a project ID and environment ID found in the URL or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_environment.prod_environment + id = "project_id:environment_id" +} + +import { + to = dbtcloud_environment.prod_environment + id = "12345:6789" +} + +# using the older import command terraform import dbtcloud_environment.prod_environment "project_id:environment_id" terraform import dbtcloud_environment.prod_environment 12345:6789 diff --git a/examples/resources/dbtcloud_environment_variable/import.sh b/examples/resources/dbtcloud_environment_variable/import.sh index c73752d5..fdc50d60 100644 --- a/examples/resources/dbtcloud_environment_variable/import.sh +++ b/examples/resources/dbtcloud_environment_variable/import.sh @@ -1,3 +1,14 @@ -# Import using a project ID and environment variable name found in the URL and UI or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_environment_variable.test_environment_variable + id = "project_id:environment_variable_name" +} + +import { + to = dbtcloud_environment_variable.test_environment_variable + id = "12345:DBT_ENV_VAR" +} + +# using the older import command terraform import dbtcloud_environment_variable.test_environment_variable "project_id:environment_variable_name" terraform import dbtcloud_environment_variable.test_environment_variable 12345:DBT_ENV_VAR diff --git a/examples/resources/dbtcloud_environment_variable_job_override/import.sh b/examples/resources/dbtcloud_environment_variable_job_override/import.sh index 9e635c98..8a9c5446 100644 --- a/examples/resources/dbtcloud_environment_variable_job_override/import.sh +++ b/examples/resources/dbtcloud_environment_variable_job_override/import.sh @@ -1,3 +1,14 @@ -# Import using a project ID, a job ID and the environment variable override ID +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_environment_variable_job_override.test_environment_variable_job_override + id = "project_id:job_id:environment_variable_override_id" +} + +import { + to = dbtcloud_environment_variable_job_override.test_environment_variable_job_override + id = "12345:678:123456" +} + +# using the older import command terraform import dbtcloud_environment_variable_job_override.test_environment_variable_job_override "project_id:job_id:environment_variable_override_id" terraform import dbtcloud_environment_variable_job_override.test_environment_variable_job_override 12345:678:123456 diff --git a/examples/resources/dbtcloud_extended_attributes/import.sh b/examples/resources/dbtcloud_extended_attributes/import.sh index bf62cda8..d861a75f 100644 --- a/examples/resources/dbtcloud_extended_attributes/import.sh +++ b/examples/resources/dbtcloud_extended_attributes/import.sh @@ -1,3 +1,14 @@ -# Import using a project ID and extended attribute ID found in the URL or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_extended_attributes.test_extended_attributes + id = "project_id_id:extended_attributes_id" +} + +import { + to = dbtcloud_extended_attributes.test_extended_attributes + id = "12345:6789" +} + +# using the older import command terraform import dbtcloud_extended_attributes.test_extended_attributes "project_id_id:extended_attributes_id" terraform import dbtcloud_extended_attributes.test_extended_attributes 12345:6789 diff --git a/examples/resources/dbtcloud_fabric_connection/import.sh b/examples/resources/dbtcloud_fabric_connection/import.sh index df93c1eb..8d996d4e 100644 --- a/examples/resources/dbtcloud_fabric_connection/import.sh +++ b/examples/resources/dbtcloud_fabric_connection/import.sh @@ -1,2 +1,14 @@ +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_fabric_connection.my_connection + id = "project_id:connection_id" +} + +import { + to = dbtcloud_fabric_connection.my_connection + id = "12345:6789" +} + +# using the older import command terraform import dbtcloud_fabric_connection.my_connection "project_id:connection_id" terraform import dbtcloud_fabric_connection.my_connection 12345:6789 diff --git a/examples/resources/dbtcloud_fabric_credential/import.sh b/examples/resources/dbtcloud_fabric_credential/import.sh index 00bfa478..19156afb 100644 --- a/examples/resources/dbtcloud_fabric_credential/import.sh +++ b/examples/resources/dbtcloud_fabric_credential/import.sh @@ -1,3 +1,14 @@ -# Import using a project ID and credential ID found in the URL or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_fabric_credential.my_fabric_credential + id = "project_id:credential_id" +} + +import { + to = dbtcloud_fabric_credential.my_fabric_credential + id = "12345:6789" +} + +# using the older import command terraform import dbtcloud_fabric_credential.my_fabric_credential "project_id:credential_id" terraform import dbtcloud_fabric_credential.my_fabric_credential 12345:6789 diff --git a/examples/resources/dbtcloud_group/import.sh b/examples/resources/dbtcloud_group/import.sh index d8a5dc94..563ff6c8 100644 --- a/examples/resources/dbtcloud_group/import.sh +++ b/examples/resources/dbtcloud_group/import.sh @@ -1,3 +1,14 @@ -# Import using a group ID found in the URL or via the API. -terraform import dbtcloud_group.test_group "group_id" -terraform import dbtcloud_group.test_group 12345 +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_group.my_group + id = "group_id" +} + +import { + to = dbtcloud_group.my_group + id = "12345" +} + +# using the older import command +terraform import dbtcloud_group.my_group "group_id" +terraform import dbtcloud_group.my_group 12345 diff --git a/examples/resources/dbtcloud_job/import.sh b/examples/resources/dbtcloud_job/import.sh index e67729a0..a72ff02e 100644 --- a/examples/resources/dbtcloud_job/import.sh +++ b/examples/resources/dbtcloud_job/import.sh @@ -1,3 +1,14 @@ -# Import using a job ID found in the URL or via the API. -terraform import dbtcloud_job.test_job "job_id" -terraform import dbtcloud_job.test_job 12345 +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_job.my_job + id = "job_id" +} + +import { + to = dbtcloud_job.my_job + id = "12345" +} + +# using the older import command +terraform import dbtcloud_job.my_job "job_id" +terraform import dbtcloud_job.my_job 12345 diff --git a/examples/resources/dbtcloud_license_map/import.sh b/examples/resources/dbtcloud_license_map/import.sh index 9c5fb880..bc7d9925 100644 --- a/examples/resources/dbtcloud_license_map/import.sh +++ b/examples/resources/dbtcloud_license_map/import.sh @@ -1,3 +1,14 @@ -# Import using a license map ID found in the URL or via the API. -terraform import dbtcloud_license_map.test_license_map "license_map_id" -terraform import dbtcloud_license_map.test_license_map 12345 +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_license_map.my_license_map + id = "license_map_id" +} + +import { + to = dbtcloud_license_map.my_license_map + id = "12345" +} + +# using the older import command +terraform import dbtcloud_license_map.my_license_map "license_map_id" +terraform import dbtcloud_license_map.my_license_map 12345 diff --git a/examples/resources/dbtcloud_notification/import.sh b/examples/resources/dbtcloud_notification/import.sh index 321bfdfb..02b15459 100644 --- a/examples/resources/dbtcloud_notification/import.sh +++ b/examples/resources/dbtcloud_notification/import.sh @@ -1,3 +1,14 @@ -# Import using a notification ID +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_notification.my_notification + id = "notification_id" +} + +import { + to = dbtcloud_notification.my_notification + id = "12345" +} + +# using the older import command terraform import dbtcloud_notification.my_notification "notification_id" terraform import dbtcloud_notification.my_notification 12345 diff --git a/examples/resources/dbtcloud_partial_notification/resource.tf b/examples/resources/dbtcloud_partial_notification/resource.tf new file mode 100644 index 00000000..c1ad28fa --- /dev/null +++ b/examples/resources/dbtcloud_partial_notification/resource.tf @@ -0,0 +1,34 @@ +// the config is the same as for `dbtcloud_notification` + +resource "dbtcloud_partial_notification" "prod_job_internal_notification" { + // user_id is the internal ID of a given user in dbt Cloud + user_id = 100 + on_success = [dbtcloud_job.prod_job.id] + on_failure = [12345] + // the Type 1 is used for internal notifications + notification_type = 1 +} + +// we can also send "external" email notifications to emails to related to dbt Cloud users +resource "dbtcloud_partial_notification" "prod_job_external_notification" { + // we still need the ID of a user in dbt Cloud even though it is not used for sending notifications + user_id = 100 + on_failure = [23456, 56788] + on_cancel = [dbtcloud_job.prod_job.id] + // the Type 4 is used for external notifications + notification_type = 4 + // the external_email is the email address that will receive the notification + external_email = "my_email@mail.com" +} + +// and finally, we can set up Slack notifications +resource "dbtcloud_partial_notification" "prod_job_slack_notifications" { + // we still need the ID of a user in dbt Cloud even though it is not used for sending notifications + user_id = 100 + on_failure = [23456, 56788] + on_cancel = [dbtcloud_job.prod_job.id] + // the Type 2 is used for Slack notifications + notification_type = 2 + slack_channel_id = "C12345ABCDE" + slack_channel_name = "#my-awesome-channel" +} \ No newline at end of file diff --git a/examples/resources/dbtcloud_postgres_credential/import.sh b/examples/resources/dbtcloud_postgres_credential/import.sh index ba58353f..a32bb64b 100644 --- a/examples/resources/dbtcloud_postgres_credential/import.sh +++ b/examples/resources/dbtcloud_postgres_credential/import.sh @@ -1,3 +1,14 @@ -# Import using a project ID and credential ID found in the URL or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_postgres_credential.my_credential + id = "project_id:credential_id" +} + +import { + to = dbtcloud_postgres_credential.my_credential + id = "12345:6789" +} + +# using the older import command terraform import dbtcloud_postgres_credential.my_credential "project_id:credential_id" terraform import dbtcloud_postgres_credential.my_credential 12345:6789 diff --git a/examples/resources/dbtcloud_project/import.sh b/examples/resources/dbtcloud_project/import.sh index fd4d1d54..0670b415 100644 --- a/examples/resources/dbtcloud_project/import.sh +++ b/examples/resources/dbtcloud_project/import.sh @@ -1,3 +1,14 @@ -# Import using a project ID found in the URL or via the API. -terraform import dbtcloud_project.test_project "project_id" -terraform import dbtcloud_project.test_project 12345 +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_project.my_project + id = "project_id" +} + +import { + to = dbtcloud_project.my_project + id = "12345" +} + +# using the older import command +terraform import dbtcloud_project.my_project "project_id" +terraform import dbtcloud_project.my_project 12345 diff --git a/examples/resources/dbtcloud_project_artefacts/import.sh b/examples/resources/dbtcloud_project_artefacts/import.sh index 257c32b2..da287874 100644 --- a/examples/resources/dbtcloud_project_artefacts/import.sh +++ b/examples/resources/dbtcloud_project_artefacts/import.sh @@ -1,3 +1,14 @@ -# Import using a project ID found in the URL or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_project_artefacts.my_artefacts + id = "project_id" +} + +import { + to = dbtcloud_project_artefacts.my_artefacts + id = "12345" +} + +# using the older import command terraform import dbtcloud_project_artefacts.my_artefacts "project_id" terraform import dbtcloud_project_artefacts.my_artefacts 12345 diff --git a/examples/resources/dbtcloud_project_connection/import.sh b/examples/resources/dbtcloud_project_connection/import.sh index 10924daa..b3678b8d 100644 --- a/examples/resources/dbtcloud_project_connection/import.sh +++ b/examples/resources/dbtcloud_project_connection/import.sh @@ -1,3 +1,14 @@ -# Import using a project ID and Connection ID found in the URL or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_project_connection.my_project + id = "project_id:connection_id" +} + +import { + to = dbtcloud_project_connection.my_project + id = "12345:5678" +} + +# using the older import command terraform import dbtcloud_project_connection.my_project "project_id:connection_id" terraform import dbtcloud_project_connection.my_project 12345:5678 diff --git a/examples/resources/dbtcloud_project_repository/import.sh b/examples/resources/dbtcloud_project_repository/import.sh index e7613b2a..ddb06e87 100644 --- a/examples/resources/dbtcloud_project_repository/import.sh +++ b/examples/resources/dbtcloud_project_repository/import.sh @@ -1,3 +1,14 @@ -# Import using a project ID and Connection ID found in the URL or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_project_repository.my_project + id = "project_id:repository_id" +} + +import { + to = dbtcloud_project_repository.my_project + id = "12345:5678" +} + +# using the older import command terraform import dbtcloud_project_repository.my_project "project_id:repository_id" terraform import dbtcloud_project_repository.my_project 12345:5678 diff --git a/examples/resources/dbtcloud_repository/import.sh b/examples/resources/dbtcloud_repository/import.sh index 5f821510..8697daf5 100644 --- a/examples/resources/dbtcloud_repository/import.sh +++ b/examples/resources/dbtcloud_repository/import.sh @@ -1,3 +1,14 @@ -# Import using a project ID and repository ID found in the URL or via the API. -terraform import dbtcloud_repository.test_repository "project_id:repository_id" -terraform import dbtcloud_repository.test_repository 12345:6789 +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_repository.my_repository + id = "project_id:repository_id" +} + +import { + to = dbtcloud_repository.my_repository + id = "12345:6789" +} + +# using the older import command +terraform import dbtcloud_repository.my_repository "project_id:repository_id" +terraform import dbtcloud_repository.my_repository 12345:6789 diff --git a/examples/resources/dbtcloud_service_token/import.sh b/examples/resources/dbtcloud_service_token/import.sh index 15521922..e2e653d8 100644 --- a/examples/resources/dbtcloud_service_token/import.sh +++ b/examples/resources/dbtcloud_service_token/import.sh @@ -1,3 +1,14 @@ -# Import using a group ID found in the URL or via the API. -terraform import dbtcloud_group.test_service_token "service_token_id" -terraform import dbtcloud_group.test_service_token 12345 +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_group.my_service_token + id = "service_token_id" +} + +import { + to = dbtcloud_group.my_service_token + id = "12345" +} + +# using the older import command +terraform import dbtcloud_group.my_service_token "service_token_id" +terraform import dbtcloud_group.my_service_token 12345 diff --git a/examples/resources/dbtcloud_snowflake_credential/import.sh b/examples/resources/dbtcloud_snowflake_credential/import.sh index eb06bc8c..50fb3777 100644 --- a/examples/resources/dbtcloud_snowflake_credential/import.sh +++ b/examples/resources/dbtcloud_snowflake_credential/import.sh @@ -1,3 +1,14 @@ -# Import using a project ID and credential ID found in the URL or via the API. +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_snowflake_credential.prod_snowflake_credential + id = "project_id:credential_id" +} + +import { + to = dbtcloud_snowflake_credential.prod_snowflake_credential + id = "12345:6789" +} + +# using the older import command terraform import dbtcloud_snowflake_credential.prod_snowflake_credential "project_id:credential_id" terraform import dbtcloud_snowflake_credential.prod_snowflake_credential 12345:6789 diff --git a/examples/resources/dbtcloud_user_groups/import.sh b/examples/resources/dbtcloud_user_groups/import.sh index 819839e3..2f6370d6 100644 --- a/examples/resources/dbtcloud_user_groups/import.sh +++ b/examples/resources/dbtcloud_user_groups/import.sh @@ -1,4 +1,15 @@ # Import using the User ID -# The User ID can be retrieved from the dbt Cloud UI or with the data source dbtcloud_user +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_user_groups.my_user_groups + id = "user_id" +} + +import { + to = dbtcloud_user_groups.my_user_groups + id = "123456" +} + +# using the older import command terraform import dbtcloud_user_groups.my_user_groups "user_id" terraform import dbtcloud_user_groups.my_user_groups 123456 diff --git a/examples/resources/dbtcloud_webhook/import.sh b/examples/resources/dbtcloud_webhook/import.sh index e72dfd7a..60b3970e 100644 --- a/examples/resources/dbtcloud_webhook/import.sh +++ b/examples/resources/dbtcloud_webhook/import.sh @@ -1,3 +1,14 @@ -# Import using a job ID found in the URL or via the API. -terraform import dbtcloud_webhook.test_webhook "job_id" -terraform import dbtcloud_webhook.test_webhook wsu_abcdefg +# using import blocks (requires Terraform >= 1.5) +import { + to = dbtcloud_webhook.my_webhook + id = "webhook_id" +} + +import { + to = dbtcloud_webhook.my_webhook + id = "wsu_abcdefg" +} + +# using the older import command +terraform import dbtcloud_webhook.my_webhook "webhook_id" +terraform import dbtcloud_webhook.my_webhook wsu_abcdefg diff --git a/go.mod b/go.mod index 4b963dfa..5299f313 100644 --- a/go.mod +++ b/go.mod @@ -5,10 +5,10 @@ go 1.21.0 toolchain go1.21.4 require ( - github.com/hashicorp/terraform-plugin-docs v0.16.0 - github.com/hashicorp/terraform-plugin-framework v1.7.0 + github.com/hashicorp/terraform-plugin-docs v0.19.2 + github.com/hashicorp/terraform-plugin-framework v1.8.0 github.com/hashicorp/terraform-plugin-framework-validators v0.12.0 - github.com/hashicorp/terraform-plugin-go v0.22.1 + github.com/hashicorp/terraform-plugin-go v0.22.2 github.com/hashicorp/terraform-plugin-log v0.9.0 github.com/hashicorp/terraform-plugin-mux v0.15.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.33.0 @@ -18,19 +18,23 @@ require ( ) require ( + github.com/BurntSushi/toml v1.2.1 // indirect + github.com/Kunde21/markdownfmt/v3 v3.1.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.2.0 // indirect github.com/Masterminds/sprig/v3 v3.2.3 // indirect - github.com/ProtonMail/go-crypto v1.1.0-alpha.0 // indirect + github.com/ProtonMail/go-crypto v1.1.0-alpha.2 // indirect github.com/agext/levenshtein v1.2.2 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/armon/go-radix v1.0.0 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect + github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/fatih/color v1.16.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/hashicorp/cli v1.1.6 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-checkpoint v0.5.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -40,7 +44,7 @@ require ( github.com/hashicorp/go-plugin v1.6.0 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/go-version v1.6.0 // indirect - github.com/hashicorp/hc-install v0.6.3 // indirect + github.com/hashicorp/hc-install v0.6.4 // indirect github.com/hashicorp/hcl/v2 v2.20.0 // indirect github.com/hashicorp/logutils v1.0.0 // indirect github.com/hashicorp/terraform-exec v0.20.0 // indirect @@ -52,7 +56,7 @@ require ( github.com/imdario/mergo v0.3.15 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mitchellh/cli v1.1.5 // indirect + github.com/mattn/go-runewidth v0.0.9 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-wordwrap v1.0.0 // indirect @@ -60,23 +64,27 @@ require ( github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/oklog/run v1.0.0 // indirect github.com/posener/complete v1.2.3 // indirect - github.com/russross/blackfriday v1.6.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/spf13/cast v1.5.1 // indirect github.com/stretchr/testify v1.8.4 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect - github.com/zclconf/go-cty v1.14.3 // indirect - golang.org/x/crypto v0.21.0 // indirect + github.com/yuin/goldmark v1.7.1 // indirect + github.com/yuin/goldmark-meta v1.1.0 // indirect + github.com/zclconf/go-cty v1.14.4 // indirect + go.abhg.dev/goldmark/frontmatter v0.2.0 // indirect + golang.org/x/crypto v0.23.0 // indirect golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect - golang.org/x/mod v0.15.0 // indirect - golang.org/x/net v0.21.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/mod v0.16.0 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/text v0.15.0 // indirect golang.org/x/tools v0.13.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect - google.golang.org/grpc v1.62.1 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/grpc v1.63.2 // indirect google.golang.org/protobuf v1.33.0 // indirect + gopkg.in/yaml.v2 v2.3.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 14ca09b1..6516086c 100644 --- a/go.sum +++ b/go.sum @@ -1,27 +1,30 @@ dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/Kunde21/markdownfmt/v3 v3.1.0 h1:KiZu9LKs+wFFBQKhrZJrFZwtLnCCWJahL+S+E/3VnM0= +github.com/Kunde21/markdownfmt/v3 v3.1.0/go.mod h1:tPXN1RTyOzJwhfHoon9wUr4HGYmWgVxSQN6VBJDkrVc= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/ProtonMail/go-crypto v1.1.0-alpha.0 h1:nHGfwXmFvJrSR9xu8qL7BkO4DqTHXE9N5vPhgY2I+j0= -github.com/ProtonMail/go-crypto v1.1.0-alpha.0/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= +github.com/ProtonMail/go-crypto v1.1.0-alpha.2 h1:bkyFVUP+ROOARdgCiJzNQo2V2kiB97LyUpzH9P6Hrlg= +github.com/ProtonMail/go-crypto v1.1.0-alpha.2/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I= +github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= @@ -33,7 +36,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= @@ -43,8 +45,8 @@ github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66D github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= -github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= -github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= +github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= +github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -54,14 +56,17 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/cli v1.1.6 h1:CMOV+/LJfL1tXCOKrgAX0uRKnzjj/mpmqNXloRSy2K8= +github.com/hashicorp/cli v1.1.6/go.mod h1:MPon5QYlgjjo0BSoAiN0ESeT5fRzDjVRp+uioJ0piz4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -84,8 +89,8 @@ github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/C github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/hc-install v0.6.3 h1:yE/r1yJvWbtrJ0STwScgEnCanb0U9v7zp0Gbkmcoxqs= -github.com/hashicorp/hc-install v0.6.3/go.mod h1:KamGdbodYzlufbWh4r9NRo8y6GLHWZP2GBtdnms1Ln0= +github.com/hashicorp/hc-install v0.6.4 h1:QLqlM56/+SIIGvGcfFiwMY3z5WGXT066suo/v9Km8e0= +github.com/hashicorp/hc-install v0.6.4/go.mod h1:05LWLy8TD842OtgcfBbOT0WMoInBMUSHjmDx10zuBIA= github.com/hashicorp/hcl/v2 v2.20.0 h1:l++cRs/5jQOiKVvqXZm/P1ZEfVXJmvLS9WSVxkaeTb4= github.com/hashicorp/hcl/v2 v2.20.0/go.mod h1:WmcD/Ym72MDOOx5F62Ly+leloeu6H7m0pG7VBiU6pQk= github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= @@ -94,14 +99,18 @@ github.com/hashicorp/terraform-exec v0.20.0 h1:DIZnPsqzPGuUnq6cH8jWcPunBfY+C+M8J github.com/hashicorp/terraform-exec v0.20.0/go.mod h1:ckKGkJWbsNqFKV1itgMnE0hY9IYf1HoiekpuN0eWoDw= github.com/hashicorp/terraform-json v0.21.0 h1:9NQxbLNqPbEMze+S6+YluEdXgJmhQykRyRNd+zTI05U= github.com/hashicorp/terraform-json v0.21.0/go.mod h1:qdeBs11ovMzo5puhrRibdD6d2Dq6TyE/28JiU4tIQxk= -github.com/hashicorp/terraform-plugin-docs v0.16.0 h1:UmxFr3AScl6Wged84jndJIfFccGyBZn52KtMNsS12dI= -github.com/hashicorp/terraform-plugin-docs v0.16.0/go.mod h1:M3ZrlKBJAbPMtNOPwHicGi1c+hZUh7/g0ifT/z7TVfA= +github.com/hashicorp/terraform-plugin-docs v0.19.2 h1:YjdKa1vuqt9EnPYkkrv9HnGZz175HhSJ7Vsn8yZeWus= +github.com/hashicorp/terraform-plugin-docs v0.19.2/go.mod h1:gad2aP6uObFKhgNE8DR9nsEuEQnibp7il0jZYYOunWY= github.com/hashicorp/terraform-plugin-framework v1.7.0 h1:wOULbVmfONnJo9iq7/q+iBOBJul5vRovaYJIu2cY/Pw= github.com/hashicorp/terraform-plugin-framework v1.7.0/go.mod h1:jY9Id+3KbZ17OMpulgnWLSfwxNVYSoYBQFTgsx044CI= +github.com/hashicorp/terraform-plugin-framework v1.8.0 h1:P07qy8RKLcoBkCrY2RHJer5AEvJnDuXomBgou6fD8kI= +github.com/hashicorp/terraform-plugin-framework v1.8.0/go.mod h1:/CpTukO88PcL/62noU7cuyaSJ4Rsim+A/pa+3rUVufY= github.com/hashicorp/terraform-plugin-framework-validators v0.12.0 h1:HOjBuMbOEzl7snOdOoUfE2Jgeto6JOjLVQ39Ls2nksc= github.com/hashicorp/terraform-plugin-framework-validators v0.12.0/go.mod h1:jfHGE/gzjxYz6XoUwi/aYiiKrJDeutQNUtGQXkaHklg= github.com/hashicorp/terraform-plugin-go v0.22.1 h1:iTS7WHNVrn7uhe3cojtvWWn83cm2Z6ryIUDTRO0EV7w= github.com/hashicorp/terraform-plugin-go v0.22.1/go.mod h1:qrjnqRghvQ6KnDbB12XeZ4FluclYwptntoWCr9QaXTI= +github.com/hashicorp/terraform-plugin-go v0.22.2 h1:5o8uveu6eZUf5J7xGPV0eY0TPXg3qpmwX9sce03Bxnc= +github.com/hashicorp/terraform-plugin-go v0.22.2/go.mod h1:drq8Snexp9HsbFZddvyLHN6LuWHHndSQg+gV+FPkcIM= github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow= github.com/hashicorp/terraform-plugin-mux v0.15.0 h1:+/+lDx0WUsIOpkAmdwBIoFU8UP9o2eZASoOnLsWbKME= @@ -116,8 +125,6 @@ github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= -github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= @@ -138,19 +145,17 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mitchellh/cli v1.1.5 h1:OxRIeJXpAMztws/XHlN2vu6imG5Dpq+j61AzAX5fLng= -github.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= @@ -169,24 +174,21 @@ github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= -github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= -github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= -github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= -github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= +github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= @@ -194,7 +196,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= @@ -209,34 +210,37 @@ github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zclconf/go-cty v1.14.3 h1:1JXy1XroaGrzZuG6X9dt7HL6s9AwbY+l4UNL8o5B6ho= -github.com/zclconf/go-cty v1.14.3/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= +github.com/yuin/goldmark v1.7.1 h1:3bajkSilaCbjdKVsKdZjZCLBNPL9pYzrCakKaf4U49U= +github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc= +github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0= +github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8= +github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= +go.abhg.dev/goldmark/frontmatter v0.2.0 h1:P8kPG0YkL12+aYk2yU3xHv4tcXzeVnN+gU0tJ5JnxRw= +go.abhg.dev/goldmark/frontmatter v0.2.0/go.mod h1:XqrEkZuM57djk7zrlRUB02x8I5J0px76YjkOzhB4YlU= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= +golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -250,21 +254,21 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= @@ -277,8 +281,12 @@ google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAs google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM= google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= +google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= @@ -289,6 +297,7 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/pkg/dbt_cloud/adapter.go b/pkg/dbt_cloud/adapter.go index 2af60bce..c7166ced 100644 --- a/pkg/dbt_cloud/adapter.go +++ b/pkg/dbt_cloud/adapter.go @@ -70,8 +70,12 @@ func createGenericAdapter(c *Client, newAdapter Adapter, projectID int) (*int, e // as there is no way to get the current token ID, we always use 1 if strings.Contains(err.Error(), "This endpoint cannot be accessed with a service token") { - serviceTokenID := 1 - newAdapter.CreatedByServiceTokenID = &serviceTokenID + // we just get the first service token ID from the list + allServiceTokens, err := c.GetAllServiceTokens() + if err != nil { + return nil, err + } + newAdapter.CreatedByServiceTokenID = allServiceTokens[0].ID } else { // if the error is different, return it return nil, err diff --git a/pkg/dbt_cloud/client.go b/pkg/dbt_cloud/client.go index 32b2c0f6..75a50055 100644 --- a/pkg/dbt_cloud/client.go +++ b/pkg/dbt_cloud/client.go @@ -8,7 +8,8 @@ import ( "time" ) -// Client - +var versionString = "dev" + type Client struct { HostURL string HTTPClient *http.Client @@ -142,9 +143,16 @@ func NewClient(account_id *int, token *string, host_url *string) (*Client, error } func (c *Client) doRequest(req *http.Request) ([]byte, error) { + + userAgentWithVersion := fmt.Sprintf( + "terraform-provider-dbtcloud/%s", + versionString, + ) + req.Header.Add("Accept", "application/json") req.Header.Add("Content-Type", "application/json") req.Header.Add("Authorization", fmt.Sprintf("Token %s", c.Token)) + req.Header.Set("User-Agent", userAgentWithVersion) res, err := c.HTTPClient.Do(req) if err != nil { diff --git a/pkg/dbt_cloud/paginate.go b/pkg/dbt_cloud/paginate.go index 84c1222b..53624c38 100644 --- a/pkg/dbt_cloud/paginate.go +++ b/pkg/dbt_cloud/paginate.go @@ -128,3 +128,41 @@ func (c *Client) GetAllEnvironments(projectID int) ([]Environment, error) { } return allEnvs, nil } + +func (c *Client) GetAllNotifications() ([]Notification, error) { + url := fmt.Sprintf("%s/v2/accounts/%d/notifications/", c.HostURL, c.AccountID) + + allNotificationsRaw := c.GetData(url) + + allNotifications := []Notification{} + for _, notification := range allNotificationsRaw { + + data, _ := json.Marshal(notification) + currentNotification := Notification{} + err := json.Unmarshal(data, ¤tNotification) + if err != nil { + return nil, err + } + allNotifications = append(allNotifications, currentNotification) + } + return allNotifications, nil +} + +func (c *Client) GetAllServiceTokens() ([]ServiceToken, error) { + url := fmt.Sprintf("%s/v3/accounts/%d/service-tokens/?state=1", c.HostURL, c.AccountID) + + allServiceTokensRaw := c.GetData(url) + + allServiceTokens := []ServiceToken{} + for _, notification := range allServiceTokensRaw { + + data, _ := json.Marshal(notification) + currentServiceToken := ServiceToken{} + err := json.Unmarshal(data, ¤tServiceToken) + if err != nil { + return nil, err + } + allServiceTokens = append(allServiceTokens, currentServiceToken) + } + return allServiceTokens, nil +} diff --git a/pkg/framework/acctest_helper/acctest_helper.go b/pkg/framework/acctest_helper/acctest_helper.go index ddce2c0b..6e447928 100644 --- a/pkg/framework/acctest_helper/acctest_helper.go +++ b/pkg/framework/acctest_helper/acctest_helper.go @@ -5,6 +5,7 @@ import ( "log" "os" "strconv" + "testing" "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/dbt_cloud" "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/provider" @@ -61,3 +62,12 @@ var TestAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServe return tf6muxserver.NewMuxServer(context.Background(), providers...) }, } + +func TestAccPreCheck(t *testing.T) { + if v := os.Getenv("DBT_CLOUD_ACCOUNT_ID"); v == "" { + t.Fatal("DBT_CLOUD_ACCOUNT_ID must be set for acceptance tests") + } + if v := os.Getenv("DBT_CLOUD_TOKEN"); v == "" { + t.Fatal("DBT_CLOUD_TOKEN must be set for acceptance tests") + } +} diff --git a/pkg/framework/objects/group_partial_permissions/resource.go b/pkg/framework/objects/group_partial_permissions/resource.go index f226d9d5..97f6e030 100644 --- a/pkg/framework/objects/group_partial_permissions/resource.go +++ b/pkg/framework/objects/group_partial_permissions/resource.go @@ -41,6 +41,7 @@ func (r *groupPartialPermissionsResource) Read( resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + // check if the ID exists groupIDFromState := state.ID.ValueInt64() group, err := r.client.GetGroup(int(groupIDFromState)) if err != nil { @@ -59,7 +60,9 @@ func (r *groupPartialPermissionsResource) Read( return } + // if the ID exists, make sure that it is the one we are looking for if group.Name != state.Name.ValueString() { + // it doesn't match, we need to find the correct one groupIDs := r.client.GetAllGroupIDsByName(state.Name.ValueString()) if len(groupIDs) > 1 { resp.Diagnostics.AddError( @@ -88,6 +91,7 @@ func (r *groupPartialPermissionsResource) Read( } } + // we set the "global" values state.ID = types.Int64Value(int64(*group.ID)) state.Name = types.StringValue(group.Name) state.AssignByDefault = types.BoolValue(group.AssignByDefault) @@ -97,6 +101,7 @@ func (r *groupPartialPermissionsResource) Read( group.SSOMappingGroups, ) + // we set the "partial" values var remotePermissions []GroupPermission for _, permission := range group.Permissions { perm := GroupPermission{ @@ -304,6 +309,7 @@ func (r *groupPartialPermissionsResource) Update( "Issue getting Group", "Error: "+err.Error(), ) + return } planAssignByDefault := plan.AssignByDefault.ValueBool() diff --git a/pkg/framework/objects/group_partial_permissions/resource_acceptance_test.go b/pkg/framework/objects/group_partial_permissions/resource_acceptance_test.go index 60c4cc0d..7ea8bd92 100644 --- a/pkg/framework/objects/group_partial_permissions/resource_acceptance_test.go +++ b/pkg/framework/objects/group_partial_permissions/resource_acceptance_test.go @@ -2,7 +2,6 @@ package group_partial_permissions_test import ( "fmt" - "os" "strings" "testing" @@ -17,7 +16,7 @@ func TestAccDbtCloudGroupPartialPermissionsResource(t *testing.T) { groupName := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { acctest_helper.TestAccPreCheck(t) }, ProtoV6ProviderFactories: acctest_helper.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ // 1. CREATE @@ -370,12 +369,3 @@ resource "dbtcloud_group_partial_permissions" "test_group_partial_permission2" { `, projectName, groupName) return groupPartialPermissionConfig } - -func testAccPreCheck(t *testing.T) { - if v := os.Getenv("DBT_CLOUD_ACCOUNT_ID"); v == "" { - t.Fatal("DBT_CLOUD_ACCOUNT_ID must be set for acceptance tests") - } - if v := os.Getenv("DBT_CLOUD_TOKEN"); v == "" { - t.Fatal("DBT_CLOUD_TOKEN must be set for acceptance tests") - } -} diff --git a/pkg/framework/objects/group_partial_permissions/schema.go b/pkg/framework/objects/group_partial_permissions/schema.go index 68a27996..cd68b079 100644 --- a/pkg/framework/objects/group_partial_permissions/schema.go +++ b/pkg/framework/objects/group_partial_permissions/schema.go @@ -29,6 +29,8 @@ func (r *groupPartialPermissionsResource) Schema( ~> This is currently an experimental resource and any feedback is welcome in the GitHub repository. + The resource currently requires a Service Token with Account Admin access. + The current behavior of the resource is the following: - when using ~~~dbt_cloud_group_partial_permissions~~~, don't use ~~~dbt_cloud_group~~~ for the same group in any other project/workspace. Otherwise, the behavior is undefined and partial permissions might be removed. diff --git a/pkg/framework/objects/notification/resource.go b/pkg/framework/objects/notification/resource.go index 875899c3..85ceed2a 100644 --- a/pkg/framework/objects/notification/resource.go +++ b/pkg/framework/objects/notification/resource.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/dbt_cloud" + "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/helper" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/types" @@ -117,7 +118,6 @@ func (r *notificationResource) Read( ) data.State = types.Int64Value(int64(notification.State)) data.NotificationType = types.Int64Value(int64(notification.NotificationType)) - data.NotificationType = types.Int64Value(int64(notification.NotificationType)) data.ExternalEmail = types.StringPointerValue(notification.ExternalEmail) data.SlackChannelID = types.StringPointerValue(notification.SlackChannelID) data.SlackChannelName = types.StringPointerValue(notification.SlackChannelName) @@ -258,7 +258,7 @@ func (r *notificationResource) Update( state.SlackChannelName = plan.SlackChannelName } - notification := convertStateToNotification(state) + notification := ConvertStateToNotification(state) notification.AccountId = r.client.AccountID // Update the notification @@ -297,12 +297,12 @@ func (r *notificationResource) Configure( r.client = req.ProviderData.(*dbt_cloud.Client) } -func convertStateToNotification(model NotificationResourceModel) dbt_cloud.Notification { +func ConvertStateToNotification(model NotificationResourceModel) dbt_cloud.Notification { notification := dbt_cloud.Notification{ UserId: int(model.UserID.ValueInt64()), - OnCancel: expandInt64SetToIntSlice(model.OnCancel), - OnFailure: expandInt64SetToIntSlice(model.OnFailure), - OnSuccess: expandInt64SetToIntSlice(model.OnSuccess), + OnCancel: helper.Int64SetToIntSlice(model.OnCancel), + OnFailure: helper.Int64SetToIntSlice(model.OnFailure), + OnSuccess: helper.Int64SetToIntSlice(model.OnSuccess), State: int(model.State.ValueInt64()), NotificationType: int(model.NotificationType.ValueInt64()), } @@ -332,12 +332,3 @@ func convertStateToNotification(model NotificationResourceModel) dbt_cloud.Notif return notification } - -func expandInt64SetToIntSlice(set types.Set) []int { - elements := set.Elements() - result := make([]int, len(elements)) - for i, el := range elements { - result[i] = int(el.(types.Int64).ValueInt64()) - } - return result -} diff --git a/pkg/framework/objects/partial_notification/model.go b/pkg/framework/objects/partial_notification/model.go new file mode 100644 index 00000000..368f774c --- /dev/null +++ b/pkg/framework/objects/partial_notification/model.go @@ -0,0 +1,67 @@ +package partial_notification + +import ( + "context" + + "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/dbt_cloud" + "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/framework/objects/notification" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +func matchPartial( + notificationModel notification.NotificationResourceModel, + notificationResponse dbt_cloud.Notification, +) bool { + if notificationModel.NotificationType != types.Int64Value( + int64(notificationResponse.NotificationType), + ) { + return false + } + switch notificationResponse.NotificationType { + case 1: + // internal notification + if !(notificationModel.UserID == types.Int64Value(int64(notificationResponse.UserId))) { + return false + } + case 2: + // slack notification + if !(notificationModel.SlackChannelID == types.StringPointerValue( + notificationResponse.SlackChannelID, + )) { + return false + } + if !(notificationModel.SlackChannelName == types.StringPointerValue( + notificationResponse.SlackChannelName, + )) { + return false + } + case 4: + // external notification + if !(notificationModel.ExternalEmail == types.StringPointerValue( + notificationResponse.ExternalEmail, + )) { + return false + } + } + return true +} + +func extractModelJobLists( + data notification.NotificationResourceModel, +) (intOnCancel, intOnFailure, intOnSuccess []int, ok bool) { + + diags := data.OnCancel.ElementsAs(context.Background(), &intOnCancel, false) + if diags.HasError() { + return nil, nil, nil, false + } + diags = data.OnFailure.ElementsAs(context.Background(), &intOnFailure, false) + if diags.HasError() { + return nil, nil, nil, false + } + + diags = data.OnSuccess.ElementsAs(context.Background(), &intOnSuccess, false) + if diags.HasError() { + return nil, nil, nil, false + } + return intOnCancel, intOnFailure, intOnSuccess, true +} diff --git a/pkg/framework/objects/partial_notification/resource.go b/pkg/framework/objects/partial_notification/resource.go new file mode 100644 index 00000000..0d2e4877 --- /dev/null +++ b/pkg/framework/objects/partial_notification/resource.go @@ -0,0 +1,481 @@ +package partial_notification + +import ( + "context" + "strconv" + "strings" + + "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/dbt_cloud" + "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/framework/objects/notification" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/samber/lo" +) + +var ( + _ resource.Resource = &partialNotificationResource{} + _ resource.ResourceWithConfigure = &partialNotificationResource{} +) + +func PartialNotificationResource() resource.Resource { + return &partialNotificationResource{} +} + +type partialNotificationResource struct { + client *dbt_cloud.Client +} + +func (r *partialNotificationResource) Metadata( + _ context.Context, + req resource.MetadataRequest, + resp *resource.MetadataResponse, +) { + resp.TypeName = req.ProviderTypeName + "_partial_notification" +} + +func (r *partialNotificationResource) ValidateConfig( + ctx context.Context, + req resource.ValidateConfigRequest, + resp *resource.ValidateConfigResponse, +) { + var data notification.NotificationResourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + if data.NotificationType == types.Int64Value(1) && + !(data.ExternalEmail.IsNull() && data.SlackChannelID.IsNull() && data.SlackChannelName.IsNull()) { + resp.Diagnostics.AddAttributeError( + path.Root("notification_type"), + "Notification type is not compatible with the other attributes", + "Notification type 1 is for internal notifications only. Please remove the external email, slack channel ID, and slack channel name attributes.", + ) + } + + if data.NotificationType == types.Int64Value(2) && + data.SlackChannelID.IsNull() && + data.SlackChannelName.IsNull() { + resp.Diagnostics.AddAttributeError( + path.Root("notification_type"), + "Notification type is not compatible with the other attributes", + "Notification type 2 requires a Slack channel ID and Slack channel name.", + ) + } + + if data.NotificationType == types.Int64Value(4) && data.ExternalEmail.IsNull() { + resp.Diagnostics.AddAttributeError( + path.Root("notification_type"), + "Notification type is not compatible with the other attributes", + "Notification type 4 requires an external email.", + ) + } +} + +func (r *partialNotificationResource) Read( + ctx context.Context, + req resource.ReadRequest, + resp *resource.ReadResponse, +) { + var state notification.NotificationResourceModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + + // check if the ID exists + notificationID := state.ID.ValueString() + notification, err := r.client.GetNotification(notificationID) + if err != nil { + if strings.HasPrefix(err.Error(), "resource-not-found") { + resp.Diagnostics.AddWarning( + "Resource not found", + "The notification resource was not found and has been removed from the state.", + ) + resp.State.RemoveResource(ctx) + return + } + resp.Diagnostics.AddError("Error getting the notification", err.Error()) + return + } + + // if the ID exists, make sure that it is the one we are looking for + if !matchPartial(state, *notification) { + // read all the notifications and check if one exists + allNotifications, err := r.client.GetAllNotifications() + if err != nil { + resp.Diagnostics.AddError( + "Unable to get all notifications", + "Error: "+err.Error(), + ) + return + } + + var fullNotification *dbt_cloud.Notification + for _, notification := range allNotifications { + if matchPartial(state, notification) { + // it exists, we stop here + fullNotification = ¬ification + break + } + } + + // if it was not found, it means that the notification was deleted + if fullNotification == nil { + resp.Diagnostics.AddWarning( + "Resource not found", + "The notification resource was not found and has been removed from the state.", + ) + resp.State.RemoveResource(ctx) + return + } + + // if it is found, we set it correctly + notificationID = strconv.Itoa(*fullNotification.Id) + notification = fullNotification + } + + // we set the "global" values + state.ID = types.StringValue(notificationID) + state.UserID = types.Int64Value(int64(notification.UserId)) + state.State = types.Int64Value(int64(notification.State)) + state.NotificationType = types.Int64Value(int64(notification.NotificationType)) + state.ExternalEmail = types.StringPointerValue(notification.ExternalEmail) + state.SlackChannelID = types.StringPointerValue(notification.SlackChannelID) + state.SlackChannelName = types.StringPointerValue(notification.SlackChannelName) + + // we set the "partial" values by intersecting the config with the remote + intOnCancel, intOnFailure, intOnSuccess, ok := extractModelJobLists(state) + if !ok { + resp.Diagnostics.AddError("Error extracting the model job lists", "") + return + } + + state.OnCancel, _ = types.SetValueFrom( + context.Background(), + types.Int64Type, + lo.Intersect(intOnCancel, notification.OnCancel), + ) + + state.OnFailure, _ = types.SetValueFrom( + context.Background(), + types.Int64Type, + lo.Intersect(intOnFailure, notification.OnFailure), + ) + + state.OnSuccess, _ = types.SetValueFrom( + context.Background(), + types.Int64Type, + lo.Intersect(intOnSuccess, notification.OnSuccess), + ) + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) + +} + +func (r *partialNotificationResource) Create( + ctx context.Context, + req resource.CreateRequest, + resp *resource.CreateResponse, +) { + var plan notification.NotificationResourceModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + // we read the values from the config + intOnCancel, intOnFailure, intOnSuccess, ok := extractModelJobLists(plan) + if !ok { + resp.Diagnostics.AddError("Error extracting the model job lists", "") + return + } + + // check if it exists + // we don't need to check uniqueness and can just return the first as the API only allows one notification per user + allNotifications, err := r.client.GetAllNotifications() + if err != nil { + resp.Diagnostics.AddError( + "Unable to get all notifications", + "Error: "+err.Error(), + ) + return + } + + var fullNotification *dbt_cloud.Notification + for _, notification := range allNotifications { + if matchPartial(plan, notification) { + // it exists, we stop here + fullNotification = ¬ification + break + } + } + + if fullNotification != nil { + // if it exists, we get the ID + notificationID := strconv.Itoa(*fullNotification.Id) + plan.ID = types.StringValue(notificationID) + + // and we calculate all the partial fields + // the global ones are already set in the plan + configOnCancel := intOnCancel + remoteOnCancel := fullNotification.OnCancel + missingOnCancel := lo.Without(configOnCancel, remoteOnCancel...) + + configOnFailure := intOnFailure + remoteOnFailure := fullNotification.OnFailure + missingOnFailure := lo.Without(configOnFailure, remoteOnFailure...) + + configOnSuccess := intOnSuccess + remoteOnSuccess := fullNotification.OnSuccess + missingOnSuccess := lo.Without(configOnSuccess, remoteOnSuccess...) + + // we only update if something global, but not part of the ID is different or if something partial needs to be added + if plan.State == types.Int64Value(int64(fullNotification.State)) && + plan.UserID == types.Int64Value(int64(fullNotification.UserId)) && + len(missingOnCancel) == 0 && + len(missingOnFailure) == 0 && + len(missingOnSuccess) == 0 { + // nothing to do if they are all the same + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) + return + } else { + // if one of them is different, we get the new values for all + // and we update the notification + allOnCancel := append(remoteOnCancel, missingOnCancel...) + allOnFailure := append(remoteOnFailure, missingOnFailure...) + allOnSuccess := append(remoteOnSuccess, missingOnSuccess...) + + _, err := r.client.UpdateNotification( + notificationID, + dbt_cloud.Notification{ + AccountId: r.client.AccountID, + Id: fullNotification.Id, + UserId: int(plan.UserID.ValueInt64()), + OnCancel: allOnCancel, + OnFailure: allOnFailure, + OnSuccess: allOnSuccess, + State: int(plan.State.ValueInt64()), + NotificationType: int(plan.NotificationType.ValueInt64()), + ExternalEmail: plan.ExternalEmail.ValueStringPointer(), + SlackChannelID: plan.SlackChannelID.ValueStringPointer(), + SlackChannelName: plan.SlackChannelName.ValueStringPointer(), + }, + ) + if err != nil { + resp.Diagnostics.AddError( + "Unable to update the existing notification", + "Error: "+err.Error(), + ) + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) + } + + } else { + // it doesn't exist so we create it + notif, err := r.client.CreateNotification( + int(plan.UserID.ValueInt64()), + intOnCancel, + intOnFailure, + intOnSuccess, + int(plan.State.ValueInt64()), + int(plan.NotificationType.ValueInt64()), + plan.ExternalEmail.ValueStringPointer(), + plan.SlackChannelID.ValueStringPointer(), + plan.SlackChannelName.ValueStringPointer(), + ) + + if err != nil { + resp.Diagnostics.AddError( + "Unable to create notification", + "Error: "+err.Error(), + ) + return + } + + plan.ID = types.StringValue(strconv.Itoa(*notif.Id)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) + } +} + +func (r *partialNotificationResource) Delete( + ctx context.Context, + req resource.DeleteRequest, + resp *resource.DeleteResponse, +) { + var state notification.NotificationResourceModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + notificationID := state.ID.ValueString() + notification, err := r.client.GetNotification(notificationID) + if err != nil { + resp.Diagnostics.AddError("Error getting the notification", err.Error()) + return + } + + // we read the values from the config + intOnCancel, intOnFailure, intOnSuccess, ok := extractModelJobLists(state) + if !ok { + resp.Diagnostics.AddError("Error extracting the model job lists", "") + return + } + + configOnCancel := intOnCancel + remoteOnCancel := notification.OnCancel + requiredOnCancel := lo.Without(remoteOnCancel, configOnCancel...) + + configOnFailure := intOnFailure + remoteOnFailure := notification.OnFailure + requiredOnFailure := lo.Without(remoteOnFailure, configOnFailure...) + + configOnSuccess := intOnSuccess + remoteOnSuccess := notification.OnSuccess + requiredOnSuccess := lo.Without(remoteOnSuccess, configOnSuccess...) + + if len(requiredOnCancel) > 0 || len(requiredOnFailure) > 0 || len(requiredOnSuccess) > 0 { + // we update the notification if there are some jobs left + // but we leave the notification existing, without deleting it entirely + _, err = r.client.UpdateNotification( + notificationID, + dbt_cloud.Notification{ + AccountId: r.client.AccountID, + Id: notification.Id, + UserId: int(state.UserID.ValueInt64()), + OnCancel: requiredOnCancel, + OnFailure: requiredOnFailure, + OnSuccess: requiredOnSuccess, + State: int(state.State.ValueInt64()), + NotificationType: int(state.NotificationType.ValueInt64()), + ExternalEmail: state.ExternalEmail.ValueStringPointer(), + SlackChannelID: state.SlackChannelID.ValueStringPointer(), + SlackChannelName: state.SlackChannelName.ValueStringPointer(), + }, + ) + if err != nil { + resp.Diagnostics.AddError( + "Unable to update the existing notification", + "Error: "+err.Error(), + ) + return + } + } else { + // we delete the notification if there are no jobs left + notification.State = dbt_cloud.STATE_DELETED + _, err = r.client.UpdateNotification(notificationID, *notification) + if err != nil { + resp.Diagnostics.AddError("Error deleting the notification", err.Error()) + return + } + } +} + +func (r *partialNotificationResource) Update( + ctx context.Context, + req resource.UpdateRequest, + resp *resource.UpdateResponse, +) { + var plan, state notification.NotificationResourceModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + notificationID := state.ID.ValueString() + notification, err := r.client.GetNotification(notificationID) + if err != nil { + resp.Diagnostics.AddError( + "Error getting the notification", + "Error: "+err.Error(), + ) + return + } + + // we compare the partial objects and update them if needed + intOnCancelPlan, intOnFailurePlan, intOnSuccessPlan, ok := extractModelJobLists(plan) + if !ok { + resp.Diagnostics.AddError("Error extracting the model job lists from the plan", "") + return + } + + intOnCancelState, intOnFailureState, intOnSuccessState, ok := extractModelJobLists(state) + if !ok { + resp.Diagnostics.AddError("Error extracting the model job lists from the state", "") + return + } + + remoteOnCancel := notification.OnCancel + deletedOnCancel := lo.Without(intOnCancelState, intOnCancelPlan...) + newOnCancel := lo.Without(intOnCancelPlan, intOnCancelState...) + requiredOnCancel := lo.Without(lo.Union(remoteOnCancel, newOnCancel), deletedOnCancel...) + + remoteOnFailure := notification.OnFailure + deletedOnFailure := lo.Without(intOnFailureState, intOnFailurePlan...) + newOnFailure := lo.Without(intOnFailurePlan, intOnFailureState...) + requiredOnFailure := lo.Without(lo.Union(remoteOnFailure, newOnFailure), deletedOnFailure...) + + remoteOnSuccess := notification.OnSuccess + deletedOnSuccess := lo.Without(intOnSuccessState, intOnSuccessPlan...) + newOnSuccess := lo.Without(intOnSuccessPlan, intOnSuccessState...) + requiredOnSuccess := lo.Without(lo.Union(remoteOnSuccess, newOnSuccess), deletedOnSuccess...) + + // we check if there are changes to be sent, both global and local + if plan.UserID != state.UserID || + plan.State != state.State || + len(deletedOnCancel) > 0 || + len(newOnCancel) > 0 || + len(deletedOnFailure) > 0 || + len(newOnFailure) > 0 || + len(deletedOnSuccess) > 0 || + len(newOnSuccess) > 0 { + + // we update the values to be the plan ones for global + // and the calculated ones for the local ones + _, err = r.client.UpdateNotification( + notificationID, + dbt_cloud.Notification{ + AccountId: r.client.AccountID, + Id: notification.Id, + UserId: int(plan.UserID.ValueInt64()), + OnCancel: requiredOnCancel, + OnFailure: requiredOnFailure, + OnSuccess: requiredOnSuccess, + State: int(plan.State.ValueInt64()), + NotificationType: int(plan.NotificationType.ValueInt64()), + ExternalEmail: plan.ExternalEmail.ValueStringPointer(), + SlackChannelID: plan.SlackChannelID.ValueStringPointer(), + SlackChannelName: plan.SlackChannelName.ValueStringPointer(), + }, + ) + if err != nil { + resp.Diagnostics.AddError( + "Unable to update the existing notification", + "Error: "+err.Error(), + ) + return + } + } + + // Set the updated state + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *partialNotificationResource) Configure( + _ context.Context, + req resource.ConfigureRequest, + _ *resource.ConfigureResponse, +) { + if req.ProviderData == nil { + return + } + + r.client = req.ProviderData.(*dbt_cloud.Client) +} diff --git a/pkg/framework/objects/partial_notification/resource_acceptance_test.go b/pkg/framework/objects/partial_notification/resource_acceptance_test.go new file mode 100644 index 00000000..dcfed295 --- /dev/null +++ b/pkg/framework/objects/partial_notification/resource_acceptance_test.go @@ -0,0 +1,257 @@ +package partial_notification_test + +import ( + "fmt" + "regexp" + "strings" + "testing" + + "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/framework/acctest_helper" + "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" +) + +func TestAccDbtCloudPartialNotificationResource(t *testing.T) { + + projectName := strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest_helper.TestAccPreCheck(t) }, + ProtoV6ProviderFactories: acctest_helper.TestAccProtoV6ProviderFactories, + CheckDestroy: testAccCheckDbtCloudPartialNotificationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDbtCloudPartialNotificationResourceCreatePartialNotifications( + projectName, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckDbtCloudPartialNotificationExists( + "dbtcloud_partial_notification.test_notification_internal", + ), + resource.TestCheckResourceAttr( + "dbtcloud_partial_notification.test_notification_internal", + "notification_type", + "1", + ), + resource.TestCheckResourceAttrSet( + "dbtcloud_partial_notification.test_notification_internal", + "on_success.0", + ), + resource.TestCheckResourceAttrSet( + "dbtcloud_partial_notification.test_notification_internal", + "on_cancel.0", + ), + resource.TestCheckResourceAttrSet( + "dbtcloud_partial_notification.test_notification_internal", + "on_cancel.1", + ), + resource.TestCheckResourceAttrSet( + "dbtcloud_partial_notification.test_notification_internal", + "on_failure.0", + ), + + testAccCheckDbtCloudPartialNotificationExists( + "dbtcloud_partial_notification.test_notification_external", + ), + resource.TestCheckResourceAttr( + "dbtcloud_partial_notification.test_notification_external", + "notification_type", + "4", + ), + resource.TestCheckResourceAttrSet( + "dbtcloud_partial_notification.test_notification_external", + "on_failure.0", + ), + resource.TestCheckResourceAttr( + "dbtcloud_partial_notification.test_notification_external", + "external_email", + "nomail@mail.com", + ), + ), + }, + // MODIFY + { + Config: testAccDbtCloudPartialNotificationResourceModifyPartialNotifications( + projectName, + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckDbtCloudPartialNotificationExists( + "dbtcloud_partial_notification.test_notification_internal", + ), + resource.TestCheckNoResourceAttr( + "dbtcloud_partial_notification.test_notification_internal", + "on_cancel.0", + ), + + testAccCheckDbtCloudPartialNotificationExists( + "dbtcloud_partial_notification.test_notification_external", + ), + resource.TestCheckResourceAttrSet( + "dbtcloud_partial_notification.test_notification_external", + "on_cancel.0", + ), + resource.TestCheckResourceAttrSet( + "dbtcloud_partial_notification.test_notification_external2", + "on_success.0", + ), + resource.TestCheckResourceAttr( + "dbtcloud_partial_notification.test_notification_external2", + "on_cancel.#", + "0", + ), + ), + }, + }, + }) +} + +func testAccDbtCloudPartialNotificationResourceBasicConfig(projectName string) string { + return fmt.Sprintf(` +resource "dbtcloud_project" "test_notification_project" { + name = "%s" +} + +resource "dbtcloud_environment" "test_notification_environment" { + project_id = dbtcloud_project.test_notification_project.id + name = "Test Env PartialNotification" + dbt_version = "%s" + type = "development" +} + +resource "dbtcloud_job" "test_notification_job_1" { + name = "Job 1 TF" + project_id = dbtcloud_project.test_notification_project.id + environment_id = dbtcloud_environment.test_notification_environment.environment_id + execute_steps = [ + "dbt compile" + ] + triggers = { + "github_webhook" : false, + "git_provider_webhook" : false, + "schedule" : false, + } +} + +resource "dbtcloud_job" "test_notification_job_2" { + name = "Job 2 TF" + project_id = dbtcloud_project.test_notification_project.id + environment_id = dbtcloud_environment.test_notification_environment.environment_id + execute_steps = [ + "dbt test" + ] + triggers = { + "github_webhook" : false, + "git_provider_webhook" : false, + "schedule" : false, + } +} +`, projectName, acctest_helper.DBT_CLOUD_VERSION) +} + +func testAccDbtCloudPartialNotificationResourceCreatePartialNotifications( + projectName string, +) string { + + notificationsConfig := ` +resource "dbtcloud_partial_notification" "test_notification_internal" { + user_id = 100 + on_success = [dbtcloud_job.test_notification_job_1.id] + on_failure = [dbtcloud_job.test_notification_job_2.id] + on_cancel = [dbtcloud_job.test_notification_job_1.id, dbtcloud_job.test_notification_job_2.id] + notification_type = 1 +} + +resource "dbtcloud_partial_notification" "test_notification_external" { + user_id = 100 + on_failure = [dbtcloud_job.test_notification_job_2.id] + notification_type = 4 + external_email = "nomail@mail.com" +} +` + return testAccDbtCloudPartialNotificationResourceBasicConfig( + projectName, + ) + "\n" + notificationsConfig +} + +func testAccDbtCloudPartialNotificationResourceModifyPartialNotifications( + projectName string, +) string { + + notificationsConfig := ` +resource "dbtcloud_partial_notification" "test_notification_internal" { + user_id = 100 + on_success = [dbtcloud_job.test_notification_job_1.id] + on_failure = [dbtcloud_job.test_notification_job_2.id] + on_cancel = [] + notification_type = 1 +} + +resource "dbtcloud_partial_notification" "test_notification_external" { + user_id = 100 + on_failure = [dbtcloud_job.test_notification_job_2.id] + on_cancel = [dbtcloud_job.test_notification_job_1.id] + notification_type = 4 + external_email = "nomail@mail.com" +} + +resource "dbtcloud_partial_notification" "test_notification_external2" { + user_id = 100 + on_success = [dbtcloud_job.test_notification_job_1.id, dbtcloud_job.test_notification_job_2.id] + notification_type = 4 + external_email = "nomail@mail.com" + depends_on = [dbtcloud_partial_notification.test_notification_external] +} +` + return testAccDbtCloudPartialNotificationResourceBasicConfig( + projectName, + ) + "\n" + notificationsConfig +} + +func testAccCheckDbtCloudPartialNotificationExists(resource string) resource.TestCheckFunc { + return func(state *terraform.State) error { + rs, ok := state.RootModule().Resources[resource] + if !ok { + return fmt.Errorf("Not found: %s", resource) + } + if rs.Primary.ID == "" { + return fmt.Errorf("No Record ID is set") + } + + apiClient, err := acctest_helper.SharedClient() + if err != nil { + return fmt.Errorf("Issue getting the client") + } + + _, err = apiClient.GetNotification(rs.Primary.ID) + if err != nil { + return fmt.Errorf("error fetching item with resource %s. %s", resource, err) + } + return nil + } +} + +func testAccCheckDbtCloudPartialNotificationDestroy(s *terraform.State) error { + + apiClient, err := acctest_helper.SharedClient() + if err != nil { + return fmt.Errorf("Issue getting the client") + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "dbtcloud_partial_notification" { + continue + } + _, err := apiClient.GetNotification(rs.Primary.ID) + if err == nil { + return fmt.Errorf("PartialNotification still exists") + } + notFoundErr := "resource-not-found" + expectedErr := regexp.MustCompile(notFoundErr) + if !expectedErr.Match([]byte(err.Error())) { + return fmt.Errorf("expected %s, got %s", notFoundErr, err) + } + } + + return nil +} diff --git a/pkg/framework/objects/partial_notification/schema.go b/pkg/framework/objects/partial_notification/schema.go new file mode 100644 index 00000000..590671aa --- /dev/null +++ b/pkg/framework/objects/partial_notification/schema.go @@ -0,0 +1,130 @@ +package partial_notification + +import ( + "context" + + "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/helper" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +func (r *partialNotificationResource) Schema( + _ context.Context, + _ resource.SchemaRequest, + resp *resource.SchemaResponse, +) { + resp.Schema = schema.Schema{ + Description: helper.DocString( + `Setup partial notifications on jobs success/failure to internal users, external email addresses or Slack channels. This is different from ~~~dbt_cloud_notification~~~ as it allows to have multiple resources updating the same notification recipient (email, user or Slack channel) and is useful for companies managing a single dbt Cloud Account configuration from different Terraform projects/workspaces. + + If a company uses only one Terraform project/workspace to manage all their dbt Cloud Account config, it is recommended to use ~~~dbt_cloud_notification~~~ instead of ~~~dbt_cloud_partial_notification~~~. + + ~> This is a new resource. Feedback is welcome. + + The resource currently requires a Service Token with Account Admin access. + + The current behavior of the resource is the following: + + - when using ~~~dbt_cloud_partial_notification~~~, don't use ~~~dbt_cloud_notification~~~ for the same notification recipient in any other project/workspace. Otherwise, the behavior is undefined and partial notifications might be removed. + - when defining a new ~~~dbt_cloud_partial_notification~~~ + - if the notification recipient doesn't exist, it will be created + - if a notification config exists for the current recipient, Job IDs will be added in the list of jobs to trigger the notifications + - in a given Terraform project/workspace, avoid having different ~~~dbt_cloud_partial_notification~~~ for the same recipient to prevent sync issues. Add all the jobs in the same resource. + - all resources for the same notification recipient need to have the same values for ~~~state~~~ and ~~~user_id~~~. Those fields are not considered "partial". + - when a resource is updated, the dbt Cloud notification recipient will be updated accordingly, removing and adding job ids in the list of jobs triggering notifications + - when the resource is deleted/destroyed, if the resulting notification recipient list of jobs is empty, the notification will be deleted ; otherwise, the notification will be updated, removing the job ids from the deleted resource + `, + ), + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + Description: "The ID of the notification", + // this is used so that we don't show that ID is going to change + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "user_id": schema.Int64Attribute{ + Required: true, + Description: "Internal dbt Cloud User ID. Must be the user_id for an existing user even if the notification is an external one [global]", + }, + "on_cancel": schema.SetAttribute{ + ElementType: types.Int64Type, + Optional: true, + Computed: true, + Default: helper.EmptySetDefault(types.Int64Type), + Description: "List of job IDs to trigger the webhook on cancel. Those will be added/removed when config is added/removed.", + }, + "on_failure": schema.SetAttribute{ + ElementType: types.Int64Type, + Optional: true, + Computed: true, + Default: helper.EmptySetDefault(types.Int64Type), + Description: "List of job IDs to trigger the webhook on failure Those will be added/removed when config is added/removed.", + }, + "on_success": schema.SetAttribute{ + ElementType: types.Int64Type, + Optional: true, + Computed: true, + Default: helper.EmptySetDefault(types.Int64Type), + Description: "List of job IDs to trigger the webhook on success Those will be added/removed when config is added/removed.", + }, + "state": schema.Int64Attribute{ + Optional: true, + Computed: true, + Default: int64default.StaticInt64(1), + Description: "State of the notification (1 = active (default), 2 = inactive) [global]", + }, + "notification_type": schema.Int64Attribute{ + Optional: true, + Computed: true, + Default: int64default.StaticInt64(1), + Description: "Type of notification (1 = dbt Cloud user email (default): does not require an external_email ; 2 = Slack channel: requires `slack_channel_id` and `slack_channel_name` ; 4 = external email: requires setting an `external_email`) [global, used as identifier]", + PlanModifiers: []planmodifier.Int64{ + int64planmodifier.RequiresReplace(), + }, + }, + "external_email": schema.StringAttribute{ + Optional: true, + Description: "The external email to receive the notification [global, used as identifier]", + Validators: []validator.String{ + stringvalidator.ConflictsWith( + path.MatchRoot("slack_channel_id"), + path.MatchRoot("slack_channel_name"), + ), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "slack_channel_id": schema.StringAttribute{ + Optional: true, + Description: "The ID of the Slack channel to receive the notification. It can be found at the bottom of the Slack channel settings [global, used as identifier]", + Validators: []validator.String{ + stringvalidator.ConflictsWith(path.MatchRoot("external_email")), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "slack_channel_name": schema.StringAttribute{ + Optional: true, + Description: "The name of the slack channel [global, used as identifier]", + Validators: []validator.String{ + stringvalidator.ConflictsWith(path.MatchRoot("external_email")), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + } +} diff --git a/pkg/helper/helper.go b/pkg/helper/helper.go index baa55efb..62f4257a 100644 --- a/pkg/helper/helper.go +++ b/pkg/helper/helper.go @@ -26,6 +26,15 @@ func SetIntToInt64OrNull(value int) types.Int64 { return types.Int64Value(int64(value)) } +func Int64SetToIntSlice(set types.Set) []int { + elements := set.Elements() + result := make([]int, len(elements)) + for i, el := range elements { + result[i] = int(el.(types.Int64).ValueInt64()) + } + return result +} + func DocString(inp string) string { newString := strings.ReplaceAll(inp, "~~~", "`") return regexp.MustCompile(`(?m)^\t+`).ReplaceAllString(newString, "") diff --git a/pkg/provider/framework_provider.go b/pkg/provider/framework_provider.go index 21c1e37d..ca428be8 100644 --- a/pkg/provider/framework_provider.go +++ b/pkg/provider/framework_provider.go @@ -9,6 +9,7 @@ import ( "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/framework/objects/environment" "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/framework/objects/group_partial_permissions" "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/framework/objects/notification" + "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/framework/objects/partial_notification" "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/framework/objects/user" "github.com/hashicorp/terraform-plugin-framework/datasource" @@ -181,5 +182,6 @@ func (p *dbtCloudProvider) Resources(_ context.Context) []func() resource.Resour return []func() resource.Resource{ notification.NotificationResource, group_partial_permissions.GroupPartialPermissionsResource, + partial_notification.PartialNotificationResource, } } diff --git a/pkg/sdkv2/resources/job.go b/pkg/sdkv2/resources/job.go index 5d3b2407..c005c755 100644 --- a/pkg/sdkv2/resources/job.go +++ b/pkg/sdkv2/resources/job.go @@ -29,6 +29,7 @@ var jobSchema = map[string]*schema.Schema{ Type: schema.TypeInt, Required: true, Description: "Project ID to create the job in", + ForceNew: true, }, "environment_id": &schema.Schema{ Type: schema.TypeInt, diff --git a/terraform_resources.d2 b/terraform_resources.d2 index 42f7e633..c4185d8d 100644 --- a/terraform_resources.d2 +++ b/terraform_resources.d2 @@ -2,7 +2,7 @@ *.*.style.font-size: 22 title: |md - # Terraform resources (v0.3.3) + # Terraform resources (v0.3.5) | {near: top-center} direction: right @@ -49,7 +49,8 @@ user_groups -- group_partial_permissions project -- environment job -- environment job -- environemnt_variable_job_override -notifications -- job +notification -- job +partial_notification -- job project_artefacts -- job project_artefacts -- project diff --git a/terraform_resources.png b/terraform_resources.png index ab85f548..9c6a7f79 100644 Binary files a/terraform_resources.png and b/terraform_resources.png differ