Inleiding¶
Het doel van Application Lifecycle Management (ALM) is om wijzigingen gecontroleerd, herhaalbaar en aantoonbaar naar productie te brengen, met aandacht voor kwaliteit, governance, security en samenwerking tussen makers, beheerders en ontwikkelteams. In deze sessie richten we ons specifiek op source control repositories en deployment pipelines als technische bouwstenen binnen ALM.
Onder ALM vallen naast repositories en deployment pipelines ook de inrichting van omgevingen, security, governance, testprocessen, release management en beheer. Deze sessie behandelt deze onderwerpen niet inhoudelijk, maar concentreert zich op source control en geautomatiseerde deployments.
Basics: wat, waarom, waar, waarmee¶
Source control¶
Afwezigheid van source control van oplossingen binnen het Power Platform komt nog veel voor en is niet zozeer een tekortkoming, maar een logisch gevolg van de oorsprong van het platform. Een maker ontwikkelt immers rechtstreeks in de omgeving waarin de oplossing wordt opgeslagen en uitgevoerd. Voor eenvoudige scenario's werkt dat prima. Dat houdt echter op op het moment dat er eisen gesteld gaan worden aan ALM. Source control in het algemeen en git in het bijzonder is dan de tool waarin de versies van configuraties gecontrolleerd worden vastgelegd en van waaruit deze configuraties over verschillende niet-development omgevingen worden uitgerold.
Geautomatiseerde deployments¶
En elke omgeving waarin ontwikkeld wordt, is een ontwikkelomgeving. Geautomatiseerde deployments maken het mogelijk oplossingen aan te bieden buiten een ontwikkelomgeving, zoals een test, acceptatie of productieomgeving. Dergelijk onderscheid heeft zin als een uitrol een voorspelbaar resultaat heeft. Hiervoor is nodig dat - het plaatsvindt onder een persoonsonafhankelijk account; - het geen handmatige handelingen vergt; - het geen impact heeft op een andere omgeving, zowel op de oplossing zelf als bijvoorbeeld op dataopslag en mailverkeer.
Power Platform Solutions¶
Afgezien van extra opties, draait van het uitrollen van een Power Platform solution om 2 stappen: 1. Exporteer uit de development omgeving een sealed package: export managed; 2. Importeer de managed package in de doelomgeving met de omgevingsafhankelijke kenmerken.
Scripts en pipelines¶
Deze twee stappen moeten ergens aangestuurd, geconfigureerd en uitgevoerd worden. Onderstaande dekken het overgrote deel af wat in de praktijk gebruikt wordt:
| Host | Compute | Pipeline | Tooling |
|---|---|---|---|
| Azure Devops | Microsoft-hosted | YAML | PAC CLI |
| Azure Devops | Microsoft-hosted | YAML | Build Tools |
| Azure Devops | Self-hosted | YAML | PAC CLI |
| Azure Devops | Self-hosted | Classic | Build Tools |
| GitHub | Github-hosted | YAML | PAC CLI |
| GitHub | Self-hosted | YAML | PAC CLI |
| Power Platform Pipelines | Microsoft-managed | PP Pipeline | Native |
| Lokale PC | N.v.t. | Script | PAC CLI |
Azure DevOps, GitHub, Jenkins, GitLab enzovoort zijn het orchestratieplatform waar een van de vier mogelijke deployment engines op draait: - Power Platform Pipelines - PAC CLI - Power Platform Build Tools (wrapper rond PAC/API's) - Rechtstreekse API-aanroepen
Opmerking bij Classic pipelines Deze kunnen uitstaan onder project settings. Opmerking bij het low code alternatief Power Platform Pipeline hosts De basisversie draait onder de gebruikerscredentials. Wellicht een use case als makers geen commandprompt hebben, maar scheiding van taken (SoD) is onhaalbaar, en dat is voor ALM de kern. Als op de host delegation is ingericht (vereist Premium licenties voor alle gebruikers van de envionments, een Power Platform Pipeline Host environment met Production status en de gebruiker moet owner zijn van de SPN) levert dit een eenvoudig in te richten DTAP straat.
Details¶
Source control details¶
Hoewel het voor Power Platform componenten nog meevalt, kan versiebeheer ook hier complex worden. Voor kleine oplossingen voldoet trunk-based development of zelfs alleen een develop branch die bij release wordt gemerged.
Authentication¶
Of je nu lokaal, in GitHub of met DevOps werkt, er moet tegen de Power Platform environment aangepraat worden. En er zijn veel, heel veel authenticatiemethoden met elk eigen sterktes en zwaktes. - PAC profiel - ADO SPN - GitHub PAT, SSH, OIDC
Solution details¶
Dit stelt eisen aan zowel de exporteerbaarheid van het geheel als aan onderdelen in een Power Platform oplossing, omdat koppelingen (Dataverse, SharePoint, SQL) en interacties (mail, teams) in elke omgeving een eigen variant moet kunnen adresseren. Stappen met de pipeline bevatten daarom: - unmanaged downdloaden - parameter bestand genereren en configureren - managed downloaden - managed importeren in omgeving #2 met parameters omgeving #2 (TEST) - managed importeren in omgeving #3 met parameters omgeving #3 (ACC) - Approval gate - managed importeren in omgeving #4 met parameters omgeving #4 (PROD)
Drie meningen¶
- Ik zie de voordelen van de actions in microsoft/powerplatform-actions/actions-install maar ik neig meer gebruik van de PAC CLI omdat die altijd voorop loopt.
- Pipelines in Power Platform heeft een te klein voor het tafellaken probleem. De basis - zonder delegation - is handig, maar voor ALM zinloos omdat je dan alsnog makers schrijfrechten moet geven in ACC en PROD. Met delegation is het bruikbaar, maar dan ben je al zo ver dat je echt een grote groep makers moet hebben om nog waarde toe te voegen boven ado of github pipelines. En vanwege de premium voor alles eis, zie ik weinig plekken waar dit de best passende oplossing biedt.
- Met de dataverse git-integratie heb ik een probleem met het koppelmodel. De unit van Dataverse Git-integratie is de omgeving: die wijst naar een repo, branch en folder. De unit waarmee ik werk, is de solution. Die twee komen niet overeen. Volgens de docs moeten bovendien alle aangesloten dev-omgevingen dezelfde binding, repo, branch en folder gebruiken. De moeilijkheid is dat een omgeving aan één branch gekoppeld is. In een gedeelde omgeving kun je die dus niet per feature wisselen, want de staat van tientallen andere solutions reist mee. Voor veel (denk canvas + powerautomate solutions) productvity solutions in een environment, is ook vaak al een andere repo strategie gekozen.
Voorbeelden¶
ADO Pipelines¶
Azure Devops regelt de aansturing van de verschillende pipelines. Welke er zijn, wanneer zij hebben gelopen, vastlegging van de artifacts (packages) die gemaakt zijn, de logging.

ADO YAML Pipeline met PAC CLI¶
In deze aanpak start je met het installeren van de PAC CLI en daarna roep je diverse PowerShell scripts aan die met de PAC CLI de export en import regelen.
stages:
- stage: Build
variables:
TemplateRoot: '$(Pipeline.Workspace)/s/templates'
jobs:
- job: BuildSolutions
steps:
- checkout: self
persistCredentials: true
fetchDepth: 0
path: s/self
- checkout: templates
path: s/templates
- task: PowerShell@2
displayName: Install PAC CLI
inputs:
targetType: filePath
filePath: $(TemplateRoot)/powerplatform/yaml_cli_v2/scripts/install-pac-cli.ps1
- ${{ each solution in parameters.solutions }}:
- task: PowerShell@2
displayName: Build ${{ solution.name }}
inputs:
targetType: filePath
filePath: $(TemplateRoot)/powerplatform/yaml_cli_v2/scripts/build-solution.ps1
arguments: >
-SolutionName "${{ solution.name }}"
-Major "${{ parameters.major }}"
-Minor "${{ parameters.minor }}"
-DevEnvironmentUrl "$(DEVEnvironmentUrl)"
-ClientId "$(ClientId)"
-ClientSecret "$(ClientSecret)"
-TenantId "$(TenantId)"
-debug ${{ parameters.debug }}
- publish: $(Build.ArtifactStagingDirectory)
artifact: powerplatform
ADO YAML Pipeline met build tools¶
Voor deze aanpak is een Power Platform Build Tool geinstalleerd in DevOps, die in elke pipeline geinstalleerd wordt. Daarmee worden Power Platform tasks beschikbaar, zoals hieronder PowerPlatformPublishCustomizations@2.
stages:
# ------------------------------------------
# Stage 1: Build & Deploy to Acceptance
# ------------------------------------------
- stage: ACC
displayName: 'Deploy to Acceptance'
jobs:
- job: BuildAndImportACC
displayName: 'Build managed solution and import into ACC'
pool:
vmImage: 'windows-latest'
steps:
- task: PowerPlatformToolInstaller@2
inputs:
DefaultVersion: true
# Publish customizations and export managed solution from Development
- task: PowerPlatformPublishCustomizations@2
displayName: 'Publish customizations in DEV'
inputs:
authenticationType: 'PowerPlatformSPN'
PowerPlatformSPN: 'DTS Managed Development'
AsyncOperation: true
MaxAsyncWaitTime: '60'
ADO Classic Pipeline¶
Super oud en sinds 2023 standaard uitgezet voor nieuwe Azure DevOps projecten. Maar werkt nog wel en wordt ook nog gebruikt.

GitHub Workflow¶
Met GitHub actions worden jobs handmatig of op basis van andere events gestart. De terminologie is anders, maar de concepten komen grotendeels overeen met Azure DevOps Pipelines.

GitHub YAML jobs met build tools in GitHub¶
name: Deploy to Test
on:
workflow_dispatch:
permissions:
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
environment: Test # optioneel: gebruik GitHub Environments voor secrets/vars en approvals
env:
SOLUTION_NAME: DTSSharedComponents
SOLUTION_FOLDER: src/DTSSharedComponents
SOLUTION_ZIP: out/DTSSharedComponents_managed.zip
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Install Power Platform CLI
uses: microsoft/powerplatform-actions/actions-install@v1
- name: Verify connection (who-am-i)
uses: microsoft/powerplatform-actions/who-am-i@v1
with:
environment-url: ${{ vars.Acceptance_Url }}
app-id: ${{ secrets.POWERPLATFORM_ADMIN_SPN_ID }}
client-secret: ${{ secrets.POWERPLATFORM_ADMIN_SPN }}
tenant-id: ${{ secrets.POWERPLATFORM_ADMIN_TENANT }}
Power Platform Pipelines¶

Lokale PC met PAC CLI script¶
$solutionPath = "C:\..."
$phase="acceptance"
$configDeployments = Get-Content ".\PowerPlatform\Solutions\Deploy\deploy-solution.parameters.json" -Raw | ConvertFrom-Json
$buildConfig=($configDeployments.environments | Where-Object name -eq "THJ3K-Dev")
$accConfig=($configDeployments.environments | Where-Object name -eq "THJ3K-QA")
if($phase -eq "build"){
.\PowerPlatform\Solutions\Deploy\connect-powerplatform-spn.ps1 -Name $buildConfig.pacProfile
get-childitem -path $solutionPath -filter *solution.json | ForEach-Object {
$configSolution = Get-Content ($_.FullName) -Raw | ConvertFrom-Json
pac solution publish
pac solution export --environment $buildConfig.id --name $configSolution.solutionName --path $solutionPath --overwrite
$solutionzip=Join-Path -Path $solutionPath -ChildPath ($configSolution.solutionName + ".zip")
pac solution check --path $solutionzip --saveResults
pac solution create-settings --solution-zip $solutionzip --settings-file (Join-Path -Path $solutionPath -ChildPath ("Deploy-" + $configSolution.solutionName + "_SRC.parameters.json"))
}
}
if($phase -eq "acceptance"){
.\PowerPlatform\Solutions\Deploy\connect-powerplatform-spn.ps1 -Name $buildConfig.pacProfile
get-childitem -path $solutionPath -filter *solution.json | ForEach-Object {
$configSolution = Get-Content ($_.FullName) -Raw | ConvertFrom-Json
pac solution export --environment $buildConfig.id --name $configSolution.solutionName --path $solutionPath --managed --overwrite
}
.\PowerPlatform\Solutions\Deploy\connect-powerplatform-spn.ps1 -Name $accConfig.pacProfile
get-childitem -path $solutionPath -filter *solution.json | ForEach-Object {
$solutionzip=Join-Path -Path $solutionPath -ChildPath ($configSolution.solutionName + "_managed.zip")
pac solution import --environment $accConfig.id --path $solutionzip --settings-file (Join-Path -Path $solutionPath -ChildPath ("Deploy-" + $configSolution.solutionName + "_ACC.parameters.json"))
}
}