From 46b5804d103858d352d8b318cc8bc0a99576b4e8 Mon Sep 17 00:00:00 2001 From: Ashton Walden Date: Wed, 11 Dec 2024 08:43:14 -0800 Subject: [PATCH 1/3] Migrate azzure_dev_ops_repository from SDKv2 to Framework --- .../azure_dev_ops_repository/data_source.go | 63 +++++++++++ .../objects/azure_dev_ops_repository/model.go | 13 +++ .../azure_dev_ops_repository/schema.go | 52 +++++++++ pkg/provider/framework_provider.go | 2 + pkg/provider/sdk_provider.go | 33 +++--- .../data_sources/azure_dev_ops_repository.go | 102 ------------------ 6 files changed, 146 insertions(+), 119 deletions(-) create mode 100644 pkg/framework/objects/azure_dev_ops_repository/data_source.go create mode 100644 pkg/framework/objects/azure_dev_ops_repository/model.go create mode 100644 pkg/framework/objects/azure_dev_ops_repository/schema.go delete mode 100644 pkg/sdkv2/data_sources/azure_dev_ops_repository.go diff --git a/pkg/framework/objects/azure_dev_ops_repository/data_source.go b/pkg/framework/objects/azure_dev_ops_repository/data_source.go new file mode 100644 index 0000000..aeba0fe --- /dev/null +++ b/pkg/framework/objects/azure_dev_ops_repository/data_source.go @@ -0,0 +1,63 @@ +package azure_dev_ops_repository + +import ( + "context" + "fmt" + + "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/dbt_cloud" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type azureDevOpsRepositoryDataSource struct { + client *dbt_cloud.Client +} + +func AzureDevOpsRepositoryDataSource() datasource.DataSource { + return &azureDevOpsRepositoryDataSource{} +} + +func (d *azureDevOpsRepositoryDataSource) Metadata( + _ context.Context, + req datasource.MetadataRequest, + resp *datasource.MetadataResponse, +) { + resp.TypeName = req.ProviderTypeName + "_azure_dev_ops_repository" +} + +func (d *azureDevOpsRepositoryDataSource) Read( + ctx context.Context, + req datasource.ReadRequest, + resp *datasource.ReadResponse, +) { + var state AzureDevopsRepositoryDataSourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &state)...) + + repositoryName := state.Name.ValueString() + azureDevOpsProjectID := state.AzureDevOpsProjectID.ValueString() + + azureDevOpsRepository, err := d.client.GetAzureDevOpsRepository(repositoryName, azureDevOpsProjectID) + + if err != nil { + resp.Diagnostics.AddError( + fmt.Sprintf("failed to get Azure Dev Ops repository %s in project %s", repositoryName, azureDevOpsProjectID), + err.Error(), + ) + } + + state.ID = types.StringValue(azureDevOpsRepository.ID) + state.Name = types.StringValue(azureDevOpsRepository.Name) + state.AzureDevOpsProjectID = types.StringValue(azureDevOpsProjectID) + state.DetailsURL = types.StringValue(azureDevOpsRepository.DetailsURL) + state.RemoteURL = types.StringValue(azureDevOpsRepository.RemoteURL) + state.WebURL = types.StringValue(azureDevOpsRepository.WebURL) + state.DefaultBranch = types.StringValue(azureDevOpsRepository.DefaultBranch) + + diags := resp.State.Set(ctx, &state) + resp.Diagnostics.Append(diags...) + + if resp.Diagnostics.HasError() { + return + } +} diff --git a/pkg/framework/objects/azure_dev_ops_repository/model.go b/pkg/framework/objects/azure_dev_ops_repository/model.go new file mode 100644 index 0000000..bcd0ef9 --- /dev/null +++ b/pkg/framework/objects/azure_dev_ops_repository/model.go @@ -0,0 +1,13 @@ +package azure_dev_ops_repository + +import "github.com/hashicorp/terraform-plugin-framework/types" + +type AzureDevopsRepositoryDataSourceModel struct { + ID types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + AzureDevOpsProjectID types.String `tfsdk:"azure_dev_ops_project_id"` + DetailsURL types.String `tfsdk:"details_url"` + RemoteURL types.String `tfsdk:"remote_url"` + WebURL types.String `tfsdk:"web_url"` + DefaultBranch types.String `tfsdk:"default_branch"` +} diff --git a/pkg/framework/objects/azure_dev_ops_repository/schema.go b/pkg/framework/objects/azure_dev_ops_repository/schema.go new file mode 100644 index 0000000..fc8334d --- /dev/null +++ b/pkg/framework/objects/azure_dev_ops_repository/schema.go @@ -0,0 +1,52 @@ +package azure_dev_ops_repository + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" +) + +func (d *azureDevOpsRepositoryDataSource) Schema( + _ context.Context, + _ datasource.SchemaRequest, + resp *datasource.SchemaResponse, +) { + resp.Schema = schema.Schema{ + Description: `Use this data source to retrieve the ID and details of an Azure Dev Ops repository +based on its name and the ID of the Azure Dev Ops project it belongs to. + +This data source requires connecting with a user token and doesn't work with a service token.`, + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + Description: "The internal Azure Dev Ops ID of the ADO Repository", + }, + "name": schema.StringAttribute{ + Required: true, + Description: "The name of the ADO repository", + }, + "azure_dev_ops_project_id": schema.StringAttribute{ + Required: true, + Description: "The internal Azure Dev Ops ID of the ADO Project. Can be retrieved using the data source dbtcloud_azure_dev_ops_project and the project name", + }, + "details_url": schema.StringAttribute{ + Computed: true, + Description: "The URL of the ADO repository showing details about the repository and its attributes", + }, + "remote_url": schema.StringAttribute{ + Computed: true, + Description: "The HTTP URL of the ADO repository used to connect to dbt Cloud", + }, + "web_url": schema.StringAttribute{ + Computed: true, + Description: "The URL of the ADO repository accessible in the browser", + }, + "default_branch": schema.StringAttribute{ + Computed: true, + Description: "The default branch of the ADO repository", + }, + }, + } + +} diff --git a/pkg/provider/framework_provider.go b/pkg/provider/framework_provider.go index 79e08c3..4b1f72a 100644 --- a/pkg/provider/framework_provider.go +++ b/pkg/provider/framework_provider.go @@ -7,6 +7,7 @@ import ( "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/dbt_cloud" "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/framework/objects/account_features" + "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/framework/objects/azure_dev_ops_repository" "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/framework/objects/environment" "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/framework/objects/global_connection" "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/framework/objects/group" @@ -181,6 +182,7 @@ func (p *dbtCloudProvider) Configure( func (p *dbtCloudProvider) DataSources(_ context.Context) []func() datasource.DataSource { return []func() datasource.DataSource{ + azure_dev_ops_repository.AzureDevOpsRepositoryDataSource, user.UserDataSource, user.UsersDataSource, notification.NotificationDataSource, diff --git a/pkg/provider/sdk_provider.go b/pkg/provider/sdk_provider.go index dc822a9..c55df13 100644 --- a/pkg/provider/sdk_provider.go +++ b/pkg/provider/sdk_provider.go @@ -36,23 +36,22 @@ func SDKProvider(version string) func() *schema.Provider { }, }, DataSourcesMap: map[string]*schema.Resource{ - "dbtcloud_job": data_sources.DatasourceJob(), - "dbtcloud_project": data_sources.DatasourceProject(), - "dbtcloud_environment_variable": data_sources.DatasourceEnvironmentVariable(), - "dbtcloud_snowflake_credential": data_sources.DatasourceSnowflakeCredential(), - "dbtcloud_bigquery_credential": data_sources.DatasourceBigQueryCredential(), - "dbtcloud_postgres_credential": data_sources.DatasourcePostgresCredential(), - "dbtcloud_databricks_credential": data_sources.DatasourceDatabricksCredential(), - "dbtcloud_connection": data_sources.DatasourceConnection(), - "dbtcloud_bigquery_connection": data_sources.DatasourceBigQueryConnection(), - "dbtcloud_repository": data_sources.DatasourceRepository(), - "dbtcloud_webhook": data_sources.DatasourceWebhook(), - "dbtcloud_privatelink_endpoint": data_sources.DatasourcePrivatelinkEndpoint(), - "dbtcloud_user_groups": data_sources.DatasourceUserGroups(), - "dbtcloud_extended_attributes": data_sources.DatasourceExtendedAttributes(), - "dbtcloud_group_users": data_sources.DatasourceGroupUsers(), - "dbtcloud_azure_dev_ops_project": data_sources.DatasourceAzureDevOpsProject(), - "dbtcloud_azure_dev_ops_repository": data_sources.DatasourceAzureDevOpsRepository(), + "dbtcloud_job": data_sources.DatasourceJob(), + "dbtcloud_project": data_sources.DatasourceProject(), + "dbtcloud_environment_variable": data_sources.DatasourceEnvironmentVariable(), + "dbtcloud_snowflake_credential": data_sources.DatasourceSnowflakeCredential(), + "dbtcloud_bigquery_credential": data_sources.DatasourceBigQueryCredential(), + "dbtcloud_postgres_credential": data_sources.DatasourcePostgresCredential(), + "dbtcloud_databricks_credential": data_sources.DatasourceDatabricksCredential(), + "dbtcloud_connection": data_sources.DatasourceConnection(), + "dbtcloud_bigquery_connection": data_sources.DatasourceBigQueryConnection(), + "dbtcloud_repository": data_sources.DatasourceRepository(), + "dbtcloud_webhook": data_sources.DatasourceWebhook(), + "dbtcloud_privatelink_endpoint": data_sources.DatasourcePrivatelinkEndpoint(), + "dbtcloud_user_groups": data_sources.DatasourceUserGroups(), + "dbtcloud_extended_attributes": data_sources.DatasourceExtendedAttributes(), + "dbtcloud_group_users": data_sources.DatasourceGroupUsers(), + "dbtcloud_azure_dev_ops_project": data_sources.DatasourceAzureDevOpsProject(), }, ResourcesMap: map[string]*schema.Resource{ "dbtcloud_job": resources.ResourceJob(), diff --git a/pkg/sdkv2/data_sources/azure_dev_ops_repository.go b/pkg/sdkv2/data_sources/azure_dev_ops_repository.go deleted file mode 100644 index cdd354d..0000000 --- a/pkg/sdkv2/data_sources/azure_dev_ops_repository.go +++ /dev/null @@ -1,102 +0,0 @@ -package data_sources - -import ( - "context" - - "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/dbt_cloud" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -var azureDevOpsRepositorySchema = map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "The internal Azure Dev Ops ID of the ADO Repository", - }, - "name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the ADO repository", - }, - "azure_dev_ops_project_id": { - Type: schema.TypeString, - Required: true, - Description: "The internal Azure Dev Ops ID of the ADO Project. Can be retrieved using the data source dbtcloud_azure_dev_ops_project and the project name", - }, - "details_url": { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the ADO repository showing details about the repository and its attributes", - }, - "remote_url": { - Type: schema.TypeString, - Computed: true, - Description: "The HTTP URL of the ADO repository used to connect to dbt Cloud", - }, - "web_url": { - Type: schema.TypeString, - Computed: true, - Description: "The URL of the ADO repository accessible in the browser", - }, - "default_branch": { - Type: schema.TypeString, - Computed: true, - Description: "The default branch of the ADO repository", - }, -} - -func DatasourceAzureDevOpsRepository() *schema.Resource { - return &schema.Resource{ - ReadContext: datasourceAzureDevOpsRepositoryRead, - Schema: azureDevOpsRepositorySchema, - Description: `Use this data source to retrieve the ID and details of an Azure Dev Ops repository -based on its name and the ID of the Azure Dev Ops project it belongs to. - -This data source requires connecting with a user token and doesn't work with a service token.`, - } -} - -func datasourceAzureDevOpsRepositoryRead( - ctx context.Context, - d *schema.ResourceData, - m interface{}, -) diag.Diagnostics { - c := m.(*dbt_cloud.Client) - - var diags diag.Diagnostics - - repositoryName := d.Get("name").(string) - azureDevOpsProjectID := d.Get("azure_dev_ops_project_id").(string) - - azureDevOpsRepository, err := c.GetAzureDevOpsRepository(repositoryName, azureDevOpsProjectID) - if err != nil { - return diag.FromErr(err) - } - - if err := d.Set("id", azureDevOpsRepository.ID); err != nil { - return diag.FromErr(err) - } - if err := d.Set("name", azureDevOpsRepository.Name); err != nil { - return diag.FromErr(err) - } - if err := d.Set("azure_dev_ops_project_id", azureDevOpsProjectID); err != nil { - return diag.FromErr(err) - } - if err := d.Set("details_url", azureDevOpsRepository.DetailsURL); err != nil { - return diag.FromErr(err) - } - if err := d.Set("remote_url", azureDevOpsRepository.RemoteURL); err != nil { - return diag.FromErr(err) - } - if err := d.Set("web_url", azureDevOpsRepository.WebURL); err != nil { - return diag.FromErr(err) - } - if err := d.Set("default_branch", azureDevOpsRepository.DefaultBranch); err != nil { - return diag.FromErr(err) - } - - d.SetId(azureDevOpsRepository.ID) - - return diags -} From 82f86b212a27aed25cb09c01dd88bedadfe7f383 Mon Sep 17 00:00:00 2001 From: Ashton Walden Date: Wed, 11 Dec 2024 08:46:03 -0800 Subject: [PATCH 2/3] Add Configure --- .../azure_dev_ops_repository/data_source.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pkg/framework/objects/azure_dev_ops_repository/data_source.go b/pkg/framework/objects/azure_dev_ops_repository/data_source.go index aeba0fe..637244a 100644 --- a/pkg/framework/objects/azure_dev_ops_repository/data_source.go +++ b/pkg/framework/objects/azure_dev_ops_repository/data_source.go @@ -61,3 +61,20 @@ func (d *azureDevOpsRepositoryDataSource) Read( return } } + +func (d *azureDevOpsRepositoryDataSource) Configure( + _ context.Context, + req datasource.ConfigureRequest, + resp *datasource.ConfigureResponse, +) { + switch c := req.ProviderData.(type) { + case nil: // do nothing + case *dbt_cloud.Client: + d.client = c + default: + resp.Diagnostics.AddError( + "Missing client", + "A client is required to configure the Azure DevOps repository data source", + ) + } +} From 2f2d98c47e0a78c32d81f7c7a2229fca0dc01730 Mon Sep 17 00:00:00 2001 From: Chase Walden Date: Thu, 12 Dec 2024 15:53:53 -0700 Subject: [PATCH 3/3] add acctest --- .../data_source_acceptance_test.go | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 pkg/framework/objects/azure_dev_ops_repository/data_source_acceptance_test.go diff --git a/pkg/framework/objects/azure_dev_ops_repository/data_source_acceptance_test.go b/pkg/framework/objects/azure_dev_ops_repository/data_source_acceptance_test.go new file mode 100644 index 0000000..58dfe2f --- /dev/null +++ b/pkg/framework/objects/azure_dev_ops_repository/data_source_acceptance_test.go @@ -0,0 +1,93 @@ +package azure_dev_ops_repository_test + +import ( + "os" + "testing" + + "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/framework/acctest_helper" + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccDbtCloudAzureDevOpsRepository(t *testing.T) { + //TODO: Remove both env var checks when this gets configurted in CI and the variables are parameterized + if os.Getenv("CI") != "" { + t.Skip("Skipping Azure DevOps Repository datasource test in CI " + + "until Azure integration and a personal access token are available") + } + + if os.Getenv("DBT_CLOUD_PERSONAL_ACCESS_TOKEN") == "" { + t.Skip("Skipping Azure DevOps Repository datasource because no personal access token is available") + } + + //TODO: Parameterize these values when a standard method is available for parameterization + adoProjectName := "dbt-cloud-ado-project" + adoRepoName := "dbt-cloud-ado-repo" + personalAccessToken := os.Getenv("DBT_CLOUD_PERSONAL_ACCESS_TOKEN") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest_helper.TestAccPreCheck(t) }, + + ProtoV6ProviderFactories: acctest_helper.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigVariables: config.Variables{ + "dbt_token": config.StringVariable(personalAccessToken), + "ado_project_name": config.StringVariable(adoProjectName), + "ado_repository_name": config.StringVariable(adoRepoName), + }, + Config: ` + variable "dbt_token" { + type = string + sensitive = true + } + + provider "dbtcloud" { + token = var.dbt_token + } + + variable "ado_project_name" { + type = string + } + + variable "ado_repository_name" { + type = string + } + + data dbtcloud_azure_dev_ops_project test { + name = var.ado_project_name + } + + data dbtcloud_azure_dev_ops_repository test { + name = var.ado_repository_name + azure_dev_ops_project_id = data.dbtcloud_azure_dev_ops_project.test.id + } + `, + // we check the computed values, for the other ones the test suite already checks that the plan and state are the same + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet( + "data.dbtcloud_azure_dev_ops_repository.test", + "id", + ), + resource.TestCheckResourceAttrSet( + "data.dbtcloud_azure_dev_ops_repository.test", + "details_url", + ), + resource.TestCheckResourceAttrSet( + "data.dbtcloud_azure_dev_ops_repository.test", + "remote_url", + ), + resource.TestCheckResourceAttrSet( + "data.dbtcloud_azure_dev_ops_repository.test", + "web_url", + ), + resource.TestCheckResourceAttrSet( + "data.dbtcloud_azure_dev_ops_repository.test", + "default_branch", + ), + ), + }, + }, + }) + +}