Developing Business Central Extensions (part 3) – Build Pipeline

If you haven't read part 1 and part 2, you should do so before continuing here. Part 1 contains the prerequisites and part 2 is about cloning the project and get your sandbox environment up running.

Create a build agent

In order to setup continuous integration, we need a machine which can perform the actual build asks for us, the build agent.

A build agent consists of a Windows Server 2016 with some software installed: Docker, NavContainerHelper and the Azure DevOps Agent. You will also need to configure the build agent to access your organization.

I have created an ARM template, with which you can create a build agent.

The Url to this template is

or you can create a Windows Server 2016 and install the components manually:

The script, which performs these steps for the ARM template can also be downloaded and used. You will find it here:

In both cases you will need a Personal Access Token for your Azure DevOps Organization in order to setup a build agent.

Open your Azure DevOps organization (eg.<organization>/) and click your avatar and select Security

In the Personal Access Tokens list, you can revoke tokens, regenerate them or edit scope, expiration date and more.

Select New Token, give the token a name, an expiration date, click show all scopes to reveal Agent Pools and select Read & manage.

Click Create and you will see the token one time and one time only. You will need to copy the token.

Note: You can use the same token for multiple agents.

For the automated build agent setup, open and specify size, location, your organization and the Personal Access Token.

After 15-20 minutes, you should see your new agent popping up (<organization>/_settings/agentpools), ready to serve you:

Access your secrets in the build system

In part 1, we created an Azure KeyVault, with a number of secrets (password, license file etc.). We need these secrets in the build and fortunately, Azure DevOps has a nice way of getting to those.

In Azure DevOps, under your Project, select Pipelines -> Library.

Click + Variable group to create a variable group. Name the variable group and select Link secrets from Azure key vault as variables.

Specify the subscription (you will need to authenticate), select the key vault and add the variables

These variables will now be available for the build tasks if you link the variable group to the pipeline.

Create a build pipeline

In Azure DevOps, under your Project, select Pipelines -> Builds. You will likely see that you have no build pipelines:

Click New pipeline and click Use the visual designer. Select your repository:

Continue and select the YAML template under Configuration as code.

Select the Default Agent pool and select the CI.yml file (included in the repository)

Select Variables, Variable Groups, Link variable group and Link your variable group you created above to the pipeline.

Click Save & queue and queue a build. You can click the link of the build to see the log...

Note: The first time you run a build on the agent, it will take significantly longer because it needs to pull the Business Central Docker image.

After some time, you should see your build successfully completed and one failing test.

A few words about Tests

Update February 27th - the helloworld template repository has been updated with a new way of running tests - a special blog post on test execution will be added to this series soon.

I should mention here, that the way tests are executed in the repository while writing this blog post is still work in progress. Currently the setup just invokes a Codeunit in a container and there are multiple reasons why this isn't sufficient. We are working on making a better approach to this and I will include this in a later blog post.

What's next

Now, we have our source in Azure DevOps and we have local and hosted builds running.

In the next Blog Post we will setup checkin policies with code reviews and pull requests - and we will create a few more pipelines for testing our app against insider builds.



Freddy Kristiansen
Technical Evangelist

Comments (23)

  1. Kine2 says:

    Hi Freddy, one question – have it some reason that you are linking the secrets to Azure key vault? You can put the values directly into the variable groups and use them as environment variables in scripts. It will make it much simpler to config. But may be there is some additional value in this I do not see now.

    1. FreddyDK says:

      Keyvaults are very easy to use:-)
      Multiple reasons really
      I can use the keyvaults locally and run local builds and when spinning up sandboxes, get the right license file.
      I can reuse the same keyvault across projects.
      I can automate generation of keyvaults.

  2. Micha Megel says:

    The option YAML is unfortunately not available for External Git Repositories – this means, you have to setup the pipeline for each project or move to VSTS Repo.
    MS support answer: “…It’s by design…” :/

    1. FreddyDK says:

      I should add a PowerShell script in the scripts folder, which is the pipeline
      Much like build-local, much like the content of the yaml file.

      1. Yeah YAML Style Build looks great, but TFS Users can not use it like that (or am I missing something here?)
        A Powershell Version would be great and more flexibel in this case

  3. AchimT says:

    For me the build pipeline fails on the “Run Tests” task.

    2018-11-16T11:13:45.1858869Z Formatted command: . ‘C:\Agent\_work\1\s\scripts\Run-Tests.ps1’ -version “current” -credential ([PSCredential]::new(“***”, (ConvertTo-SecureString -String “***” -AsPlainText -Force))) -TestResultsFile (Join-Path “C:\Agent\_work\1\s” “TestResults.xml”) -test “unittests”
    2018-11-16T11:13:45.2641729Z ##[command]”C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe” -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command “. ‘C:\Agent\_work\_temp\a6f21efc-f670-4eef-8329-867ac0a1f71b.ps1′”
    2018-11-16T11:13:49.1375029Z You do not have the following permissions on TableData CAL Test Enabled Codeunit: Insert.
    2018-11-16T11:13:49.1375954Z To view details about your permissions, see the Effective Permissions page. To report a problem, refer to the
    2018-11-16T11:13:49.1376544Z following server session ID: ’48’.

    Any suggestions?

    1. FreddyDK says:

      For that, I think you need to specify your own license file in the key vault.

  4. JatinPatel22 says:

    Hi Freddy, When I try to Queue a Build it is giving below error “The value specified for SourceVersion is not a valid commit ID.”
    What value we have to put in Commit field on Queue build page? If I leave it blank then it is giving different error “Unable to resolve the reference ‘refs/heads/master’ to a specific version. Verify the reference exists in the source repository.”
    Any suggestions?

    1. FreddyDK says:

      I am not a git expert and it sounds like something is wrong at that level.
      Maybe you can clone the repo to a different folder and use that?

  5. jwinberg says:

    Hi Freddy,
    This has really been a great blog series. I have been testing this build process, but I had a problem that all build were failing on the “Remove Build Container” step.
    The failing part was

    Remove-Item : Cannot remove item C:\ProgramData\NavContainerHelper\Extensions\xxxx-bld\my: The process cannot
    2018-12-18T21:15:45.5570806Z ##[error]access the file ‘C:\ProgramData\NavContainerHelper\Extensions\xxxx-bld\my’ because it is being used by another
    2018-12-18T21:15:45.5744371Z ##[error]At C:\Program Files\WindowsPowerShell\Modules\navcontainerhelper\\ContainerHandling\Remove-NavContainer.ps1:39

    I was finally able to come round this by a small change in Remove-NavContainer.ps1 by adding “-ErrorAction Ignore” in the Remove-Item command. No errors now and at least the contents of all folders are deleted.
    Has anybody else experienced this, or what could be locking the files from being removed?

    1. FreddyDK says:

      I have seen that a few times and also AJ has reported this here:
      It doesn’t seem to be consistent, but I will double check and might just include your fix.

  6. Is it possible to setup a build agent outside of Azure, like a local machine/server? Could you elaborate on this scenario a bit more?
    PS. the link does not work…

      1. I’m getting this error during Installation of Powershell -step. Any idea?

        2019-02-11T21:49:08.5351213Z ##[section]Starting: Install NavContainerHelper
        2019-02-11T21:49:08.5456801Z ==============================================================================
        2019-02-11T21:49:08.5456921Z Task : PowerShell
        2019-02-11T21:49:08.5456993Z Description : Run a PowerShell script on Windows, macOS, or Linux.
        2019-02-11T21:49:08.5457061Z Version : 2.140.2
        2019-02-11T21:49:08.5457118Z Author : Microsoft Corporation
        2019-02-11T21:49:08.5457198Z Help : [More Information](
        2019-02-11T21:49:08.5457280Z ==============================================================================
        2019-02-11T21:49:09.2927101Z Generating script.
        2019-02-11T21:49:09.3016376Z Formatted command: . ‘C:\Agent\_work\2\s\scripts\Install-NavContainerHelper.ps1’
        2019-02-11T21:49:09.3487472Z ##[command]”C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe” -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command “. ‘C:\Agent\_work\_temp\1fd65b53-09a2-44ff-9d20-45021f4bc309.ps1′”
        2019-02-11T21:49:12.1192345Z Installing NavContainerHelper
        2019-02-11T21:49:15.4103483Z Install-NuGetClientBinaries : Exception calling “ShouldContinue” with “2” argument(s): “Windows PowerShell is in NonInt
        2019-02-11T21:49:15.4108572Z eractive mode. Read and Prompt functionality is not available.”
        2019-02-11T21:49:15.4130392Z At C:\Program Files (x86)\WindowsPowerShell\Modules\PowerShellGet\\PSModule.psm1:1725 char:9
        2019-02-11T21:49:15.4172098Z + Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy …
        2019-02-11T21:49:15.4174145Z + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        2019-02-11T21:49:15.4174369Z + CategoryInfo : NotSpecified: (:) [Install-NuGetClientBinaries], MethodInvocationException
        2019-02-11T21:49:15.4174551Z + FullyQualifiedErrorId : PSInvalidOperationException,Install-NuGetClientBinaries
        2019-02-11T21:49:15.4884330Z ##[error]PowerShell exited with code ‘1’.
        2019-02-11T21:49:15.5038436Z ##[section]Finishing: Install NavContainerHelper

        1. Anonymous says:
          (The content was deleted per user request)
        2. ps When I open the VM and run Install-NAVContainerHelper.ps1 manually it does not fail:
          NavContainerHelper is installed
          Determine latest NavContainerHelper version
          NavContainerHelper is the latest version

          1. Solution to my problem was adding the following line to Install-NAVContainerHelper.ps1:
            Get-PackageProvider NuGet -ForceBootstrap

          2. jwinberg says:

            Thank you Peter-Paul. I had exactly same problem and this solved it for me

  7. Hi Freddy, finally got this working on a VM, but got an error about the testtoolkit: In step “Compile Test App”:
    ##[error]C:\Agent\_work\2\s\test\Codeunit 50132 – HelloWorld,17): error AL0185: Codeunit ‘Assert’ is missing
    ##[error]Codeunit ‘Assert’ is missing

    I tried to add “test”: “” to the testapp, but the I got the error:
    Reference to object Assert is ambiguous. Make sure you are not referencing packages containing objects with the same names.

    Do you have any idea?

    1. ps, using image:

      1. FreddyDK says:

        If you start your container using -enableSymbolLoading, you should not have a test line in app.json and you should unpoublish the application symbols in the database.
        Btw – I do not check comments on my blog post regularly – please use github issues on navcontainerhelper for issues.

Skip to main content