Migration guide to the v2 integration
This guide walks through the process of migrating from Port's GitLab integration to the new GitLab-v2 integration.
Overviewโ
GitLab-v2 introduces significant authentication and performance improvements:
- Simplified authentication: Replace multiple group tokens with a single service account token.
 - Enhanced performance: Faster resync with improved API efficiency.
 - New capabilities: Support for pipeline jobs and enhanced group handling.
 
Changesโ
Authentication modelโ
GitLab approach: Multiple group access tokens mapped to specific paths
integration:
  secrets:
    tokenMapping: |
      {"glpat-token1": ["**/Group1/**"], "glpat-token2": ["**/Group2/**"]}
GitLab-v2 approach: Single service account token with broad access
integration:
  secrets:
    token: "glpat-service-account-token"
Blueprint mapping changesโ
The blueprints used in GitLab-v2 have evolved to provide cleaner data structures and better relationships between entities. Understanding these changes is essential for a successful migration.
Kind mapping changes by resource typeโ
1. project kind (Required update)โ
GitLab configuration:
- kind: project
  selector:
    query: "true"
    includeLabels: "true"  # โ Remove: No longer supported
  port:
    entity:
      mappings:
        identifier: .path_with_namespace | gsub(" "; "")
        title: .name
        blueprint: '"service"'  # โ
 Keep: Already uses 'service'
        properties:
          language: .__languages | to_entries | max_by(.value) | .key
          labels: .__labels  # โ Remove: Labels no longer available
GitLab-v2 configuration:
- kind: project
  selector:
    query: "true"
    includeLanguages: "true"  # โ
 Add: New selector for language detection
  port:
    entity:
      mappings:
        identifier: .path_with_namespace | gsub(" "; "")
        title: .name
        blueprint: '"service"'  # โ
 No change needed
        properties:
          language: .__languages | to_entries | max_by(.value) | .key
          # Remove labels property - no longer available
2. merge-request kind (Configuration update)โ
GitLab configuration:
- kind: merge-request
  port:
    entity:
      mappings:
        identifier: .id | tostring
        title: .title
        blueprint: '"gitlabMergeRequest"'
GitLab-v2 configuration:
- kind: merge-request
  selector:
    query: "true"
    states: ["opened", "merged"]  # โ
 Add: New selector options
    updatedAfter: 90  # โ
 Add: Filter by update time (days)
  port:
    entity:
      mappings:
        identifier: .id | tostring
        title: .title
        blueprint: '"gitlabMergeRequest"'  # โ
 No change needed
        properties:
          creator: .author.name
          reviewers: .reviewers | map(.name)
3. Member handling changes (Architecture change)โ
GitLab and GitLab-v2 handle members differently. GitLab embeds members as properties within projects/groups, while GitLab-v2 treats members as separate entities with relations.
GitLab approach - Members as embedded properties:
- kind: project-with-members # โ Remove: No longer supported
  selector:
    query: 'true'
    includeInheritedMembers: false 
    includeBotMembers: false
    includeVerboseMemberObject: false
  port:
    entity:
      mappings:
        identifier: .path_with_namespace | gsub(" "; "")
        title: .name
        blueprint: '"service"'
        properties:
          members: .__members  # โ Members embedded as properties
- kind: group-with-members
  selector:
    query: 'true'
    includeInheritedMembers: false # โ Remove: No longer supported
    includeBotMembers: false # โ
 Keep: Still supported
    includeVerboseMemberObject: false # โ Remove: No longer supported
  port:
    entity:
      mappings:
        identifier: .full_path
        title: .name
        blueprint: '"gitlabGroup"'
        properties:
          members: .__members  # โ Members embedded as properties
GitLab-v2 approach - Members as separate entities with relations:
# โ
 New: Dedicated member entities
- kind: member
  selector:
    query: 'true'
    includeBotMembers: false
  port:
    entity:
      mappings:
        identifier: .username
        title: .name
        blueprint: '"gitlabMember"'
        properties:
          url: .web_url
          state: .state
          email: .email
          locked: .locked
# โ
 Updated: Groups with member relations (not embedded properties)
- kind: group-with-members
  selector:
    query: 'true'
    includeBotMembers: false
  port:
    entity:
      mappings:
        identifier: .full_path
        title: .name
        blueprint: '"gitlabGroup"'
        properties:
          url: .web_url
          visibility: .visibility
          description: .description
        relations:
          gitlabMembers: .__members | map(.username)  # โ
 Relations, not properties
4. file kind (Search API and repository format changes)โ
For file resync, GitLab-v2 now uses GitLab's Advanced Search API with its specific syntax and limitations:
GitLab format:
- kind: file
  selector:
    files:
      path: '**/package.json'  # โ Custom glob patterns
      repos:
        - "backend-service"  # โ Simple repository name
        - "frontend-app"
GitLab-v2 format:
- kind: file
  selector:
    files:
      path: 'package.json'  # โ
 GitLab Advanced Search syntax (https://docs.gitlab.com/user/search/advanced_search/#use-advanced-search)
      repos:
        - "my-org/backend-service"  # โ
 Full namespace/project path
        - "my-org/frontend-app"
      skipParsing: false  # โ
 New option to skip parsing and return raw content
GitLab-v2's path parameter uses GitLab's Advanced Search syntax, which differs from v1's glob patterns. The search supports simple * wildcards for filename patterns like *.tf, package.json, and test_*, as well as exact file paths like src/app/main.py and infra/terraform/main.tf.
The search doesn't support path wildcards like infra/terraform/*.tf โ, recursive patterns like **/filename โ, or complex patterns like *.{js,ts}, [abc]*, and !exclude โ.
When migrating complex v1 patterns, you can split them into multiple file kinds or specify exact paths for targeted files. See the Migration Pattern Comparison table below for specific examples.
5. folder kind (Repository selector changes)โ
For folder resync, GitLab-v2 changes the repository specification format to support branch-specific folder mapping:
GitLab format:
- kind: folder
  selector:
    folders:
      - path: "src"
        repos:
          - "backend-service"  # โ Simple repository name
          - "frontend-app"
        branch: "main"  # โ Single branch for all repos
GitLab-v2 format:
- kind: folder
  selector:
    folders:
      - path: "src"
        repos:
          - name: "my-org/backend-service"  # โ
 Full namespace/project path
            branch: "main"  # โ
 Branch specified per repository
          - name: "my-org/frontend-app"
            branch: "develop"  # โ
 Different branches per repository
6. New kinds available in GitLab-v2โ
GitLab-v2 introduces several new kinds not available in GitLab:
pipeline kind (New):
- kind: pipeline
  selector:
    query: 'true'
  port:
    entity:
      mappings:
        identifier: .id | tostring
        title: .name
        blueprint: '"gitlabPipeline"'
job kind (New):
- kind: job
  selector:
    query: 'true'
  port:
    entity:
      mappings:
        identifier: .id | tostring
        title: .name
        blueprint: '"gitlabJob"'
        properties:
          status: .status
          stage: .stage
          duration: .duration
issue kind (Enhanced):
- kind: issue
  selector:
    query: 'true'
  port:
    entity:
      mappings:
        identifier: .id | tostring
        title: .title
        blueprint: '"gitlabIssue"'
        properties:
          creator: .author.name
          status: .state
          labels: "[.labels[]]"
        relations:
          project: .references.full | gsub("#.+"; "")
Configuration selector changesโ
GitLab-v2 introduces new selector options while removing some GitLab-specific configurations that are no longer needed.
Removed selectorsโ
The following selectors from GitLab are no longer available in GitLab-v2:
- includeLabels: Filtered projects based on labels but was rarely used and added unnecessary complexity
 - includeInheritedMembers: Member inheritance is now handled differently in GitLab-v2, making this selector obsolete
 - includeVerboseMemberObject: The member object structure has been standardized in GitLab-v2, eliminating the need for this verbose option
 
New selectors in GitLab-v2โ
GitLab-v2 introduces several new selector options that provide better control over data resync:
- includeLanguages: Enables language detection and inclusion in project entities. When set to true, the integration will analyze repository languages and include the primary language in the project properties
 - states: Available for merge requests, allows you to specify which merge request states to resync (opened, closed, merged)
 - updatedAfter: For merge requests, helps limit resync to recently updated merge requests by specifying the number of days to look back
 
Summary of key changesโ
The following table summarizes all the major differences between GitLab and GitLab-v2 to help you prepare for migration:
| Kind/Feature | GitLab | GitLab-v2 | Action Required | 
|---|---|---|---|
| project kind | includeLabels selector | includeLanguages selector | Replace includeLabels: true with includeLanguages: true | 
| merge-request kind | Basic configuration | Enhanced selectors | Add states and updatedAfter selectors | 
| Member handling | project-with-members + group-with-members (embedded) | member kind + group-with-members (relations) | Add dedicated member kind, update group relations | 
| project-with-members kind | โ Supported | โ Not available | Remove and use separate member + project kinds | 
| file kind | Custom glob patterns + simple repo names | GitLab Advanced Search syntax + full namespace paths + skipParsing option | Update to GitLab search syntax, update repo names to org/repo format | 
| folder kind | Simple repo names + single branch | Repository objects with name/branch pairs | Update repos to objects with name and branch properties | 
| pipeline kind | โ Not available | โ New kind | Add pipeline mapping if needed | 
| job kind | โ Not available | โ New kind | Add job mapping if needed | 
| issue kind | โ Limited support | โ Enhanced | Update to new issue mapping | 
File and folder mapping updatesโ
The way you specify repositories for file and folder resync has changed significantly between versions.
| Repository Specification | GitLab Format | GitLab-v2 Format | 
|---|---|---|
| File repos | "backend-service" | "my-org/backend-service" | 
| Folder repos | "frontend-app" | "my-org/frontend-app" | 
The namespace path format follows GitLab's standard group/project or group/subgroup/project structure, ensuring accurate repository identification even when multiple projects share the same name across different groups.
Migration stepsโ
Step 1: Create a GitLab service accountโ
Choose the appropriate setup method for your GitLab instance:
For GitLab.com (SaaS):
- Navigate to your top-level group settings
 - Go to Access Tokens under the group settings
 - Create a Group Service Account
 
For GitLab self-managed:
- Create a new user account (e.g., 
port-integration-bot) - Add this user to all relevant groups with Developer permissions or higher
 
Step 2: Generate the access tokenโ
- Sign in to your service account
 - Navigate to User Settings > Access Tokens
 - Create a new personal access token with:
- Name: 
Port Integration Token - Scopes: 
api(orread_api+read_repositoryfor read-only) - Expiration: Set according to your security policy
 
 - Name: 
 - Save the generated token securely
 
The service account needs access to all groups and projects you want to sync. For webhook functionality, it also needs permission to create webhooks.
Step 3: Update your integration configurationโ
Replace your current token mapping configuration with the new single token approach. This step eliminates the complexity of managing multiple tokens while ensuring the service account has appropriate access across your GitLab instance.
Before: GitLab configuration with token mapping
integration:
  secrets:
    tokenMapping: |
      {
        "glpat-old-token-1": ["**/DevTeam/**", "**/BackendServices/**"],
        "glpat-old-token-2": ["**/FrontendApps/**"]
      }
After: GitLab-v2 configuration with single token
integration:
  secrets:
    token: "glpat-your-new-service-account-token"
Step 4: Update resource selectors and blueprintsโ
Review your mapping configuration for deprecated selectors and blueprint references:
Update each kind mapping specifically:
- 
For
projectkinds:- Remove 
includeLabels: truefrom selectors - Add 
includeLanguages: trueto selectors - Remove 
labels: .__labelsfrom property mappings 
 - Remove 
 - 
For
merge-requestkinds:- Add 
states: ["opened", "merged"]to selectors (optional) - Add 
updatedAfter: 90to selectors (optional) - Simplify reviewer mappings to 
reviewers: .reviewers | map(.name) 
 - Add 
 - 
For member handling (architecture change):
- Remove 
project-with-memberskind configurations - Update 
group-with-membersto use relations instead of embedded properties - Add new 
memberkind withincludeBotMembers: falseselector - Remove deprecated selectors: 
includeInheritedMembers,includeVerboseMemberObject 
 - Remove 
 - 
For
filekinds:- Update file paths to use GitLab Advanced Search syntax (change 
'**/package.json'to'*package.json') - Update all repo specifications from 
"repo-name"to"org/repo-name"format - Optionally add 
skipParsing: falseto selector if you want to control content parsing 
 - Update file paths to use GitLab Advanced Search syntax (change 
 - 
For
folderkinds:- Update all repo specifications from simple strings to objects with 
nameandbranchproperties - Change from 
repos: ["repo-name"]torepos: [{"name": "org/repo-name", "branch": "main"}] - Take advantage of per-repository branch specification for more flexible folder mapping
 
 - Update all repo specifications from simple strings to objects with 
 - 
Add new kinds if needed:
- Add 
pipelinekind for CI/CD pipeline tracking - Add 
jobkind for individual job monitoring - Add 
issuekind for issue tracking 
 - Add 
 
Step 5: Update file and folder mappingsโ
Update any file or folder mappings to use GitLab's Advanced Search API syntax and repository formats required by GitLab-v2:
- 
Update file paths to GitLab Advanced Search syntax:
- Change 
path: '**/package.json'topath: 'package.json' - Change 
path: '**/*.yml'topath: '*.yml' - GitLab-v2 uses GitLab's Advanced Search API which supports 
*wildcards but follows GitLab's search syntax 
 - Change 
 - 
Update repository specifications:
- Change repository names to include the full group path
 - Review all 
reposspecifications in your file and folder kinds 
 - 
Test the updated configuration with a small subset first
 
Example file kind transformation:
# GitLab format
- kind: file
  selector:
    files:
      path: '**/package.json'  # โ Custom glob pattern
      repos:
        - "backend-service"    # โ Simple name
# GitLab-v2 format  
- kind: file
  selector:
    files:
      path: '*package.json'         # โ
 GitLab Advanced Search syntax
      repos:
        - "my-org/backend-service"   # โ
 Full namespace
      skipParsing: false             # โ
 Optional parsing control
Example folder kind transformation:
# GitLab format
- kind: folder
  selector:
    folders:
      - path: "src"
        repos:
          - "backend-service"  # โ Simple name
        branch: "main"         # โ Single branch for all repos
# GitLab-v2 format  
- kind: folder
  selector:
    folders:
      - path: "src"
        repos:
          - name: "my-org/backend-service"  # โ
 Full namespace with branch object
            branch: "main"
          - name: "my-org/frontend-app"     # โ
 Different branches per repo
            branch: "develop"
Migration Pattern Comparisonโ
| V1 Pattern | V2 Pattern | What it matches | Migration Notes | 
|---|---|---|---|
**/infra/**/terraform/*.{tf,tfvars} | *.tf + *.tfvars | Terraform files anywhere | Split into multiple file kinds | 
**/infra/**/terraform/*.{tf,tfvars} | infra/prod/terraform/main.tf + infra/staging/terraform/main.tf | Terraform files in specific paths | Split into multiple file kinds with exact paths | 
**/package.json | package.json | Files named "package.json" anywhere | Searches entire repository | 
**/Dockerfile | Dockerfile | All Dockerfiles anywhere | Searches entire repository | 
**/docker-compose.yml | docker-compose.yml | Docker Compose files anywhere | Searches entire repository | 
GitLab-v2 follows GitLab's Advanced Search syntax which supports:
*for partial matches (e.g.,*package.jsonor*.yml)filename:prefix for filename searches- Other advanced search operators
 
See GitLab's documentation for the complete list of supported search patterns and limitations.
This change ensures accurate repository identification and prevents conflicts when multiple repositories share the same name across different GitLab groups.
Step 6: Deploy and verifyโ
- Deploy the GitLab-v2 integration with your updated configuration
 - Trigger a manual resync from Port's UI to initiate data resync
 - Verify data consistency:
- Check that all expected projects are resynced
 - Confirm merge requests and issues are updating correctly
 - Test webhook functionality if enabled
 
 - Monitor the logs for any authentication or permission issues
 
Consider running both GitLab and GitLab-v2 integrations temporarily to compare results before fully switching over.
Step 7: Clean up GitLab integrationโ
Once GitLab-v2 is working correctly:
- Disable the GitLab integration
 - Revoke the old group access tokens
 - Remove GitLab configuration files
 - Update any documentation referencing the old setup
 
This cleanup ensures security by removing unused tokens and prevents confusion from having multiple configurations.
New features in GitLab-v2โ
Pipeline jobs supportโ
GitLab-v2 introduces comprehensive pipeline job tracking, allowing you to monitor CI/CD job status, stages, and duration. This feature provides detailed insight into your build and deployment processes.
- kind: job
  selector:
    query: 'true'
  port:
    entity:
      mappings:
        identifier: .id | tostring
        title: .name
        blueprint: '"gitlabJob"'
        properties:
          status: .status
          stage: .stage
          duration: .duration
Enhanced group managementโ
Groups in GitLab-v2 provide cleaner member resync and better hierarchy handling. The separation of member and group concerns allows for more flexible data modeling and improved relationship management between users, groups, and projects.
Troubleshoot common issuesโ
| Issue | Cause | Solution | 
|---|---|---|
| Authentication errors | Service account lacks access to required groups | Verify service account has been added to all relevant groups with appropriate permissions | 
| Missing repositories | Incorrect namespace formatting in GitLab-v2 | Ensure repository paths use the full namespace/project format | 
| Missing member data | Using old project-with-members kind | Remove project-with-members kinds and add dedicated member kind mapping | 
| Member relation errors | Members configured as properties instead of relations | Update group-with-members to use relations, not embedded member properties | 
| Webhook failures | Service account lacks webhook creation permissions | Check that service account has sufficient privileges to create and manage webhooks | 
| File sync issues | Incorrect search syntax | Update file paths to use GitLab Advanced Search syntax (e.g., *package.json instead of **/package.json) | 
| Repository not found errors | Outdated repository names in file/folder selectors | Update repo names to use full namespace format (org/repo) | 
If you encounter issues during migration:
- Check the integration logs in Port's UI for specific error messages
 - Verify your service account permissions in GitLab to ensure proper access
 - Contact Port support with your specific error messages and configuration details
 
This migration ensures your GitLab integration benefits from improved security through centralized token management, enhanced performance with optimized API calls, and new capabilities including pipeline job tracking while maintaining all your existing data resync patterns.