Skip to content

Commit f443c01

Browse files
feat: add ownership field to blueprint (#193)
Add support to the new ownership field for blueprints
1 parent e85b0cc commit f443c01

File tree

6 files changed

+159
-2
lines changed

6 files changed

+159
-2
lines changed

bin/golangci-lint

27.3 MB
Binary file not shown.

internal/cli/models.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,11 @@ type (
201201
Path string `json:"path,omitempty"`
202202
}
203203

204+
Ownership struct {
205+
Type string `json:"type"`
206+
Path *string `json:"path,omitempty"`
207+
}
208+
204209
Step = struct {
205210
Title string `json:"title"`
206211
Order []string `json:"order"`
@@ -249,6 +254,7 @@ type (
249254
ChangelogDestination *ChangelogDestination `json:"changelogDestination,omitempty"`
250255
TeamInheritance *TeamInheritance `json:"teamInheritance,omitempty"`
251256
Relations map[string]Relation `json:"relations"`
257+
Ownership *Ownership `json:"ownership,omitempty"`
252258
}
253259

254260
Action struct {

port/blueprint/model.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ type TeamInheritanceModel struct {
1212
Path types.String `tfsdk:"path"`
1313
}
1414

15+
type OwnershipModel struct {
16+
Type types.String `tfsdk:"type"`
17+
Path types.String `tfsdk:"path"`
18+
}
19+
1520
type SpecAuthenticationModel struct {
1621
AuthorizationUrl types.String `tfsdk:"authorization_url"`
1722
TokenUrl types.String `tfsdk:"token_url"`
@@ -176,4 +181,5 @@ type BlueprintModel struct {
176181
CalculationProperties map[string]CalculationPropertyModel `tfsdk:"calculation_properties"`
177182
ForceDeleteEntities types.Bool `tfsdk:"force_delete_entities"`
178183
CreateCatalogPage types.Bool `tfsdk:"create_catalog_page"`
184+
Ownership *OwnershipModel `tfsdk:"ownership"`
179185
}

port/blueprint/resource.go

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@ package blueprint
33
import (
44
"context"
55
"fmt"
6+
"strings"
7+
"time"
8+
69
"github.com/hashicorp/terraform-plugin-framework/path"
710
"github.com/hashicorp/terraform-plugin-framework/resource"
811
"github.com/hashicorp/terraform-plugin-framework/types"
912
"github.com/hashicorp/terraform-plugin-log/tflog"
1013
"github.com/port-labs/terraform-provider-port-labs/v2/internal/cli"
1114
"github.com/port-labs/terraform-provider-port-labs/v2/internal/consts"
1215
"github.com/port-labs/terraform-provider-port-labs/v2/internal/flex"
13-
"strings"
14-
"time"
1516
)
1617

1718
var _ resource.Resource = &BlueprintResource{}
@@ -103,6 +104,15 @@ func refreshBlueprintState(ctx context.Context, bm *BlueprintModel, b *cli.Bluep
103104
}
104105
}
105106

107+
if b.Ownership != nil {
108+
bm.Ownership = &OwnershipModel{
109+
Type: types.StringValue(b.Ownership.Type),
110+
}
111+
if b.Ownership.Path != nil {
112+
bm.Ownership.Path = types.StringValue(*b.Ownership.Path)
113+
}
114+
}
115+
106116
if len(b.Schema.Properties) > 0 {
107117
err := updatePropertiesToState(ctx, b, bm)
108118
if err != nil {
@@ -335,6 +345,22 @@ func blueprintResourceToPortRequest(ctx context.Context, state *BlueprintModel)
335345
}
336346
}
337347

348+
if state.Ownership != nil && !state.Ownership.Type.IsNull() {
349+
ownershipType := state.Ownership.Type.ValueString()
350+
if ownershipType == "Inherited" && state.Ownership.Path.IsNull() {
351+
return nil, fmt.Errorf("path is required when ownership type is Inherited")
352+
}
353+
354+
ownership := &cli.Ownership{
355+
Type: ownershipType,
356+
}
357+
if !state.Ownership.Path.IsNull() {
358+
path := state.Ownership.Path.ValueString()
359+
ownership.Path = &path
360+
}
361+
b.Ownership = ownership
362+
}
363+
338364
required := []string{}
339365
props := map[string]cli.BlueprintProperty{}
340366
var err error

port/blueprint/resource_test.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,103 @@ func TestAccPortDestroyDeleteAllEntities(t *testing.T) {
832832
})
833833
}
834834

835+
// Commented out until we have a way to mock feature flags in Terraform tests
836+
// func TestAccPortBlueprintOwnership(t *testing.T) {
837+
// parentIdentifier := utils.GenID()
838+
// var testAccConfigDirect = fmt.Sprintf(`
839+
// resource "port_blueprint" "parent_blueprint" {
840+
// title = "Parent Blueprint"
841+
// icon = "Terraform"
842+
// identifier = "%s"
843+
// properties = {
844+
// string_props = {
845+
// team = {
846+
// type = "string"
847+
// format = "team"
848+
// title = "Team"
849+
// }
850+
// }
851+
// }
852+
// ownership = {
853+
// type = "Direct"
854+
// }
855+
// }
856+
// `, parentIdentifier)
857+
858+
// childIdentifier := utils.GenID()
859+
// var testAccConfigInherited = fmt.Sprintf(`
860+
// resource "port_blueprint" "parent_blueprint" {
861+
// title = "Parent Blueprint"
862+
// icon = "Terraform"
863+
// identifier = "%s"
864+
// properties = {
865+
// string_props = {
866+
// team = {
867+
// type = "string"
868+
// format = "team"
869+
// title = "Team"
870+
// }
871+
// }
872+
// }
873+
// ownership = {
874+
// type = "Direct"
875+
// }
876+
// }
877+
878+
// resource "port_blueprint" "child_blueprint" {
879+
// title = "Child Blueprint"
880+
// icon = "Terraform"
881+
// identifier = "%s"
882+
// properties = {
883+
// string_props = {
884+
// team = {
885+
// type = "string"
886+
// format = "team"
887+
// title = "Team"
888+
// }
889+
// }
890+
// }
891+
// relations = {
892+
// parent = {
893+
// target = port_blueprint.parent_blueprint.identifier
894+
// title = "Parent Service"
895+
// required = false
896+
// many = false
897+
// }
898+
// }
899+
// ownership = {
900+
// type = "Inherited"
901+
// path = "parent"
902+
// }
903+
// }
904+
// `, parentIdentifier, childIdentifier)
905+
906+
// resource.Test(t, resource.TestCase{
907+
// PreCheck: func() { acctest.TestAccPreCheck(t) },
908+
// ProtoV6ProviderFactories: acctest.TestAccProtoV6ProviderFactories,
909+
// Steps: []resource.TestStep{
910+
// {
911+
// Config: acctest.ProviderConfig + testAccConfigDirect,
912+
// Check: resource.ComposeTestCheckFunc(
913+
// resource.TestCheckResourceAttr("port_blueprint.parent_blueprint", "title", "Parent Blueprint"),
914+
// resource.TestCheckResourceAttr("port_blueprint.parent_blueprint", "identifier", parentIdentifier),
915+
// resource.TestCheckResourceAttr("port_blueprint.parent_blueprint", "ownership.type", "Direct"),
916+
// resource.TestCheckNoResourceAttr("port_blueprint.parent_blueprint", "ownership.path"),
917+
// ),
918+
// },
919+
// {
920+
// Config: acctest.ProviderConfig + testAccConfigInherited,
921+
// Check: resource.ComposeTestCheckFunc(
922+
// resource.TestCheckResourceAttr("port_blueprint.child_blueprint", "title", "Child Blueprint"),
923+
// resource.TestCheckResourceAttr("port_blueprint.child_blueprint", "identifier", childIdentifier),
924+
// resource.TestCheckResourceAttr("port_blueprint.child_blueprint", "ownership.type", "Inherited"),
925+
// resource.TestCheckResourceAttr("port_blueprint.child_blueprint", "ownership.path", "parent"),
926+
// ),
927+
// },
928+
// },
929+
// })
930+
// }
931+
835932
func TestAccPortBlueprintCatalogPageCreation(t *testing.T) {
836933
testCases := []struct {
837934
name string

port/blueprint/schema.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,27 @@ func ArrayPropertySchema() schema.MapNestedAttribute {
253253
}
254254
}
255255

256+
func OwnershipSchema() schema.Attribute {
257+
return schema.SingleNestedAttribute{
258+
MarkdownDescription: "Optional ownership field for Blueprint. 'type' can be Inherited or Direct. If 'Inherited', then 'path' is required and must be a valid relation identifiers path.",
259+
Optional: true,
260+
261+
Attributes: map[string]schema.Attribute{
262+
"type": schema.StringAttribute{
263+
MarkdownDescription: "Ownership type: either 'Inherited' or 'Direct'.",
264+
Required: true,
265+
Validators: []validator.String{
266+
stringvalidator.OneOf("Inherited", "Direct"),
267+
},
268+
},
269+
"path": schema.StringAttribute{
270+
MarkdownDescription: "Path for the Inherited ownership type. Required when type is 'Inherited'. Must be a valid relation identifiers path.",
271+
Optional: true,
272+
},
273+
},
274+
}
275+
}
276+
256277
func ObjectPropertySchema() schema.MapNestedAttribute {
257278

258279
objectPropertySchema := map[string]schema.Attribute{
@@ -464,6 +485,7 @@ func BlueprintSchema() map[string]schema.Attribute {
464485
Computed: true,
465486
Default: booldefault.StaticBool(true),
466487
},
488+
"ownership": OwnershipSchema(),
467489
}
468490
}
469491

0 commit comments

Comments
 (0)