Skip to content

Commit

Permalink
Merge pull request #330 from dbt-labs/awalden/migrate-project-artefacts
Browse files Browse the repository at this point in the history
  • Loading branch information
ashtonwalden authored Dec 23, 2024
2 parents 253e9aa + 32bd23f commit fd8f238
Show file tree
Hide file tree
Showing 9 changed files with 319 additions and 218 deletions.
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

0 comments on commit fd8f238

Please sign in to comment.