Skip to main content

Check out Port for yourself ➜ 

Azure DevOps

Loading version...

Port's Azure DevOps integration allows you to model Azure DevOps resources in your software catalog and ingest data into them.

Supported deployments models

This integration supports both Azure DevOps Services (cloud) and Azure DevOps Server (on-premises).

Note: When using the on-premises model, releases and work items are not supported due to API version differences. All other supported resources work the same as the cloud version.

Prerequisites

  • An Azure DevOps account with admin privileges.
  • If you choose the self-hosted installation method, you will need a Kubernetes cluster on which to install the integration.
  • Your Port user role is set to Admin.

Create a personal access token

The integration requires a personal access token to authenticate with your Azure DevOps account. You can create one by following these steps.

The token should either have admin permissions, or read permissions for each of the supported resources you want to ingest into Port.

Setup

Choose your preferred installation method below. Not sure which to pick? See the installation methods overview.

Configuration

Port integrations use a YAML mapping block to ingest data from the third-party api into Port.

The mapping makes use of the JQ JSON processor to select, modify, concatenate, transform and perform other operations on existing fields and values from the integration API.

Default mapping configuration

This is the default mapping configuration for this integration:

Default mapping configuration (click to expand)
deleteDependentEntities: true
createMissingRelatedEntities: true
enableMergeEntity: true
resources:
- kind: project
selector:
query: 'true'
defaultTeam: 'false'
port:
entity:
mappings:
identifier: .id | gsub(" "; "")
blueprint: '"azureDevopsProject"'
title: .name
properties:
state: .state
revision: .revision
visibility: .visibility
defaultTeam: .defaultTeam.name
link: .url | gsub("_apis/projects/"; "")
- kind: repository
selector:
query: 'true'
includedFiles:
- README.md
port:
entity:
mappings:
identifier: .id
title: .name
blueprint: '"azureDevopsRepository"'
properties:
url: .remoteUrl
readme: .__includedFiles["README.md"]
id: .id
last_activity: .project.lastUpdateTime
relations:
project: .project.id | gsub(" "; "")
- kind: repository-policy
selector:
query: .type.displayName=="Minimum number of reviewers"
port:
entity:
mappings:
identifier: .__repository.id
blueprint: '"azureDevopsRepository"'
properties:
minimumApproverCount: .settings.minimumApproverCount
- kind: repository-policy
selector:
query: .type.displayName=="Work item linking"
port:
entity:
mappings:
identifier: .__repository.id
blueprint: '"azureDevopsRepository"'
properties:
workItemLinking: .isEnabled and .isBlocking
- kind: user
selector:
query: 'true'
port:
entity:
mappings:
identifier: .id
title: .user.displayName
blueprint: '"azureDevopsMember"'
properties:
url: .user.url
email: .user.mailAddress
- kind: team
selector:
query: 'true'
includeMembers: true
port:
entity:
mappings:
identifier: .id
title: .name
blueprint: '"azureDevopsTeam"'
properties:
url: .url
description: .description
relations:
project: .projectId | gsub(" "; "")
members: .__members | map(.identity.id)
- kind: pull-request
selector:
query: 'true'
port:
entity:
mappings:
identifier: .repository.id + "/" + (.pullRequestId | tostring)
blueprint: '"azureDevopsPullRequest"'
properties:
status: .status
createdAt: .creationDate
leadTimeHours: (.creationDate as $createdAt | .status as $status | .closedDate as $closedAt | ($createdAt | sub("\\..*Z$"; "Z") | strptime("%Y-%m-%dT%H:%M:%SZ") | mktime) as $createdTimestamp | ($closedAt | if . == null then null else sub("\\..*Z$"; "Z") | strptime("%Y-%m-%dT%H:%M:%SZ") | mktime end) as $closedTimestamp | if $status == "completed" and $closedTimestamp != null then (((($closedTimestamp - $createdTimestamp) / 3600) * 100 | floor) / 100) else null end)
relations:
repository: .repository.id
service:
combinator: '"and"'
rules:
- operator: '"="'
property: '"ado_repository_id"'
value: .repository.id
creator:
combinator: '"and"'
rules:
- operator: '"="'
property: '"$identifier"'
value: .createdBy.uniqueName
reviewers:
combinator: '"and"'
rules:
- operator: '"in"'
property: '"$identifier"'
value: '[.reviewers[].uniqueName]'
azure_devops_reviewers: '[.reviewers[].id]'
azure_devops_creator: .createdBy.id
- kind: build
selector:
query: "true"
port:
entity:
mappings:
identifier: .__project.id + "/" + (.repository.id | tostring) + "/" + (.id | tostring) | gsub(" "; "")
title: .buildNumber
blueprint: '"azureDevopsBuild"'
properties:
status: .status
result: .result
queueTime: .queueTime
startTime: .startTime
finishTime: .finishTime
definitionName: .definition.name
requestedFor: .requestedFor.displayName
link: ._links.web.href
relations:
project: .__project.id | gsub(" "; "")
- kind: pipeline-stage
selector:
query: 'true'
port:
entity:
mappings:
identifier: .__project.id + "/" + (.__build.repository.id | tostring) + "/" + (.__build.id | tostring) + "/" + (.id | tostring) | gsub(" "; "")
title: .name
blueprint: '"azureDevopsPipelineStage"'
properties:
state: .state
result: .result
startTime: .startTime
finishTime: .finishTime
stageType: .type
relations:
project: .__project.id | gsub(" "; "")
build: (.__project.id + "/" + (.__build.repository.id | tostring) + "/" + (.__build.id | tostring)) | gsub(" "; "")
- kind: pipeline-run
selector:
query: 'true'
port:
entity:
mappings:
identifier: .__project.id + "/" + (.__pipeline.id | tostring) + "/" + (.id | tostring) | gsub(" "; "")
blueprint: '"azureDevopsPipelineRun"'
properties:
state: .state
result: .result
createdDate: .createdDate
finishedDate: .finishedDate
pipelineName: .pipeline.name
relations:
project: .__project.id | gsub(" "; "")
- kind: environment
selector:
query: 'true'
port:
entity:
mappings:
identifier: .project.id + "/" + (.id | tostring) | gsub(" "; "")
title: .name | tostring
blueprint: '"azureDevopsEnvironment"'
properties:
description: .description
createdOn: .createdOn
lastModifiedOn: .lastModifiedOn
relations:
project: .project.id
- kind: release-deployment
selector:
query: 'true'
includeRelease: true
port:
entity:
mappings:
identifier: .releaseDefinition.projectReference.id + "/" + (.release.id | tostring) + "/" + (.id | tostring) | gsub(" "; "")
title: .release.name + "-" + (.id | tostring) | gsub(" "; "")
blueprint: '"azureDevopsReleaseDeployment"'
properties:
status: .deploymentStatus
url: .url
reason: .reason
startedOn: .startedOn
completedOn: .completedOn
requestedBy: .requestedBy.displayName
operationStatus: .operationStatus
environment: .releaseEnvironment.name
relations:
project: .releaseDefinition.projectReference.id | gsub(" "; "")
release: .releaseDefinition.projectReference.id + "/" + (.release.id | tostring) | gsub(" "; "")
- kind: pipeline-deployment
selector:
query: 'true'
port:
entity:
mappings:
identifier: .__project.id + "/" + (.environmentId | tostring) + "/" + (.id | tostring) | gsub(" "; "")
title: .requestIdentifier | tostring
blueprint: '"azureDevopsPipelineDeployment"'
properties:
planType: .planType
stageName: .stageName
jobName: .jobName
result: .result
startTime: .startTime
finishTime: .finishTime
relations:
project: .__project.id | gsub(" "; "")
environment: .__project.id + "/" + (.environmentId | tostring) | gsub(" "; "")

Mapping & examples per resource

Use the explorer below to view sample payloads and the resulting Port entities for each resource type. For additional resources and advanced configurations, see the examples page.

Monitoring and sync status

To learn more about how to monitor and check the sync status of your integration, see the relevant documentation.

Examples

Refer to the examples page for practical configurations and their corresponding blueprint definitions.

Relevant Guides

For relevant guides and examples, see the guides section.

GitOps

Port's Azure DevOps integration also provides GitOps capabilities, refer to the GitOps page to learn more.

Advanced

Refer to the advanced page for advanced use cases and examples.