Mastering Solution Versioning in the Power Platform
Streamline Deployments and Keep Your Applications Organized with Effective Version Control Strategies
When creating software, assigning a version number is critical. This version number acts as a label that identifies what is included in a particular release, providing clarity and traceability for deployments. In this blog I describe how I tried to solve this problem at one of my customers.
Dataverse solution versions
In the Power Platform, following best practices means you should be developing within a Dataverse solution. This approach packages all components together, making it easier to deploy them from the development environment to test or production environments. This Dataverse solution will receive a version number when exported from the development environment. The first number is going to be 1.0.0.0
. This format follows the convention: <major>.<minor>.<build>.<revision>
.
Using version numbers
There are different strategies for assigning version numbers in the Power Platform. Some teams incorporate dates into the version, such as 2024.20.11.1
. Ultimately, how you use these numbers depends on what works best for your team. Establishing clear guidelines ensures consistency.
My take on versioning
In a recent project, I needed to implement a versioning system for a solution built in the Power Platform. All development work was low-code and done in a Canvas application, model driven application, custom pages and Power Automate Cloud Flows. There were the following prerequisites:
The team needed a clear understanding of what each part of the version number signified.
New versions had to be set and exported via Azure DevOps (ADO) pipelines.
Each deployment required a higher version number than the previous one.
All developers needed access to change version numbers.
It was essential to track which version was deployed to which environment.
Defining the versioning system
We adopted the following rules for managing version numbers.
Given a version number MAJOR.MINOR.BUILD.REVISION, increment the:
MAJOR: Incremented when adding significant new modules or functionality.
MINOR: Incremented for new features.
BUILD (BUGFIX): Incremented for bug fixes or minor immediate improvements.
REVISION (COMMIT): Auto-incremented upon export.
At the start of each sprint, we discussed the appropriate MAJOR and MINOR versions, and all completed features were added to the designated version.
Example:
This sprint we are working on MINOR version number ‘3’ and MAJOR version ‘2’ so we are working on version 2.3.0.0
. Whenever a bug comes up in the previous version, 2.2.0.0
, we would fix that bug and deploy version 2.2.1.0
.
Setting versions in ADO
To automate versioning I used the Power Platform Build Tools in ADO. With these tools you can use the Set Solution Version step to adjust the version number in your pipeline.
You add this step to your YAML deployment script before you export your solution to set the version number. It would look like this:
- task: PowerPlatformSetSolutionVersion@2
inputs:
authenticationType: 'PowerPlatformSPN'
PowerPlatformSPN: 'PowerPlatform-ServiceConnection-Dev'
SolutionName: '${{parameters.SolutionName}}'
SolutionVersionNumber: '$(versionNumber)'
- task: PowerPlatformExportSolution@2
displayName: 'Export Managed Solution'
inputs:
authenticationType: 'PowerPlatformSPN'
PowerPlatformSPN: 'PowerPlatform-ServiceConnection-Dev'
SolutionName: '${{parameters.SolutionName}}'
Managed: true
SolutionOutputFile: '$(Build.ArtifactStagingDirectory)\Solutions\${{parameters.SolutionName}}.zip'
AsyncOperation: true
MaxAsyncWaitTime: '60'
This step ensured that subsequent operations in the pipeline used the correct version number.
Managing version numbers
Now we have to manage the version number so it can be changed by all developers. For this I decided to use the variable groups in Azure DevOps. This way, we would have a central location where everybody could see the version of the application. That would look as follows:
In my YAML script I would use the following variables to build the version number:
variables:
- group: ${{parameters.SolutionName}}-solution-versioning-variable-group
- name: version.MajorMinorPatch # Manually adjust the version number as needed for semantic versioning in the variable group. Build is auto-incremented.
value: '$(Major).$(Minor).$(Patch)'
- name: version.Build
value: $[counter(variables['version.MajorMinorPatch'], 0)]
- name: versionNumber
value: '$(version.MajorMinorPatch).$(version.Build)'
For the version.Build variable I use the counter function to increment the Build number. This number will reset back to 0 as soon as one of the other numbers increments. This way it is also easier to deploy a higher version number than the previous one.
EDIT: I found out later that the counter function actually doesn’t work with these type variables. These expressions are evaluated before the pipeline is run so the variable from the variable group is empty at compile time. I reverted to going back to a manual build number change and added it to the variable group.
Now, all developers can change the version number if needed. This is especially helpful when deploying bugfixes.
Tracking deployed versions
Lastly, we need to keep track of the versions in ADO. Since we were deploying to upwards of 40 environments spread over 20 tenants, and counting, this could become very confusing.
Unfortunately, there is no out of the box feature to get an holistic overview of the deployed versions in ADO. I also did not want to create different ADO environments since I would have to manage upwards of a 100 environments. Therefore, I opted for a change in the build number. This way we could at least see which version ran in which pipeline. The below image shows in green the build number of the pipeline run which has been altered to show the version number of the solution we wanted to deploy.
Since every pipeline was connected to a specific tenant I could now see the last pipeline run and what version we tried to deploy in that pipeline to a specific environment.
For this I used some PowerShell inline script to change the build number.
- task: PowerShell@2
name: ChangeBuildNumber
inputs:
targetType: 'inline'
script: |
Write-Host "##vso[task.setvariable variable=ProjectBuildNumber;]YourUpdateValue"
Write-Host "##vso[build.updatebuildnumber]${{parameters.SolutionName}}.$(versionNumber)"
And since the pipelines in the first image above where my continuous deployment (CD) pipelines I had to use the runName of the continuous integration pipeline that triggered these pipelines. Adding the following PowerShell inline script to my CD pipelines:
- task: PowerShell@2
name: ChangeBuildNumber
inputs:
targetType: 'inline'
script: |
Write-Host "##vso[task.setvariable variable=ProjectBuildNumber;]YourUpdateValue"
Write-Host "##vso[build.updatebuildnumber]$(resources.pipeline.export-and-unpack-to-git-pipeline.runName)"
Wrapping up
Have you ever struggled with managing versions across environments? I hope this can help you with deciding how to manage your versioning process. Especially when you have multiple developers and need to deploy to multiple tenants. If you have any comments or suggestions please let me know.