Skip to content

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

  1. 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.
  2. 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.
  3. 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. image-ado-pipelines.png

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. ado-classic-pipeline

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. image-github-actions.png

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

image-pp-pipeline.png

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"))
    }
}