Case Study · Enterprise ALM Migration
Enterprise Power Platform ALM Overhaul: From Legacy Pipelines to Production-Grade GitHub Actions
An enterprise Home Services & Facility Solutions company needed its sprawling Power Platform estate (30+ solutions across 8 environments) modernized from fragile Azure DevOps pipelines to a robust, secretless, GitHub-native ALM system. We delivered the full migration and transformation.
The Challenge
The client operates a large Power Platform estate supporting operational, compliance, and reporting workloads across the Home Services & Facility Solutions sector. Over time the platform had accumulated significant technical debt that was actively slowing the business down:
Multi-Hour Deployments That Failed Late
Deployments regularly took several hours to complete and would occasionally fail partway through, sometimes hours in. A failed deployment meant starting over, burning an entire day and blocking every other team waiting on the environment.
No Developer Isolation
All developers worked in a single shared development environment with no mechanism to isolate their changes. In practice, one developer had to wait for everyone else to finish before a deployment could go out — turning parallel work into a bottleneck.
Nightly-Only Testing Deployments
Deployments to testing ran on a nightly schedule only. Developers couldn’t push work to test on demand, which meant bugs were discovered late, feedback loops stretched across days, and untested changes piled up before production releases.
Environment as Source of Truth
The development environment — not source control — was treated as the authoritative source for solutions and code. The repository served mostly as a backup with no gating, no review process, and no guarantee that what was in Git matched what was actually deployed.
The Solution
Every design decision stems from one principle: accept Power Platform's constraints as requirements, not obstacles. The branching strategy, deployment model, web resource organization, and developer workflow patterns were all designed around how Dataverse actually works, not how a generic CI/CD system expects things to work.
Repository Structure & Branching
The repository uses a two-branch persistent model designed around Power Platform's constraints. main represents production-ready code, tagged for every release. release-integration is the staging accumulator where features collect before promotion. Feature branches are squash-merged to release-integration for clean atomic commits, then merge-committed to main to preserve full history for production audit.
atlas-power-platform/ ├── .github/workflows/ # 8 GitHub Actions workflows + PowerShell scripts ├── src/plugins/ # 8 .NET Framework C# plugin projects ├── src/controls/ # PCF TypeScript/React custom controls ├── src/solutions/ # 30+ unpacked Dataverse solutions ├── deployment-settings/ # Connection mappings and env variable config ├── data/deployment-config/ # Reference data exports per environment └── scripts/deployment/ # Local PowerShell wrappers mirroring CI/CD
Eight CI/CD Workflows
| Workflow | Trigger | Purpose |
|---|---|---|
| PR Validation | PR open/update | Full quality gate: compile, test, solution build, settings validation, Solution Checker |
| Build & Release | Push to main | Smart change detection → build changed solutions → create versioned GitHub Release |
| Deploy Solutions | Auto or manual | Deploy from Release to target environment(s) with approval gates |
| Build & Deploy | Manual dispatch | Ad-hoc build + deploy for pre-release testing |
| Sync Solution | Manual dispatch | Export solution from Dataverse → unpack → commit to Git |
| Transport Solution | Manual dispatch | Move solution from source environment to target environment |
| Sync-Build-Deploy | Manual dispatch | Unified: sync + build + deploy in a single workflow |
| Check Source Branch | PR check | Enforces branch protection policy for merge targets |
Smart Change Detection
Every workflow begins by computing which solutions, plugins, and PCF controls actually changed. Unmodified solutions skip build entirely. Transitive dependency analysis ensures that when Solution A changes, any downstream solutions that depend on it are also rebuilt and tested. This slashed average PR validation time and eliminated wasted compute.
OIDC Federated Authentication
Every environment uses its own Azure app registration configured with federated credentials trusting the GitHub OIDC provider. Workflows exchange a short-lived OIDC token for an Azure access token at runtime. No client secrets, no rotation policy, no variable group sprawl.
Deployment Settings Pipeline
A three-stage settings pipeline handles environment-specific configuration: (1) sync extracts templates from dev environments, (2) developers maintain per-environment JSON override files, and (3) build-time merges generate final deployment settings. Every connection reference, environment variable, and data map is accounted for. PR validation catches missing values before code reaches any branch.
Extensible Hook System
A convention-based hook system provides named stages throughout the pipeline lifecycle. PowerShell scripts placed in a hooks directory matching the stage name are automatically discovered and executed. Post-deployment configuration, data seeding, and custom validation all slot in without modifying core workflow files.
The Migration
Moving from a 40 GB Azure DevOps repository to a clean GitHub repository was a significant operation in itself. Six years of history (933 commits from 41 contributors) needed to be preserved while shedding the accumulated weight. We treated it as a first-class workstream with its own quality gates.
40 GB → 25 MB
git-filter-repo permanently removed Lib/ and Tools/ folders from all historical commits. 933 commits and 41 contributors were cleanly preserved. The resulting repository clones in seconds on any developer machine.
Architectural Reset
The legacy exported / unpacked solutions were not migrated. Solutions were re-exported using pac solution clone, producing properly unpacked XML in a modern src/solutions/ structure and buildable .cdsproj files compatible with current Power Platform CLI tooling.
Security Remediation
A pre-migration scan found hardcoded service account credentials in a test project — four occurrences across three files. All were rotated, purged from history, and secret scanning was enabled on the repository to prevent recurrence.
Azure Pipelines → GitHub Actions
All pipelines were rewritten from scratch as composable GitHub Actions workflows. No marketplace extensions. No YAML anchors. Every step is a PowerShell script callable locally. Azure DevOps Boards was retained for work item tracking via the AB# convention.
Key Design Decisions
Two-branch persistent model, not trunk-based
Trunk-based development doesn’t work for Power Platform. Dataverse is the component merge engine, not Git — you can’t reliably merge solution XML in source control. Integration testing requires a dedicated environment with managed solutions. And auto-generated Dataverse XML mixed with hand-written code produces unreadable diffs. The two-branch model isn’t a compromise — it’s the correct model for this platform.
Solution-embedded web resources
Several approaches to web resource organization were evaluated. Solution-embedded won simply due to the fact that there had been a divergence away from using a single source location for web-resources that couldn't be reconciled.
Configuration data and deployment settings as separate systems
Connection references must resolve during import or the import fails. Reference data can only be imported after tables exist. Different timing, different tooling, different failure modes. Treating them as one system would require complicated sequencing logic. Treating them as two gives clean separation and predictable behavior.
PowerShell-first, not YAML-first
Workflow YAML files are thin orchestrators. All meaningful logic lives in PowerShell scripts that developers can run locally, debug interactively, and test independently of CI.
CalVer versioning (YYYY.MM.DD.N)
Calendar versioning provides instant traceability from any deployed solution version back to its build date and daily sequence number via Git tag calculation.
Outcomes
Source control as the source of truth
Git replaced the development environment as the authoritative source for every solution. What’s in the repository is what gets deployed — with pull request reviews, branch policies, and automated validation gating every change.
Code-first development flows
Developers work in a code-first model: plugins, PCF controls, and web resources are authored and reviewed in source control. The environment reflects the repo, not the other way around.
On-demand deployments to test
Testing deployments went from a nightly-only schedule to fully on-demand. Developers push work to test whenever it’s ready, get feedback in hours instead of days, and iterate without waiting for the next overnight window.
20 minute production deployments
Production deployments that previously took multiple hours — and sometimes failed partway through — now complete in under 20 minutes with smart change detection building and deploying only what actually changed.
Zero secret management overhead
OIDC federated credentials eliminated all client secrets for Dataverse authentication. No rotation schedules, no expired-secret incidents, no variable group sprawl.
Platform ready for AI agents
The scriptable, convention-based architecture makes this ALM system a natural fit for AI-assisted development workflows as the platform evolves.
“The real measure of an ALM system isn't what it does on day one. It's whether the team can extend it on day one hundred without calling the people who built it.”
Design principle for the migration
Facing a similar challenge?
Whether you're migrating from legacy pipelines or starting fresh, we can design an ALM system that scales with your platform.

