> For the complete documentation index, see llms.txt.
Skip to main content

Check out Port for yourself ➜ 

Build GitHub dashboards in Port

Implement with AI

Send this guide to your coding agent.

Prerequisite: Install Port MCP

Open plan mode. Implement this Port guide in my org via MCP:

https://docs.port.io/guides/all/build-github-dashboards-in-port

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. Diff the guide's data model (blueprints, properties, relations, actions, agents, automations, integrations, secrets) against mine.
3. Propose adaptations for gaps, reusing existing blueprints/relations over guide-named duplicates.
4. Flag what needs a UI click, credential, or secret from me, testing MCP capability empirically before ruling anything out.
5. 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.
- 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, 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:
- Confirm the guide's expected output exists and runs in Port.
- Summarize adaptations, seeded data, what was mocked or skipped, remaining UI steps, and how to verify.

This guide demonstrates how to build GitHub dashboards in Port for dependency security alerts, identity and access management, repository activity, and engineering metrics.

Use the sections below independently, or combine them into one GitHub operations dashboard. Each section includes the data model, ingestion mapping, and dashboard widgets needed for that GitHub use case.

Common use cases

  • Monitor open and resolved Dependabot alerts across repositories.
  • Audit GitHub organization members, teams, and permissions.
  • Track repository visibility, pull requests, issues, and developer activity.
  • Collect GitHub engineering metrics and visualize PR and workflow performance.

Prerequisites

This guide assumes the following:

Dependency security alerts

Use this section to build a dashboard for GitHub Dependabot alerts. You will learn how to:

  • Create a Dependabot Alert blueprint.
  • Ingest Dependabot alerts from GitHub.
  • Visualize alert severity, package ecosystem, CVSS trends, and unresolved alerts.
Dependabot Alert Insights dashboard overview Unresolved alerts table and CVSS score line chart

Set up the Dependabot alert data model

When installing the GitHub integration, the Repository blueprint is created by default. The Dependabot Alert blueprint is not created automatically, so we will need to create it manually.

Create the GitHub Dependabot alert blueprint

Follow the steps below to create the Dependabot Alert blueprint.
Skip to the data source mapping step below if you already have the blueprint.

  1. Go to your Builder page.

  2. Click on + Blueprint.

  3. Click on the {...} button in the top right corner, and choose Edit JSON.

  4. Add this JSON schema:

    GitHub Dependabot alert blueprint (Click to expand)
    {
    "identifier": "githubDependabotAlert",
    "title": "Dependabot Alert",
    "icon": "Github",
    "schema": {
    "properties": {
    "severity": {
    "title": "Severity",
    "type": "string",
    "enum": ["low", "medium", "high", "critical"],
    "enumColors": {
    "low": "yellow",
    "medium": "orange",
    "high": "red",
    "critical": "red"
    },
    "icon": "DefaultProperty"
    },
    "state": {
    "title": "State",
    "type": "string",
    "enum": ["auto_dismissed", "dismissed", "fixed", "open"],
    "enumColors": {
    "auto_dismissed": "green",
    "dismissed": "green",
    "fixed": "green",
    "open": "red"
    },
    "icon": "DefaultProperty"
    },
    "packageName": {
    "icon": "DefaultProperty",
    "title": "Package Name",
    "type": "string"
    },
    "packageEcosystem": {
    "title": "Package Ecosystem",
    "type": "string"
    },
    "manifestPath": {
    "title": "Manifest Path",
    "type": "string"
    },
    "scope": {
    "title": "Scope",
    "type": "string"
    },
    "ghsaID": {
    "title": "GHSA ID",
    "type": "string"
    },
    "cveID": {
    "title": "CVE ID",
    "type": "string"
    },
    "cvssScore": {
    "type": "number",
    "title": "CVSS Score"
    },
    "url": {
    "title": "URL",
    "type": "string",
    "format": "url"
    },
    "references": {
    "icon": "Vulnerability",
    "title": "References",
    "type": "array",
    "items": {
    "type": "string",
    "format": "url"
    }
    },
    "alertCreatedAt": {
    "icon": "DefaultProperty",
    "type": "string",
    "title": "Alert Created At",
    "format": "date-time"
    },
    "alertUpdatedAt": {
    "icon": "DefaultProperty",
    "type": "string",
    "title": "Alert Updated At",
    "format": "date-time"
    }
    },
    "required": []
    },
    "mirrorProperties": {},
    "calculationProperties": {},
    "relations": {
    "repository": {
    "title": "Repository",
    "target": "githubRepository",
    "required": true,
    "many": false
    }
    }
    }
  5. Click Save to create the blueprint.

Ingest Dependabot alerts from GitHub

  1. Go to your Data Source page.

  2. Select the GitHub integration relevant to you.

  3. Add the following YAML block into the editor to ingest data from GitHub:

    GitHub Ocean integration configuration (Click to expand)
    resources:
    - kind: repository
    selector:
    query: "true"
    includedFiles:
    - README.md
    port:
    entity:
    mappings:
    identifier: .name
    title: .name
    blueprint: '"githubRepository"'
    properties:
    readme: .__includedFiles["README.md"]
    url: .html_url
    defaultBranch: .default_branch

    - kind: dependabot-alert
    selector:
    query: "true"
    states: ["open", "fixed"]
    port:
    entity:
    mappings:
    identifier: .__repository + "/" + (.number | tostring)
    title: .number | tostring
    blueprint: '"githubDependabotAlert"'
    properties:
    state: .state
    severity: .security_advisory.severity
    packageName: .dependency.package.name
    packageEcosystem: .dependency.package.ecosystem
    manifestPath: .dependency.manifest_path
    scope: .dependency.scope
    ghsaID: .security_advisory.ghsa_id
    cveID: .security_advisory.cve_id
    cvssScore: .security_advisory.cvss.score
    url: .html_url
    references: "[.security_advisory.references[].url]"
    alertCreatedAt: .created_at
    alertUpdatedAt: .updated_at
    relations:
    repository: .__repository
  4. Click Save & Resync to apply the mapping.

Visualize Dependabot alert insights

Once the GitHub data is synced, we can create a dedicated dashboard in Port to monitor and analyze dependency vulnerability alerts using customizable widgets.

Create the Dependabot alerts dashboard

  1. Navigate to your software catalog.

  2. Click on the + button in the left sidebar.

  3. Select New dashboard.

  4. Name the dashboard Dependabot Alert Insights.

  5. Select the Vulnerability icon.

  6. Click Create.

We now have a blank dashboard where we can start adding widgets to visualize insights from the Dependabot alerts.

Add Dependabot alert widgets

In the new dashboard, create the following widgets:

Vulnerability by severity (Click to expand)
  1. Click + Widget and select Pie chart.

  2. Title: Vulnerability by severity.

  3. Choose the Dependabot Alert blueprint.

  4. Under Breakdown by property, select the Severity property

    Dependabot vulnerabilities pie chart by severity
  5. Click Save.

Vulnerability by package type (Click to expand)
  1. Click + Widget and select Pie chart.

  2. Title: Vulnerability by package type.

  3. Choose the Dependabot Alert blueprint.

  4. Under Breakdown by property, select the Package Ecosystem property

    Dependabot vulnerabilities pie chart by package ecosystem
  5. Click Save.

Open alerts updated in the last 6 months (Click to expand)
  1. Click + Widget and select Number Chart.

  2. Title: Open alerts (add the Alert icon).

  3. Select Count entities Chart type and choose Dependabot Alert as the Blueprint.

  4. Select count for the Function.

  5. Add this JSON to the Additional filters editor to filter open alerts updated in the last 6 months:

    [
    {
    "combinator":"and",
    "rules":[
    {
    "property":"state",
    "operator":"=",
    "value":"open"
    },
    {
    "property":"alertUpdatedAt",
    "operator":"between",
    "value":{
    "preset":"last6Months"
    }
    }
    ]
    }
    ]
  6. You may optionally configure conditional formatting to contextualize the numbers on the widget.

    Number chart counting open Dependabot alerts Conditional formatting for open alerts number chart
  7. Click Save.

Fixed alerts (Click to expand)
  1. Click + Widget and select Number Chart.

  2. Title: Fixed alerts (add the BadgeAlert icon).

  3. Select Count entities Chart type and choose Dependabot Alert as the Blueprint.

  4. Select count for the Function.

  5. Add this JSON to the Additional filters editor to filter fixed alerts:

    [
    {
    "combinator":"and",
    "rules":[
    {
    "property":"state",
    "operator":"=",
    "value":"fixed"
    }
    ]
    }
    ]
    Number chart counting fixed Dependabot alerts
  6. Click Save.

Dismissed alerts (Click to expand)
  1. Click + Widget and select Number Chart.

  2. Title: Dismissed alerts.

  3. Select Count entities Chart type and choose Dependabot Alert as the Blueprint.

  4. Select count for the Function.

  5. Add this JSON to the Additional filters editor to filter Dismissed alerts alerts:

    [
    {
    "combinator":"and",
    "rules":[
    {
    "property":"state",
    "operator":"=",
    "value":"auto_dismissed"
    }
    ]
    }
    ]
    Number chart counting dismissed Dependabot alerts
  6. Click Save.

Average CVSS score over time (Click to expand)
  1. Click + Widget and select Line Chart.

  2. Title: Average CVSS Score Over Time (add the LineChart icon).

  3. Set X axis:

    • Title: Months.
    • Time interval: Month.
    • Time range: In the past 365 days.
  4. Set Y axis title: CVSS Score.

  5. Click + Line and configure:

    • Title: Average CVSS score.
    • Chart type: Aggregate by property.
    • Blueprint: Dependabot Alert.
    • Property: CVSS Score.
    • Function: Average.
    • Measure time by: alertCreatedAt.
    Average CVSS Score Over Time line chart Line chart X axis CVSS score monthly settings
  6. Click Save.

Repos with unresolved critical alerts (Click to expand)
  1. Click + Widget and select Table.

  2. Title the widget Repos with unresolved alerts.

  3. Choose the Dependabot Alert blueprint.

    Table showing repos with unresolved Dependabot alerts
  4. Click Save to add the widget to the dashboard.

  5. Click on the ... button in the top right corner of the table and select Customize table.

  6. In the top right corner of the table, click on Manage Properties and add the following properties:

    • Repository: The name of each related repository.
    • Package Name: The name of the package.
    • CVE-ID: The ID of the vulnerability.
  7. Click on Group by any Column in the top right corner and select Repository.

  8. Click on the save icon in the top right corner of the widget to save the customized table.

Identity and access management

Use this section to build a dashboard for GitHub identity and access management. You will learn how to:

  • Create GitHub User and GitHub Team blueprints.
  • Ingest repositories, teams, and users from GitHub.
  • Visualize team permissions, admin access, team count, and user count.
GitHub IAM Security dashboard overview

Set up the GitHub IAM data model

When installing the GitHub Ocean integration, the Repository blueprint is created by default. However, the GitHub User and GitHub Team blueprints are not created automatically, so we will need to create them manually.

Create the GitHub user blueprint

Skip to the data source mapping step below if you already have the blueprint.

  1. Go to the Builder page of your portal.

  2. Click on + Blueprint.

  3. Click on the {...} button in the top right corner, and choose Edit JSON.

  4. Add this JSON schema:

    GitHub user blueprint (Click to expand)
    {
    "identifier": "githubUser",
    "title": "GitHub User",
    "icon": "Microservice",
    "schema": {
    "properties": {
    "email": {
    "title": "Email",
    "type": "string"
    }
    },
    "required": []
    },
    "mirrorProperties": {},
    "calculationProperties": {},
    "aggregationProperties": {},
    "relations": {}
    }
  5. Click Save to create the blueprint.

Create the GitHub team blueprint

Skip to the data source mapping step below if you already have the blueprint.

  1. Go to the Builder page of your portal.

  2. Click on + Blueprint.

  3. Click on the {...} button in the top right corner, and choose Edit JSON.

  4. Add this JSON schema:

    GitHub team blueprint (Click to expand)
    {
    "identifier": "githubTeam",
    "title": "GitHub Team",
    "icon": "Github",
    "schema": {
    "properties": {
    "slug": {
    "title": "Slug",
    "type": "string"
    },
    "description": {
    "title": "Description",
    "type": "string"
    },
    "link": {
    "title": "Link",
    "icon": "Link",
    "type": "string",
    "format": "url"
    },
    "permission": {
    "title": "Permission",
    "type": "string"
    },
    "notification_setting": {
    "title": "Notification Setting",
    "type": "string"
    }
    },
    "required": []
    },
    "mirrorProperties": {},
    "calculationProperties": {},
    "relations": {
    "members": {
    "title": "Members",
    "target": "githubUser",
    "many": true,
    "required": false
    }
    }
    }
  5. Click Save to create the blueprint.

Ingest GitHub users and teams

  1. In your GitHub repository (or .github-private for organization-wide config), add or update the port-app-config.yml file with the following configuration to ingest repositories, teams, and users:

    Port port-app-config.yml (Click to expand)
    resources:
    - kind: repository
    selector:
    query: 'true'
    includedFiles:
    - README.md
    port:
    entity:
    mappings:
    identifier: .name
    title: .name
    blueprint: '"githubRepository"'
    properties:
    readme: .__includedFiles["README.md"]
    url: .html_url
    defaultBranch: .default_branch
    visibility: .visibility

    - kind: team
    selector:
    query: "true"
    members: true
    port:
    entity:
    mappings:
    identifier: .databaseId | tostring
    title: .name
    blueprint: '"githubTeam"'
    properties:
    name: .name
    slug: .slug
    description: .description
    link: .url
    permission: .permission
    notification_setting: .notificationSetting
    relations:
    members: '[.members.nodes[].login]'

    - kind: user
    selector:
    query: "true"
    port:
    entity:
    mappings:
    identifier: .login
    title: .login
    blueprint: '"githubUser"'
    properties:
    email: .email
  2. Commit and push the configuration. The integration will sync automatically.

Visualize GitHub IAM insights

Once the GitHub data is synced, we can create a dashboard and add widgets to monitor IAM.

Create the GitHub IAM dashboard

  1. Navigate to your software catalog.

  2. Click on the + button in the left sidebar.

  3. Select New dashboard.

  4. Name the dashboard GitHub IAM Overview.

  5. Click Create.

We now have a blank dashboard where we can start adding widgets to visualize our identity and access management.

Add GitHub IAM widgets

Teams by permission (Click to expand)
  1. Click + Widget and select Pie chart.

  2. Title: Teams by permission.

  3. Choose the GitHub Team blueprint.

  4. Under Breakdown by property, select the Permission property

    Pie chart teams by permission type
  5. Click Save.

Teams with admin permission (Click to expand)
  1. Click + Widget and select Number Chart.

  2. Title: Teams with admin permission.

  3. Select Count entities Chart type and choose GitHub Team as the Blueprint.

  4. Select count for the Function.

  5. Add this JSON to the Additional filters editor to filter admin permission:

    [
    {
    "combinator":"and",
    "rules":[
    {
    "property":"permission",
    "operator":"=",
    "value":"admin"
    }
    ]
    }
    ]
  6. Select custom as the Unit and input teams as the Custom unit.

    Number chart counting GitHub admin teams
  7. Click Save.

Total number of teams (Click to expand)
  1. Click + Widget and select Number Chart.

  2. Title: Total teams (add the Team icon).

  3. Select Count entities Chart type and choose GitHub Team as the Blueprint.

  4. Select count for the Function.

    Number chart counting total GitHub teams
  5. Click Save.

Total number of users (Click to expand)
  1. Click + Widget and select Number Chart.

  2. Title: Total users (add the Team icon).

  3. Select Count entities Chart type and choose GitHub User as the Blueprint.

  4. Select count for the Function.

    Number chart counting total GitHub users
  5. Click Save.

Repository and developer activity

Use this section to build a dashboard for repository visibility, pull requests, issues, and developer activity. You will learn how to:

  • Extend the Repository blueprint with visibility data.
  • Create an Issue blueprint.
  • Ingest repositories, pull requests, and issues from GitHub.
  • Visualize repository visibility, PRs, merged PRs, and open issues.
GitHub Insight dashboard repository visibility and PRs GitHub Insight dashboard merged PRs and lead time

Set up the repository activity data model

When installing the GitHub integration, the Repository and Pull Request blueprints are created by default. The Issue blueprint is not created automatically, so we will need to create it manually.

Additionally, we will update the Repository blueprint to include a visibility property, which is not part of the default schema.

Update the Repository blueprint with visibility

Follow the steps below to update the Repository blueprint:

  1. Navigate to the Repository blueprint in your Port Builder.

  2. Hover over it, click on the ... button on the right, and select Edit JSON.

  3. Add the visibility property:

    Visibility property (Click to expand)
    "visibility": {
    "type": "string",
    "title": "Visibility"
    }
  4. Click Save.

Create the GitHub issue blueprint

We will then create the Issue blueprint.
Skip to the data source mapping step below if you already have the blueprint.

  1. Go to your Builder page.

  2. Click on + Blueprint.

  3. Click on the {...} button in the top right corner, and choose Edit JSON.

  4. Add this JSON schema:

    GitHub issue blueprint (Click to expand)
    {
    "identifier": "githubIssue",
    "title": "Issue",
    "icon": "Github",
    "schema": {
    "properties": {
    "creator": {
    "title": "Creator",
    "type": "string"
    },
    "assignees": {
    "title": "Assignees",
    "type": "array"
    },
    "labels": {
    "title": "Labels",
    "type": "array"
    },
    "status": {
    "title": "Status",
    "type": "string",
    "enum": ["open", "closed"],
    "enumColors": {
    "open": "green",
    "closed": "purple"
    }
    },
    "createdAt": {
    "title": "Created At",
    "type": "string",
    "format": "date-time"
    },
    "closedAt": {
    "title": "Closed At",
    "type": "string",
    "format": "date-time"
    },
    "updatedAt": {
    "title": "Updated At",
    "type": "string",
    "format": "date-time"
    },
    "description": {
    "title": "Description",
    "type": "string",
    "format": "markdown"
    },
    "issueNumber": {
    "title": "Issue Number",
    "type": "number"
    },
    "link": {
    "title": "Link",
    "type": "string",
    "format": "url"
    }
    },
    "required": []
    },
    "mirrorProperties": {},
    "calculationProperties": {},
    "relations": {
    "repository": {
    "target": "githubRepository",
    "required": true,
    "many": false
    }
    }
    }
  5. Click Save to create the blueprint.

Ingest repositories, pull requests, and issues

  1. Go to your Data Source page.

  2. Select the GitHub integration relevant to you.

  3. Add the following YAML block into the editor to ingest data from GitHub:

    GitHub Ocean integration configuration (Click to expand)
    resources:
    - kind: repository
    selector:
    query: "true"
    includedFiles:
    - README.md
    port:
    entity:
    mappings:
    identifier: .name
    title: .name
    blueprint: '"githubRepository"'
    properties:
    description: if .description then .description else "" end
    visibility: if .private then "private" else "public" end
    language: if .language then .language else "" end
    readme: .__includedFiles["README.md"]
    url: .html_url
    defaultBranch: .default_branch
    relations:
    organization: .owner.login

    - kind: pull-request
    selector:
    query: "true"
    states: ["open", "closed"]
    port:
    entity:
    mappings:
    identifier: .__repository + (.id|tostring)
    title: .title
    blueprint: '"githubPullRequest"'
    properties:
    creator: .user.login
    assignees: '[.assignees[].login]'
    reviewers: '[.requested_reviewers[].login]'
    status: .state
    closedAt: .closed_at
    updatedAt: .updated_at
    mergedAt: .merged_at
    createdAt: .created_at
    prNumber: .id
    link: .html_url
    leadTimeHours: >-
    (.created_at as $createdAt | .merged_at as $mergedAt | ($createdAt
    | sub("\\..*Z$"; "Z") | strptime("%Y-%m-%dT%H:%M:%SZ") | mktime)
    as $createdTimestamp | ($mergedAt | if . == null then null else
    sub("\\..*Z$"; "Z") | strptime("%Y-%m-%dT%H:%M:%SZ") | mktime end)
    as $mergedTimestamp | if $mergedTimestamp == null then null else
    (((($mergedTimestamp - $createdTimestamp) / 3600) * 100 | floor) /
    100) end)
    relations:
    repository: .__repository

    - kind: issue
    selector:
    query: .pull_request == null
    state: "open"
    port:
    entity:
    mappings:
    identifier: .__repository + (.id|tostring)
    title: .title
    blueprint: '"githubIssue"'
    properties:
    creator: .user.login
    assignees: '[.assignees[].login]'
    labels: '[.labels[].name]'
    status: .state
    createdAt: .created_at
    closedAt: .closed_at
    updatedAt: .updated_at
    description: .body
    issueNumber: .number
    link: .html_url
    relations:
    repository: .__repository
Ocean differences

GitHub (Ocean) provides additional repository properties (description, visibility, language) and an organization relation. For pull requests, use states: ["open", "closed"] selector, .__repository for the repository relation, and .state for the status property mapping. For issues, use .__repository for the repository relation. File content is accessed via .__includedFiles["filename"] instead of the file:// prefix.

  1. Click Save & Resync to apply the mapping.

Visualize repository and developer activity

Once the GitHub data is synced, we can create a dashboard and add widgets to monitor repository visibility and developer activity.

Create the repository activity dashboard

  1. Navigate to your software catalog.

  2. Click on the + button in the left sidebar.

  3. Select New dashboard.

  4. Name the dashboard GitHub - Insight.

  5. Click Create.

We now have a blank dashboard where we can start adding widgets to visualize our developer activities.

Add repository activity widgets

Repository visibility (Click to expand)
  1. Click + Widget and select Pie chart.

  2. Title: Repository Visibility.

  3. Choose the Repository blueprint.

  4. Under Breakdown by property, select the Visibility property

    Pie chart repository visibility breakdown
  5. Click Save.

Total number of repositories (Click to expand)
  1. Click + Widget and select Number Chart.

  2. Title: Number of repos.

  3. Select Count entities Chart type and choose Repository as the Blueprint.

  4. Select count for the Function.

  5. Select custom as the Unit and input repos as the Custom unit.

    Number chart counting GitHub Repository entities
  6. Click Save.

Total number of public repositories (Click to expand)
  1. Click + Widget and select Number Chart.

  2. Title: Public repos (add the Url icon).

  3. Select Count entities Chart type and choose Repository as the Blueprint.

  4. Select count for the Function.

  5. Add this JSON to the Additional filters editor to filter public repositories:

    [
    {
    "combinator":"and",
    "rules":[
    {
    "property":"visibility",
    "operator":"=",
    "value":"public"
    }
    ]
    }
    ]
  6. Select custom as the Unit and input repos as the Custom unit.

    Number chart counting public GitHub repositories
  7. Click Save.

Total number of open pull requests (Click to expand)
  1. Click + Widget and select Number Chart.

  2. Title: Open pull requests (add the GitPullRequest icon).

  3. Select Count entities Chart type and choose Pull Request as the Blueprint.

  4. Select count for the Function.

  5. Add this JSON to the Additional filters editor to filter open pull requests:

    [
    {
    "combinator":"and",
    "rules":[
    {
    "property":"status",
    "operator":"=",
    "value":"open"
    }
    ]
    }
    ]
  6. Select custom as the Unit and input PRs as the Custom unit.

    Number chart counting open pull requests
  7. Click Save.

Total number of merged pull requests (Click to expand)
  1. Click + Widget and select Number Chart.

  2. Title: Merged pull requests (30 days) (add the Merge icon).

  3. Select Count entities Chart type and choose Pull Request as the Blueprint.

  4. Select count for the Function.

  5. Add this JSON to the Additional filters editor to filter merged pull requests updated in the last month:

    [
    {
    "combinator":"and",
    "rules":[
    {
    "property":"status",
    "operator":"=",
    "value":"merged"
    },
    {
    "property":"updatedAt",
    "operator":"between",
    "value":{
    "preset":"lastMonth"
    }
    }
    ]
    }
    ]
  6. Select custom as the Unit and input PRs as the Custom unit.

    Number chart counting merged PRs last 30 days
  7. Click Save.

Total number of open GitHub issues (Click to expand)
  1. Click + Widget and select Number Chart.

  2. Title: Open issues (add the Alert icon).

  3. Select Count entities Chart type and choose Issue as the Blueprint.

  4. Select count for the Function.

  5. Add this JSON to the Additional filters editor to filter open issues:

    [
    {
    "combinator":"and",
    "rules":[
    {
    "property":"status",
    "operator":"=",
    "value":"open"
    }
    ]
    }
    ]
  6. Select custom as the Unit and input issues as the Custom unit.

    Number chart counting open GitHub issues
  7. Click Save.

Engineering metrics

Use this section to build a dashboard for GitHub engineering performance metrics. You will learn how to:

  • Extend the GitHub Pull Request blueprint with PR metrics.
  • Create a GitHub Workflow blueprint.
  • Set up automated metric collection with GitHub Actions.
  • Visualize PR lifetime, PR size, workflow success rate, and workflow duration.
GitHub Engineering Metrics dashboard overview

Set up the engineering metrics data model

The Service and User blueprints are created by default during onboarding. The GitHub Pull Request blueprint is created by your GitHub integration. We need to extend the existing Pull Request blueprint to capture the detailed metrics we want to track.

Extend the GitHub Pull Request blueprint with metrics

The Pull Request blueprint is created by default when you install the GitHub integration.

Ocean mapping configuration

If you're using GitHub Ocean, configure your pull-request selector with states: ["open"], use .__repository for the repository relation, and .state for the status property mapping. See the GitHub Ocean migration guide for details.

  1. Go to the Builder page of your portal.

  2. Find and click on the Pull Request blueprint.

  3. Click on the {...} button in the top right corner, and choose Edit JSON.

  4. Add these additional properties to the existing schema:

    Extended Pull Request properties (Click to expand)
    {
    "pr_size": {
    "title": "PR Size",
    "type": "number"
    },
    "pr_lifetime": {
    "title": "PR Lifetime (seconds)",
    "type": "number"
    },
    "pr_pickup_time": {
    "title": "PR Pickup Time (seconds)",
    "type": "number"
    },
    "pr_success_rate": {
    "title": "PR Success Rate (%)",
    "type": "number"
    },
    "review_participation": {
    "title": "Review Participation",
    "type": "number"
    }
    }
  5. Click Save to update the blueprint.

Create the GitHub Workflow blueprint

We need to create a new blueprint to track GitHub workflow metrics.

  1. Go to the Builder page of your portal.

  2. Click on + Blueprint.

  3. Click on the {...} button in the top right corner, and choose Edit JSON.

  4. Add this JSON schema:

    GitHub Workflow blueprint (Click to expand)
    {
    "identifier": "githubWorkflow",
    "title": "Workflow",
    "icon": "Github",
    "schema": {
    "properties": {
    "path": {
    "title": "Path",
    "type": "string"
    },
    "status": {
    "title": "Status",
    "type": "string",
    "enum": [
    "active",
    "deleted",
    "disabled_fork",
    "disabled_inactivity",
    "disabled_manually"
    ],
    "enumColors": {
    "active": "green",
    "deleted": "red"
    }
    },
    "createdAt": {
    "title": "Created At",
    "type": "string",
    "format": "date-time"
    },
    "updatedAt": {
    "title": "Updated At",
    "type": "string",
    "format": "date-time"
    },
    "deletedAt": {
    "title": "Deleted At",
    "type": "string",
    "format": "date-time"
    },
    "link": {
    "title": "Link",
    "type": "string",
    "format": "url"
    },
    "medianDuration_last_30_days": {
    "title": "Median Duration Last 30 days",
    "description": "Median Duration of Successful runs in the last 30 days",
    "type": "number"
    },
    "maxDuration_last_30_days": {
    "title": "Max Duration Last 30 days",
    "description": "Max Duration of Successful runs in the last 30 days",
    "type": "number"
    },
    "minDuration_last_30_days": {
    "title": "Min Duration Last 30 days",
    "description": "Min Duration of Successful runs in the last 30 days",
    "type": "number"
    },
    "meanDuration_last_30_days": {
    "title": "Mean Duration Last 30 days",
    "description": "Mean Duration of Successful runs in the last 30 days",
    "type": "number"
    },
    "totalRuns_last_30_days": {
    "title": "Total Runs Last 30 days",
    "description": "Total workflow runs in the last 30 days",
    "type": "number"
    },
    "totalFailures_last_30_days": {
    "title": "Total Failures Last 30 days",
    "description": "Total Workflow Run Failures in the last 30 days",
    "type": "number"
    },
    "successRate_last_30_days": {
    "title": "Success Rate Last 30 days",
    "description": "Success Rate for the workflow in the last 30 days",
    "type": "number"
    },
    "medianDuration_last_90_days": {
    "title": "Median Duration Last 90 days",
    "description": "Median Duration of Successful runs in the last 90 days",
    "type": "number"
    },
    "maxDuration_last_90_days": {
    "title": "Max Duration Last 90 days",
    "description": "Max Duration of Successful runs in the last 90 days",
    "type": "number"
    },
    "minDuration_last_90_days": {
    "title": "Min Duration Last 90 days",
    "description": "Min Duration of Successful runs in the last 90 days",
    "type": "number"
    },
    "meanDuration_last_90_days": {
    "title": "Mean Duration Last 90 days",
    "description": "Mean Duration of Successful runs in the last 90 days",
    "type": "number"
    },
    "totalRuns_last_90_days": {
    "title": "Total Runs Last 90 days",
    "description": "Total workflow runs in the last 90 days",
    "type": "number"
    },
    "totalFailures_last_90_days": {
    "title": "Total Failures Last 90 days",
    "description": "Total Workflow Run Failures in the last 90 days",
    "type": "number"
    },
    "successRate_last_90_days": {
    "title": "Success Rate Last 90 days",
    "description": "Success Rate for the workflow in the last 90 days",
    "type": "number"
    }
    },
    "required": []
    },
    "mirrorProperties": {},
    "calculationProperties": {},
    "aggregationProperties": {},
    "relations": {
    "repository": {
    "title": "Repository",
    "target": "service",
    "required": false,
    "many": false
    }
    }
    }
  5. Click Save to create the blueprint.

Collect GitHub engineering metrics

Now we will set up automated metric collection using the GitHub metrics exporter. This tool will pull data from the GitHub API and calculate the metrics we defined in our blueprints.

Configure a GitHub personal access token

The metric exporter needs access to the GitHub API to pull the relevant data. You will need to configure a classic Personal Access Token (PAT) with the following permissions:

  • repo - Full control of private repositories.
  • workflow - Update GitHub Action workflows.
  • read:org - Read org and team data.
  • read:user - Read user profile data.
  • user:email - Access user email addresses.
  • read:enterprise - Read enterprise data.
  • read:audit_log - Read audit logs (required for determining join dates).
Required permissions

The GitHub PAT requires enterprise-level permissions to access audit logs for determining user join dates. Make sure your token has the necessary scope.

Set up the metrics exporter

  1. Clone the repository from https://github.com/port-experimental/github-metrics.git

  2. Copy the example environment file and configure it with your access keys:

    cp .env.example .env
  3. Fill out the .env file with the following variables:

    • PORT_CLIENT_ID - Your Port Client ID.
    • PORT_CLIENT_SECRET - Your Port Client Secret.
    • X_GITHUB_ORGS - Comma-separated list of GitHub organizations to monitor.
    • X_GITHUB_ENTERPRISE - Your GitHub Enterprise instance (if applicable).
    • X_GITHUB_TOKEN - Your GitHub personal access token.
  4. Install the CLI:

    npm install
    npm run build
    npm link
  5. Run the metric collectors:

    gh-metrics onboarding-metrics
    gh-metrics pr-metrics
    gh-metrics workflow-metrics

Run the metrics exporter as a GitHub Action

For automated metric collection, add the required secrets and workflow file in the repository that will run the exporter.

Add GitHub metrics secrets

In your GitHub repository, go to Settings > Secrets and add the following secrets:

  • PORT_CLIENT_ID - Port Client ID learn more.
  • PORT_CLIENT_SECRET - Port Client Secret learn more.
  • X_GITHUB_ORGS - Comma-separated list of GitHub organizations to monitor.
  • X_GITHUB_ENTERPRISE - Your GitHub Enterprise instance (if applicable).
  • X_GITHUB_TOKEN - Your GitHub personal access token.

Create the metric collection workflow

Create the file .github/workflows/collect_metrics.yml in your repository:

GitHub metrics collection workflow (Click to expand)
name: collect_metrics
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * *'
jobs:
onboarding:
name: onboarding_metrics
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: oven-sh/setup-bun@v2
- run: bun run src/main.ts onboarding-metrics
env:
X_GITHUB_ORGS: ${{ secrets.X_GITHUB_ORGS }}
X_GITHUB_ENTERPRISE: ${{ secrets.X_GITHUB_ENTERPRISE }}
X_GITHUB_TOKEN: ${{ secrets.X_GITHUB_TOKEN }}
PORT_CLIENT_ID: ${{ secrets.PORT_CLIENT_ID }}
PORT_CLIENT_SECRET: ${{ secrets.PORT_CLIENT_SECRET }}
pr:
name: pr_metrics
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: oven-sh/setup-bun@v2
- run: bun run src/main.ts pr-metrics
env:
X_GITHUB_ORGS: ${{ secrets.X_GITHUB_ORGS }}
X_GITHUB_ENTERPRISE: ${{ secrets.X_GITHUB_ENTERPRISE }}
X_GITHUB_TOKEN: ${{ secrets.X_GITHUB_TOKEN }}
PORT_CLIENT_ID: ${{ secrets.PORT_CLIENT_ID }}
PORT_CLIENT_SECRET: ${{ secrets.PORT_CLIENT_SECRET }}
workflow:
name: workflow_metrics
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: oven-sh/setup-bun@v2
- run: bun run src/main.ts workflow-metrics
env:
X_GITHUB_ORGS: ${{ secrets.X_GITHUB_ORGS }}
X_GITHUB_ENTERPRISE: ${{ secrets.X_GITHUB_ENTERPRISE }}
X_GITHUB_TOKEN: ${{ secrets.X_GITHUB_TOKEN }}
PORT_CLIENT_ID: ${{ secrets.PORT_CLIENT_ID }}
PORT_CLIENT_SECRET: ${{ secrets.PORT_CLIENT_SECRET }}

This workflow will run daily at midnight and collect metrics for:

  • Onboarding metrics - Track user join dates and team assignments.
  • PR metrics - Calculate PR size, lifetime, pickup time, and success rates.
  • Workflow metrics - Track workflow execution times and success rates.
Metric collection frequency

The metrics are collected daily by default. You can adjust the cron schedule in the GitHub Action to collect metrics more or less frequently based on your needs.

For large organizations with many repositories, run the metrics collection during off-peak hours to reduce the chance of GitHub API rate limit issues.

Visualize GitHub engineering metrics

With your data collection in place, we can create a dashboard in Port to visualize all GitHub metrics and track engineering performance.

Create the engineering metrics dashboard

  1. Navigate to your software catalog.

  2. Click on the + button in the left sidebar.

  3. Select New dashboard.

  4. Name the dashboard GitHub Engineering Metrics.

  5. Input Monitor engineering performance and workflow metrics from GitHub under Description.

  6. Select the GitHub icon.

  7. Click Create.

Add engineering metrics widgets

In the new dashboard, create the following widgets to visualize your GitHub metrics:

Average PR Lifetime (Click to expand)
  1. Click + Widget and select Number Chart.

  2. Title: Average PR Lifetime (add the GitHub icon).

  3. Select Average entities Chart type and choose GitHub Pull Request as the Blueprint.

  4. Select pr_lifetime for the Property and choose Average of total.

  5. Select custom as the Unit and input seconds as the Custom unit.

  6. Click Save.

Average PR Size (Click to expand)
  1. Click + Widget and select Number Chart.

  2. Title: Average PR Size (add the GitHub icon).

  3. Select Average entities Chart type and choose GitHub Pull Request as the Blueprint.

  4. Select pr_size for the Property and choose Average of total.

  5. Select custom as the Unit and input lines of code as the Custom unit.

  6. Click Save.

Total Merged PRs (Click to expand)
  1. Click + Widget and select Number Chart.

  2. Title: Total Merged PRs (add the GitHub icon).

  3. Select Count entities Chart type and choose GitHub Pull Request as the Blueprint.

  4. Select count for the Function.

  5. Add this JSON to the Additional filters editor to filter merged PRs:

    [
    {
    "combinator":"and",
    "rules":[
    {
    "property":"pr_success_rate",
    "operator":"=",
    "value": 1
    }
    ]
    }
    ]
  6. Select custom as the Unit and input PRs as the Custom unit.

  7. Click Save.

Workflow Success Rates (Click to expand)
  1. Click + Widget and select Number Chart.

  2. Title: Average Workflow Success Rate (30 days) (add the GitHub icon).

  3. Select Average entities Chart type and choose Workflow as the Blueprint.

  4. Select successRate_last_30_days for the Property and choose Average of total.

  5. Select custom as the Unit and input % as the Custom unit.

  6. Click Save.

Average Workflow Duration (Click to expand)
  1. Click + Widget and select Number Chart.

  2. Title: Average Workflow Duration (add the GitHub icon).

  3. Select Average entities Chart type and choose Workflow as the Blueprint.

  4. Select meanDuration_last_30_days for the Property and choose Average of total.

  5. Select custom as the Unit and input seconds as the Custom unit.

  6. Click Save.

PR Metrics Table (Click to expand)
  1. Click + Widget and select Table.

  2. Title: PR Performance Metrics (add the GitHub icon).

  3. Choose the GitHub Pull Request blueprint.

  4. Click Save to add the widget to the dashboard.

  5. Click on the ... button in the top right corner of the table and select Customize table.

  6. In the top right corner of the table, click on Manage Properties and add the following properties:

    • Title: The PR title.
    • PR Size: Number of lines changed.
    • PR Lifetime (seconds): Time from creation to merge.
    • PR Pickup Time (seconds): Time to first review.
    • PR Success Rate (%): Percentage of successful PRs.
    • Review Participation: Number of reviewers.
    • State: Current PR state (open, closed, merged).
  7. Click on Group by any Column and select Repository.

  8. Click on the save icon in the top right corner of the widget to save the customized table.