Skip to content

Commit

Permalink
Add Search data source (#153)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tankilevitch authored Jun 6, 2024
1 parent 69bdc2d commit 58f8e1b
Show file tree
Hide file tree
Showing 11 changed files with 1,757 additions and 11 deletions.
227 changes: 227 additions & 0 deletions docs/data-sources/port_search.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "port_search Data Source - terraform-provider-port-labs"
subcategory: ""
description: |-
Search Data Source
The search data source allows you to search for entities in Port.
See the Port documentation https://docs.getport.io/search-and-query/ for more information about the search capabilities in Port.
Example Usage
Search for all entities in a specific blueprint:
```hcl
data "portsearch" "allservice" {
query = jsonencode({
"combinator" : "and", "rules" : [
{ "operator" : "=", "property" : "$blueprint", "value" : "Service" },
]
})
}
```
Search for entity with specific identifier in a specific blueprint to create another resource based on the values of the entity:
```hcl
data "portsearch" "adsservice" {
query = jsonencode({
"combinator" : "and", "rules" : [
{ "operator" : "=", "property" : "$blueprint", "value" : "Service" },
{ "operator" : "=", "property" : "$identifier", "value" : "Ads" },
]
})
}
```
Scorecards automation example
In this example we are creating a jira task for each service that its Ownership Scorecard hasn't reached Gold level :
```hcl
data "portsearch" "allservices" {
query = jsonencode({
"combinator" : "and", "rules" : [
{ "operator" : "=", "property" : "$blueprint", "value" : "microservice" },
]
})
}
locals {
// Count the number of services that are not owned by a team with a Gold level
microserviceownershipwithoutgoldlevel = length([
for entity in data.portsearch.allservices.entities : entity.scorecards["ownership"].level
if entity.scorecards["ownership"].level != "Gold"
])
}
// create jira issue per service that is not owned by a team with a Gold level
resource "jiraissue" "microserviceownershipwithoutgoldlevel" {
count = local.microserviceownershipwithoutgoldlevel
issuetype = "Task"
project_key = "PORT"
summary = "Service ${data.portsearch.backendservices.entities[count.index].title} hasn't reached Gold level in Ownership Scorecard"
description = "Service https://app.getport.io/${port_blueprint.microservice.identifier}Entity/${data.port_search.backend_services.entities[count.index].identifier} is not owned by a team with a Gold level, please assign a team with a Gold level to the service"
}
```
---

# port_search (Data Source)

# Search Data Source

The search data source allows you to search for entities in Port.

See the [Port documentation](https://docs.getport.io/search-and-query/) for more information about the search capabilities in Port.

## Example Usage

### Search for all entities in a specific blueprint:

```hcl
data "port_search" "all_service" {
query = jsonencode({
"combinator" : "and", "rules" : [
{ "operator" : "=", "property" : "$blueprint", "value" : "Service" },
]
})
}
```

### Search for entity with specific identifier in a specific blueprint to create another resource based on the values of the entity:


```hcl
data "port_search" "ads_service" {
query = jsonencode({
"combinator" : "and", "rules" : [
{ "operator" : "=", "property" : "$blueprint", "value" : "Service" },
{ "operator" : "=", "property" : "$identifier", "value" : "Ads" },
]
})
}
```

### Scorecards automation example
In this example we are creating a jira task for each service that its Ownership Scorecard hasn't reached Gold level :

```hcl
data "port_search" "all_services" {
query = jsonencode({
"combinator" : "and", "rules" : [
{ "operator" : "=", "property" : "$blueprint", "value" : "microservice" },
]
})
}
locals {
// Count the number of services that are not owned by a team with a Gold level
microservice_ownership_without_gold_level = length([
for entity in data.port_search.all_services.entities : entity.scorecards["ownership"].level
if entity.scorecards["ownership"].level != "Gold"
])
}
// create jira issue per service that is not owned by a team with a Gold level
resource "jira_issue" "microservice_ownership_without_gold_level" {
count = local.microservice_ownership_without_gold_level
issue_type = "Task"
project_key = "PORT"
summary = "Service ${data.port_search.backend_services.entities[count.index].title} hasn't reached Gold level in Ownership Scorecard"
description = "[Service](https://app.getport.io/${port_blueprint.microservice.identifier}Entity/${data.port_search.backend_services.entities[count.index].identifier}) is not owned by a team with a Gold level, please assign a team with a Gold level to the service"
}
```



<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `query` (String) The search query

### Optional

- `attach_title_to_relation` (Boolean) Attach title to relation
- `exclude` (List of String) Properties to exclude from the results
- `exclude_calculated_properties` (Boolean) Exclude calculated properties
- `include` (List of String) Properties to include in the results

### Read-Only

- `entities` (Attributes List) A list of entities matching the search query (see [below for nested schema](#nestedatt--entities))
- `id` (String) The ID of this resource.
- `matching_blueprints` (List of String) The matching blueprints for the search query

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

Optional:

- `icon` (String) The icon of the entity
- `properties` (Attributes) The properties of the entity (see [below for nested schema](#nestedatt--entities--properties))
- `relations` (Attributes) The relations of the entity (see [below for nested schema](#nestedatt--entities--relations))
- `run_id` (String) The runID of the action run that created the entity
- `scorecards` (Map of Object) The scorecards of the entity (see [below for nested schema](#nestedatt--entities--scorecards))
- `teams` (List of String) The teams the entity belongs to
- `title` (String) The title of the entity

Read-Only:

- `blueprint` (String) The blueprint identifier the entity relates to
- `created_at` (String) The creation date of the entity
- `created_by` (String) The creator of the entity
- `identifier` (String) The identifier of the entity
- `updated_at` (String) The last update date of the entity
- `updated_by` (String) The last updater of the entity

<a id="nestedatt--entities--properties"></a>
### Nested Schema for `entities.properties`

Optional:

- `array_props` (Attributes) The array properties of the entity (see [below for nested schema](#nestedatt--entities--properties--array_props))
- `boolean_props` (Map of Boolean) The bool properties of the entity
- `number_props` (Map of Number) The number properties of the entity
- `object_props` (Map of String) The object properties of the entity
- `string_props` (Map of String) The string properties of the entity

<a id="nestedatt--entities--properties--array_props"></a>
### Nested Schema for `entities.properties.array_props`

Optional:

- `boolean_items` (Map of List of Boolean)
- `number_items` (Map of List of Number)
- `object_items` (Map of List of String)
- `string_items` (Map of List of String)



<a id="nestedatt--entities--relations"></a>
### Nested Schema for `entities.relations`

Optional:

- `many_relations` (Map of List of String) The many relation of the entity
- `single_relations` (Map of String) The single relation of the entity


<a id="nestedatt--entities--scorecards"></a>
### Nested Schema for `entities.scorecards`

Read-Only:

- `level` (String)
- `rules` (List of Object) (see [below for nested schema](#nestedobjatt--entities--scorecards--rules))

<a id="nestedobjatt--entities--scorecards--rules"></a>
### Nested Schema for `entities.scorecards.rules`

Read-Only:

- `identifier` (String)
- `level` (String)
- `status` (String)
49 changes: 43 additions & 6 deletions internal/cli/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,27 @@ type (
ExpiresIn int64 `json:"expiresIn"`
TokenType string `json:"tokenType"`
}

ScorecardRulesModel struct {
Identifier string `tfsdk:"identifier"`
Status string `tfsdk:"status"`
Level string `tfsdk:"level"`
}

ScorecardModel struct {
Rules []ScorecardRulesModel `tfsdk:"rules"`
Level string `tfsdk:"level"`
}

Entity struct {
Meta
Identifier string `json:"identifier,omitempty"`
Title string `json:"title"`
Blueprint string `json:"blueprint"`
Team []string `json:"team,omitempty"`
Properties map[string]any `json:"properties"`
Relations map[string]any `json:"relations"`
Identifier string `json:"identifier,omitempty"`
Title string `json:"title"`
Blueprint string `json:"blueprint"`
Team []string `json:"team,omitempty"`
Properties map[string]any `json:"properties"`
Relations map[string]any `json:"relations"`
Scorecards map[string]ScorecardModel `json:"scorecards,omitempty"`
// TODO: add the rest of the fields.
}

Expand Down Expand Up @@ -385,6 +398,14 @@ type (
FailureCount int `json:"failureCount,omitempty"`
SuccessCount int `json:"successCount,omitempty"`
}

SearchRequestQuery struct {
Query *map[string]any `json:"query"`
ExcludeCalculatedProperties *bool `json:"exclude_calculated_properties,omitempty"`
Include []string `json:"include,omitempty"`
Exclude []string `json:"exclude,omitempty"`
AttachTitleToRelation *bool `json:"attach_title_to_relation,omitempty"`
}
)

type PortBody struct {
Expand All @@ -402,6 +423,22 @@ type PortBody struct {
Migration Migration `json:"migration"`
}

type SearchEntityResult struct {
Meta
Identifier string `json:"identifier,omitempty"`
Title string `json:"title,omitempty"`
Icon *string `json:"icon,omitempty"`
Team []string `json:"team,omitempty"`
Properties map[string]any `json:"properties,omitempty"`
Relations map[string]any `json:"relations,omitempty"`
}

type SearchResult struct {
OK bool `json:"ok"`
MatchingBlueprints []string `json:"matchingBlueprints"`
Entities []Entity `json:"entities"`
}

type PortPagePermissionsBody struct {
OK bool `json:"ok"`
PagePermissions PagePermissions `json:"permissions"`
Expand Down
48 changes: 48 additions & 0 deletions internal/cli/search.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package cli

import (
"context"
"encoding/json"
"fmt"
"strings"
)

func (c *PortClient) Search(ctx context.Context, searchRequest *SearchRequestQuery) (*SearchResult, error) {
url := "v1/entities/search"

req := c.Client.R().
SetContext(ctx).
SetBody(*searchRequest.Query).
SetHeader("Accept", "application/json")

if searchRequest.ExcludeCalculatedProperties != nil {
req.SetQueryParam("exclude_calculated_properties", fmt.Sprintf("%v", &searchRequest.ExcludeCalculatedProperties))
}

if searchRequest.Include != nil && len(searchRequest.Include) > 0 {
req.SetQueryParam("include", strings.Join(searchRequest.Include, ","))
}

if searchRequest.Exclude != nil && len(searchRequest.Exclude) > 0 {
req.SetQueryParam("exclude", strings.Join(searchRequest.Exclude, ","))
}

if searchRequest.AttachTitleToRelation != nil {
req.SetQueryParam("attach_title_to_relation", fmt.Sprintf("%v", &searchRequest.AttachTitleToRelation))
}

resp, err := req.Post(url)

if err != nil {
return nil, err
}
var searchResult SearchResult
err = json.Unmarshal(resp.Body(), &searchResult)
if err != nil {
return nil, err
}
if !searchResult.OK {
return nil, fmt.Errorf("failed to search, got: %s", resp.Body())
}
return &searchResult, nil
}
4 changes: 0 additions & 4 deletions port/integration/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,6 @@ func IntegrationSchema() map[string]schema.Attribute {
}
}

func StaticString(s string) {
panic("unimplemented")
}

func (r *IntegrationResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: IntegrationResourceMarkdownDescription,
Expand Down
Loading

0 comments on commit 58f8e1b

Please sign in to comment.