Setting Up ALM for Power Platform with GitHub Actions
This episode demystifies Power Platform ALM with GitHub Actions so you can see—and control—every step from source to prod. Learn why deployments fail (connector references, environment variables, and human-led imports), how to wire service principals and scoped secrets, and how to structure GitHub workflows (triggers, jobs, env-specific vaults) that validate, remap, and deploy solutions predictably. We cover source management with unpacked solutions, build-time checks, connector/variable remapping at deploy, and guardrails that stop silent breakages. If your Power Apps and flows “work in dev” but die in test or prod, this is your step-by-step playbook to ship reliable, auditable releases—without guesswork.
See every step. Control every secret. Ship the same app across dev → test → prod—on purpose.
What you’ll learn
-
Why Power Platform ALM breaks (hidden connector refs, env vars, drift, DLP)
-
How to structure GitHub Actions: triggers, jobs, environments, approvals
-
Secure identity & secrets: service principals, scoped env secrets, variable remapping
-
Build/test steps that catch issues early (solution validation, dependency checks)
-
A clean deploy pattern with rollback-ready artifacts
The ALM maze: what’s really different
-
Source ≠ code: Solutions bundle XML/JSON + hidden logic; changes aren’t visible until export.
-
Connectors are per-environment: References point to objects that don’t exist elsewhere by default.
-
Environment variables matter: Endpoints/keys must be swapped at deploy time, not baked in.
-
People-based deploys fail audits: Use service principals for consistency and traceability.
Core system: Source → Build → Test → Deploy (for Power Platform)
Source
-
Keep solutions in Git as unpacked (pac CLI) for diff-friendly PRs.
-
Commit both managed (release) and unmanaged (dev) exports; tag with solution version.
-
Store a
/configfolder per environment (env vars, connection ref mappings).
Build
-
Use GitHub Actions to pack/validate:
-
Unpack/pack with PAC CLI
-
Run Solution Checker (fail on criticals)
-
Generate dependency report (child flows, PCF, connection refs)
-
Publish artifacts: managed.zip + reports
-
Test
-
Spin up a test job against the target environment:
-
Verify env variables exist/are populated
-
Resolve connection refs to approved connectors
-
Optional “no-op” flow test runs (trigger test execution where safe)
-
Deploy
-
Import managed solution with service principal scoped to that environment.
-
Remap environment variables and connection references from
/config/test|prod. -
Post-deploy smoke checks (key flow run, app open, role access).
GitHub Actions: triggers, jobs, environments
Recommended triggers
-
pushtofeature/*→ build & validate only -
pull_requesttomain→ full build + solution checker + artifact -
workflow_dispatchonrelease/*→ deploy to test -
environment: productionwith required reviewers → deploy to prod
Job separation
-
build: pack, validate, solution checker, publish artifacts
-
prepare-env: fetch env config, map variables/refs
-
deploy-test/prod: import managed, apply mappings, smoke checks
Environment protection
-
Use GitHub Environments with scoped secrets:
DEV,TEST,PROD -
Require approvals for
PROD; restrict who can read those secrets -
Never reuse secrets across envs; name them with env prefixes (e.g.,
PROD_DATAVERSE_URL)
Secrets, service principals, and connectors
Service principals
-
One app registration per tenant; one SP per environment (least privilege).
-
Grant Dataverse roles sized for ALM tasks; store client ID/secret per env as GitHub secrets.
-
Rotate secrets; prefer federated credentials if available.
Environment variables
-
Store endpoints, table names, feature flags; never hardcode.
-
Maintain
/config/{env}/envvars.json; pipeline injects on import.
Connection references
-
Maintain
/config/{env}/connections.jsonmapping solution refs → target connectors. -
Validate existence & DLP compliance before import; fail fast if unresolved.
Guardrails that prevent “silent” breakage
-
Solution Checker gate (block on high/critical).
-
Dependency scan: ensure child flows/PCF/refs are included in the solution.
-
Config audit: ensure every required env var has a value in the target env.
-
DLP/Datasource check: block personal/unapproved connectors; enforce allow-lists.
-
Schema drift: compare Dataverse changes; require approval for destructive diffs.
Rollback & observability
Rollback
-
Always publish the previous managed.zip as an artifact; re-import on failure.
-
For severe issues, restore environment backup (Dataverse snapshot).
-
Practice restores in a sandbox; document timings and owners.
Observability
-
Log each step’s outputs (solution checker report, mapping summary, import result).
-
Emit deployment markers (run IDs, solution versions) to an audit table/dashboard.
-
Track KPIs: change failure rate, MTTR, % failures blocked pre-deploy.
Reference workflow outline (pseudo-YAML)
-
on: PR to main → build/validate; manualworkflow_dispatch→ deploy -
jobs.build: checkout → pac unpack/pack → solution checker → publish artifacts -
jobs.prepare-env: download artifacts → load/config/${{ env }}→ validate mappings -
jobs.deploy: use env-scoped secrets → pac auth (SP) → import managed → apply mappings → smoke tests
Common pitfalls (and fast fixes)
-
Works in dev, fails in test → missing connection ref mapping
-
Fix: add
/config/{env}/connections.json; validation step blocks if unresolved.
-
-
Wrong endpoint in prod → env vars not swapped
-
Fix: map on import; forbid hardcoded endpoints via linter script.
-
-
Audit issues → human account used for deploy
-
Fix: switch to SPs; restrict env secrets with approvals.
-
-
Unpack/pack drift → only commit unpacked; rebuild managed in CI.
-
Half imports → use “stage for upgrade” and auto-rollback to last artifact on failure.
Quick-start checklist (this week)
-
Create SPs + GitHub envs (DEV/TEST/PROD) with scoped secrets
-
Unpack your solution into Git; add Solution Checker to PRs
-
Add
/config/{env}/envvars.jsonandconnections.jsontemplates -
Build job: pack → validate → publish managed.zip
-
Deploy jobs: import with SP, remap vars/refs, smoke-test, approvals for PROD
-
Save previous managed.zip as rollback artifact; test a rollback in sandbox