Back to Dynamics 365 CE

Dynamics 365 Customer Engagement

CI/CD & ALM

How a change travels from a developer's environment to production: automated, checked and repeatable.

Why CI/CD for Dynamics 365

Exporting a solution by hand and importing it somewhere else works until the day it doesn't. A pipeline makes every release the same release.

Repeatable

The same steps, in the same order, for every release and every environment.

Traceable

Every deployment links back to a commit, a work item and the person who approved it.

Safe

Quality checks and approvals stop problems before they reach production users.

Fast

Small, frequent releases instead of a stressful big bang every quarter.

A pipeline, stage by stage

This is the shape of a typical release pipeline for a Dynamics 365 solution. Watch it run, or select a stage to see what happens there.

Commit

A developer exports the unmanaged solution from Dev, unpacks it into source files and pushes a branch. A pull request starts the pipeline.

Pipeline log
$ pac solution export --name ContosoCore --path out/ContosoCore.zip
$ pac solution unpack --zipfile out/ContosoCore.zip --folder src/ContosoCore --packagetype Both
$ git push origin feature/case-routing
✓ Pull request opened, pipeline triggered

Environment strategy

Multi-environment approach for quality assurance:

DevUnmanaged
Build
Test
UAT
Production

The solution changes form once, in the build, and is never edited by hand downstream.

Unmanaged in development, managed everywhere else

  • Development: Unmanaged solutions for active development
  • Build/integration: Automated build and test environment
  • User acceptance testing (UAT): Stakeholder validation
  • Production: Managed solutions with change control
  • Sandbox: Training and experimentation environments

Solution management

  • Managed vs unmanaged solutions: Proper solution layering strategy
  • Solution segmentation: Modular solutions for independent deployment
  • Solution patching: Hot fixes and incremental updates
  • Dependency management: Clean dependency chains and upgrade paths

Source control and branching

The unpacked solution lives in Git next to the plugin and PCF source, so every change is reviewed like code.

mainfeature/case-routingfeature/sla-rulesv1.4v1.5
  • Short-lived feature branches, merged through pull requests with a required build.
  • One solution unpacked per folder, so diffs show exactly which form, view or flow changed.
  • Version numbers set by the pipeline, never by hand.
  • Main is always deployable; releases are tagged.

An Azure DevOps pipeline in YAML

A trimmed-down example using the Power Platform Build Tools. Real pipelines add the plugin build, tests and approvals per environment.

azure-pipelines.yml
1trigger:
2 branches:
3 include: [ main ]
4
5pool:
6 vmImage: windows-latest
7
8variables:
9 SolutionName: ContosoCore
10
11stages:
12- stage: Build
13 jobs:
14 - job: Pack
15 steps:
16 - task: PowerPlatformToolInstaller@2
17 - task: PowerPlatformPackSolution@2
18 inputs:
19 SolutionSourceFolder: src/$(SolutionName)
20 SolutionOutputFile: $(Build.ArtifactStagingDirectory)/$(SolutionName)_managed.zip
21 SolutionType: Managed
22 - task: PowerPlatformChecker@2
23 inputs:
24 authenticationType: PowerPlatformSPN
25 PowerPlatformSPN: pp-build
26 FilesToAnalyze: $(Build.ArtifactStagingDirectory)/*.zip
27 RuleSet: 0ad12346-e108-40b8-a956-9a8f95ea18c9
28 - publish: $(Build.ArtifactStagingDirectory)
29 artifact: drop
30
31- stage: DeployTest
32 dependsOn: Build
33 jobs:
34 - deployment: Import
35 environment: Test
36 strategy:
37 runOnce:
38 deploy:
39 steps:
40 - checkout: self
41 - task: PowerPlatformToolInstaller@2
42 - task: PowerPlatformImportSolution@2
43 inputs:
44 authenticationType: PowerPlatformSPN
45 PowerPlatformSPN: pp-test
46 SolutionInputFile: $(Pipeline.Workspace)/drop/$(SolutionName)_managed.zip
47 UseDeploymentSettingsFile: true
48 DeploymentSettingsFile: settings/test.json
49 HoldingSolution: true
50 AsyncOperation: true
51 MaxAsyncWaitTime: 60
52 - task: PowerPlatformApplySolutionUpgrade@2
53 inputs:
54 authenticationType: PowerPlatformSPN
55 PowerPlatformSPN: pp-test
56 SolutionName: $(SolutionName)
57 AsyncOperation: true
58 MaxAsyncWaitTime: 60

Choosing the tooling

Build Tools and GitHub Actions wrap the same Power Platform CLI commands; Pipelines in Power Platform is a built-in Dataverse service that you can also trigger from the CLI. The choice depends on where your team already works.

Pipelines in Power Platform

Built into the maker experience. Ideal for makers and smaller teams that want governed deployments without running a DevOps platform. Target environments must be Managed Environments, deployments stay within one tenant, and each solution is developed in a single development environment.

Azure DevOps

Full control with YAML pipelines, Power Platform Build Tools, approvals, boards and test plans in one place.

GitHub Actions

The same capabilities for teams whose code already lives on GitHub, using Microsoft's Power Platform actions.

CI/CD automation

I implement automated deployment pipelines using:

  • Azure DevOps: Build and release pipelines with Power Platform Build Tools
  • GitHub Actions: Git-based workflows for solution deployment
  • Power Platform CLI: Command-line automation for solution operations
  • Solution checker: Automated code quality and best practice validation

Configuration per environment

A solution should not contain anything that differs between environments. Those values live outside it:

  • Environment variables for URLs, feature flags and settings.
  • Connection references, so flows bind to each environment's own connections.
  • A deployment settings file per environment, applied automatically at import.
  • Secrets in Azure Key Vault, referenced rather than copied.

Automated testing

  • Unit tests for plugins and custom APIs, run in the build with a faked Dataverse context.
  • Solution Checker on every build, with critical rules failing the pipeline.
  • UI tests for the processes that must never break, run against Test after each deployment.
  • Smoke tests after the Production deployment, with the result posted to the team channel.

Practices that keep releases boring

1

Deploy with a service principal registered as an application user, never a personal account.

2

Build once and promote the same artifact through every environment.

3

Use upgrades rather than updates when components are removed, so deleted items disappear cleanly.

4

Keep no unmanaged changes in Test or Production; treat them as defects.

5

Split large implementations into a few solutions with clear dependencies.

6

Generate release notes from the linked work items, so everyone knows what changed.

Ready to transform your Customer Engagement?

Let's discuss how Dynamics 365 CE can drive your digital transformation. I'd be glad to help you design, build, and optimize your Dynamics 365 solution.