Map PRs to services in a monorepo
Send this guide to your coding agent.
Prerequisite: Install Port MCP
Open plan mode if your tool supports it; otherwise present the plan below filled in and wait for my approval. Implement this Port guide in my org via MCP: https://docs.port.io/guides/all/map-prs-to-services-in-monorepo Read the raw markdown version at https://docs.port.io/guides/all/map-prs-to-services-in-monorepo.md - it contains every tab and code block without page markup. Goal: get the guide's core flow working end-to-end in my org; adapting it to fit my existing setup takes priority over matching the guide 1:1. Plan: 1. Confirm MCP is connected, in the right org, with sufficient permissions. 2. If the guide offers alternative implementation paths (tabs), pick the one matching my installed integrations and tools, confirm it with me, and implement only that path. 3. Diff the guide's data model (blueprints, properties, relations, workflows, actions, agents, automations, integrations, webhook data sources, secrets) against mine. 4. Propose adaptations for gaps, reusing existing blueprints/relations over guide-named duplicates. 5. Flag what needs a UI click, credential, or secret from me, testing MCP capability empirically before ruling anything out. If the guide has a "Set up via API" section, use it for anything MCP can't do before treating a step as UI-only. 6. Stop on any blocker and give me options. Approving this plan authorizes the writes it lists; pause only for writes beyond what's listed. Build: - Extend blueprint schema additively when upserting; don't remove or overwrite existing properties, and treat type conflicts as a blocker, not an auto-fix. - Never print secret values into the chat or logs; ask me to set them in Port, or write them via the secrets API without echoing them back. - List any mock data in the plan, minimal and labeled mock; once approved, seed it without re-asking, and tell me what you seeded. - For anything the guide writes downstream (e.g. a webhook target), use a real entity, not a mock. - For pages/widgets, use the real page identifier from the app URL, not a guessed slug. - When you hit a UI step confirmed (not assumed) unsupported via MCP and not covered by the guide's API sections, pause, give exact clicks, then resume via MCP. - Validate and give links after each meaningful step (only a tool-returned URL, no guessed paths); don't proceed if the last run wasn't a success. Done: - Run the guide's "Let's test it" steps where possible (e.g. execute a workflow test run) and confirm the expected output exists in Port. - Summarize adaptations, seeded data, what was mocked or skipped, remaining UI steps, and how to verify.
Overview
This guide demonstrates how to implement an automation in Port to map GitHub pull requests to sub-components in your monorepo based on the files that were changed.
This functionality streamlines monorepo management by enabling teams to quickly understand which sub-components are affected by each change without manual analysis. We will refer to those sub-components as 'services' throughout this guide.
Prerequisites
-
Complete the onboarding process.
-
A GitHub repository with a monorepo structure containing multiple sub-components.
-
GitHub Ocean installed.
-
Access to GitHub API tokens for automation.
This guide assumes that the sub-components are organized in directories with a service.yml file (or similar configuration file). You can modify the path pattern to match your actual service configuration file (e.g., **/package.json, **/docker-compose.yml, etc.).
Set up data model
After installing Port's GitHub Ocean integration, several blueprints are automatically created in Port, including the githubPullRequest blueprint. However, you need to update the blueprint with some additional properties in this setup.
Update the pull request blueprint
-
Go to the blueprints page in Port.
-
Find the
githubPullRequestblueprint and click on it. -
Click on the
Edit JSONbutton in the top right corner. -
Add the snippet below to the
schemasection:"file_change_url": {"type": "string","title": "File change URL","format": "url"} -
Add the following snippet to the
relationssection:"services": {"title": "Services","target": "service","required": false,"many": true} -
Click "Save" to update the blueprint.
Update the data source
The first step is to configure how services are mapped from your monorepo structure. We'll use Port's file ingestion feature to automatically create service entities based on file paths.
Add the service mapping configuration
Follow the steps below to update the data source:
-
Go to the Data sources page in Port.
-
Find the GitHub exporter (Legacy) or GitHub Ocean integration and click on it.
-
Add the following yaml to the mapping section:
Service mapping configuration (Click to expand)
- kind: fileselector:query: 'true'files:- path: '**/service.yml' # or your actual service configuration filerepos:- platformport:entity:mappings:identifier: .file.path | split("/")[:-1] | join("/")title: .file.content.service_nameblueprint: '"service"'Note: Adjust the
pathpattern andreposlist according to your monorepo structure. Theidentifiermapping extracts the directory path above the service configuration file (e.g.,service.yml), which becomes the service identifier. -
Click "Save & Resync" to update the data source.
This configuration assumes each service (sub-component) has a service.yml file in its root directory. You can modify the path pattern to match your actual service configuration file (e.g., **/package.json, **/docker-compose.yml, etc.).
Update the pull request kind to include the file change URL
-
Still in the data sources page in Port.
-
Update the
pull-requestkind to include thefile_change_urlproperty.Pull request kind configuration (Click to expand)
- kind: pull-requestselector:query: 'true'states: ["open"]port:entity:mappings:identifier: .id|tostringtitle: .titleblueprint: '"githubPullRequest"'properties:status: .statelabel: .labelsfile_change_url: .commits_url | split("/")[:8] | join("/") + "/files"relations:repository: .__repository -
Click "Save & Resync" to update the data source.
Set up automations
Now we'll create a two-step automation workflow that:
- Fetches the files changed in a pull request
- Updates the PR with relations to the affected services
Get PR files changed
This automation triggers when a new pull request is created and fetches the list of changed files.
-
Go to the automations page in Port.
-
Click on
+ Automation. -
Click on the
Edit JSONbutton in the top right corner. -
Copy and paste the following JSON schema:
Get files changed automation (Click to expand)
{"identifier": "get_files_changed_for_a_pr","title": "Get files changed for a PR","description": "","trigger": {"type": "automation","event": {"type": "ENTITY_CREATED","blueprintIdentifier": "githubPullRequest"},"condition": {"type": "JQ","expressions": [],"combinator": "and"}},"invocationMethod": {"type": "WEBHOOK","url": "{{ .event.diff.after.properties.file_change_url }}","agent": false,"synchronized": true,"method": "GET","headers": {"Authorization": "Bearer {{ .secrets.YOUR_GITHUB_TOKEN }}","X-GitHub-Api-Version": "2022-11-28","Identifier": "{{ .event.context.entityIdentifier | tostring }}"},"body": {}},"publish": true} -
Click "Save" to create the automation.
This automation requires a GitHub personal access token with repo scope permissions. Make sure to add this token to your Port secrets as YOUR_GITHUB_TOKEN.
Update PR with service relations
This automation triggers after the first automation completes successfully and creates relations between the PR and the affected services.
Follow the steps below to create the automation:
-
Go back to the automations page.
-
Click on
+ Automationand selectEdit JSON. -
Copy and paste the following JSON schema:
Update PR with service relations automation (Click to expand)
{"identifier": "update_pr_with_service","title": "Update PR with files changed","description": "","trigger": {"type": "automation","event": {"type": "RUN_UPDATED","actionIdentifier": "get_files_changed_for_a_pr"},"condition": {"type": "JQ","expressions": [".diff.after.status == \"SUCCESS\""],"combinator": "and"}},"invocationMethod": {"type": "UPSERT_ENTITY","blueprintIdentifier": "githubPullRequest","mapping": {"identifier": "{{ .event.diff.before.payload.headers.Identifier | tostring }}","relations": {"service": "{{ .event.diff.before.response | map(.filename | split(\"/\")[:-1] | join(\"/\")) }}"}}},"publish": true} -
Click "Save" to create the automation.
This automation is chained to the first one, meaning it will only execute after the "Get files changed for a PR" automation completes successfully. The chain ensures proper sequencing of operations.
Let's test it
-
Create a new pull request in your GitHub repository.
-
Check the PR in Port.
-
Check the services that were affected by the PR.
-
Check the Audit log to see the chain of actions