Examples
This page contains mapping configuration examples for the GitLab integration.
Groups
The following example demonstrates how to ingest your GitLab groups, subgroups and projects to Port.
You can use the following Port blueprint definitions and integration configuration:
Group blueprint (click to expand)
{
"identifier": "gitlabGroup",
"title": "Group",
"icon": "GitLab",
"schema": {
"properties": {
"visibility": {
"icon": "Lock",
"title": "Visibility",
"type": "string",
"enum": [
"public",
"internal",
"private"
],
"enumColors": {
"public": "red",
"internal": "yellow",
"private": "green"
}
},
"url": {
"title": "URL",
"format": "url",
"type": "string",
"icon": "Link"
},
"description": {
"title": "Description",
"type": "string",
"icon": "BlankPage"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"aggregationProperties": {},
"relations": {}
}
Project blueprint (click to expand)
{
"identifier": "service",
"title": "Service",
"icon": "Microservice",
"schema": {
"properties": {
"url": {
"title": "URL",
"type": "string",
"format": "url"
},
"readme": {
"title": "README",
"type": "string",
"format": "markdown"
},
"description": {
"title": "Description",
"type": "string"
},
"language": {
"title": "Language",
"type": "string"
},
"namespace": {
"title": "Namespace",
"type": "string"
},
"fullPath": {
"title": "Full Path",
"type": "string"
},
"defaultBranch": {
"title": "Default Branch",
"type": "string"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"relations": {
"group": {
"title": "Group",
"target": "gitlabGroup",
"required": true,
"many": false
}
}
}
Integration mapping (click to expand)
deleteDependentEntities: true
createMissingRelatedEntities: true
enableMergeEntity: true
resources:
- kind: group
selector:
query: "true"
port:
entity:
mappings:
identifier: .full_path
title: .name
blueprint: '"gitlabGroup"'
properties:
url: .web_url
visibility: .visibility
description: .description
- kind: project
selector:
query: "true"
includeLanguages: "true"
includedFiles:
- README.md
port:
entity:
mappings:
identifier: .path_with_namespace | gsub(" "; "")
title: .name
blueprint: '"service"'
properties:
url: .web_url
readme: .__includedFiles["README.md"]
description: .description
language: .__languages | to_entries | max_by(.value) | .key
namespace: .namespace.name
fullPath: .namespace.full_path
defaultBranch: .default_branch
relations:
group: >-
.path_with_namespace | gsub(" "; "") | split("/") | .[:-1] |
join("/")
Group configuration options
The includeOnlyActiveGroups selector allows you to filter groups based on whether they are active or not.
By default, if not specified, all groups will be synced.
- kind: group
selector:
query: 'true'
includeOnlyActiveGroups: true
Projects, README.md and merge requests
Merge requests are fetched at the group level. Ensure your integration token has access to the parent GitLab group that contains your projects. Project-level access alone is not sufficient for merge request visibility.
For more information, see the troubleshooting section.
The following example demonstrates how to ingest your GitLab projects, their README.md file contents and merge requests to Port.
You can use the following Port blueprint definitions and integration configuration:
Project blueprint (click to expand)
{
"identifier": "service",
"title": "Service",
"icon": "Microservice",
"schema": {
"properties": {
"url": {
"title": "URL",
"type": "string",
"format": "url"
},
"readme": {
"title": "README",
"type": "string",
"format": "markdown"
},
"description": {
"title": "Description",
"type": "string"
},
"language": {
"title": "Language",
"type": "string"
},
"namespace": {
"title": "Namespace",
"type": "string"
},
"fullPath": {
"title": "Full Path",
"type": "string"
},
"defaultBranch": {
"title": "Default Branch",
"type": "string"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"relations": {}
}
Merge request blueprint (click to expand)
{
"identifier": "gitlabMergeRequest",
"title": "Merge Request",
"icon": "GitVersion",
"schema": {
"properties": {
"creator": {
"title": "Creator",
"type": "string"
},
"status": {
"title": "Status",
"type": "string",
"enum": [
"opened",
"closed",
"merged",
"locked"
],
"enumColors": {
"opened": "yellow",
"closed": "red",
"merged": "green",
"locked": "blue"
}
},
"createdAt": {
"title": "Created At",
"type": "string",
"format": "date-time"
},
"updatedAt": {
"title": "Updated At",
"type": "string",
"format": "date-time"
},
"mergedAt": {
"title": "Merged At",
"type": "string",
"format": "date-time"
},
"link": {
"title": "Link",
"format": "url",
"type": "string"
},
"leadTimeHours": {
"title": "Lead Time in hours",
"type": "number"
},
"reviewers": {
"title": "Reviewers",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"aggregationProperties": {},
"relations": {
"project": {
"title": "Service",
"target": "service",
"required": false,
"many": false
}
}
}
Integration configuration (click to expand)
resources:
- kind: project
selector:
query: "true"
includeLanguages: "true"
includedFiles:
- README.md
port:
entity:
mappings:
identifier: .path_with_namespace | gsub(" "; "")
title: .name
blueprint: '"service"'
properties:
url: .web_url
readme: .__includedFiles["README.md"]
description: .description
language: .__languages | to_entries | max_by(.value) | .key
namespace: .namespace.name
fullPath: .namespace.full_path
defaultBranch: .default_branch
- kind: merge-request
selector:
query: "true"
port:
entity:
mappings:
identifier: .id | tostring
title: .title
blueprint: '"gitlabMergeRequest"'
properties:
creator: .author.name
status: .state
createdAt: .created_at
updatedAt: .updated_at
mergedAt: .merged_at
link: .web_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)
reviewers: .reviewers | map(.name)
relations:
project: .references.full | gsub("!.+"; "")
Project configuration options
The includeOnlyActiveProjects selector allows you to filter projects based on whether they are active or not.
By default, if not specified, all projects will be synced.
- kind: project
selector:
query: 'true'
includeOnlyActiveProjects: true
Merge request configuration options
- States
- Updated After
- Include active groups
The states selector allows you to filter merge requests based on their state. You can specify one or more states to include in the sync.
Allowed values:
opened: Merge requests that are currently open.closed: Merge requests that have been closed without merging.merged: Merge requests that have been merged.
By default, if not specified, only opened merge requests will be synced.
- kind: merge-request
selector:
query: 'true'
states:
- merged
- opened
The updatedAfter selector allows you to filter merge requests based on when they were last updated. This helps you focus on recent changes and reduce the amount of historical data being synced.
The value represents the number of days to look back for merge requests. For example, setting it to 90 will only sync merge requests that have been updated in the last 90 days.
The updatedAfter parameter only affects merge requests that are not in the "opened" state. Open merge requests will always be synced regardless of their last update time.
By default, if not specified, it is set to 90 days.
- kind: merge-request
selector:
query: 'true'
updatedAfter: 90
The includeOnlyActiveGroups selector allows you to filter merge requests based on whether the parent group is active or not.
By default, if not specified, all merge requests for the authorized groups will be synced.
- kind: merge-request
selector:
query: 'true'
includeOnlyActiveGroups: true
Projects and issues
The following example demonstrates how to ingest your GitLab projects and their issues to Port.
You can use the following Port blueprint definitions and integration configuration:
Project blueprint (click to expand)
{
"identifier": "service",
"title": "Service",
"icon": "Microservice",
"schema": {
"properties": {
"url": {
"title": "URL",
"type": "string",
"format": "url"
},
"readme": {
"title": "README",
"type": "string",
"format": "markdown"
},
"description": {
"title": "Description",
"type": "string"
},
"language": {
"title": "Language",
"type": "string"
},
"namespace": {
"title": "Namespace",
"type": "string"
},
"fullPath": {
"title": "Full Path",
"type": "string"
},
"defaultBranch": {
"title": "Default Branch",
"type": "string"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"relations": {}
}
Issue blueprint (click to expand)
{
"identifier": "gitlabIssue",
"title": "Issue",
"icon": "GitLab",
"schema": {
"properties": {
"link": {
"title": "Link",
"type": "string",
"format": "url"
},
"description": {
"title": "Description",
"type": "string",
"format": "markdown"
},
"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"
},
"creator": {
"title": "Creator",
"type": "string"
},
"status": {
"title": "Status",
"type": "string",
"enum": ["opened", "closed"],
"enumColors": {
"opened": "green",
"closed": "purple"
}
}
}
},
"mirrorProperties": {},
"calculationProperties": {},
"aggregationProperties": {},
"relations": {
"project": {
"title": "Service",
"target": "service",
"required": false,
"many": false
}
}
}
Integration mapping (click to expand)
resources:
- kind: project
selector:
query: "true"
includeLanguages: "true"
port:
entity:
mappings:
identifier: .path_with_namespace | gsub(" "; "")
title: .name
blueprint: '"service"'
properties:
url: .web_url
description: .description
language: .__languages | to_entries | max_by(.value) | .key
namespace: .namespace.name
fullPath: .namespace.full_path
defaultBranch: .default_branch
- kind: issue
selector:
query: "true"
port:
entity:
mappings:
identifier: .id | tostring
title: .title
blueprint: '"gitlabIssue"'
properties:
creator: .author.name
status: .state
createdAt: .created_at
closedAt: .closed_at
updatedAt: .updated_at
description: .description
link: .web_url
labels: "[.labels[]]"
relations:
project: .references.full | gsub("#.+"; "")
Issues configuration options
- State
- Updated after
- Include Active Groups
- Issue Type
- Labels
- Include Non-Archived
The state selector allows you to filter issues based on their state. You can specify one of the allowed values to include in the sync.
Allowed values:
opened: Issues that are currently open.closed: Issues that have been closed.
By default, if not specified, all issues for the authorized groups will be synced.
- kind: issue
selector:
query: 'true'
state: "closed"
The updatedAfter selector allows you to filter issues based on when they were last updated. This helps you focus on recent changes and reduce the amount of historical data being synced.
The value represents the number of days to look back for issues. For example, setting it to 90 will only sync issues that have been updated on or after the last 90 days.
The updatedAfter parameter only affects issues that are not in the "opened" state. Open issues will always be synced regardless of their last update time.
By default, if not specified, all issues for the authorized groups will be synced.
- kind: issue
selector:
query: 'true'
updatedAfter: 90
The includeOnlyActiveGroups selector allows you to filter issues based on whether the parent group is active or not.
By default, if not specified, all issues for the authorized groups will be synced.
- kind: issue
selector:
query: 'true'
includeOnlyActiveGroups: true
The issueType selector allows you to filter issues based on their type.
Allowed values:
incidentissuetest_casetask
By default, if not specified, all issues for the authorized groups will be synced.
- kind: issue
selector:
query: 'true'
issueType: "incident"
The labels selector allows you to filter issues based on a comma-separated list of labels.
By default, if not specified, all issues for the authorized groups will be synced.
Issue must have all labels to be returned.
- kind: issue
selector:
query: 'true'
labels: "dev,v1"
The includeNonArchived selector allows you to filter issues from non-archived projects.
By default, if not specified, all issues for the authorized groups will be synced.
- kind: issue
selector:
query: 'true'
nonArchived: true
Project and branches
The following example demonstrates how to ingest your GitLab projects and their branches to Port.
You can use the following Port blueprint definitions and integration configuration:
Project blueprint (click to expand)
{
"identifier": "service",
"title": "Service",
"icon": "Microservice",
"schema": {
"properties": {
"url": {
"title": "URL",
"type": "string",
"format": "url"
},
"readme": {
"title": "README",
"type": "string",
"format": "markdown"
},
"description": {
"title": "Description",
"type": "string"
},
"language": {
"title": "Language",
"type": "string"
},
"namespace": {
"title": "Namespace",
"type": "string"
},
"fullPath": {
"title": "Full Path",
"type": "string"
},
"defaultBranch": {
"title": "Default Branch",
"type": "string"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"relations": {}
}
Branch blueprint (click to expand)
{
"identifier": "gitlabBranch",
"title": "Gitlab Branch",
"icon": "GitLab",
"schema": {
"properties": {
"default": {
"type": "boolean",
"title": "Default",
"description": "Is default branch",
"default": false
},
"protected": {
"type": "boolean",
"title": "Protected",
"default": false
},
"last_commit_id": {
"type": "string",
"title": "Last Commit ID",
"icon": "Git"
},
"last_contributor": {
"type": "string",
"title": "Last Contributor",
"icon": "User"
},
"last_commit_date": {
"type": "string",
"format": "date-time",
"title": "Last Commit Date",
"dateFormat": "iso"
},
"name": {
"type": "string",
"title": "Name"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"aggregationProperties": {},
"relations": {
"project": {
"title": "Service",
"target": "service",
"required": true,
"many": false
}
}
}
Integration Mapping (click to expand)
resources:
- kind: branch
selector:
query: 'true'
defaultBranchOnly: true
port:
entity:
mappings:
identifier: .__project.path_with_namespace + "/" + .name | gsub(" "; "")
title: .name
blueprint: '"gitlabBranch"'
properties:
name: .name
default: .default
protected: .protected
last_commit_id: .commit?.id
last_contributor: .commit?.committer_email
last_commit_date: .commit?.committed_date
relations:
project: .__project.path_with_namespace | gsub(" "; "")
Branch configuration options
- Default branch only
- Search
- Regex
- Include active projects
When set to true, only the default branch of each repository is ingested. Defaults to true.
- kind: branch
selector:
query: 'true'
defaultBranchOnly: true
The search selector ingests only branches whose names include the specified search string. Use ^term or term$ to match the start or end of a branch name.
The following example ingests all branches starting with test:
- kind: branch
selector:
query: 'true'
defaultBranchOnly: false
search: ^test
The regex selector ingests only branches that match a specified Re2 regular expression. The regex and search selectors cannot be used together - if both are specified, regex takes precedence.
The following example ingests all branches starting with test:
- kind: branch
selector:
query: 'true'
defaultBranchOnly: false
regex: ^test
When set to true, the includeOnlyActiveProjects selector ingests only branches belonging to active projects. By default, branches from all projects are ingested regardless of project status.
- kind: branch
selector:
query: 'true'
includeOnlyActiveProjects: true
Files and file contents
Below are two examples for mapping files and contents:
The following example shows how to ingest dependencies from a package.json file in your GitLab repository into Port.
You can use the following Port blueprint definitions and integration configuration:
Package blueprint (click to expand)
{
"identifier": "package",
"title": "Package",
"icon": "Package",
"schema": {
"properties": {
"package": {
"icon": "DefaultProperty",
"type": "string",
"title": "Package"
},
"version": {
"icon": "DefaultProperty",
"type": "string",
"title": "Version"
}
},
"required": [
"package",
"version"
]
},
"mirrorProperties": {},
"calculationProperties": {},
"aggregationProperties": {},
"relations": {}
}
Integration mapping (click to expand)
resources:
- kind: file
selector:
query: 'true'
files:
# The path field uses GitLab's Advanced Search syntax: supports simple * wildcards (e.g., *.tf, test_*) and exact paths (e.g., src/app/main.py)
path: package.json
repos:
# Replace with your repository's path_with_namespace (e.g., "group/project" or "group/subgroup/project")
- group/my-project
port:
itemsToParse: .file.content.dependencies | to_entries
entity:
mappings:
identifier: >-
.item.key + "_" + if (.item.value | startswith("^")) then
.item.value[1:] else .item.value end
title: .item.key + "@" + .item.value
blueprint: '"package"'
properties:
package: .item.key
version: .item.value
The example will parse the package.json file in your repository and extract the dependencies into Port entities.
The following example shows how to ingest teams from a YAML file in your GitLab repository into Port.
Team blueprint (click to expand)
{
"identifier": "team",
"title": "team",
"icon": "Team",
"schema": {
"properties": {
"description": {
"type": "string",
"title": "Description"
},
"slack_channel_name": {
"type": "string",
"title": "Slack channel name"
}
},
"required": [
"description"
]
},
"mirrorProperties": {},
"calculationProperties": {},
"aggregationProperties": {},
"relations": {}
}
YAML file example (click to expand)
blueprint: team
identifier: team
title: development_team
properties:
description: Development team
slack_channel_name: development-team
Integration mapping (click to expand)
resources:
- kind: file
selector:
query: 'true'
files:
path: teams_file.yml
repos:
# Replace with your repository's path_with_namespace (e.g., "group/project" or "group/subgroup/project")
- getport-labs/my-project
port:
entity:
mappings:
# Note that when parsing a YAML file, you should specify the index of the parsed document event when there is only one document.
identifier: .file.content.[0].identifier
title: .file.content.[0].title
blueprint: .file.content.[0].blueprint
properties:
slack_channel_name: .file.content.[0].properties.slack_channel_name
description: .file.content.[0].properties.description
The example will parse the YAML file in your repository and extract the teams into Port entities.
For more information about ingesting files and file contents, see the capabilities page.
Projects and monorepos
The following example demonstrates how to ingest your GitLab projects and their monorepo folders to Port.
You can use the following Port blueprint definitions and integration configuration:
Project blueprint (click to expand)
{
"identifier": "service",
"title": "Service",
"icon": "Microservice",
"schema": {
"properties": {
"url": {
"title": "URL",
"type": "string",
"format": "url"
},
"readme": {
"title": "README",
"type": "string",
"format": "markdown"
},
"description": {
"title": "Description",
"type": "string"
},
"language": {
"title": "Language",
"type": "string"
},
"namespace": {
"title": "Namespace",
"type": "string"
},
"fullPath": {
"title": "Full Path",
"type": "string"
},
"defaultBranch": {
"title": "Default Branch",
"type": "string"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"relations": {}
}
Integration mapping (click to expand)
resources:
- kind: folder
selector:
query: "true" # JQ boolean query. If evaluated to false - skip syncing the object.
folders: # Specify the repositories and folders to include under this relative path.
- path: "apps/" # Relative path to the folders within the repositories.
repos: # List of repositories to include folders from.
- backend-service
- frontend-service
includedFiles:
- README.md
port:
entity:
mappings:
identifier: .folder.name
title: .folder.name
blueprint: '"service"'
properties:
url: >-
.repo.web_url + "/tree/" + .repo.default_branch + "/" +
.folder.path
description: .repo.description
namespace: .repo.namespace.name
full_path: .repo.path_with_namespace + "/" + folder.path
language: .repo.__languages | to_entries | max_by(.value) | .key
readme: .__includedFiles["README.md"]
To retrieve the root folders of your monorepo, you can use this following syntax in your port-app-config.yml:
- kind: folder
selector:
query: "true" # JQ boolean query. If evaluated to false - skip syncing the object.
folders: # Specify the repositories and folders to include under this relative path.
- path: "/" # Relative path to the folders within the repositories
repos: # List of repositories to include folders from.
- backend-service
- frontend-service
You can also specify a different path for each monorepo repository, for example:
- kind: folder
selector:
query: "true" # JQ boolean query. If evaluated to false - skip syncing the object.
folders: # Specify the repositories and folders to include under this relative path.
- path: "apps/"
repos:
- gaming-apps
- path: "microservices/"
repos:
- backend-services
Projects and folders
The following example demonstrates how to ingest your GitLab projects and their folders to Port.
You can use the following Port blueprint definitions and integration configuration:
Project blueprint (click to expand)
{
"identifier": "service",
"title": "Service",
"icon": "Microservice",
"schema": {
"properties": {
"url": {
"title": "URL",
"type": "string",
"format": "url"
},
"readme": {
"title": "README",
"type": "string",
"format": "markdown"
},
"description": {
"title": "Description",
"type": "string"
},
"language": {
"title": "Language",
"type": "string"
},
"namespace": {
"title": "Namespace",
"type": "string"
},
"fullPath": {
"title": "Full Path",
"type": "string"
},
"defaultBranch": {
"title": "Default Branch",
"type": "string"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"relations": {}
}
Folder blueprint (click to expand)
{
"identifier": "gitlabFolder",
"title": "Folder",
"icon": "GitLab",
"schema": {
"properties": {
"url": {
"type": "string",
"title": "URL",
"format": "url",
"description": "Link to the folder in GitLab"
},
"readme": {
"type": "string",
"title": "README",
"format": "markdown",
"description": "Content of the folder's README file"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"aggregationProperties": {},
"relations": {
"project": {
"title": "Service",
"target": "service",
"required": false,
"many": false
}
}
}
Integration mapping (click to expand)
resources:
- kind: project
selector:
query: "true"
includeLanguages: "true"
includedFiles:
- README.md
port:
entity:
mappings:
identifier: .path_with_namespace | gsub(" "; "")
title: .name
blueprint: '"service"'
properties:
url: .web_url
readme: .__includedFiles["README.md"]
description: .description
language: .__languages | to_entries | max_by(.value) | .key
namespace: .namespace.name
fullPath: .namespace.full_path
defaultBranch: .default_branch
- kind: folder
selector:
query: "true"
folders:
- path: "/" # Using "/" will ingest the folders from the root of each of repository as entities
repos:
# Replace with your repository's path_with_namespace
- group/backend-service
- group/frontend-service
includedFiles:
- README.md
port:
entity:
mappings:
identifier: .folder.name
title: .folder.name
blueprint: '"gitlabFolder"'
properties:
url: >-
.repo.web_url + "/tree/" + .repo.default_branch + "/" +
.folder.path
readme: .__includedFiles["README.md"]
relations:
project: .references.full | gsub("!.+"; "")
Folder mapping patterns
You can specify different paths for different repositories:
resources:
- kind: folder
selector:
query: "true"
folders:
- path: "apps/"
repos:
- group/gaming-services
- path: "packages/"
repos:
- group/shared-libraries
Members and group with members
Prerequisites
- When using GitLab Self Hosted, an admin token is required, rather than a group access token, to retrieve the
primary email addressesof members. - When using GitLab Enterprise, accounts can retrieve the
primary email addressesof members within their groups, provided the members are part of user accounts administered by an organization with verified domains for groups. For more information, see limitations.
Primary email addresses are not available for GitLab "Free plan" users.
Members
The following example demonstrates how to ingest your GitLab members to Port.
You can use the following Port blueprint definitions and integration configuration:
Member blueprint (click to expand)
{
"identifier": "gitlabMember",
"title": "GitLab Member",
"icon": "GitLab",
"schema": {
"properties": {
"url": {
"type": "string",
"title": "URL",
"format": "url",
"description": "Link to the member's GitLab profile"
},
"state": {
"type": "string",
"title": "State",
"description": "The state of the member's account"
},
"email": {
"type": "string",
"title": "Email",
"format": "email",
"description": "The member's email address"
},
"created_by": {
"type": "string",
"title": "Created By",
"description": "Name of the user who added this member"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"aggregationProperties": {},
"relations": {}
}
Integration Mapping (click to expand)
resources:
- kind: member
selector:
query: 'true'
port:
entity:
mappings:
identifier: .username
title: .name
blueprint: '"gitlabMember"'
properties:
url: .web_url
state: .state
email: .email
created_by: .created_by.name
To retrieve the members of your active groups only, you can use the following syntax in your port-app-config.yml:
- kind: member
selector:
query: "true"
includeOnlyActiveGroups: true
Groups with members
The following example demonstrates how to ingest your GitLab groups and their members to Port.
You can use the following Port blueprint definitions and integration configuration:
Group with members blueprint (click to expand)
{
"identifier": "gitlabGroup",
"title": "Group",
"icon": "GitLab",
"schema": {
"properties": {
"visibility": {
"icon": "Lock",
"title": "Visibility",
"type": "string",
"enum": [
"public",
"internal",
"private"
],
"enumColors": {
"public": "red",
"internal": "yellow",
"private": "green"
}
},
"url": {
"title": "URL",
"format": "url",
"type": "string",
"icon": "Link"
},
"description": {
"title": "Description",
"type": "string",
"icon": "BlankPage"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"aggregationProperties": {},
"relations": {
"gitlabMembers": {
"title": "Members",
"target": "gitlabMember",
"required": false,
"many": true
}
}
}
Integration mapping (click to expand)
resources:
- kind: group-with-members
selector:
query: 'true'
port:
entity:
mappings:
identifier: .full_path
title: .name
blueprint: '"gitlabGroup"'
properties:
url: .web_url
visibility: .visibility
description: .description
relations:
gitlabMembers: .__members | map(.username)
- Include Bot Members
- Include Inherited and Invited Members
GitLab allows the creation of tokens (bots) for automated tasks, which can be associated with groups or projects via access tokens.
The includeBotMembers parameter is used to filter out bot members from the actual GitLab members.
By default, this selector is set to false, which means the integration will only sync actual members.
- kind: group-with-members
selector:
query: 'true'
includeBotMembers: false
- kind: members
selector:
query: 'true'
includeBotMembers: false
You can also specify the includeInheritedMembers selector to control the inclusion of inherited and invited members in the member data.
By default, this parameter is set to false, and the integration will sync only direct members without inherited members and/or invited members.
Enabling includeInheritedMembers uses GitLab endpoints that return all members, including inherited and invited membership, not just direct members. That means much larger payloads, more work for GitLab, and longer resyncs and higher API volume. The slowdown can be several times worse than direct members only, depending on group depth and how many inherited or invited members you have.
Keep this selector false unless you explicitly need inherited or invited members. Prefer validating on a narrow selector.query or a non-production GitLab scope first.
For background on the API, see the GitLab members API.
- kind: group-with-members
selector:
query: 'true'
includeInheritedMembers: true
- kind: members
selector:
query: 'true'
includeInheritedMembers: true
- Refer to the setup section to learn more about the integration configuration setup process.
- We leverage JQ JSON processor to map and transform GitLab objects to Port entities.
- See GitLab group and project member object structure in the GitLab API documentation.
Mapping projects with members
Set up the blueprint and mapping on the GitLab V2 configuration page first. The tabs below cover selectors for this kind (includeBotMembers, includeInheritedMembers, includeOnlyActiveProjects). Each synced project includes a __members array with its direct (and optionally inherited) members.
Integration mapping (click to expand)
resources:
- kind: project-with-members
selector:
query: 'true'
includeBotMembers: false
# Use true only if you need inherited members; GitLab /members/all is much heavier than direct members.
includeInheritedMembers: false
port:
entity:
mappings:
identifier: .path_with_namespace | gsub(" "; "")
title: .name
blueprint: '"service"'
properties:
url: .web_url
relations:
gitlabMembers: .__members | map(.username)
- Include Bot Members
- Include Inherited Members
- Include Only Active Projects
GitLab allows the creation of tokens (bots) for automated tasks, which can be associated with groups or projects via access tokens.
The includeBotMembers parameter is used to filter out bot members from the actual GitLab members.
By default, this selector is set to false, which means the integration will only sync actual members.
- kind: project-with-members
selector:
query: 'true'
includeBotMembers: false
You can specify the includeInheritedMembers selector to control the inclusion of inherited members in the member data.
By default, this parameter is set to false, and the integration will use /projects/:id/members to sync only direct members.
When set to true, the integration uses /projects/:id/members/all to include inherited members from parent groups.
The /projects/:id/members/all path returns every effective member on the project (including membership inherited from parent groups), so it is much heavier than direct members only. Expect higher GitLab load, larger __members arrays, and longer resyncs (often several times longer on large hierarchies, depending on inherited membership).
Enable this only when you truly need inherited members. Start with a narrow selector.query or a small set of projects and measure duration before rolling out broadly.
This mirrors the cost profile of includeInheritedMembers on group-with-members, which keeps behavior aligned between group-level and project-level membership in the integration.
- kind: project-with-members
selector:
query: 'true'
includeInheritedMembers: true
You can specify the includeOnlyActiveProjects selector to filter projects by their activity status.
By default, this parameter is set to null, which means all projects are included.
- kind: project-with-members
selector:
query: 'true'
includeOnlyActiveProjects: true
- Refer to the setup section to learn more about the integration configuration setup process.
- We leverage JQ JSON processor to map and transform GitLab objects to Port entities.
- See GitLab group and project member object structure in the GitLab API documentation.
Projects, pipelines and jobs
The following example demonstrates how to ingest your GitLab projects, their pipelines and jobs runs to Port.
You can use the following Port blueprint definitions and integration configuration:
Pipeline blueprint (click to expand)
{
"identifier": "gitlabPipeline",
"title": "GitLab Pipeline",
"icon": "GitLab",
"schema": {
"properties": {
"creator": {
"type": "string",
"title": "Creator",
"description": "Name of the user who triggered the pipeline"
},
"status": {
"type": "string",
"title": "Status",
"description": "Current status of the pipeline"
},
"createdAt": {
"type": "string",
"title": "Created At",
"format": "date-time",
"description": "When the pipeline was created"
},
"updatedAt": {
"type": "string",
"title": "Updated At",
"format": "date-time",
"description": "When the pipeline was last updated"
},
"description": {
"type": "string",
"title": "Description",
"description": "Pipeline description"
},
"link": {
"type": "string",
"title": "Link",
"format": "url",
"description": "URL to the pipeline in GitLab"
}
},
"required": []
},
"relations": {
"project": {
"title": "Service",
"target": "service",
"required": false,
"many": false
}
}
}
Job blueprint (click to expand)
{
"identifier": "gitlabJob",
"title": "GitLab Job",
"icon": "GitLab",
"schema": {
"properties": {
"creator": {
"type": "string",
"title": "Creator",
"description": "Name of the user who triggered the job"
},
"startedAt": {
"type": "string",
"title": "Started At",
"format": "date-time",
"description": "When the job started"
},
"updatedAt": {
"type": "string",
"title": "Updated At",
"format": "date-time",
"description": "When the job was last updated"
},
"finishedAt": {
"type": "string",
"title": "Finished At",
"format": "date-time",
"description": "When the job finished"
},
"stage": {
"type": "string",
"title": "Stage",
"description": "Pipeline stage this job belongs to"
},
"status": {
"type": "string",
"title": "Status",
"description": "Current status of the job"
},
"link": {
"type": "string",
"title": "Link",
"format": "url",
"description": "URL to the job in GitLab"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"aggregationProperties": {},
"relations": {
"pipeline": {
"title": "Pipeline",
"target": "gitlabPipeline",
"required": false,
"many": false
}
}
}
Integration Mapping (click to expand)
resources:
- kind: pipeline
selector:
query: "true"
port:
entity:
mappings:
identifier: .id | tostring
title: .title // (.id | tostring)
blueprint: '"gitlabPipeline"'
properties:
creator: .user.name
status: .status
createdAt: .created_at
updatedAt: .updated_at
description: .description
link: .web_url
relations:
project: .__project.path_with_namespace
- kind: job
selector:
query: "true"
port:
entity:
mappings:
identifier: .id | tostring
title: .name
blueprint: '"gitlabJob"'
properties:
creator: .user.name
startedAt: .started_at
updatedAt: .updated_at
finishedAt: .finished_at
stage: .stage
status: .status
link: .web_url
relations:
pipeline: .pipeline.id | tostring
To retrieve the pipelines of your active projects only, you can use the following syntax in your port-app-config.yml:
- kind: pipeline
selector:
query: "true"
includeOnlyActiveProjects: true
To retrieve the jobs of your active projects only, you can use the following syntax in your port-app-config.yml:
- kind: job
selector:
query: "true"
includeOnlyActiveProjects: true
Releases
The following example demonstrates how to ingest your GitLab releases to Port.
You can use the following Port blueprint definitions and integration configuration:
Release blueprint (click to expand)
{
"identifier": "gitlabRelease",
"title": "GitLab Release",
"icon": "GitVersion",
"schema": {
"properties": {
"tagName": {
"title": "Tag Name",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"title": "Description",
"type": "string",
"format": "markdown"
},
"createdAt": {
"title": "Created At",
"type": "string",
"format": "date-time"
},
"releasedAt": {
"title": "Released At",
"type": "string",
"format": "date-time"
},
"author": {
"title": "Author",
"type": "string"
},
"commitSha": {
"title": "Commit SHA",
"type": "string"
},
"upcomingRelease": {
"title": "Upcoming Release",
"type": "boolean"
}
}
},
"calculationProperties": {},
"aggregationProperties": {},
"relations": {
"service": {
"title": "Service",
"target": "service",
"required": false,
"many": false
},
"gitlabMember": {
"title": "Author",
"target": "gitlabMember",
"required": false,
"many": false
}
}
}
Integration Mapping (click to expand)
resources:
- kind: release
selector:
query: 'true'
port:
entity:
mappings:
identifier: .__project.path_with_namespace + "/" + .tag_name | gsub(" "; "")
title: .name
blueprint: '"gitlabRelease"'
properties:
tagName: .tag_name
name: .name
description: .description
createdAt: .created_at
releasedAt: .released_at
author: .author.name
commitSha: .commit.id
upcomingRelease: .upcoming_release
relations:
service: .__project.path_with_namespace | gsub(" "; "")
gitlabMember: .author.username
To retrieve the releases of your active projects only, you can use the following syntax in your port-app-config.yml:
- kind: release
selector:
query: "true"
includeOnlyActiveProjects: true
Tags
The following example demonstrates how to ingest your GitLab tags to Port.
You can use the following Port blueprint definitions and integration configuration:
Tag blueprint (click to expand)
{
"identifier": "gitlabTag",
"title": "GitLab Tag",
"icon": "GitVersion",
"schema": {
"properties": {
"tagName": {
"title": "Tag Name",
"type": "string"
},
"message": {
"title": "Message",
"type": "string"
},
"protected": {
"title": "Protected",
"type": "boolean"
},
"createdAt": {
"title": "Created At",
"type": "string",
"format": "date-time"
},
"commitSha": {
"title": "Commit SHA",
"type": "string"
},
"commitTitle": {
"title": "Commit Title",
"type": "string"
}
}
},
"calculationProperties": {},
"aggregationProperties": {},
"relations": {
"service": {
"title": "Service",
"target": "service",
"required": false,
"many": false
}
}
}
Integration Mapping (click to expand)
resources:
- kind: tag
selector:
query: 'true'
port:
entity:
mappings:
identifier: .__project.path_with_namespace + "/" + .name | gsub(" "; "")
title: .name
blueprint: '"gitlabTag"'
properties:
tagName: .name
message: .message
protected: .protected
createdAt: .created_at
commitSha: .commit.id
commitTitle: .commit.title
relations:
service: .__project.path_with_namespace | gsub(" "; "")
To retrieve the tags of your active projects only, you can use the following syntax in your port-app-config.yml:
- kind: tag
selector:
query: "true"
includeOnlyActiveProjects: true