Automatically set relations between entities with automation
This guide demonstrates how to set up an automation in Port that automatically creates relations between entities. We will use a specific example of automatically linking new service entities to their owning teams based on GitHub repository metadata.
Once implemented, when a new service entity is created with a repository relation, the automation will automatically link it to the appropriate team based on the GitHub organization name.
Common use casesโ
- Team ownership: Automatically link services to their owning team based on repository metadata
- Environment mapping: Connect deployments to their target environments based on branch names or tags
- Service dependencies: Link services to their dependencies based on configuration files or API calls
- Infrastructure relationships: Connect cloud resources to the services that consume them based on tags or naming conventions
Prerequisitesโ
This guide assumes the following:
- You have a Port account and have completed the onboarding process.
- Port's GitHub app is installed in your account.
- You have setup automatic discovery between the
service
andrepository
blueprints. - Permissions to create and edit Port automations.
Set up data modelโ
After completing the onboarding process, you should have both a service
blueprint and a team
blueprint.
If you have installed the GitHub app, you should have a repository
blueprint and
your service
blueprint should have a repository
relation. Now we need to add a relation between the service
and the team
blueprints.
Add team relation to the service blueprint
-
Go to your Builder page.
-
Find and click on the
Service
blueprint. -
Click on
New relation
. -
Fill out the form:
- Title:
Owning Team
- Identifier:
owning_team
- Target Blueprint:
Team
- Limit:
1 entity
- Required: False
- Title:
-
Click
Create
to add the relation.
Set up the automationโ
Now let's create an automation that automatically sets the team relation when a service is created.
-
Go to the Automations page in your portal.
-
Click on
+ Automation
to create a new automation. -
Copy and paste the following JSON structure for your automation:
Auto-assign service owner (Click to expand)
{
"identifier": "auto_assign_service_owner",
"title": "Auto-assign Service Owner",
"description": "Automatically assigns services to teams based on repository owner",
"trigger": {
"type": "automation",
"event": {
"type": "ENTITY_CREATED",
"blueprintIdentifier": "service"
},
"condition": {
"type": "JQ",
"expressions": [
".diff.after.relations.repository != null"
],
"combinator": "and"
}
},
"invocationMethod": {
"type": "UPSERT_ENTITY",
"blueprintIdentifier": "service",
"mapping": {
"identifier": "{{ .event.diff.after.identifier }}",
"title": "{{ .event.diff.after.title }}",
"properties": {},
"relations": {
"repository": "{{ .event.diff.after.relations.repository }}",
"owning_team": "{{ .event.diff.after.relations.repository | split(\"_\") | .[0] | split(\"/\") | .[1] | gsub(\"-\"; \"_\") }}"
}
}
},
"publish": true
} -
Click
Save
to create the automation.
How the automation worksโ
When a service entity is created with a repository relation, the automation will:
-
Extract the GitHub organization from the repository identifier (e.g.,
myorganization/acme-corp_my-service
โacme_corp
) -
Automatically set the
owning_team
relation toacme_corp
(assuming you have a team with that identifier) -
The service is now linked to its owning team
The automation uses this JQ expression to extract the team name:
.event.diff.after.relations.repository | split("_") | .[0] | split("/") | .[1] | gsub("-"; "_")
This expression works as follows:
-
split("_")
splitsmyorganization/acme-corp_my-service
โ["myorganization/acme-corp", "my-service"]
-
.[0]
takes the first part โ"myorganization/acme-corp"
-
split("/")
splits that โ["myorganization", "acme-corp"]
-
.[1]
takes the second part โ"acme-corp"
-
gsub("-"; "_")
converts hyphens to underscores โ"acme_corp"
This automation assumes your team identifiers use underscores and match your GitHub organization names, and that repository identifiers follow the pattern username/organization_repository-name
. If your naming convention is different, you'll need to adjust the JQ expression in the owning_team
mapping accordingly.
Customizationsโ
You can customize this automation to fit your specific naming conventions:
Different repository patterns
-
If your repository naming convention uses dashes instead of underscores:
"owning_team": "{{ .event.diff.after.relations.repository | split(\"-\") | .[0] | split(\"/\") | .[1] | gsub(\"-\"; \"_\") }}"
-
If your GitHub organization name preserves hyphens (no conversion to underscores):
"owning_team": "{{ .event.diff.after.relations.repository | split(\"_\") | .[0] | split(\"/\") | .[1] }}"
-
If your team names have regional suffixes (e.g.,
acme-corp-region
โacme_corp_region
):"owning_team": "{{ .event.diff.after.relations.repository | split(\"_\") | .[0] | split(\"/\") | .[1] | gsub(\"-\"; \"_\") }}"
-
If your team names have role-based suffixes (e.g.,
rnd-taskforce
โrnd_taskforce
):"owning_team": "{{ .event.diff.after.relations.repository | split(\"_\") | .[0] | split(\"/\") | .[1] | gsub(\"-\"; \"_\") }}"
-
If your team names are complex with multiple segments (e.g.,
rnd-developer-team-product
โrnd_developer_team_product
):"owning_team": "{{ .event.diff.after.relations.repository | split(\"_\") | .[0] | split(\"/\") | .[1] | gsub(\"-\"; \"_\") }}"
Team suffix patterns
If your team identifiers include a suffix like "_team":
"owning_team": "{{ (.event.diff.after.relations.repository | split(\"_\") | .[0] | split(\"/\") | .[1] | gsub(\"-\"; \"_\")) + \"_team\" }}"
Additional conditions
To ensure the automation only runs when the service doesn't already have an owner:
"condition": {
"type": "JQ",
"expressions": [
".diff.after.relations.repository != null",
".diff.before.relations.owning_team == null"
],
"combinator": "and"
}
Additional examplesโ
Here are more examples of automations that automatically set relations between entities:
Environment-based deployment relationships
Link deployments to environments based on branch names (Click to expand)
{
"identifier": "link_deployment_to_environment",
"title": "Link Deployment to Environment",
"description": "Automatically links deployments to environments based on branch name",
"trigger": {
"type": "automation",
"event": {
"type": "ENTITY_CREATED",
"blueprintIdentifier": "deployment"
},
"condition": {
"type": "JQ",
"expressions": [
".diff.after.properties.branch != null"
],
"combinator": "and"
}
},
"invocationMethod": {
"type": "UPSERT_ENTITY",
"blueprintIdentifier": "deployment",
"mapping": {
"identifier": "{{ .event.diff.after.identifier }}",
"title": "{{ .event.diff.after.title }}",
"properties": {},
"relations": {
"environment": "{{ if (.event.diff.after.properties.branch | test(\"^main$|^master$\")) then \"production\" elif (.event.diff.after.properties.branch | test(\"^develop$|^dev$\")) then \"development\" elif (.event.diff.after.properties.branch | test(\"^staging$|^stage$\")) then \"staging\" else \"development\" end }}"
}
}
},
"publish": true
}
Cloud resource to service mapping
Link AWS resources to services based on tags (Click to expand)
{
"identifier": "map_aws_resources_to_services",
"title": "Map AWS Resources to Services",
"description": "Links AWS resources to services based on the 'service' tag",
"trigger": {
"type": "automation",
"event": {
"type": "ENTITY_CREATED",
"blueprintIdentifier": "awsResource"
},
"condition": {
"type": "JQ",
"expressions": [
".diff.after.properties.tags != null",
".diff.after.properties.tags | has(\"service\")"
],
"combinator": "and"
}
},
"invocationMethod": {
"type": "UPSERT_ENTITY",
"blueprintIdentifier": "awsResource",
"mapping": {
"identifier": "{{ .event.diff.after.identifier }}",
"title": "{{ .event.diff.after.title }}",
"properties": {},
"relations": {
"consumingService": "{{ .event.diff.after.properties.tags.service }}"
}
}
},
"publish": true
}
Conclusionโ
By leveraging Port's automation capabilities, you can create a self-maintaining software catalog that automatically establishes relationships between entities. This approach saves time, ensures consistency, reduces errors, and scales effortlessly to handle hundreds or thousands of entities automatically.
Start with simple property-based mappings and gradually implement more sophisticated logic as your needs grow.