diff --git a/docs/resources/port_action.md b/docs/resources/port_action.md
index c4d1bf1d..b1daa57c 100644
--- a/docs/resources/port_action.md
+++ b/docs/resources/port_action.md
@@ -3,12 +3,376 @@
page_title: "port_action Resource - terraform-provider-port-labs"
subcategory: ""
description: |-
- Action resource
+ Action
+ This resource allows you to manage self-service action.
+ See the Port documentation https://docs.getport.io/create-self-service-experiences/ for more information about self-service actions.
+ Example Usage
+ Create a blueprint and an action relating to that blueprint which triggers a github workflow:
+ ```hcl
+ resource "portblueprint" "myBlueprint" {
+ icon = "Terraform"
+ identifier = "myBlueprint"
+ title = "My Blueprint"
+ properties = {
+ numberprops = {
+ "numberProp" = {
+ title = "Number Property"
+ required = false
+ }
+ }
+ }
+ }
+ resource "portaction" "myAction" {
+ title = "My Action"
+ blueprint = portblueprint.myBlueprint.identifier
+ identifier = "myAction"
+ trigger = "CREATE"
+ requiredapproval = false
+ githubmethod = {
+ org = "your-org"
+ repo = "your-repo"
+ workflow = "your-workflow"
+ }
+ userproperties = {
+ stringprops = {
+ stringValue = {
+ title = "String Value"
+ }
+ }
+ number_props = {
+ "numberProp" = {
+ title = "Number Value"
+ required = true
+ }
+ }
+ }
+ }
+ ```
+ Create related "parent" and "child" blueprints and a CREATE action for the child blueprint with user inputs to select entities from the parent blueprint and triggers a github workflow:
+ ```hcl
+ resource "port_blueprint" "parent" {
+ icon = "Terraform"
+ title = "Parent"
+ identifier = "parent"
+ properties = {}
+ }
+ resource "portblueprint" "child" {
+ icon = "Terraform"
+ title = "Child"
+ identifier = "child"
+ properties = {}
+ relations = {
+ "childOf" = {
+ title = "Child Of"
+ many = true
+ required = false
+ target = portblueprint.parent.identifier
+ }
+ }
+ }
+ resource "portaction" "myAction" {
+ title = "My Action"
+ blueprint = portblueprint.child.identifier
+ identifier = "myAction"
+ trigger = "CREATE"
+ requiredapproval = false
+ githubmethod = {
+ org = "your-org"
+ repo = "your-repo"
+ workflow = "your-workflow"
+ }
+ userproperties = {
+ stringprops = {
+ singleParent = {
+ title = "Single Parent Entity Selection"
+ format = "entity"
+ blueprint = portblueprint.parent.identifier
+ }
+ }
+ arrayprops = {
+ miltipleParents = {
+ title = "Single Parent Entity Selection"
+ stringitems = {
+ format = "entity"
+ blueprint = portblueprint.parent.identifier
+ }
+ }
+ }
+ }
+ }
+ ```
+ Create the same resources as in the previous example, but the action's entity selection properties will only allow entities which pass the datasets:
+ ```hcl
+ resource "port_blueprint" "parent" {
+ icon = "Terraform"
+ title = "Parent"
+ identifier = "parent"
+ properties = {}
+ }
+ resource "portblueprint" "child" {
+ icon = "Terraform"
+ title = "Child"
+ identifier = "child"
+ properties = {}
+ relations = {
+ "childOf" = {
+ title = "Child Of"
+ many = true
+ required = false
+ target = portblueprint.parent.identifier
+ }
+ }
+ }
+ resource "portaction" "myAction" {
+ title = "My Action"
+ blueprint = portblueprint.child.identifier
+ identifier = "myAction"
+ trigger = "CREATE"
+ requiredapproval = false
+ githubmethod = {
+ org = "your-org"
+ repo = "your-repo"
+ workflow = "your-workflow"
+ omitpayload = true
+ omituserinputs = true
+ reportworkflowstatus = true
+ }
+ userproperties = {
+ stringprops = {
+ singleParent = {
+ title = "Single Parent Entity Selection"
+ format = "entity"
+ blueprint = portblueprint.parent.identifier
+ dataset = {
+ combinator = "and"
+ rules = [{
+ property = "$title"
+ operator = "contains"
+ value = {
+ jqquery = "\"specificValue\""
+ }
+ }]
+ }
+ }
+ }
+ arrayprops = {
+ miltipleParents = {
+ title = "Single Parent Entity Selection"
+ stringitems = {
+ format = "entity"
+ blueprint = portblueprint.parent.identifier
+ dataset = jsonencode({
+ combinator = "and"
+ rules = [{
+ property = "$title"
+ operator = "contains"
+ value = "specificValue"
+ }]
+ })
+ }
+ }
+ }
+ }
+ }
+ ```
---
# port_action (Resource)
-Action resource
+# Action
+
+This resource allows you to manage self-service action.
+
+See the [Port documentation](https://docs.getport.io/create-self-service-experiences/) for more information about self-service actions.
+
+## Example Usage
+
+Create a blueprint and an action relating to that blueprint which triggers a github workflow:
+
+```hcl
+
+resource "port_blueprint" "myBlueprint" {
+ icon = "Terraform"
+ identifier = "myBlueprint"
+ title = "My Blueprint"
+ properties = {
+ number_props = {
+ "numberProp" = {
+ title = "Number Property"
+ required = false
+ }
+ }
+ }
+}
+
+resource "port_action" "myAction" {
+ title = "My Action"
+ blueprint = port_blueprint.myBlueprint.identifier
+ identifier = "myAction"
+ trigger = "CREATE"
+ required_approval = false
+ github_method = {
+ org = "your-org"
+ repo = "your-repo"
+ workflow = "your-workflow"
+ }
+ user_properties = {
+ string_props = {
+ stringValue = {
+ title = "String Value"
+ }
+ }
+ number_props = {
+ "numberProp" = {
+ title = "Number Value"
+ required = true
+ }
+ }
+ }
+}
+
+```
+
+Create related "parent" and "child" blueprints and a CREATE action for the child blueprint with user inputs to select entities from the parent blueprint and triggers a github workflow:
+
+```hcl
+
+
+resource "port_blueprint" "parent" {
+ icon = "Terraform"
+ title = "Parent"
+ identifier = "parent"
+ properties = {}
+}
+
+resource "port_blueprint" "child" {
+ icon = "Terraform"
+ title = "Child"
+ identifier = "child"
+ properties = {}
+ relations = {
+ "childOf" = {
+ title = "Child Of"
+ many = true
+ required = false
+ target = port_blueprint.parent.identifier
+ }
+ }
+}
+
+resource "port_action" "myAction" {
+ title = "My Action"
+ blueprint = port_blueprint.child.identifier
+ identifier = "myAction"
+ trigger = "CREATE"
+ required_approval = false
+ github_method = {
+ org = "your-org"
+ repo = "your-repo"
+ workflow = "your-workflow"
+ }
+ user_properties = {
+ string_props = {
+ singleParent = {
+ title = "Single Parent Entity Selection"
+ format = "entity"
+ blueprint = port_blueprint.parent.identifier
+ }
+ }
+ array_props = {
+ miltipleParents = {
+ title = "Single Parent Entity Selection"
+ string_items = {
+ format = "entity"
+ blueprint = port_blueprint.parent.identifier
+ }
+ }
+ }
+ }
+}
+
+```
+
+
+Create the same resources as in the previous example, but the action's entity selection properties will only allow entities which pass the `dataset`s:
+
+```hcl
+
+resource "port_blueprint" "parent" {
+ icon = "Terraform"
+ title = "Parent"
+ identifier = "parent"
+ properties = {}
+}
+
+resource "port_blueprint" "child" {
+ icon = "Terraform"
+ title = "Child"
+ identifier = "child"
+ properties = {}
+ relations = {
+ "childOf" = {
+ title = "Child Of"
+ many = true
+ required = false
+ target = port_blueprint.parent.identifier
+ }
+ }
+}
+
+resource "port_action" "myAction" {
+ title = "My Action"
+ blueprint = port_blueprint.child.identifier
+ identifier = "myAction"
+ trigger = "CREATE"
+ required_approval = false
+ github_method = {
+ org = "your-org"
+ repo = "your-repo"
+ workflow = "your-workflow"
+ omit_payload = true
+ omit_user_inputs = true
+ report_workflow_status = true
+ }
+ user_properties = {
+ string_props = {
+ singleParent = {
+ title = "Single Parent Entity Selection"
+ format = "entity"
+ blueprint = port_blueprint.parent.identifier
+ dataset = {
+ combinator = "and"
+ rules = [{
+ property = "$title"
+ operator = "contains"
+ value = {
+ jq_query = "\"specificValue\""
+ }
+ }]
+ }
+ }
+ }
+ array_props = {
+ miltipleParents = {
+ title = "Single Parent Entity Selection"
+ string_items = {
+ format = "entity"
+ blueprint = port_blueprint.parent.identifier
+ dataset = jsonencode({
+ combinator = "and"
+ rules = [{
+ property = "$title"
+ operator = "contains"
+ value = "specificValue"
+ }]
+ })
+ }
+ }
+ }
+ }
+}
+
+```
@@ -126,7 +490,6 @@ Optional:
Optional:
- `boolean_items` (Attributes) The items of the array property (see [below for nested schema](#nestedatt--user_properties--array_props--boolean_items))
-- `dataset` (Attributes) The dataset of the property (see [below for nested schema](#nestedatt--user_properties--array_props--dataset))
- `default_jq_query` (String) The default jq query of the array property
- `depends_on` (List of String) The properties that this property depends on
- `description` (String) The description of the property
@@ -149,37 +512,6 @@ Optional:
- `default` (List of Boolean) The default of the items
-
-### Nested Schema for `user_properties.array_props.dataset`
-
-Required:
-
-- `combinator` (String) The combinator of the dataset
-- `rules` (Attributes List) The rules of the dataset (see [below for nested schema](#nestedatt--user_properties--array_props--dataset--rules))
-
-
-### Nested Schema for `user_properties.array_props.dataset.rules`
-
-Required:
-
-- `operator` (String) The operator of the rule
-- `value` (Object) The value of the rule (see [below for nested schema](#nestedatt--user_properties--array_props--dataset--rules--value))
-
-Optional:
-
-- `blueprint` (String) The blueprint identifier of the rule
-- `property` (String) The property identifier of the rule
-
-
-### Nested Schema for `user_properties.array_props.dataset.rules.value`
-
-Optional:
-
-- `jq_query` (String)
-
-
-
-
### Nested Schema for `user_properties.array_props.number_items`
@@ -204,6 +536,7 @@ Optional:
Optional:
- `blueprint` (String) The blueprint identifier the property relates to
+- `dataset` (String) The dataset of an the entity-format items
- `default` (List of String) The default of the items
- `enum` (List of String) The enum of the items
- `enum_jq_query` (String) The enum jq query of the string items
@@ -216,7 +549,6 @@ Optional:
Optional:
-- `dataset` (Attributes) The dataset of the property (see [below for nested schema](#nestedatt--user_properties--boolean_props--dataset))
- `default` (Boolean) The default of the boolean property
- `default_jq_query` (String) The default jq query of the boolean property
- `depends_on` (List of String) The properties that this property depends on
@@ -227,44 +559,12 @@ Optional:
- `visible` (Boolean) The visibility of the boolean property
- `visible_jq_query` (String) The visibility condition jq query of the boolean property
-
-### Nested Schema for `user_properties.boolean_props.dataset`
-
-Required:
-
-- `combinator` (String) The combinator of the dataset
-- `rules` (Attributes List) The rules of the dataset (see [below for nested schema](#nestedatt--user_properties--boolean_props--dataset--rules))
-
-
-### Nested Schema for `user_properties.boolean_props.dataset.rules`
-
-Required:
-
-- `operator` (String) The operator of the rule
-- `value` (Object) The value of the rule (see [below for nested schema](#nestedatt--user_properties--boolean_props--dataset--rules--value))
-
-Optional:
-
-- `blueprint` (String) The blueprint identifier of the rule
-- `property` (String) The property identifier of the rule
-
-
-### Nested Schema for `user_properties.boolean_props.dataset.rules.value`
-
-Optional:
-
-- `jq_query` (String)
-
-
-
-
### Nested Schema for `user_properties.number_props`
Optional:
-- `dataset` (Attributes) The dataset of the property (see [below for nested schema](#nestedatt--user_properties--number_props--dataset))
- `default` (Number) The default of the number property
- `default_jq_query` (String) The default jq query of the number property
- `depends_on` (List of String) The properties that this property depends on
@@ -279,44 +579,12 @@ Optional:
- `visible` (Boolean) The visibility of the number property
- `visible_jq_query` (String) The visibility condition jq query of the number property
-
-### Nested Schema for `user_properties.number_props.dataset`
-
-Required:
-
-- `combinator` (String) The combinator of the dataset
-- `rules` (Attributes List) The rules of the dataset (see [below for nested schema](#nestedatt--user_properties--number_props--dataset--rules))
-
-
-### Nested Schema for `user_properties.number_props.dataset.rules`
-
-Required:
-
-- `operator` (String) The operator of the rule
-- `value` (Object) The value of the rule (see [below for nested schema](#nestedatt--user_properties--number_props--dataset--rules--value))
-
-Optional:
-
-- `blueprint` (String) The blueprint identifier of the rule
-- `property` (String) The property identifier of the rule
-
-
-### Nested Schema for `user_properties.number_props.dataset.rules.value`
-
-Optional:
-
-- `jq_query` (String)
-
-
-
-
### Nested Schema for `user_properties.object_props`
Optional:
-- `dataset` (Attributes) The dataset of the property (see [below for nested schema](#nestedatt--user_properties--object_props--dataset))
- `default` (String) The default of the object property
- `default_jq_query` (String) The default jq query of the object property
- `depends_on` (List of String) The properties that this property depends on
@@ -328,37 +596,6 @@ Optional:
- `visible` (Boolean) The visibility of the object property
- `visible_jq_query` (String) The visibility condition jq query of the object property
-
-### Nested Schema for `user_properties.object_props.dataset`
-
-Required:
-
-- `combinator` (String) The combinator of the dataset
-- `rules` (Attributes List) The rules of the dataset (see [below for nested schema](#nestedatt--user_properties--object_props--dataset--rules))
-
-
-### Nested Schema for `user_properties.object_props.dataset.rules`
-
-Required:
-
-- `operator` (String) The operator of the rule
-- `value` (Object) The value of the rule (see [below for nested schema](#nestedatt--user_properties--object_props--dataset--rules--value))
-
-Optional:
-
-- `blueprint` (String) The blueprint identifier of the rule
-- `property` (String) The property identifier of the rule
-
-
-### Nested Schema for `user_properties.object_props.dataset.rules.value`
-
-Optional:
-
-- `jq_query` (String)
-
-
-
-
### Nested Schema for `user_properties.string_props`
@@ -366,7 +603,7 @@ Optional:
Optional:
- `blueprint` (String) The blueprint identifier the string property relates to
-- `dataset` (Attributes) The dataset of the property (see [below for nested schema](#nestedatt--user_properties--string_props--dataset))
+- `dataset` (Attributes) The dataset of an the entity-format property (see [below for nested schema](#nestedatt--user_properties--string_props--dataset))
- `default` (String) The default of the string property
- `default_jq_query` (String) The default jq query of the string property
- `depends_on` (List of String) The properties that this property depends on
diff --git a/internal/utils/utils.go b/internal/utils/utils.go
index f012d021..f1407731 100644
--- a/internal/utils/utils.go
+++ b/internal/utils/utils.go
@@ -85,6 +85,19 @@ func GoObjectToTerraformString(v interface{}) (types.String, error) {
return types.StringValue(value), nil
}
+func TerraformJsonStringToGoObject(v *string) (*map[string]any, error) {
+ if v == nil || *v == "" {
+ return nil, nil
+ }
+
+ vMap := make(map[string]any)
+ if err := json.Unmarshal([]byte(*v), &vMap); err != nil {
+ return nil, err
+ }
+
+ return &vMap, nil
+}
+
func InterfaceToStringArray(o interface{}) []string {
items := o.([]interface{})
res := make([]string, len(items))
diff --git a/port/action-permissions/actionPermissionToPortBody.go b/port/action-permissions/actionPermissionToPortBody.go
index d5d996a9..00d93904 100644
--- a/port/action-permissions/actionPermissionToPortBody.go
+++ b/port/action-permissions/actionPermissionToPortBody.go
@@ -1,27 +1,11 @@
package action_permissions
import (
- "encoding/json"
"github.com/port-labs/terraform-provider-port-labs/internal/cli"
"github.com/port-labs/terraform-provider-port-labs/internal/flex"
+ "github.com/port-labs/terraform-provider-port-labs/internal/utils"
)
-func policyToPortBody(policy *string) (*map[string]any, error) {
- // if policy is empty, set it to nil, so it will override the existing policy on server,
- // as opposed to merging it, due to only having a PATCH endpoint
-
- if policy == nil || *policy == "" {
- return nil, nil
- }
-
- policyMap := make(map[string]any)
- if err := json.Unmarshal([]byte(*policy), &policyMap); err != nil {
- return nil, err
- }
-
- return &policyMap, nil
-}
-
func actionPermissionsToPortBody(state *PermissionsModel) (*cli.ActionPermissions, error) {
if state == nil {
return nil, nil
@@ -41,12 +25,12 @@ func actionPermissionsToPortBody(state *PermissionsModel) (*cli.ActionPermission
},
}
- approvePolicyMap, err := policyToPortBody(state.Approve.Policy.ValueStringPointer())
+ approvePolicyMap, err := utils.TerraformJsonStringToGoObject(state.Approve.Policy.ValueStringPointer())
if err != nil {
return nil, err
}
- executePolicyMap, err := policyToPortBody(state.Execute.Policy.ValueStringPointer())
+ executePolicyMap, err := utils.TerraformJsonStringToGoObject(state.Execute.Policy.ValueStringPointer())
if err != nil {
return nil, err
}
diff --git a/port/action/array.go b/port/action/array.go
index 24dafd10..c4149107 100644
--- a/port/action/array.go
+++ b/port/action/array.go
@@ -38,6 +38,15 @@ func handleArrayItemsToBody(ctx context.Context, property *cli.ActionProperty, p
items["enum"] = enumList
}
+ if !prop.StringItems.Dataset.IsNull() {
+ v, err := utils.TerraformJsonStringToGoObject(prop.StringItems.Dataset.ValueStringPointer())
+ if err != nil {
+ return err
+ }
+
+ items["dataset"] = v
+ }
+
if !prop.StringItems.Format.IsNull() {
items["format"] = prop.StringItems.Format.ValueString()
}
@@ -165,9 +174,6 @@ func arrayPropResourceToBody(ctx context.Context, d *ActionModel, props map[stri
property.DependsOn = utils.InterfaceToStringArray(dependsOn)
}
- if prop.Dataset != nil {
- property.Dataset = actionDataSetToPortBody(prop.Dataset)
- }
err := handleArrayItemsToBody(ctx, &property, prop, required)
if err != nil {
@@ -233,6 +239,13 @@ func addArrayPropertiesToResource(v *cli.ActionProperty) (*ArrayPropModel, error
if value, ok := v.Items["blueprint"]; ok && value != nil {
arrayProp.StringItems.Blueprint = types.StringValue(v.Items["blueprint"].(string))
}
+ if value, ok := v.Items["dataset"]; ok && value != nil {
+ ds, err := utils.GoObjectToTerraformString(v.Items["dataset"])
+ if err != nil {
+ return nil, err
+ }
+ arrayProp.StringItems.Dataset = ds
+ }
if value, ok := v.Items["enum"]; ok && value != nil {
v := reflect.ValueOf(value)
diff --git a/port/action/boolean.go b/port/action/boolean.go
index 1b5b7263..51a95457 100644
--- a/port/action/boolean.go
+++ b/port/action/boolean.go
@@ -49,9 +49,6 @@ func booleanPropResourceToBody(ctx context.Context, d *ActionModel, props map[st
property.DependsOn = utils.InterfaceToStringArray(dependsOn)
}
- if prop.Dataset != nil {
- property.Dataset = actionDataSetToPortBody(prop.Dataset)
- }
if !prop.Visible.IsNull() {
property.Visible = prop.Visible.ValueBoolPointer()
diff --git a/port/action/model.go b/port/action/model.go
index ca017c73..5123375b 100644
--- a/port/action/model.go
+++ b/port/action/model.go
@@ -71,15 +71,14 @@ type StringPropModel struct {
}
type NumberPropModel struct {
- Title types.String `tfsdk:"title"`
- Icon types.String `tfsdk:"icon"`
- Description types.String `tfsdk:"description"`
- Required types.Bool `tfsdk:"required"`
- DependsOn types.List `tfsdk:"depends_on"`
- Dataset *DatasetModel `tfsdk:"dataset"`
- DefaultJqQuery types.String `tfsdk:"default_jq_query"`
- Visible types.Bool `tfsdk:"visible"`
- VisibleJqQuery types.String `tfsdk:"visible_jq_query"`
+ Title types.String `tfsdk:"title"`
+ Icon types.String `tfsdk:"icon"`
+ Description types.String `tfsdk:"description"`
+ Required types.Bool `tfsdk:"required"`
+ DependsOn types.List `tfsdk:"depends_on"`
+ DefaultJqQuery types.String `tfsdk:"default_jq_query"`
+ Visible types.Bool `tfsdk:"visible"`
+ VisibleJqQuery types.String `tfsdk:"visible_jq_query"`
Default types.Float64 `tfsdk:"default"`
Maximum types.Float64 `tfsdk:"maximum"`
@@ -89,29 +88,27 @@ type NumberPropModel struct {
}
type BooleanPropModel struct {
- Title types.String `tfsdk:"title"`
- Icon types.String `tfsdk:"icon"`
- Description types.String `tfsdk:"description"`
- Required types.Bool `tfsdk:"required"`
- DependsOn types.List `tfsdk:"depends_on"`
- Dataset *DatasetModel `tfsdk:"dataset"`
- DefaultJqQuery types.String `tfsdk:"default_jq_query"`
- Visible types.Bool `tfsdk:"visible"`
- VisibleJqQuery types.String `tfsdk:"visible_jq_query"`
+ Title types.String `tfsdk:"title"`
+ Icon types.String `tfsdk:"icon"`
+ Description types.String `tfsdk:"description"`
+ Required types.Bool `tfsdk:"required"`
+ DependsOn types.List `tfsdk:"depends_on"`
+ DefaultJqQuery types.String `tfsdk:"default_jq_query"`
+ Visible types.Bool `tfsdk:"visible"`
+ VisibleJqQuery types.String `tfsdk:"visible_jq_query"`
Default types.Bool `tfsdk:"default"`
}
type ArrayPropModel struct {
- Title types.String `tfsdk:"title"`
- Icon types.String `tfsdk:"icon"`
- Description types.String `tfsdk:"description"`
- Required types.Bool `tfsdk:"required"`
- DependsOn types.List `tfsdk:"depends_on"`
- Dataset *DatasetModel `tfsdk:"dataset"`
- DefaultJqQuery types.String `tfsdk:"default_jq_query"`
- Visible types.Bool `tfsdk:"visible"`
- VisibleJqQuery types.String `tfsdk:"visible_jq_query"`
+ Title types.String `tfsdk:"title"`
+ Icon types.String `tfsdk:"icon"`
+ Description types.String `tfsdk:"description"`
+ Required types.Bool `tfsdk:"required"`
+ DependsOn types.List `tfsdk:"depends_on"`
+ DefaultJqQuery types.String `tfsdk:"default_jq_query"`
+ Visible types.Bool `tfsdk:"visible"`
+ VisibleJqQuery types.String `tfsdk:"visible_jq_query"`
MaxItems types.Int64 `tfsdk:"max_items"`
MinItems types.Int64 `tfsdk:"min_items"`
@@ -122,15 +119,14 @@ type ArrayPropModel struct {
}
type ObjectPropModel struct {
- Title types.String `tfsdk:"title"`
- Icon types.String `tfsdk:"icon"`
- Description types.String `tfsdk:"description"`
- Required types.Bool `tfsdk:"required"`
- DependsOn types.List `tfsdk:"depends_on"`
- Dataset *DatasetModel `tfsdk:"dataset"`
- DefaultJqQuery types.String `tfsdk:"default_jq_query"`
- Visible types.Bool `tfsdk:"visible"`
- VisibleJqQuery types.String `tfsdk:"visible_jq_query"`
+ Title types.String `tfsdk:"title"`
+ Icon types.String `tfsdk:"icon"`
+ Description types.String `tfsdk:"description"`
+ Required types.Bool `tfsdk:"required"`
+ DependsOn types.List `tfsdk:"depends_on"`
+ DefaultJqQuery types.String `tfsdk:"default_jq_query"`
+ Visible types.Bool `tfsdk:"visible"`
+ VisibleJqQuery types.String `tfsdk:"visible_jq_query"`
Default types.String `tfsdk:"default"`
Encryption types.String `tfsdk:"encryption"`
@@ -142,6 +138,7 @@ type StringItems struct {
Default types.List `tfsdk:"default"`
Enum types.List `tfsdk:"enum"`
EnumJqQuery types.String `tfsdk:"enum_jq_query"`
+ Dataset types.String `tfsdk:"dataset"`
}
type NumberItems struct {
diff --git a/port/action/number.go b/port/action/number.go
index a5dfa73a..4bd30cfe 100644
--- a/port/action/number.go
+++ b/port/action/number.go
@@ -81,10 +81,6 @@ func numberPropResourceToBody(ctx context.Context, state *ActionModel, props map
}
- if prop.Dataset != nil {
- property.Dataset = actionDataSetToPortBody(prop.Dataset)
- }
-
if !prop.Visible.IsNull() {
property.Visible = prop.Visible.ValueBoolPointer()
}
diff --git a/port/action/object.go b/port/action/object.go
index 49ac66a1..2c2f2d6d 100644
--- a/port/action/object.go
+++ b/port/action/object.go
@@ -63,10 +63,6 @@ func objectPropResourceToBody(ctx context.Context, d *ActionModel, props map[str
property.Encryption = &encryption
}
- if prop.Dataset != nil {
- property.Dataset = actionDataSetToPortBody(prop.Dataset)
- }
-
if !prop.Visible.IsNull() {
property.Visible = prop.Visible.ValueBoolPointer()
}
diff --git a/port/action/refreshActionState.go b/port/action/refreshActionState.go
index 525b9734..1eb37d17 100644
--- a/port/action/refreshActionState.go
+++ b/port/action/refreshActionState.go
@@ -3,9 +3,10 @@ package action
import (
"context"
"fmt"
- "github.com/samber/lo"
"reflect"
+ "github.com/samber/lo"
+
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/port-labs/terraform-provider-port-labs/internal/cli"
"github.com/port-labs/terraform-provider-port-labs/internal/consts"
@@ -57,18 +58,16 @@ func writeInvocationMethodToResource(a *cli.Action, state *ActionModel) {
}
}
-func writeDatasetToResource(v cli.ActionProperty) *DatasetModel {
- if v.Dataset == nil {
+func writeDatasetToResource(ds *cli.Dataset) *DatasetModel {
+ if ds == nil {
return nil
}
- dataset := v.Dataset
-
datasetModel := &DatasetModel{
- Combinator: types.StringValue(dataset.Combinator),
+ Combinator: types.StringValue(ds.Combinator),
}
- for _, v := range dataset.Rules {
+ for _, v := range ds.Rules {
rule := &Rule{
Blueprint: flex.GoStringToFramework(v.Blueprint),
Property: flex.GoStringToFramework(v.Property),
@@ -390,23 +389,6 @@ func setCommonProperties(ctx context.Context, v cli.ActionProperty, prop interfa
p.DependsOn = flex.GoArrayStringToTerraformList(ctx, v.DependsOn)
}
- case "Dataset":
- dataset := writeDatasetToResource(v)
- if dataset != nil {
- switch p := prop.(type) {
- case *StringPropModel:
- p.Dataset = dataset
- case *NumberPropModel:
- p.Dataset = dataset
- case *BooleanPropModel:
- p.Dataset = dataset
- case *ArrayPropModel:
- p.Dataset = dataset
- case *ObjectPropModel:
- p.Dataset = dataset
- }
- }
-
case "Visible":
visible, visibleJq := writeVisibleToResource(v)
if !visible.IsNull() {
diff --git a/port/action/resource_test.go b/port/action/resource_test.go
index abda8d55..8ff6a39c 100644
--- a/port/action/resource_test.go
+++ b/port/action/resource_test.go
@@ -470,50 +470,72 @@ func TestAccPortActionAdvancedFormConfigurations(t *testing.T) {
identifier := utils.GenID()
actionIdentifier := utils.GenID()
var testAccActionConfigCreate = testAccCreateBlueprintConfig(identifier) + fmt.Sprintf(`
- resource "port_action" "action1" {
- title = "Action 1"
- blueprint = port_blueprint.microservice.id
- identifier = "%s"
- trigger = "DAY-2"
- description = "This is a test action"
- required_approval = true
- github_method = {
- org = "port-labs"
- repo = "Port"
- workflow = "lint"
+
+resource "port_action" "action1" {
+ title = "Action 1"
+ blueprint = port_blueprint.microservice.id
+ identifier = "%s"
+ trigger = "DAY-2"
+ description = "This is a test action"
+ required_approval = true
+ github_method = {
+ org = "port-labs"
+ repo = "Port"
+ workflow = "lint"
+ }
+ user_properties = {
+ string_props = {
+ myStringIdentifier = {
+ title = "myStringIdentifier"
+ default = "default"
}
- user_properties = {
- string_props = {
- myStringIdentifier = {
- title = "myStringIdentifier"
- default = "default"
- }
- myStringIdentifier2 = {
- title = "myStringIdentifier2"
- default = "default"
- depends_on = ["myStringIdentifier"]
- }
- myStringIdentifier3 = {
- title = "myStringIdentifier3"
- required = true
- format = "entity"
- blueprint = port_blueprint.microservice.id
- dataset = {
- "combinator" : "and",
- "rules" : [
- {
- "property" : "$team",
- "operator" : "containsAny",
- "value" : {
- "jq_query" : "Test"
- }
- }
- ]
+ myStringIdentifier2 = {
+ title = "myStringIdentifier2"
+ default = "default"
+ depends_on = ["myStringIdentifier"]
+ }
+ myStringIdentifier3 = {
+ title = "myStringIdentifier3"
+ required = true
+ format = "entity"
+ blueprint = port_blueprint.microservice.id
+ dataset = {
+ "combinator" : "and",
+ "rules" : [
+ {
+ "property" : "$team",
+ "operator" : "containsAny",
+ "value" : {
+ "jq_query" : "Test"
+ }
}
- }
+ ]
}
}
- }`, actionIdentifier)
+ }
+ array_props = {
+ myArrayPropIdentifier = {
+ title = "myArrayPropIdentifier"
+ required = true
+ blueprint = port_blueprint.microservice.id
+ string_items = {
+ blueprint = port_blueprint.microservice.id
+ format = "entity"
+ dataset = jsonencode({
+ "combinator" : "and",
+ "rules" : [
+ {
+ "property" : "$identifier",
+ "operator" : "containsAny",
+ "value" : "Test"
+ }
+ ]
+ })
+ }
+ }
+ }
+ }
+ }`, actionIdentifier)
resource.Test(t, resource.TestCase{
PreCheck: func() { acctest.TestAccPreCheck(t) },
@@ -544,7 +566,7 @@ func TestAccPortActionAdvancedFormConfigurations(t *testing.T) {
resource.TestCheckResourceAttr("port_action.action1", "user_properties.string_props.myStringIdentifier3.dataset.rules.0.property", "$team"),
resource.TestCheckResourceAttr("port_action.action1", "user_properties.string_props.myStringIdentifier3.dataset.rules.0.operator", "containsAny"),
resource.TestCheckResourceAttr("port_action.action1", "user_properties.string_props.myStringIdentifier3.dataset.rules.0.value.jq_query", "Test"),
- ),
+ resource.TestCheckResourceAttr("port_action.action1", "user_properties.array_props.myArrayPropIdentifier.string_items.dataset", "{\"combinator\":\"and\",\"rules\":[{\"operator\":\"containsAny\",\"property\":\"$identifier\",\"value\":\"Test\"}]}")),
},
},
})
diff --git a/port/action/schema.go b/port/action/schema.go
index a9a6e29e..348157c6 100644
--- a/port/action/schema.go
+++ b/port/action/schema.go
@@ -3,6 +3,7 @@ package action
import (
"context"
"fmt"
+
"github.com/hashicorp/terraform-plugin-framework-validators/boolvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
@@ -43,46 +44,6 @@ func MetadataProperties() map[string]schema.Attribute {
Optional: true,
ElementType: types.StringType,
},
- "dataset": schema.SingleNestedAttribute{
- MarkdownDescription: "The dataset of the property",
- Optional: true,
- Attributes: map[string]schema.Attribute{
- "combinator": schema.StringAttribute{
- MarkdownDescription: "The combinator of the dataset",
- Required: true,
- Validators: []validator.String{
- stringvalidator.OneOf("and", "or"),
- },
- },
- "rules": schema.ListNestedAttribute{
- MarkdownDescription: "The rules of the dataset",
- Required: true,
- NestedObject: schema.NestedAttributeObject{
- Attributes: map[string]schema.Attribute{
- "blueprint": schema.StringAttribute{
- MarkdownDescription: "The blueprint identifier of the rule",
- Optional: true,
- },
- "property": schema.StringAttribute{
- MarkdownDescription: "The property identifier of the rule",
- Optional: true,
- },
- "operator": schema.StringAttribute{
- MarkdownDescription: "The operator of the rule",
- Required: true,
- },
- "value": schema.ObjectAttribute{
- MarkdownDescription: "The value of the rule",
- Required: true,
- AttributeTypes: map[string]attr.Type{
- "jq_query": types.StringType,
- },
- },
- },
- },
- },
- },
- },
}
}
@@ -355,6 +316,46 @@ func StringPropertySchema() schema.Attribute {
stringvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("visible")),
},
},
+ "dataset": schema.SingleNestedAttribute{
+ MarkdownDescription: "The dataset of an the entity-format property",
+ Optional: true,
+ Attributes: map[string]schema.Attribute{
+ "combinator": schema.StringAttribute{
+ MarkdownDescription: "The combinator of the dataset",
+ Required: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf("and", "or"),
+ },
+ },
+ "rules": schema.ListNestedAttribute{
+ MarkdownDescription: "The rules of the dataset",
+ Required: true,
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "blueprint": schema.StringAttribute{
+ MarkdownDescription: "The blueprint identifier of the rule",
+ Optional: true,
+ },
+ "property": schema.StringAttribute{
+ MarkdownDescription: "The property identifier of the rule",
+ Optional: true,
+ },
+ "operator": schema.StringAttribute{
+ MarkdownDescription: "The operator of the rule",
+ Required: true,
+ },
+ "value": schema.ObjectAttribute{
+ MarkdownDescription: "The value of the rule",
+ Required: true,
+ AttributeTypes: map[string]attr.Type{
+ "jq_query": types.StringType,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
}
utils.CopyMaps(stringPropertySchema, MetadataProperties())
@@ -564,6 +565,10 @@ func ArrayPropertySchema() schema.Attribute {
stringvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("enum")),
},
},
+ "dataset": schema.StringAttribute{
+ MarkdownDescription: "The dataset of an the entity-format items",
+ Optional: true,
+ },
},
},
"number_items": schema.SingleNestedAttribute{
@@ -640,7 +645,7 @@ func ArrayPropertySchema() schema.Attribute {
func (r *ActionResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
- MarkdownDescription: "Action resource",
+ MarkdownDescription: actionResourceMarkdownDescription,
Attributes: ActionSchema(),
}
}
@@ -696,3 +701,204 @@ func validateUserInputRequiredNotSetToFalse(state *ActionModel, resp *resource.V
}
}
}
+
+var actionResourceMarkdownDescription = `
+
+# Action
+
+This resource allows you to manage self-service action.
+
+See the [Port documentation](https://docs.getport.io/create-self-service-experiences/) for more information about self-service actions.
+
+## Example Usage
+
+Create a blueprint and an action relating to that blueprint which triggers a github workflow:
+
+` + "```hcl" + `
+
+resource "port_blueprint" "myBlueprint" {
+ icon = "Terraform"
+ identifier = "myBlueprint"
+ title = "My Blueprint"
+ properties = {
+ number_props = {
+ "numberProp" = {
+ title = "Number Property"
+ required = false
+ }
+ }
+ }
+}
+
+resource "port_action" "myAction" {
+ title = "My Action"
+ blueprint = port_blueprint.myBlueprint.identifier
+ identifier = "myAction"
+ trigger = "CREATE"
+ required_approval = false
+ github_method = {
+ org = "your-org"
+ repo = "your-repo"
+ workflow = "your-workflow"
+ }
+ user_properties = {
+ string_props = {
+ stringValue = {
+ title = "String Value"
+ }
+ }
+ number_props = {
+ "numberProp" = {
+ title = "Number Value"
+ required = true
+ }
+ }
+ }
+}
+
+` + "```" + `
+
+Create related "parent" and "child" blueprints and a CREATE action for the child blueprint with user inputs to select entities from the parent blueprint and triggers a github workflow:
+
+` + "```hcl" + `
+
+
+resource "port_blueprint" "parent" {
+ icon = "Terraform"
+ title = "Parent"
+ identifier = "parent"
+ properties = {}
+}
+
+resource "port_blueprint" "child" {
+ icon = "Terraform"
+ title = "Child"
+ identifier = "child"
+ properties = {}
+ relations = {
+ "childOf" = {
+ title = "Child Of"
+ many = true
+ required = false
+ target = port_blueprint.parent.identifier
+ }
+ }
+}
+
+resource "port_action" "myAction" {
+ title = "My Action"
+ blueprint = port_blueprint.child.identifier
+ identifier = "myAction"
+ trigger = "CREATE"
+ required_approval = false
+ github_method = {
+ org = "your-org"
+ repo = "your-repo"
+ workflow = "your-workflow"
+ }
+ user_properties = {
+ string_props = {
+ singleParent = {
+ title = "Single Parent Entity Selection"
+ format = "entity"
+ blueprint = port_blueprint.parent.identifier
+ }
+ }
+ array_props = {
+ miltipleParents = {
+ title = "Single Parent Entity Selection"
+ string_items = {
+ format = "entity"
+ blueprint = port_blueprint.parent.identifier
+ }
+ }
+ }
+ }
+}
+
+` + "```" + `
+
+
+Create the same resources as in the previous example, but the action's entity selection properties will only allow entities which pass the ` + "`dataset`s" + `:
+
+` + "```hcl" + `
+
+resource "port_blueprint" "parent" {
+ icon = "Terraform"
+ title = "Parent"
+ identifier = "parent"
+ properties = {}
+}
+
+resource "port_blueprint" "child" {
+ icon = "Terraform"
+ title = "Child"
+ identifier = "child"
+ properties = {}
+ relations = {
+ "childOf" = {
+ title = "Child Of"
+ many = true
+ required = false
+ target = port_blueprint.parent.identifier
+ }
+ }
+}
+
+resource "port_action" "myAction" {
+ title = "My Action"
+ blueprint = port_blueprint.child.identifier
+ identifier = "myAction"
+ trigger = "CREATE"
+ required_approval = false
+ github_method = {
+ org = "your-org"
+ repo = "your-repo"
+ workflow = "your-workflow"
+ omit_payload = true
+ omit_user_inputs = true
+ report_workflow_status = true
+ }
+ user_properties = {
+ string_props = {
+ singleParent = {
+ title = "Single Parent Entity Selection"
+ format = "entity"
+ blueprint = port_blueprint.parent.identifier
+ dataset = {
+ combinator = "and"
+ rules = [{
+ property = "$title"
+ operator = "contains"
+ value = {
+ jq_query = "\"specificValue\""
+ }
+ }]
+ }
+ }
+ }
+ array_props = {
+ miltipleParents = {
+ title = "Single Parent Entity Selection"
+ string_items = {
+ format = "entity"
+ blueprint = port_blueprint.parent.identifier
+ dataset = jsonencode({
+ combinator = "and"
+ rules = [{
+ property = "$title"
+ operator = "contains"
+ value = "specificValue"
+ }]
+ })
+ }
+ }
+ }
+ }
+}
+
+` + "```" + `
+
+
+
+`
diff --git a/port/action/string.go b/port/action/string.go
index 8e967e13..dd7442d1 100644
--- a/port/action/string.go
+++ b/port/action/string.go
@@ -131,6 +131,7 @@ func addStringPropertiesToResource(ctx context.Context, v *cli.ActionProperty) *
Format: flex.GoStringToFramework(v.Format),
Blueprint: flex.GoStringToFramework(v.Blueprint),
Encryption: flex.GoStringToFramework(v.Encryption),
+ Dataset: writeDatasetToResource(v.Dataset),
}
if v.Enum != nil {
diff --git a/port/aggregation-properties/readStateToPortBody.go b/port/aggregation-properties/readStateToPortBody.go
index b6445291..809836c9 100644
--- a/port/aggregation-properties/readStateToPortBody.go
+++ b/port/aggregation-properties/readStateToPortBody.go
@@ -1,8 +1,8 @@
package aggregation_properties
import (
- "encoding/json"
"github.com/port-labs/terraform-provider-port-labs/internal/cli"
+ "github.com/port-labs/terraform-provider-port-labs/internal/utils"
)
func aggregationPropertiesToBody(state *AggregationPropertiesModel) (*map[string]cli.BlueprintAggregationProperty, error) {
@@ -49,7 +49,7 @@ func aggregationPropertiesToBody(state *AggregationPropertiesModel) (*map[string
}
}
- query, err := queryToPortBody(aggregationProperty.Query.ValueStringPointer())
+ query, err := utils.TerraformJsonStringToGoObject(aggregationProperty.Query.ValueStringPointer())
if err != nil {
return nil, err
@@ -66,16 +66,3 @@ func aggregationPropertiesToBody(state *AggregationPropertiesModel) (*map[string
return &aggregationProperties, nil
}
-
-func queryToPortBody(query *string) (*map[string]any, error) {
- if query == nil || *query == "" {
- return nil, nil
- }
-
- queryMap := make(map[string]any)
- if err := json.Unmarshal([]byte(*query), &queryMap); err != nil {
- return nil, err
- }
-
- return &queryMap, nil
-}
diff --git a/port/blueprint/schema.go b/port/blueprint/schema.go
index f789e9b7..c9008ea8 100644
--- a/port/blueprint/schema.go
+++ b/port/blueprint/schema.go
@@ -2,6 +2,7 @@ package blueprint
import (
"context"
+
"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
diff --git a/port/page/pageToPortBody.go b/port/page/pageToPortBody.go
index 5c909792..d3c4e506 100644
--- a/port/page/pageToPortBody.go
+++ b/port/page/pageToPortBody.go
@@ -1,9 +1,9 @@
package page
import (
- "encoding/json"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/port-labs/terraform-provider-port-labs/internal/cli"
+ "github.com/port-labs/terraform-provider-port-labs/internal/utils"
)
func PageToPortBody(pm *PageModel) (*cli.Page, error) {
@@ -33,11 +33,13 @@ func widgetsToPortBody(widgets []types.String) (*[]map[string]any, error) {
}
widgetsBody := make([]map[string]any, len(widgets))
for i, w := range widgets {
- var widgetObject map[string]any
- if err := json.Unmarshal([]byte(w.ValueString()), &widgetObject); err != nil {
+ v, err := utils.TerraformJsonStringToGoObject(w.ValueStringPointer())
+
+ if err != nil {
return nil, err
}
- widgetsBody[i] = widgetObject
+
+ widgetsBody[i] = *v
}
return &widgetsBody, nil