Promotion Workflow
Changes are promoted from DEV to UAT to PROD using cherry-pick PRs -- not full branch merges. This gives the team selective control over what reaches each environment, avoiding the "all-or-nothing" problem of traditional merge-based promotion.
One-Click Promotion via Dashboard
The dev dashboard (/cherrypick) provides a one-click Promote to UAT / Promote to PROD button per pending PR, automating the cherry-pick + push + PR-open flow:
-
Open the dashboard and navigate to the Cherry-pick queue page (
/cherrypick). -
The queue determines what is pending for each environment by checking, for every merged-on-
mainPR, whether it has been delivered to the liveorigin/release/uat(ororigin/release/prod) branch. A PR is considered delivered when either:- its merge_sha is an ancestor of the target branch (merge-sync delivery), or
- a commit on the target branch carries the
(cherry picked from commit <merge_sha>)trailer thatgit cherry-pick -xemits (cherry-pick delivery).
The queue does not use
uat/*/prod/*deployment tags as the source of truth — those tags only update when the deploy pipeline finishes, which lags the branch tip and caused "phantom pending" entries. -
Click Promote to UAT (or Promote to PROD). The dashboard runs as a background job:
- Fetches the latest from origin.
- Creates an isolated worktree at
.claude/worktrees/cherry-{target}-{pr_id}-{sha}. - Runs
git cherry-pick -x <merge_sha>(the-xflag is required so the queue can detect delivery on the next refresh). - On clean apply: pushes the branch and calls the ADO REST API to open a PR against
release/uatorrelease/prod. - On conflict: aborts cleanly, shows the conflicting file list, and does not open a broken-state PR.
- Always removes the temporary worktree at the end.
- On success the job page auto-opens the newly created DevOps PR in a new tab (review, approve, and merge happen in DevOps itself). A fallback "Open PR in DevOps" button appears in the result panel if your browser blocks the popup.
-
On success, a link to the new ADO PR is shown in the job output. Merge it to trigger the deployment pipeline.
If the dashboard is unavailable or a cherry-pick conflicts, use the manual procedure below.
Cherry-Pick Promotion Flow
sequenceDiagram
participant Dev as Developer
participant Main as main (DEV)
participant UAT as release/uat
participant PROD as release/prod
Note over Dev,Main: Feature development
Dev->>Main: PR (squash merge)
Note over Main: Auto-deploy to DEV
Main->>UAT: Cherry-pick PR (1 reviewer)
Note over UAT: Auto-deploy to UAT
Note over UAT: Validate in UAT environment
UAT->>PROD: Cherry-pick PR (2 reviewers)
Note over PROD: Manual approval gate
PROD->>PROD: Deploy with approval
Why Cherry-Pick?
The alternative -- merging main into release/uat -- would promote every commit on main, including work that is not yet validated or intended for UAT. Cherry-pick promotion enables:
- Hotfix isolation: Fix a single model in PROD without promoting unrelated DEV work
- Incremental validation: Promote tested changes one at a time to UAT
- Clean rollback: Revert a specific cherry-pick without affecting other promotions
- Independent timelines: DEV can move fast while UAT and PROD advance at their own pace
The trade-off is more manual work per promotion (one cherry-pick command per commit). In practice, this overhead is small compared to the safety benefit.
Step-by-Step: Promoting to UAT
-
Identify the commit to promote from
main:git log main --oneline # Find the commit hash you want to promote -
Cherry-pick to
release/uat(use-xso the cherry-pick queue can detect delivery):git checkout release/uat git cherry-pick -x <commit-hash> git push origin release/uat -
Create a PR in Azure DevOps targeting
release/uat. The PR requires:- 1 reviewer (a Lead from
FP GER Fabric Platform Team) - DuckDB Smoke CI must pass
- 1 reviewer (a Lead from
-
Merge the PR. This triggers the UAT deployment pipelines automatically based on which files changed (dbt, Terraform, security, functions, or semantic/reports).
-
Validate in the UAT environment before promoting to PROD.
Step-by-Step: Promoting to PROD
-
Cherry-pick from
release/uat(not frommain-- PROD should only receive commits that passed UAT validation; use-xso the cherry-pick queue can detect delivery):git checkout release/prod git cherry-pick -x <commit-hash> git push origin release/prod -
Create a PR targeting
release/prod. The PR requires:- 2 reviewers (Leads)
- DuckDB Smoke CI must pass
-
Merge the PR. The PROD pipeline triggers but pauses at the deployment job.
-
Approve the deployment via the Azure DevOps
productionenvironment gate. Approvers receive an email notification with a link to the pipeline run. They review the changes and click Approve or Reject. -
Verify the deployment completed successfully.
Two-Pass Deploy for Semantic Models + Reports
The fabric-deploy pipeline uses a two-pass strategy for environments that require semantic model ID resolution (UAT):
- Pass 1 (all environments): Deploys semantic models via
fabric-cicd(publish_all_itemsforSemanticModelitems). UAT additionally resolves semantic model IDs and regeneratesparameter-uat.ymlat this point. - Pass 2 (all environments): Deploys reports via
scripts/upload_reports_direct.py --env <env> --replace-existing. This script calls the Fabric REST API directly instead of using fabric-cicd, which is required because fabric-cicd'spublish_all_itemsfails on.pbirfiles that usedatasetReference.byConnection(returnsPowerBIEntityNotFound).
Bronze workspace items (MirroredDatabase, DataPipeline, Notebook, SparkJobDefinition, Environment) continue to use fabric-cicd as they do not use byConnection and are not affected by the bug.
When promoting a new semantic model together with its report, the pipeline may still need two runs if the semantic model connection has not been fully established before the reports pass runs. This is a known Fabric API timing issue for new model + report pairs; updates to existing pairs deploy in a single run.
Changelog Generation
UAT and PROD deployment pipelines automatically generate a changelog by diffing the current manifest.json against the previous deployment's manifest. The changelog includes:
- New, modified, and removed models
- Column-level schema changes
- Test changes
- Git log between deployment tags
Deployment tags: Each successful deployment creates a git tag in the format ENV/YYYY-MM-DD-HH (UTC), for example uat/2026-03-22-14 or prod/2026-03-22-14.
Pipeline artifacts: Each deployment publishes dbt-uat-changelog or dbt-prod-changelog containing both changelog.md (human-readable) and changelog.json (structured).
Optional changelog commit: Set the pipeline variable COMMIT_CHANGELOG to true to automatically commit the changelog Markdown to docs/changelogs/ENV-YYYY-MM-DD-HH.md. This is opt-in -- by default, changelogs are only published as pipeline artifacts.
Rollback Procedure
To roll back a change that was promoted to UAT or PROD:
-
Identify the cherry-pick commit on the target branch:
git log release/uat --oneline -
Revert the commit:
git checkout release/uat git revert <cherry-pick-commit-hash> git push origin release/uat -
Create a PR with the revert. The same review and approval process applies.
-
Merge the PR. The deployment pipeline re-runs, applying the reverted state.
For PROD rollbacks, the same process applies with the additional manual approval gate. In an emergency, Leads can bypass branch policies to push the revert directly.
Power Automate Exception
Power Automate flows are the one exception to automated promotion. They must be manually cloned and reconfigured per environment because Fabric does not support solution-based flow export/import. See the deployment guide for details.
Related Pages
- Environment Strategy -- branch mapping, triggers, manifest isolation
- Pipeline Architecture -- trigger model, Key Vault, lock behavior
- Pipeline Reference -- per-pipeline details