Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Migrate project artefact resource from SDKv2 to plugin framework #330

Merged
merged 4 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ terraform-provider*
autogen
TODO.md
NOTES.md
.DS_Store
.DS_Store
.env
2 changes: 1 addition & 1 deletion docs/resources/project_artefacts.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ resource "dbtcloud_project_artefacts" "my_project_artefacts" {

### Read-Only

- `id` (String) The ID of this resource.
- `id` (String) The ID of the project artefacts resource.

## Import

Expand Down
12 changes: 12 additions & 0 deletions pkg/framework/objects/project_artefacts/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package project_artefacts

import (
"github.com/hashicorp/terraform-plugin-framework/types"
)

type ProjectArtefactsResourceModel struct {
ID types.String `tfsdk:"id"`
ProjectID types.Int64 `tfsdk:"project_id"`
DocsJobID types.Int64 `tfsdk:"docs_job_id"`
FreshnessJobID types.Int64 `tfsdk:"freshness_job_id"`
}
238 changes: 238 additions & 0 deletions pkg/framework/objects/project_artefacts/resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
package project_artefacts

import (
"context"
"strconv"
"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"
)

var (
_ resource.Resource = &projectArtefactsResource{}
_ resource.ResourceWithConfigure = &projectArtefactsResource{}
_ resource.ResourceWithImportState = &projectArtefactsResource{}
)

type projectArtefactsResource struct {
client *dbt_cloud.Client
}

// ImportState implements resource.ResourceWithImportState.
func (p *projectArtefactsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
id_as_int, err := strconv.Atoi(req.ID)
if err != nil {
resp.Diagnostics.AddError("Invalid ID", "The ID must be an integer")
return
}
resp.State.SetAttribute(ctx, path.Root("id"), req.ID)
resp.State.SetAttribute(ctx, path.Root("project_id"), id_as_int)

}

// Configure implements resource.ResourceWithConfigure.
func (p *projectArtefactsResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
switch c := req.ProviderData.(type) {
case nil: // do nothing
case *dbt_cloud.Client:
p.client = c
default:
resp.Diagnostics.AddError("Missing client", "A client is required to configure the project artefacts resource")
}
}

// Create implements resource.Resource.
func (p *projectArtefactsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var plan ProjectArtefactsResourceModel

resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}

projectIDString := strconv.FormatInt(plan.ProjectID.ValueInt64(), 10)

project, err := p.client.GetProject(projectIDString)
if err != nil {
resp.Diagnostics.AddError(
"Unable to get project",
"Error: "+err.Error(),
)

return
}

if plan.DocsJobID.ValueInt64() != 0 {
conv := int(plan.DocsJobID.ValueInt64())
project.DocsJobId = &conv
} else {
project.DocsJobId = nil
}

if plan.FreshnessJobID.ValueInt64() != 0 {
conv := int(plan.FreshnessJobID.ValueInt64())
project.FreshnessJobId = &conv
} else {
project.FreshnessJobId = nil
}

if _, err := p.client.UpdateProject(projectIDString, *project); err != nil {
resp.Diagnostics.AddError(
"Unable to update project",
"Error: "+err.Error(),
)

return
}

plan.ID = types.StringValue(strconv.Itoa(*project.ID))

resp.Diagnostics.Append(resp.State.Set(ctx, plan)...)
}

// Delete implements resource.Resource.
func (p *projectArtefactsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var state ProjectArtefactsResourceModel

resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}

projectIDString := strconv.FormatInt(state.ProjectID.ValueInt64(), 10)

project, err := p.client.GetProject(projectIDString)
if err != nil {
resp.Diagnostics.AddError(
"Unable to get project",
"Error: "+err.Error(),
)

return
}

project.FreshnessJobId = nil
project.DocsJobId = nil

_, err = p.client.UpdateProject(projectIDString, *project)
if err != nil {
resp.Diagnostics.AddError(
"Unable to update project",
"Error: "+err.Error(),
)

return
}
}

// Metadata implements resource.Resource.
func (p *projectArtefactsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_project_artefacts"
}

// Read implements resource.Resource.
func (p *projectArtefactsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var state ProjectArtefactsResourceModel

resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}

projectIDString := strconv.FormatInt(state.ProjectID.ValueInt64(), 10)

project, err := p.client.GetProject(projectIDString)
if err != nil {
if strings.HasPrefix(err.Error(), "resource-not-found") {
resp.Diagnostics.AddError(
"Project not found",
"The project artefacts resource was not found and has been removed from the state.",
)
resp.State.RemoveResource(ctx)
return
}
resp.Diagnostics.AddError(
"Unable to get project",
"Error: "+err.Error(),
)

return
}

state.ID = types.StringValue(strconv.Itoa(*project.ID))
if project.DocsJobId != nil {
state.DocsJobID = types.Int64PointerValue(helper.IntPointerToInt64Pointer(project.DocsJobId))
}

if project.FreshnessJobId != nil {
state.FreshnessJobID = types.Int64PointerValue(helper.IntPointerToInt64Pointer(project.FreshnessJobId))
}

resp.Diagnostics.Append(resp.State.Set(ctx, state)...)

}

// Update implements resource.Resource.
func (p *projectArtefactsResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var plan, state ProjectArtefactsResourceModel

resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}

projectIDString := strconv.FormatInt(plan.ProjectID.ValueInt64(), 10)

project, err := p.client.GetProject(projectIDString)
if err != nil {
resp.Diagnostics.AddError(
"Unable to get project",
"Error: "+err.Error(),
)

return
}

if !state.DocsJobID.Equal(plan.DocsJobID) {
if plan.DocsJobID.ValueInt64() != 0 {
conv := int(plan.DocsJobID.ValueInt64())
project.DocsJobId = &conv
} else {
project.DocsJobId = nil
}
}

if !state.FreshnessJobID.Equal(plan.FreshnessJobID) {
if plan.FreshnessJobID.ValueInt64() != 0 {
conv := int(plan.FreshnessJobID.ValueInt64())
project.FreshnessJobId = &conv
} else {
project.FreshnessJobId = nil
}
}

project, err = p.client.UpdateProject(projectIDString, *project)

if err != nil {
resp.Diagnostics.AddError(
"Unable to update project",
"Error: "+err.Error(),
)

return
}

plan.DocsJobID = types.Int64PointerValue(helper.IntPointerToInt64Pointer(project.DocsJobId))
plan.FreshnessJobID = types.Int64PointerValue(helper.IntPointerToInt64Pointer(project.FreshnessJobId))

resp.Diagnostics.Append(resp.State.Set(ctx, plan)...)
}

func ProjectArtefactsResource() resource.Resource {
return &projectArtefactsResource{}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package resources_test
package project_artefacts_test

import (
"fmt"
Expand All @@ -19,7 +19,7 @@ func TestAccDbtCloudProjectArtefactsResource(t *testing.T) {
environmentName := 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,
CheckDestroy: testAccCheckDbtCloudProjectArtefactsDestroy,
Steps: []resource.TestStep{
Expand Down Expand Up @@ -89,7 +89,7 @@ resource "dbtcloud_project_artefacts" "test_project_artefacts" {
docs_job_id = dbtcloud_job.test_job.id
freshness_job_id = dbtcloud_job.test_job.id
}
`, projectName, environmentName, DBT_CLOUD_VERSION, jobName)
`, projectName, environmentName, acctest_helper.DBT_CLOUD_VERSION, jobName)
}

func testAccDbtCloudProjectArtefactsResourceEmptyConfig(projectName string) string {
Expand Down
47 changes: 47 additions & 0 deletions pkg/framework/objects/project_artefacts/schema.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package project_artefacts

import (
"context"

"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"
)

// Schema implements resource.Resource.
func (p *projectArtefactsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "[Deprecated] Resource for mentioning what jobs are the source of truth for the legacy dbt Docs and dbt Source Freshness pages. dbt Explorer doesn't require this config anymore.",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
Description: "The ID of the project artefacts resource.",
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"project_id": schema.Int64Attribute{
Description: "Project ID",
Required: true,
PlanModifiers: []planmodifier.Int64{
int64planmodifier.RequiresReplace(),
},
},
"docs_job_id": schema.Int64Attribute{
Description: "Docs Job ID",
Optional: true,
Computed: true,
Default: int64default.StaticInt64(0),
},
"freshness_job_id": schema.Int64Attribute{
Description: "Freshness Job ID",
Optional: true,
Computed: true,
Default: int64default.StaticInt64(0),
},
},
}
}
30 changes: 16 additions & 14 deletions pkg/provider/framework_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/dbt-labs/terraform-provider-dbtcloud/pkg/framework/objects/partial_license_map"
"github.com/dbt-labs/terraform-provider-dbtcloud/pkg/framework/objects/partial_notification"
"github.com/dbt-labs/terraform-provider-dbtcloud/pkg/framework/objects/project"
"github.com/dbt-labs/terraform-provider-dbtcloud/pkg/framework/objects/project_artefacts"
"github.com/dbt-labs/terraform-provider-dbtcloud/pkg/framework/objects/service_token"
"github.com/dbt-labs/terraform-provider-dbtcloud/pkg/framework/objects/user"

Expand Down Expand Up @@ -186,33 +187,34 @@ func (p *dbtCloudProvider) DataSources(_ context.Context) []func() datasource.Da
return []func() datasource.DataSource{
azure_dev_ops_project.AzureDevOpsProjectDataSource,
azure_dev_ops_repository.AzureDevOpsRepositoryDataSource,
user.UserDataSource,
user.UsersDataSource,
notification.NotificationDataSource,
environment.EnvironmentDataSource,
environment.EnvironmentsDataSource,
global_connection.GlobalConnectionDataSource,
global_connection.GlobalConnectionsDataSource,
group.GroupDataSource,
job.JobsDataSource,
service_token.ServiceTokenDataSource,
notification.NotificationDataSource,
project.ProjectsDataSource,
global_connection.GlobalConnectionDataSource,
global_connection.GlobalConnectionsDataSource,
service_token.ServiceTokenDataSource,
user.UserDataSource,
user.UsersDataSource,
}
}

func (p *dbtCloudProvider) Resources(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{
notification.NotificationResource,
account_features.AccountFeaturesResource,
global_connection.GlobalConnectionResource,
group_partial_permissions.GroupPartialPermissionsResource,
partial_notification.PartialNotificationResource,
partial_license_map.PartialLicenseMapResource,
group.GroupResource,
service_token.ServiceTokenResource,
global_connection.GlobalConnectionResource,
lineage_integration.LineageIntegrationResource,
oauth_configuration.OAuthConfigurationResource,
account_features.AccountFeaturesResource,
ip_restrictions_rule.IPRestrictionsRuleResource,
license_map.LicenseMapResource,
lineage_integration.LineageIntegrationResource,
notification.NotificationResource,
oauth_configuration.OAuthConfigurationResource,
partial_license_map.PartialLicenseMapResource,
partial_notification.PartialNotificationResource,
project_artefacts.ProjectArtefactsResource,
service_token.ServiceTokenResource,
}
}
Loading
Loading