Why?
In the previous post Power Platform: connect an Azure DevOps Pipeline » Knowhere365, I showed how to connect an Azure DevOps Pipeline to the Power Platform. Now we are going to let the Pipeline export a Power Platform Solution.
What?
In this post, I am going to let the Azure DevOps Pipeline export a Power Platform Solution to our Git Repo.
How?
Most blog posts on this topic will keep it “simple” and only use Variables defined in the Pipeline itself: see Define variables – Azure Pipelines | Microsoft Docs. I want to be prepared for multiple Pipelines using the same Variables over and over again… To support this I will use Variable Groups stored in the Azure DevOps Project Libary: see Variable groups for Azure Pipelines – Azure Pipelines | Microsoft Docs.
1) Create a Variable Group for our DEV Environment. I named this group after the the environment itself to be consistent:
For now, I only know three variables so I added them already:
2) Because I am such a control freak, I want to save all variants of the Power Platform Solution.
This means I want to save the Unmanaged Solution as a .zip file. I also want the Managed Solution saved as a .zip file. And I want to save the Unmanaged Solution unpacked as individual files so all the source code files are saved separately. Last but not least, I want the Pipeline to save all these variants to our Git Repo and make sure that Git delivers nice versioning on all these files. An important aspect to verify, is if the Git Repo is configured to allow the Pipeline Machine to commit files. Select Manage repositories of the desired Git Repo:
In the Security tab we need to make sure that the Build Service of our Azure DevOps Project is allowed to:
– Bypass policies when pushing
– Contribute
In a previous post, I already mentioned that any Azure DevOps Project could host a Pipeline. Even when yoy want to save to a Git Repo of another Azure DevOps Project. For that scenario, this will also be the place to add the Build Service of that Azure DevOps Project and give it the correct permissions on the specific Git Repo 🔓.
3) Below an example of a .yml Pipline that uses the Variable Group and will do all these Tasks (for details see Build tool tasks – Power Platform | Microsoft Docs):
trigger: none
pool:
vmImage: windows-latest
variables:
- group: 'insbadev01'
steps:
# Prepare #
- checkout: self
persistCredentials: true
- task: PowerPlatformToolInstaller@0 #Always Install this when using PowerPlatformBuiltTools on machine
displayName: Prepare - Install PP Tool
inputs:
DefaultVersion: true
# Solutions logic #
- task: PowerPlatformPublishCustomizations@0 #Publish Environment Customizations
displayName: Solutions - Publish customizations
inputs:
authenticationType: 'PowerPlatformSPN'
PowerPlatformSPN: 'insbadev01connection'
- task: PowerPlatformExportSolution@0 #Export Unmanaged Solution to machine
displayName: Solutions - UnmSol export zip locally
inputs:
authenticationType: 'PowerPlatformSPN'
PowerPlatformSPN: 'insbadev01connection'
SolutionName: '$(PowerPlatformSolution01)'
SolutionOutputFile: '$(GitDirectoryExportedSolutions)\$(PowerPlatformSolution01)UM.zip'
AsyncOperation: true
MaxAsyncWaitTime: '60'
ExportAutoNumberingSettings: true
- task: PowerShell@2 #Push Unmanaged Solution zip file to Git Repo
displayName: Solutions - UnmSol zip to repo
inputs:
targetType: 'inline'
script: |
# Write your PowerShell commands here.
ls ${env:GitDirectoryExportedSolutions}
git config --global user.email ${env:gituser}
git config --global user.name ${env:gituser}
git checkout main
git add ${env:GitDirectoryExportedSolutions}
git commit -am "Added Solution Export ${env:PowerPlatformSolution01}UM as zip"
git push origin main
- task: PowerPlatformUnpackSolution@0 #Unpack Unmanaged Solution zip file
displayName: Solutions - UnmSol export folders locally
inputs:
SolutionInputFile: '$(GitDirectoryExportedSolutions)\$(PowerPlatformSolution01)UM.zip'
SolutionTargetFolder: '$(GitDirectoryExportedSolutions)\$(PowerPlatformSolution01)Unmanaged'
- task: PowerShell@2 #Push unpacked Unmanaged Solution files to Git Repo
displayName: Solutions - UnmSol folders to repo
inputs:
targetType: 'inline'
script: |
# Write your PowerShell commands here.
ls ${env:GitDirectoryExportedSolutions}
git config --global user.email ${env:gituser}
git config --global user.name ${env:gituser}
git checkout main
git add ${env:GitDirectoryExportedSolutions}\${env:PowerPlatformSolution01}Unmanaged
git commit -am "Added Solution Export ${env:PowerPlatformSolution01} unpacked"
git push origin main
- task: PowerPlatformExportSolution@0 #Push solution Managed zip file to Git Repo
displayName: Solutions - ManSol export zip locally
inputs:
authenticationType: 'PowerPlatformSPN'
PowerPlatformSPN: 'insbadev01connection'
SolutionName: '$(PowerPlatformSolution01)'
SolutionOutputFile: '$(GitDirectoryExportedSolutions)\$(PowerPlatformSolution01)M.zip'
Managed: true
AsyncOperation: true
MaxAsyncWaitTime: '60'
ExportAutoNumberingSettings: true
- task: PowerShell@2 #Push solution Managed zip file to repo
displayName: Solutions - ManSol zip to repo
inputs:
targetType: 'inline'
script: |
# Write your PowerShell commands here.
ls ${env:GitDirectoryExportedSolutions}
git config --global user.email ${env:gituser}
git config --global user.name ${env:gituser}
git checkout main
git add ${env:GitDirectoryExportedSolutions}
git commit -am "Added Solution Export ${env:PowerPlatformSolution01}M as zip"
git push origin main
The hardcore .yml Pipeline builders may have noticed one Variable defined on Pipeline level: gituser. I have chosen for this approach so a person performing a manual run can change it to their own e-mail address. This will result in the Git history, showing that person being the one committing the files.
Because I am using a Variable Group, I needed to give the Pipeline permissions for the first run:
This should result in a nice successful Job Run:
And off course a nice Git Repo storing the Solution files:
Here we are! A Git Repo containing the three options to record our Power Platform Solution as source code worthy files. An Unmanaged Solution as a .zip file, a Managed Solution as a .zip file and an Unmanaged Solution unpacked. With version history containing a new version every time the Pipeline runs 😎
Will the managed and unmanaged files be over written each time theres a change or will it keep the files for each version i.e previous files and new file so in your example there will be a four files in the next build when there’s a change?
Hi Shomari,
In this example there will be three files as output:
“An Unmanaged Solution as a .zip file, a Managed Solution as a .zip file and an Unmanaged Solution unpacked.”
With every Build run of a Pipeline new versions of alle files will be saved giving us a history of changes per file. Especially the unpacked versions are very useful because this will actually show the changes on the lowest level but only in the files that were changed. This gives you a very nice delta between versions (commits).
The zip files off course only show one big file and not what was actually changed within the Solution…
Thanks for the speedy reply. I will be definitely be applying your method in the blogs and I just have some more questions which out of the three file which one will I deploy to production. It should be the manèges zip file but I just want to double check
hi, it’s very nice and detailed article. I just have a question, right now there is an option to give only one solution name for export, how do we handle if there is a need for multiple solution export in a single pipeline.
Is there any way to provide json file as an input for looping through?
Hi Arul,
The concept of a Pipeline Template will make life easier: https://knowhere365.space/power-platform-export-solutions-with-an-azure-devops-pipeline-template/
Then you would define the same step multiple times with different parameters 👍