Development Documentation
View as:

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:

  1. Open the dashboard and navigate to the Cherry-pick queue page (/cherrypick).

  2. The queue determines what is pending for each environment by checking, for every merged-on-main PR, whether it has been delivered to the live origin/release/uat (or origin/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 that git cherry-pick -x emits (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.

  3. 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 -x flag 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/uat or release/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.
  4. 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

  1. Identify the commit to promote from main:

    git log main --oneline
    # Find the commit hash you want to promote
    
  2. Cherry-pick to release/uat (use -x so the cherry-pick queue can detect delivery):

    git checkout release/uat
    git cherry-pick -x <commit-hash>
    git push origin release/uat
    
  3. 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
  4. Merge the PR. This triggers the UAT deployment pipelines automatically based on which files changed (dbt, Terraform, security, functions, or semantic/reports).

  5. Validate in the UAT environment before promoting to PROD.

Step-by-Step: Promoting to PROD

  1. Cherry-pick from release/uat (not from main -- PROD should only receive commits that passed UAT validation; use -x so the cherry-pick queue can detect delivery):

    git checkout release/prod
    git cherry-pick -x <commit-hash>
    git push origin release/prod
    
  2. Create a PR targeting release/prod. The PR requires:

    • 2 reviewers (Leads)
    • DuckDB Smoke CI must pass
  3. Merge the PR. The PROD pipeline triggers but pauses at the deployment job.

  4. Approve the deployment via the Azure DevOps production environment gate. Approvers receive an email notification with a link to the pipeline run. They review the changes and click Approve or Reject.

  5. 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_items for SemanticModel items). UAT additionally resolves semantic model IDs and regenerates parameter-uat.yml at 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's publish_all_items fails on .pbir files that use datasetReference.byConnection (returns PowerBIEntityNotFound).

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:

  1. Identify the cherry-pick commit on the target branch:

    git log release/uat --oneline
    
  2. Revert the commit:

    git checkout release/uat
    git revert <cherry-pick-commit-hash>
    git push origin release/uat
    
  3. Create a PR with the revert. The same review and approval process applies.

  4. 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