Skip to content

Add support for owner relationships & a few other requests#629

Merged
andrewstillv15 merged 15 commits intomainfrom
andrew/14198/add-support-for-owner-relationships
Dec 16, 2025
Merged

Add support for owner relationships & a few other requests#629
andrewstillv15 merged 15 commits intomainfrom
andrew/14198/add-support-for-owner-relationships

Conversation

@andrewstillv15
Copy link
Copy Markdown
Contributor

@andrewstillv15 andrewstillv15 commented Dec 12, 2025

Resolves ##14198

Problem

We need to support owner relationships

Solution

Given this Terraform config file

I had claude write some test cases for me

# ============================================================================
# Tests with owner_relationship and management rules
# ============================================================================

# Test 1: Basic owner relationship with built-in property (alias)
resource "opslevel_component_type" "backend_with_owner" {
  name        = "Backend Service"
  alias       = "backend-service"
  description = "Backend services with automatic team ownership"
  properties  = {}
  
  icon = {
    color = "#3B82F6"
    name  = "PhDatabase"
  }
  
  owner_relationship = {
    management_rules = [
      {
        operator        = "EQUALS"
        source_property = "alias"
        target_property = "alias"
        target_type     = "team"
      }
    ]
  }
}

# Test 2: Owner relationship with tag matching
resource "opslevel_component_type" "frontend_with_tags" {
  name        = "Frontend Service"
  alias       = "frontend-service"
  description = "Frontend services with tag-based team ownership"
  properties  = {}
  
  icon = {
    color = "#EC4899"
    name  = "PhDesktop"
  }
  
  owner_relationship = {
    management_rules = [
      {
        operator              = "EQUALS"
        source_property       = "tag"
        source_tag_key        = "team"
        source_tag_operation  = "equals"
        target_property       = "name"
        target_type           = "team"
      }
    ]
  }
}

# Test 3: Owner relationship with starts_with tag operation
resource "opslevel_component_type" "mobile_with_prefix" {
  name        = "Mobile App"
  alias       = "mobile-app"
  description = "Mobile apps with prefix-based team ownership"
  properties  = {}
  
  icon = {
    color = "#14B8A6"
    name  = "PhDeviceMobile"
  }
  
  owner_relationship = {
    management_rules = [
      {
        operator              = "EQUALS"
        source_property       = "tag"
        source_tag_key        = "owner"
        source_tag_operation  = "starts_with"
        target_property       = "alias"
        target_type           = "team"
      }
    ]
  }
}

# Test 4: Multiple management rules (OR logic)
resource "opslevel_component_type" "api_multiple_rules" {
  name        = "API Service"
  alias       = "api-service"
  description = "API services with multiple ownership matching rules"
  properties  = {}
  
  icon = {
    color = "#8B5CF6"
    name  = "PhPlug"
  }
  
  owner_relationship = {
    management_rules = [
      # Rule 1: Match by alias
      {
        operator        = "EQUALS"
        source_property = "alias"
        target_property = "alias"
        target_type     = "team"
      },
      # Rule 2: Match by owner tag
      {
        operator              = "EQUALS"
        source_property       = "tag"
        source_tag_key        = "owner"
        source_tag_operation  = "equals"
        target_property       = "alias"
        target_type           = "team"
      },
      # Rule 3: Match by department tag to team tag
      {
        operator              = "EQUALS"
        source_property       = "tag"
        source_tag_key        = "department"
        source_tag_operation  = "starts_with"
        target_property       = "tag"
        target_tag_key        = "department"
        target_tag_operation  = "equals"
        target_type           = "team"
      }
    ]
  }
}

# Test 5: Owner relationship with name matching
resource "opslevel_component_type" "library_name" {
  name        = "Library"
  alias       = "library"
  description = "Libraries with name-based team ownership"
  properties  = {}
  
  icon = {
    color = "#F59E0B"
    name  = "PhBooks"
  }
  
  owner_relationship = {
    management_rules = [
      {
        operator        = "EQUALS"
        source_property = "name"
        target_property = "name"
        target_type     = "team"
      }
    ]
  }
}

# Test 6: Tag to tag matching (both source and target are tags)
resource "opslevel_component_type" "microservice_tag_to_tag" {
  name        = "Microservice"
  alias       = "microservice"
  description = "Microservices with tag-to-tag ownership matching"
  properties  = {}
  
  icon = {
    color = "#10B981"
    name  = "PhCube"
  }
  
  owner_relationship = {
    management_rules = [
      {
        operator              = "EQUALS"
        source_property       = "tag"
        source_tag_key        = "responsible-team"
        source_tag_operation  = "equals"
        target_property       = "tag"
        target_tag_key        = "team-identifier"
        target_tag_operation  = "starts_with"
        target_type           = "team"
      }
    ]
  }
}

# ============================================================================
# Tests for edge cases (nil, null, empty)
# ============================================================================

# Test 7: owner_relationship block completely absent (nil)
resource "opslevel_component_type" "no_owner_block" {
  name        = "No Owner Block"
  alias       = "no-owner-block"
  description = "Component type with no owner_relationship block at all"
  properties  = {}
  
  icon = {
    color = "#6366F1"
    name  = "PhClock"
  }
  
  # No owner_relationship block
}

# Test 8: owner_relationship block present but management_rules not specified
resource "opslevel_component_type" "owner_no_rules" {
  name        = "Owner No Rules"
  alias       = "owner-no-rules"
  description = "Component type with owner_relationship block but no management_rules"
  properties  = {}
  
  icon = {
    color = "#EF4444"
    name  = "PhWarning"
  }
  
  owner_relationship = {
    # No management_rules specified (null)
  }
}

# Test 9: owner_relationship block with empty management_rules list
resource "opslevel_component_type" "owner_empty_rules" {
  name        = "Owner Empty Rules"
  alias       = "owner-empty-rules"
  description = "Component type with owner_relationship block and empty management_rules"
  properties  = {}
  
  icon = {
    color = "#8B5CF6"
    name  = "PhList"
  }
  
  owner_relationship = {
    management_rules = []
  }
}

# Test 10: No owner relationship (alias for clarity)
resource "opslevel_component_type" "no_owner" {
  name        = "Configuration"
  alias       = "configuration"
  description = "Configuration components without automatic ownership"
  properties  = {}
  
  icon = {
    color = "#6B7280"
    name  = "PhGear"
  }
  
  # No owner_relationship block
}

# ============================================================================
# Outputs
# ============================================================================

output "component_type_ids" {
  value = {
    backend_with_owner      = opslevel_component_type.backend_with_owner.id
    frontend_with_tags      = opslevel_component_type.frontend_with_tags.id
    mobile_with_prefix      = opslevel_component_type.mobile_with_prefix.id
    api_multiple_rules      = opslevel_component_type.api_multiple_rules.id
    library_name            = opslevel_component_type.library_name.id
    microservice_tag_to_tag = opslevel_component_type.microservice_tag_to_tag.id
    no_owner_block          = opslevel_component_type.no_owner_block.id
    owner_no_rules          = opslevel_component_type.owner_no_rules.id
    owner_empty_rules       = opslevel_component_type.owner_empty_rules.id
    no_owner                = opslevel_component_type.no_owner.id
  }
}

output "test_summary" {
  value = {
    total_tests              = 10
    with_management_rules    = 6
    without_management_rules = 4
    edge_cases = {
      no_block    = "no_owner_block"
      null_rules  = "owner_no_rules"
      empty_rules = "owner_empty_rules"
    }
  }
}

The terraform apply output

component_type_ids = {
  "api_multiple_rules" = "Z2lkOi8vb3BzbGV2ZWwvQ29tcG9uZW50VHlwZXM6OlNlcnZpY2UvNTE5NA"
  "backend_with_owner" = "Z2lkOi8vb3BzbGV2ZWwvQ29tcG9uZW50VHlwZXM6OlNlcnZpY2UvNTE5Mw"
  "frontend_with_tags" = "Z2lkOi8vb3BzbGV2ZWwvQ29tcG9uZW50VHlwZXM6OlNlcnZpY2UvNTE4OQ"
  "library_name" = "Z2lkOi8vb3BzbGV2ZWwvQ29tcG9uZW50VHlwZXM6OlNlcnZpY2UvNTE5Mg"
  "microservice_tag_to_tag" = "Z2lkOi8vb3BzbGV2ZWwvQ29tcG9uZW50VHlwZXM6OlNlcnZpY2UvNTE5NQ"
  "mobile_with_prefix" = "Z2lkOi8vb3BzbGV2ZWwvQ29tcG9uZW50VHlwZXM6OlNlcnZpY2UvNTE5MA"
  "no_owner" = "Z2lkOi8vb3BzbGV2ZWwvQ29tcG9uZW50VHlwZXM6OlNlcnZpY2UvNTE4OA"
  "no_owner_block" = "Z2lkOi8vb3BzbGV2ZWwvQ29tcG9uZW50VHlwZXM6OlNlcnZpY2UvNTE4Nw"
  "owner_empty_rules" = "Z2lkOi8vb3BzbGV2ZWwvQ29tcG9uZW50VHlwZXM6OlNlcnZpY2UvNTE5MQ"
  "owner_no_rules" = "Z2lkOi8vb3BzbGV2ZWwvQ29tcG9uZW50VHlwZXM6OlNlcnZpY2UvNTE4Ng"
}
test_summary = {
  "edge_cases" = {
    "empty_rules" = "owner_empty_rules"
    "no_block" = "no_owner_block"
    "null_rules" = "owner_no_rules"
  }
  "total_tests" = 10
  "with_management_rules" = 6
  "without_management_rules" = 4
}

We also have support for a new filter on component_category

resource "opslevel_filter" "test_component_category" {
  name = "Test Component Category Filter"
  
  predicate {
    key   = "component_category"
    type  = "equals"
    value = "service"
  }
}

Checklist

  • I have run this code, and it appears to resolve the stated issue.
  • This PR does not reduce total test coverage
  • This PR has no user interface changes or has already received approval from product management to change the interface.
  • Make a changie entry that explains the customer facing outcome of this change

@andrewstillv15 andrewstillv15 changed the title Andrew/14198/add support for owner relationships Add support for owner relationships Dec 13, 2025
allowedCategories := make([]attr.Value, len(rel.Metadata.AllowedCategories))
for i, t := range rel.Metadata.AllowedCategories {
allowedCategories[i] = types.StringValue(t)
// Relationships can either be managed independently or within the context of a component but not both. Only fetch relationships if they have
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pertains to this bit of feedback.

},
"allowed_categories": schema.ListAttribute{
MarkdownDescription: "The categories of resources that can be selected for this relationship definition. Can include any component category alias on your account.",
Computed: true,
Copy link
Copy Markdown
Contributor Author

@andrewstillv15 andrewstillv15 Dec 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pertains to this bit of feedback.

@@ -0,0 +1,3 @@
kind: Added
body: Support for component category filter
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pertaining to this request.

@andrewstillv15 andrewstillv15 changed the title Add support for owner relationships Add support for owner relationships & a few other requests Dec 13, 2025
Copy link
Copy Markdown
Contributor

@derek-etherton-opslevel derek-etherton-opslevel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Nice job with the refactoring to move management rules into its own area, and the thorough functional tests

@andrewstillv15 andrewstillv15 merged commit 2a7ecbf into main Dec 16, 2025
7 checks passed
@andrewstillv15 andrewstillv15 deleted the andrew/14198/add-support-for-owner-relationships branch December 16, 2025 14:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants