Azure DevOps Pipelines & Dynamics 365 Deployment

Pipeline Types & Official Resources

  • Two Azure DevOps pipeline flavors mentioned

    • Classic (no new features being added)

    • YAML (all modern development done here; presenter started directly with YAML)

  • Recommended reading: Microsoft documentation for Azure DevOps Pipelines (link referenced in session)

  • Build/Release automation toolsets used

    • Power Platform Build Tools (current, covers every required task)

    • Formerly used XRM CI Framework / CRM DevOps Tools (still viable but no longer primary)

From Monolith to Modular

  • Original "big pipeline" characteristics

    • Single YAML handled web resources, middle-tier, Azure Functions, solutions … “everything under the sun”

    • Cons:

    • Always overwrote entire environment because all solutions were pushed regardless of what changed

    • Slow: full build time ≈ 2530 minutes25\text{–}30\text{ minutes} (example call-out 32 min32\text{ min})

  • Refactor mandate → 7 focussed pipelines

    • Each dedicated to a bounded context (core, CTI, clinical, etc.)

    • Re-useable templates ensure all look & behave identically

YAML Pipeline Anatomy (generic pattern)

  • Top-level keys demonstrate repeatable structure across all 7 definitions

    • trigger / prbranch filters

    • Include: develop

    • Exclude: release/* (future-proofing), feature branches fire only via manual run

    • paths filter so pipeline fires only when specific folders change

    • variables

    • Reference Library → Variable Groups (e.g., group: common variables)

    • Templates for variable sets allowed (template: vars-global.yml)

    • stages

    • Build ⇒ Test ⇒ CI CD (QA1) ⇒ CI CD 2 (QA2) ⇒ Trunk (UAT) ⇒ Release-UAT ⇒ Release-Training ⇒ Release-PreProd ⇒ Release-Prod

    • Each stage contains jobs (deploy middle tier, deploy functions, etc.)

    • conditions

    • Example: UAT stage only executes when build.configuration == 'Debug' AND not pullRequest.

    • Release stages run when build.configuration == 'Release'.

    • environment: tag on every deploy job → ties to Azure DevOps Environments view for traceability ("what’s in UAT?")

Branch Policies & Build Validation

  • develop protected by Pull Request (PR) policy

    • Build must succeed (branch-specific pipeline triggered via build-validation)

  • Manual pipeline run still possible (used for hot-fixes or direct UAT validation)

Variable Logic Example

variables:
  - template: vars-global.yml

# inside vars-global.yml
- name: Configuration
  value: ${{ if startsWith(variables['Build.SourceBranch'], 'refs/heads/release') }} \
         Release \
         ${{ else }} Debug
  • Same template also stores Dev vs Prod connection strings & script paths.

Template-Based Re-use

  • "Think of a template as a function": YAML fragments parameterised and shared

  • Key templates

    • functions-build.yml & functions-deploy.yml

    • Accept list of Azure Functions → loop restore, build, archive, deploy

    • Saves re-specifying steps for QA, QA2, UAT, Training…

    • solution-build.yml

    • Parameters: solutions: array, each with friendlyName, uniqueName, dataFiles, etc.

    • Handles: restore NPM, run Webpack (npm run build:<env>), build plug-ins if present, pack solution, publish as Build Artifact

    • solution-import.yml

    • Parameters allow multi-org deployment (ex: PSW Play, PSW Engage, PSW Port)

    • Turns off SLA, evaluates minor-version upgrade logic, stages for upgrade when needed, imports data, shares records, re-enables SLA.

Function Build/Deploy Workflow

  1. Restore NuGet packages (only for projects in supplied list)

  2. dotnet build specific functions → artefact archive

  3. Loop in deploy template pushes each .zip to corresponding App Service.

  4. Optimisation: only build & restore what actually changed (time saver vs monolith).

Hot-Fix & Stage Skipping

  • Hotfix pipeline run detected by branch name containing “hotfix”

  • Logic: skip Release-UAT stage (UAT already received change via develop → trunk) preventing overwriting newer commits users may be testing.

Solution / Data Versioning Rules

  • Dynamics 365 version format Major.Minor.Build.RevisionMajor.Minor.Build.Revision

    • Minor bumped when update/upgrade required.

  • Import script:

$deployed = <get version from target>
$incoming = <version in artefact>
if($incoming.minor > $deployed.minor){ importMode = 'StageForUpgrade' }
else               { importMode = 'Update'          }
  • Always imports data files; future enhancement will import only when the data file actually changed (work item created).

  • Multiple PR scenario clarified

    • Solutions skip import when version identical → safe to test independent PRs concurrently

    • Data files overwrite previous content irrespective of author order (current design)

Shared Records Automation

  • Script invoked only from Core pipeline

    • Creates Business Unit owner teams, shares environment records, card libraries, etc.

    • To add new “global” shares, edit scripts/CreateSharedRecords.ps1 (executed every Core run).

Plug-in Package Caveats

  • Current mapping XML cannot rebuild plug-in package from source → exports whatever was inside CRM at pack time (risk of stale package).

  • Issues observed during last release (package missing/incorrect).

  • Action items

    • Re-work mapping so plug-in package pulled from repo artefact, not dev export

    • or split pack commands per pipeline to avoid collisions.

Rebasing & Merge Conflicts (PR hygiene)

  • Required when two developers touch same component within same solution folder

    • Example: Both modify ConsumerSolutions\CustomRules.xml → whichever PR merges first updates develop, second dev must git pull --rebase so export contains latest base.

  • If components do not overlap, only potential action is to adjust solution version number so import isn’t skipped in next environment.

Manual UAT Runs & Release Impact

  • Manual pipeline run on feature branch (Run → choose branch)

    • Skips PR gates, goes Build→Test→UAT directly (because not pullRequest met)

  • Later merge to develop triggers pipeline again; UAT import skipped (identical versions) so no harm.

  • For production hot-fix

    1. Create release/* branch, bump version (usually append revision) so Prod receives new build.

Key Numbers & Defaults

  • Full monolithic build: 2530 min25\text{–}30\text{ min} (peak example 32 min32\text{ min})

  • Current pipelines: 7 parallel YAML definitions

  • Data import concurrency: 1515 parallel threads (Power Platform Import Data task setting)

  • Function app count example: QA, QA2, QA3, QA4, UAT, Training, Prod (loop deploy via template)

Troubleshooting & Visibility Tips

  • Azure DevOps → Pipelines → Environments shows which build/branch is live in each env.

  • Artifacts tab → CRM Build → download EnvironmentSettings_<org>.json to inspect environment variable values that will be applied.

  • For "Why did UAT fail?" check conditions section in stage log (skipped, failed, never triggered, etc.)

Best Practices & Future Enhancements

  • ALWAYS commit source (web resources, plug-ins, data) before exporting solution → ensures pack maps find latest artefacts.

  • Keep solutions small & feature-centric to minimise overlap.

  • Plan shared-component edits (Consumer Solutions et al.) – daily PR cadence or dedicated day-1/day-2 branches.

  • Upcoming tasks

    • Detect data-file deltas to avoid unnecessary imports in lower envs

    • Fix plug-in package mapping or introduce versioning strategy

    • Consider disabling "skip lower version" in dev/QA to simplify concurrent work; discuss before enabling.