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

Scorecard filter support #202

Merged
merged 2 commits into from
Jan 26, 2025
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
27 changes: 26 additions & 1 deletion docs/resources/port_scorecard.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -473,6 +489,15 @@ Required:



<a id="nestedatt--filter"></a>
### 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


<a id="nestedatt--levels"></a>
### Nested Schema for `levels`

Expand Down
1 change: 1 addition & 0 deletions internal/cli/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
}
Expand Down
1 change: 1 addition & 0 deletions port/scorecard/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand Down
12 changes: 12 additions & 0 deletions port/scorecard/refreshScorecardState.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
OmriGez marked this conversation as resolved.
Show resolved Hide resolved
stateFilter.Conditions[i] = cond
}
state.Filter = stateFilter
}

stateRules := []Rule{}
for _, rule := range s.Rules {
stateRule := &Rule{
Expand Down
32 changes: 32 additions & 0 deletions port/scorecard/resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand Down Expand Up @@ -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"),
Expand All @@ -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"),
Expand Down
21 changes: 21 additions & 0 deletions port/scorecard/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
20 changes: 20 additions & 0 deletions port/scorecard/scorecardResourceToPortBody.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down