Skip to content

PORTN-1360 Add advanced configuration section for triggering pipelines in non-default branches #2462

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ When using this backend, you need to provide the following:
- **ADO organization name** - can be found in your URL: `https://dev.azure.com/{AZURE-DEVOPS-ORG}`.
- **Webhook name** - the name you gave to the webhook resource in the Azure yaml pipeline file.

## Advanced configuration

### Trigger pipelines in non-default branches

By default, Azure DevOps pipelines triggered through Port run from the repository's default branch. If you need to trigger pipelines from a specific branch or allow users to select which branch to run from, see our guide on [triggering pipelines in non-default branches](./trigger-non-default-branch).

## Examples

For complete examples of self-service actions using Azure pipelines as the backend, check out the [guides section](/guides?tags=Azure&tags=Actions).
Original file line number Diff line number Diff line change
@@ -0,0 +1,297 @@
---
title: Trigger pipelines in non-default branch
sidebar_position: 2
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Trigger Azure DevOps pipelines in non-default branch

By default, Azure DevOps pipelines triggered through Port self-service actions run from the repository's default branch (typically `main` or `master`).
We will demonstrate how to configure your action to trigger pipelines from a specific non-default branch.

## Understanding the challenge

1. Azure DevOps webhook triggers don't automatically handle branch specification like GitHub.
2. The pipeline YAML file location and the branch to run from need to be explicitly defined.
3. The API payload structure requires specific `refName` formatting.


## Solution overview

To trigger Azure DevOps pipelines in a non-default branch, you need to:

1. **Add a branch input** to your self-service action (optional - for user selection).
2. **Configure the webhook payload** to include the correct `refName` parameter.
3. **Ensure your pipeline YAML** exists in the target branch.

## Implementation methods

<Tabs>
<TabItem value="fixed-branch" label="Fixed branch" default>

Use this approach when you always want to trigger from a specific branch.

<h4> Step 1: Configure the action backend</h4>

In your self-service action configuration, use the webhook backend with a payload that specifies the target branch:

```json showLineNumbers
{
"invocationMethod": {
"type": "WEBHOOK",
"url": "https://dev.azure.com/{{.secrets.AZURE_DEVOPS_ORG}}/{{.secrets.AZURE_DEVOPS_PROJECT}}/_apis/pipelines/{{.secrets.PIPELINE_ID}}/runs?api-version=7.1",
"agent": false,
"synchronized": true,
"method": "POST",
"headers": {
"Content-Type": "application/json",
"Authorization": "Basic {{.secrets.AZURE_DEVOPS_PAT_BASE64}}"
},
"body": {
"resources": {
"repositories": {
"self": {
"refName": "refs/heads/feature/my-feature-branch"
}
}
},
"templateParameters": {
"{{ spreadValue() }}": "{{ .inputs }}"
},
"variables": {
"PORT_RUN_ID": {
"value": "{{ .run.id }}"
}
}
}
}
}
```

<h4> Step 2: Set up secrets</h4>

Add the following secrets to your Port organization:

- `AZURE_DEVOPS_ORG`: Your Azure DevOps organization name.
- `AZURE_DEVOPS_PROJECT`: Your project name.
- `PIPELINE_ID`: The numeric ID of your pipeline.
- `AZURE_DEVOPS_PAT_BASE64`: Base64 encoded Personal Access Token.

:::tip Getting your pipeline ID
You can find your pipeline ID in the Azure DevOps URL when viewing the pipeline:
`https://dev.azure.com/{org}/{project}/_build?definitionId={PIPELINE_ID}`
:::

</TabItem>
<TabItem value="user-selectable" label="User-selectable branch">

Use this approach when you want users to choose which branch to trigger.

<h4> Step 1: Add branch input to your action</h4>

Add a branch selection input to your action's user interface:

```json showLineNumbers
{
"userInputs": {
"properties": {
"target_branch": {
"title": "Target Branch",
"type": "string",
"enum": [
"main",
"develop",
"feature/deployment",
"hotfix/critical-fix"
],
"default": "main",
"description": "Select the branch to run the pipeline from"
}
// ... other inputs
}
}
}
```

<h4> Step 2: Use the input in the webhook payload</h4>

Reference the user input in your webhook body:

```json showLineNumbers
{
"body": {
"resources": {
"repositories": {
"self": {
"refName": "refs/heads/{{ .inputs.target_branch }}"
}
}
},
"templateParameters": {
"{{ spreadValue() }}": "{{ .inputs }}"
}
}
}
```

</TabItem>
<TabItem value="dynamic-branch" label="Dynamic branch selection">

For advanced use cases, you can use JQ expressions to dynamically determine the branch:

```json showLineNumbers
{
"body": {
"resources": {
"repositories": {
"self": {
"refName": "{{ if .trigger.operation == \"CREATE\" then \"refs/heads/main\" elif .inputs.environment == \"staging\" then \"refs/heads/develop\" else \"refs/heads/feature/\" + .inputs.feature_name end }}"
}
}
}
}
}
```

This approach is useful when you need to:
- Route different operations to different branches.
- Use environment-specific branches (staging → develop, production → main).
- Create dynamic branch names based on user inputs.

</TabItem>
</Tabs>

<h3>Complete example</h3>

Here's a complete self-service action that allows users to deploy from different branches:

<details>
<summary><b>Complete action JSON</b></summary>

```json showLineNumbers
{
"identifier": "deploy_to_environment",
"title": "Deploy to Environment",
"icon": "Azure",
"description": "Deploy application to specified environment from selected branch",
"trigger": {
"type": "self-service",
"operation": "DAY-2",
"userInputs": {
"properties": {
"environment": {
"title": "Environment",
"type": "string",
"enum": ["staging", "production"],
"enumColors": {
"staging": "orange",
"production": "red"
}
},
"target_branch": {
"title": "Branch",
"type": "string",
"enum": ["main", "develop", "feature/latest"],
"default": "main"
},
"deployment_notes": {
"title": "Deployment Notes",
"type": "string",
"description": "Optional notes for this deployment"
}
},
"required": ["environment", "target_branch"],
"order": ["environment", "target_branch", "deployment_notes"]
},
"blueprintIdentifier": "service"
},
"invocationMethod": {
"type": "WEBHOOK",
"url": "https://dev.azure.com/{{.secrets.AZURE_DEVOPS_ORG}}/{{.secrets.AZURE_DEVOPS_PROJECT}}/_apis/pipelines/{{.secrets.DEPLOYMENT_PIPELINE_ID}}/runs?api-version=7.1",
"agent": false,
"synchronized": true,
"method": "POST",
"headers": {
"Content-Type": "application/json",
"Authorization": "Basic {{.secrets.AZURE_DEVOPS_PAT_BASE64}}"
},
"body": {
"resources": {
"repositories": {
"self": {
"refName": "refs/heads/{{ .inputs.target_branch }}"
}
}
},
"templateParameters": {
"environment": "{{ .inputs.environment }}",
"deployment_notes": "{{ .inputs.deployment_notes }}",
"triggered_by": "{{ .trigger.by.user.email }}",
"port_run_id": "{{ .run.id }}"
},
"variables": {
"ENVIRONMENT": {
"value": "{{ .inputs.environment }}"
},
"PORT_RUN_ID": {
"value": "{{ .run.id }}"
}
}
}
},
"requiredApproval": false
}
```

</details>

<h4> Pipeline YAML considerations</h4>

Ensure your pipeline YAML file exists in the target branch and is configured to handle webhook triggers:

```yaml showLineNumbers title="azure-pipelines.yml"
# Disable automatic CI triggers since we're using webhooks
trigger: none

# Define the webhook resource
resources:
webhooks:
- webhook: port_trigger
connection: port_trigger # Your service connection name

# Pipeline parameters (optional)
parameters:
- name: environment
type: string
default: 'staging'
- name: deployment_notes
type: string
default: ''

variables:
- name: targetEnvironment
value: ${{ parameters.environment }}

stages:
- stage: Deploy
jobs:
- job: DeployJob
steps:
- script: |
echo "Deploying to: $(targetEnvironment)"
echo "Branch: $(Build.SourceBranch)"
echo "Notes: ${{ parameters.deployment_notes }}"
echo "Port Run ID: $(PORT_RUN_ID)"
displayName: 'Deploy Application'

# Add your actual deployment steps here
- script: |
# Your deployment logic
echo "Deployment completed successfully"
displayName: 'Run Deployment'
```

## Troubleshoot
You can find more information on how to troubleshoot Azure DevOps pipelines in our [troubleshooting guide](/actions-and-automations/setup-backend/azure-pipeline/troubleshooting).