---
url: /salesforce-devops-starter-kit/workflows/promote.md
description: >-
  Reusable workflow that prepares a promotion between long-lived branches as a
  pull request.
---

# Promote

Reusable workflow that prepares a promotion between long-lived branches as a pull request: it cuts a branch from a base, merges one or more source branches into it and opens a pull request into the target. One mechanism covers story promotion, release bundles and the sync of environment branches after a release. Merge conflicts are never resolved automatically - the run fails and its summary lists the files and the commands to finish the promotion locally.

> Reusable workflow - call it from your own repository with `uses:`. [View source](https://github.com/svierk/salesforce-devops-starter-kit/blob/main/.github/workflows/promote.yml)

## Inputs

| Input | Description | Type | Required | Default |
| --- | --- | --- | --- | --- |
| `target` | Branch the pull request goes into, e.g. "uat". | string | yes | - |
| `sources` | Comma-separated or multi-line list of branches to merge, in order, e.g. "feature/story-123". Leave empty to open the pull request from the base branch itself, e.g. a release branch into main. | string | no | - |
| `base` | Branch to cut the promotion branch from. Leave empty to use the target - right for story promotion and the sync after a release. | string | no | - |
| `branch` | Name of the branch to create, e.g. "release/2026-11". Leave empty for "promotion/\<source>-\<target>" with one source, or "promotion/\<target>-\<run number>" with several. | string | no | - |
| `title` | Title of the pull request. Leave empty for "Promote \<sources> to \<target>". | string | no | - |

## Secrets

| Secret | Description | Required |
| --- | --- | --- |
| `PROMOTION_APP_ID` | ID of a GitHub App with contents and pull request write access. Pull requests opened with the default GITHUB_TOKEN do not trigger other workflows, so without an app the pull request validation never starts on the promotion pull request. | no |
| `PROMOTION_APP_PRIVATE_KEY` | Private key of that GitHub App. | no |

## Outputs

| Output | Description |
| --- | --- |
| `pull-request` | URL of the opened pull request; empty when there was nothing to promote. |
| `branch` | Name of the branch the pull request was opened from. |

## Example usage

Copy this caller into your project's `.github/workflows/` directory ([source](https://github.com/svierk/salesforce-devops-starter-kit/blob/main/examples/promote.yml)):

```yaml
# Example: call the reusable promote workflow.
# Copy this file into your project's .github/workflows/ directory.
#
# Adds a "Run workflow" form to the Actions tab that prepares a promotion as a
# pull request - for environment-branch models with story promotion or release
# bundles (see the B2 blueprint):
#
# - story promotion:  target uat, sources feature/story-123
# - release bundle:   target preprod, sources = the signed-off stories,
#                     base main, branch release/2026-11
#                     then: target main, base release/2026-11, no sources
# - sync after release: target uat, sources main

name: Promote

on:
  workflow_dispatch:
    inputs:
      target:
        description: Environment branch to promote into
        type: choice
        options: [integration, uat, preprod, main]
      sources:
        description: Branches to merge, comma-separated (empty = open a pull request from base)
        type: string
      base:
        description: Branch to start from (empty = the target)
        type: string
      branch:
        description: Name of the branch to create (empty = promotion/<source>-<target>)
        type: string

# The called workflow pushes the promotion branch and opens the pull request. A
# reusable workflow can never get more permissions than the caller grants here.
permissions:
  contents: write
  pull-requests: write

jobs:
  promote:
    uses: svierk/salesforce-devops-starter-kit/.github/workflows/promote.yml@v1.5.0
    with:
      target: ${{ inputs.target }}
      sources: ${{ inputs.sources }}
      base: ${{ inputs.base }}
      branch: ${{ inputs.branch }}
    # A GitHub App with contents and pull request write access, installed on this
    # repository. Without it the pull request is opened with the GITHUB_TOKEN and
    # the PR validation never starts on it.
    secrets:
      PROMOTION_APP_ID: ${{ secrets.PROMOTION_APP_ID }}
      PROMOTION_APP_PRIVATE_KEY: ${{ secrets.PROMOTION_APP_PRIVATE_KEY }}

# To open the sync pull requests automatically after every production
# deployment, add a second workflow triggered on push to main:
#
#   on:
#     push:
#       branches: [main]
#   jobs:
#     sync:
#       strategy:
#         fail-fast: false
#         matrix:
#           target: [integration, uat, preprod]
#       uses: svierk/salesforce-devops-starter-kit/.github/workflows/promote.yml@v1.5.0
#       with:
#         target: ${{ matrix.target }}
#         sources: main
#       secrets: inherit
```
