diff --git a/docs/resources/port_scorecard.md b/docs/resources/port_scorecard.md
index 8a3fe24c..09bb905e 100644
--- a/docs/resources/port_scorecard.md
+++ b/docs/resources/port_scorecard.md
@@ -312,7 +312,7 @@ resource "port_scorecard" "readiness" {
```
-## Example Usage with Levels
+## Example Usage with Levels and Filter
This will override the default levels (Basic, Bronze, Silver, Gold) with the provided levels: Not Ready, Partially Ready, Ready.
@@ -349,6 +349,21 @@ resource "port_scorecard" "readiness" {
identifier = "Readiness"
title = "Readiness"
blueprint = port_blueprint.microservice.identifier
+ filter = {
+ combinator = "and"
+ conditions = [
+ jsonencode({
+ property = "required"
+ operator = "="
+ value = true
+ }),
+ jsonencode({
+ property = "sum"
+ operator = ">"
+ value = 5
+ })
+ ]
+ }
levels = [
{
color = "red"
@@ -439,6 +454,7 @@ resource "port_scorecard" "readiness" {
### Optional
+- `filter` (Attributes) The filter to apply on the entities before calculating the scorecard (see [below for nested schema](#nestedatt--filter))
- `levels` (Attributes List) The levels of the scorecard. This overrides the default levels (Basic, Bronze, Silver, Gold) if provided (see [below for nested schema](#nestedatt--levels))
### Read-Only
@@ -473,6 +489,15 @@ Required:
+
+### Nested Schema for `filter`
+
+Required:
+
+- `combinator` (String) The combinator of the filter
+- `conditions` (List of String) The conditions of the filter. Each condition object should be encoded to a string
+
+
### Nested Schema for `levels`
diff --git a/internal/cli/models.go b/internal/cli/models.go
index 48ec4f48..ce0234a9 100644
--- a/internal/cli/models.go
+++ b/internal/cli/models.go
@@ -349,6 +349,7 @@ type (
Identifier string `json:"identifier,omitempty"`
Title string `json:"title,omitempty"`
Blueprint string `json:"blueprint,omitempty"`
+ Filter *Query `json:"filter,omitempty"`
Levels []Level `json:"levels,omitempty"`
Rules []Rule `json:"rules,omitempty"`
}
diff --git a/port/scorecard/model.go b/port/scorecard/model.go
index 43db81ff..34bc58fb 100644
--- a/port/scorecard/model.go
+++ b/port/scorecard/model.go
@@ -27,6 +27,7 @@ type ScorecardModel struct {
Identifier types.String `tfsdk:"identifier"`
Blueprint types.String `tfsdk:"blueprint"`
Title types.String `tfsdk:"title"`
+ Filter *Query `tfsdk:"filter"`
Levels []Level `tfsdk:"levels"`
Rules []Rule `tfsdk:"rules"`
CreatedAt types.String `tfsdk:"created_at"`
diff --git a/port/scorecard/refreshScorecardState.go b/port/scorecard/refreshScorecardState.go
index bc82830b..70120b3c 100644
--- a/port/scorecard/refreshScorecardState.go
+++ b/port/scorecard/refreshScorecardState.go
@@ -76,6 +76,18 @@ func refreshScorecardState(ctx context.Context, state *ScorecardModel, s *cli.Sc
state.UpdatedAt = types.StringValue(s.UpdatedAt.String())
state.UpdatedBy = types.StringValue(s.UpdatedBy)
+ if s.Filter != nil {
+ stateFilter := &Query{
+ Combinator: types.StringValue(s.Filter.Combinator),
+ }
+ stateFilter.Conditions = make([]types.String, len(s.Filter.Conditions))
+ for i, u := range s.Filter.Conditions {
+ cond, _ := utils.GoObjectToTerraformString(u)
+ stateFilter.Conditions[i] = cond
+ }
+ state.Filter = stateFilter
+ }
+
stateRules := []Rule{}
for _, rule := range s.Rules {
stateRule := &Rule{
diff --git a/port/scorecard/resource_test.go b/port/scorecard/resource_test.go
index 3d61ef5d..f4697b6e 100644
--- a/port/scorecard/resource_test.go
+++ b/port/scorecard/resource_test.go
@@ -192,6 +192,16 @@ func TestAccPortScorecardUpdate(t *testing.T) {
identifier = "%s"
title = "Scorecard 1"
blueprint = "%s"
+ filter = {
+ combinator = "and"
+ conditions = [
+ jsonencode({
+ property = "required"
+ operator = "="
+ value = true
+ })
+ ]
+ }
rules = [{
identifier = "hasTeam"
title = "Has Team"
@@ -216,6 +226,21 @@ func TestAccPortScorecardUpdate(t *testing.T) {
identifier = "%s"
title = "Scorecard 2"
blueprint = "%s"
+ filter = {
+ combinator = "or"
+ conditions = [
+ jsonencode({
+ property = "required"
+ operator = "="
+ value = true
+ }),
+ jsonencode({
+ property = "sum"
+ operator = ">"
+ value = 10
+ })
+ ]
+ }
rules = [{
identifier = "hasTeam"
title = "Has Team"
@@ -244,6 +269,9 @@ func TestAccPortScorecardUpdate(t *testing.T) {
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("port_scorecard.test", "title", "Scorecard 1"),
resource.TestCheckResourceAttr("port_scorecard.test", "blueprint", blueprintIdentifier),
+ resource.TestCheckResourceAttr("port_scorecard.test", "filter.combinator", "and"),
+ resource.TestCheckResourceAttr("port_scorecard.test", "filter.conditions.#", "1"),
+ resource.TestCheckResourceAttr("port_scorecard.test", "filter.conditions.0", "{\"operator\":\"=\",\"property\":\"required\",\"value\":true}"),
resource.TestCheckResourceAttr("port_scorecard.test", "rules.#", "1"),
resource.TestCheckResourceAttr("port_scorecard.test", "rules.0.identifier", "hasTeam"),
resource.TestCheckResourceAttr("port_scorecard.test", "rules.0.title", "Has Team"),
@@ -259,6 +287,10 @@ func TestAccPortScorecardUpdate(t *testing.T) {
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("port_scorecard.test", "title", "Scorecard 2"),
resource.TestCheckResourceAttr("port_scorecard.test", "blueprint", blueprintIdentifier),
+ resource.TestCheckResourceAttr("port_scorecard.test", "filter.combinator", "or"),
+ resource.TestCheckResourceAttr("port_scorecard.test", "filter.conditions.#", "2"),
+ resource.TestCheckResourceAttr("port_scorecard.test", "filter.conditions.0", "{\"operator\":\"=\",\"property\":\"required\",\"value\":true}"),
+ resource.TestCheckResourceAttr("port_scorecard.test", "filter.conditions.1", "{\"operator\":\"\\u003e\",\"property\":\"sum\",\"value\":10}"), // u003e is how > is returned
resource.TestCheckResourceAttr("port_scorecard.test", "rules.#", "1"),
resource.TestCheckResourceAttr("port_scorecard.test", "rules.0.identifier", "hasTeam"),
resource.TestCheckResourceAttr("port_scorecard.test", "rules.0.title", "Has Team"),
diff --git a/port/scorecard/schema.go b/port/scorecard/schema.go
index e2cab003..cfb82c14 100644
--- a/port/scorecard/schema.go
+++ b/port/scorecard/schema.go
@@ -85,6 +85,27 @@ func ScorecardSchema() map[string]schema.Attribute {
MarkdownDescription: "The title of the scorecard",
Required: true,
},
+ "filter": schema.SingleNestedAttribute{
+ MarkdownDescription: "The filter to apply on the entities before calculating the scorecard",
+ Optional: true,
+ Attributes: map[string]schema.Attribute{
+ "combinator": schema.StringAttribute{
+ MarkdownDescription: "The combinator of the filter",
+ Required: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf("and", "or"),
+ },
+ },
+ "conditions": schema.ListAttribute{
+ MarkdownDescription: "The conditions of the filter. Each condition object should be encoded to a string",
+ Required: true,
+ ElementType: types.StringType,
+ Validators: []validator.List{
+ listvalidator.SizeAtLeast(1),
+ },
+ },
+ },
+ },
"levels": schema.ListNestedAttribute{
MarkdownDescription: "The levels of the scorecard. This overrides the default levels (Basic, Bronze, Silver, Gold) if provided",
Optional: true,
diff --git a/port/scorecard/scorecardResourceToPortBody.go b/port/scorecard/scorecardResourceToPortBody.go
index b0c2ad0f..baf0272d 100644
--- a/port/scorecard/scorecardResourceToPortBody.go
+++ b/port/scorecard/scorecardResourceToPortBody.go
@@ -25,6 +25,26 @@ func scorecardResourceToPortBody(ctx context.Context, state *ScorecardModel) (*c
Title: state.Title.ValueString(),
}
+ if state.Filter != nil {
+ filter := &cli.Query{
+ Combinator: state.Filter.Combinator.ValueString(),
+ }
+ var conditions []interface{}
+ for _, stateCondition := range state.Filter.Conditions {
+ if !stateCondition.IsNull() {
+ stringCond := stateCondition.ValueString()
+ cond := map[string]interface{}{}
+ err := json.Unmarshal([]byte(stringCond), &cond)
+ if err != nil {
+ return nil, err
+ }
+ conditions = append(conditions, cond)
+ }
+ }
+ filter.Conditions = conditions
+ s.Filter = filter
+ }
+
var rules []cli.Rule
for _, stateRule := range state.Rules {