Application Versions – CI / CD Part 5

Application Versions – CI / CD Part 5

Classic NAV development processes, customizations with C/Side became obsolete in the Business Central age was replaced by Apps. Apps have version numbers to identify which app version is newer, handle updates and finally synchronize data changes in the right order.

New App Versions are produced by fully automated CI processes in a very short time and the generated Artifacts replace the installed version in target environments during automated CD processes.

The application version helps to keep the necessary overview and answer the question: “Which App is installed at my target environment?

Application Version

The Application Version is defined in the app.json by 4 numbers/parts:

"version": "[Major].[Minor].[Build].[Revision]"

Major & Minor Version

A major version identifies a new major release – something has been changed totally:

  • New major version of the base application
  • New or changed application dependencies

The change of minor version shows you:

  • Breaking change, a data upgrade is needed because the table schema has changed
  • The changes affect the user experience and/or the workflow
  • A significant new feature was implemented

Mostly a change of major or minor version indicates a “Breaking Change”. Your App have to implement an Upgrade CodeUnit and provide code to upgrade existing data to the new structure.

More details for Install & Upgrade CodeUnits can be found at Dmitry Katson’s Blog-Posts about demystifying installation process for Business Central Apps. [Link]

Build Version & Revision

Each CI Build generates a new Artifact and a build version makes the combination of “[major].[minor]” unique.


The revision can be set normally to 0. When the branching model and release strategy require to show the origin of a hotfix – used this notation:


Continuous Integration – CI Builds

As prerequisite my numbering test project repository contains 3 folders:

  • ‘.devops’, the folder for Azure DevOps CI pipeline YAML files
  • ‘app’, the Dynamics 365 Business Central App project folder
  • ‘test’, the Test App project folder

Application Version (Artifact Version)

Each new compiled App needs a unique number, independent if the artifact is used for a release or not. The following versioning works fine for my projects:


[Major] and [Minor] are defined and changed in the project. [Build] is automatically incremented by each CI-Build for the latest [Major].[Minor] combination and starts by 0. This will be calculated by the pipeline.

CI Build Triggers

An automated CI-Build (CI-Pipeline) can be triggered from a Commit on a Branch like ‘master’ at the Source Repository. Such triggers are defined in the respective pipeline yaml file. My pipeline uses the trigger parameter path and is only invoked when a changed file was committed at the app or test folder:

    - master
    - release/*
    - app/*
    - test/*

Another way is to setup a Branch Policy with Build Validation which trigger the assigned pipeline on each Pull Request:

CI Build Variables

Azure DevOps support expressions like counters in Azure pipelines. Such counters can be used to calculate the automatic incremented Application Version for each build. The following yaml snippet show my global pipeline variables responsible for the for CI-Versioning of an Dynamics 365 Business Central App:

  # Automatic Build Artifact Versioning
  - name:  'Version.Major'
    value: '1'  
  - name:  'Version.Minor'
    value: '0'
  # auto-increment based on: [major].[minor] (variable 'Fixed.Build' can overrule auto-increment)
  - name:  'Version.Build'
    value: $[ coalesce(variables['Fixed.Build'], counter(format('{0}.{1}', variables['Version.Major'], variables['Version.Minor']), 0)) ]
  # by default 0 (auto-increment based on: [major].[minor].[build])
  - name:  'Version.Revision'
    value: $[ counter(format('{0}.{1}.{2}', variables['Version.Major'], variables['Version.Minor'], variables['Version.Build']), 0) ]
  # App-Version: [Major].[Minor].[Build].[Revision]
  - name:  'AppVersion'
    value: $[ format('{0}.{1}.{2}.{3}', variables['Version.Major'], variables['Version.Minor'], variables['Version.Build'], variables['Version.Revision']) ]

These variables are used for the pipeline tasks. My compile task (yaml) for the Dynamics 365 Business Central App with use of the generated Application Version based on ALOps is:

    - task: ALOpsAppCompiler@1
      displayName: 'ALOPS Compile App'
        usedocker: true
        targetproject: 'app/app.json'
        nav_app_version: '$(AppVersion)'

Finally, I like to see which Application Version was used for the App at the list of CI Builds. To display the generated Application Version my CI pipeline (yaml) have a name:

name: "$(AppVersion) [$(Build.SourceBranch)]"

For my tests I have included also the source branch name to see the reason of the CI Build – Pull Request or Branch Trigger. Later I discovered this information was already displayed:

What’s next

I’ll continue my series soon… One of my next posts will cover my preferred Branching model, I’ll share some insights, why I use Universal Packages for my Artifacts and where you can use “Badges” for documentation. So, stay tuned!

I like to read your comments, suggestions, and be curious if this fits into your process. Do you use the same App-versioning and automation for your Apps?


6 thoughts on “Application Versions – CI / CD Part 5

  1. Hi,

    I really like this version idea, I´m still playing around with alops.

    But how do you determine from the version number that you app work e.g under version 14 or v15 , you might have customer still running under v14 or 14.5 , would it not be a good idea to include which version your app is compiled against, MS uses 15 as Major

  2. I really like your posts! 🙂

    Need your help with this.

    We created build pipelines and release pipelines where when build runs the package with the latest version falls in Artifacts. So for the latest version in the artifacts we are creating releases using Invoke Rest API call -DELETE- GET- PUT tasks sequentially. Each time when creating releases we are manually editing version to latest in Put and releasing, so this latest version is picked by Kie servers on successful release.

    Can some one please let me know what is the plugins or extensions available so that the release pipeline picks up the latest version from the artifacts by itself and get deployed.

    Any inputs?

Comments are closed.

Comments are closed.