Behold #XppGroupies! The day we’ve been waiting for has come! The Azure hosted builds are in public preview with PU35!! We can now stop asking Joris when will this be available, because it already is! Check the docs!

I’ve been able to write this because, thanks to Antonio Gilabert, we’ve been testing this at Axazure for a few months with access to the private preview. And of course thanks to Joris for inviting us to the preview!

Azure hosted build
Riding the Azure Pipelines by Caza Pelusas

What does this mean? We no longer need a VM to run the build pipelines! Nah, we still need! If you’re running tests or synchronizing the DB as a part of your build pipeline you still need the VM. But we can move CI builds to the Azure hosted agent!

You can also read my full guide on MSDyn365FO & Azure DevOps ALM.

Remember this is a public preview. If you want to join the preview you first need to be part of the Dynamics 365 Insider Program where you can join the “Dynamics 365 for Finance and Operations Insider Community“. Once invited you should see a new LCS project called PEAP Assets, and inside its Asset Library you’ll find the nugets in the Nuget package section.

Azure agents

With the capacity to run an extra Azure hosted build we get another agent to run a pipeline, and can run multiple pipelines at the same time. But it still won’t be parallel pipelines, because we only get one VM-less agent. This means we can run a self-hosted and azure hosted pipeline at the same time, but we cannot run two of the same type in parallel. If we want that we need to purchase extra agents.

With a private Azure DevOps project we get 2GB of Artifacts space (we’ll see that later) and one self-hosted and one Microsoft hosted agent with 1800 free minutes:

08CEA665 618A 4F15 B9EC F86A405FA7D8
Azure hosted build: Azure DevOps project pricing

We’ll still keep the build VM, so it’s difficult to tell a customer we need to pay extra money without getting rid of its cost. Plus we’ve been doing everything with one agent until now and it’s been fine, right? So take this like extra capacity, we can divide the build between both agents and leave the MS hosted one for short builds to squeeze the 1800 free minutes as much as possible.

How does it work?

There’s really no magic in this. We move from a self-hosted agent in the build VM to a Microsoft-hosted agent.

The Azure hosted build relies on nuget packages to compile our X++ code. The contents of the PackagesLocalDirectory folder, platform and the compiler tools have basically been put into nugets and what we have in the build VM is now on 3 nugets.

When the build runs it downloads & installs the nugets and uses them to compile our code on the Azure hosted build along the standard packages.

What do I need?

To configure the Azure hosted build we need:

  • The 3 nuget packages from LCS: Compiler tools, Platform X++ and Application X++.
  • A user with rights at the organization level to upload the nugets to Azure DevOps.
  • Some patience to get everything running 🙂

So the first step is going to the PEAP LCS’ Asset Library and downloading the 3 nuget packages:

Nugets for the Azure Hosted Build
Nugets for the Azure Hosted Build

Azure DevOps artifact

All of this can be done on your PC or in a dev VM, but you’ll need to add some files and a VS project to your source control so you need to use the developer box for sure.

Head to your Azure DevOps project and go to the Artifacts section. Here we’ll create a new feed and give it a name:

Azure DevOps artifact feed
Azure DevOps artifact feed

You get 2GB for artifacts, the 3 nuget packages’ size is around 500MB, you should have no issues with space unless you have other artifacts in your project.

Now press the “Connect to feed” button and select nuget.exe. You’ll find the instructions to continue there but I’ll explain it anyway.

Then you need to download nuget.exe and put it in the Windows PATH. You can also get the nugets and nuget.exe in the same folder and forget about the PATH. Up to you. Finally install the credential provider: download this Powershell script and run it. Edit: if the script keeps asking for your credentials and fails try adding -AddNetfx as a parameter. Thanks to Erik Norell for finding this and sharing in the comments!

Create a new file called nuget.config in the same folder where you’ve downloaded the nugets. It will have the content you can see in the “Connect to feed” page, something like this:

This file’s content has to be exactly the same as what’s displayed in your “Connect to feed” page.

And finally, we’ll push (upload) the nugets to our artifacts feed. We have to do this for each one of the 3 nugets we’ve downloaded:

You’ll get prompted for the user. Remember it needs to have enough rights on the project.

Of course, you need to change “AASBuild” for your artifact feed name. And we’re done with the artifacts.

Prepare Azure DevOps

This new agent needs a solution to build our packages. This means we have to create an empty solution in Visual Studio and set the package of the project to our main package. Like this:

2020 04 24 14 20 58
Visual Studio solution

If you have more than one package or models, you need to add a project to this solution for each separate model you have.

We have to create another file called packages.config with the following content:

The version tag will depend on when you’re reading this, but the one above is the correct one for PU35. We’ll need to update this file each time a new version of the nugets is published.

And, to end with this part, we need to add the solution, the nuget.config and the packages.config files to TFVC. This is what I’ve done:

2020 04 24 14 29 01
Azure DevOps

You can see I’ve created a Build folder in the root of my DevOps project. That’s only my preference, but I like to only have code in my branches, even the projects are outside of the branches, I only want the code to move between merges and branches. Place the files and solution inside the Build folder (or wherever you decide).

Configure pipeline

Now we need to create a new pipeline, you can just import this template from the newly created X++ (Dynamics 365) Samples and Tools Github project. After importing the template we’ll modify it a bit. Initially, it will look like this:

2020 04 24 14 35 07 1
Azure hosted build: Default imported pipeline

As you can see the pipeline has all the steps needed to generate the DP, but some of them, the ones contained in the Dynamics 365 tasks, won’t load correctly after the import. You just need to add those steps to your pipeline manually and complete its setup.

Pipeline root

2020 04 24 14 38 27

You need to select the Hosted Azure Pipelines for the Agent pool, and vs2017-win2016 as Agent Specification.

Get sources

DevOps mappings
Azure hosted build: Our mappings

I’ve mapped 2 things here: our codebase in the first mapping and the Build folder where I’ve added the solution and config files. If you’ve placed these files inside your Metadata folder you don’t need the extra mapping.

NuGet install Packages

This step gets the nugets from our artifacts feeds and the installs to be used in each pipeline execution.

2020 04 25 12 41 47 1
Azure hosted build: nuget install

The command uses the config files we have uploaded to the Build folder, and as you can see it’s fetching the files from the $(build.sourcesDirectory)\Build directory we’ve configured in the Get sources step. If you’ve placed those files in a diferent place you need to change the paths as needed.

Update Model Version

This is one of the steps that are displaying issues even though I got the Dynamics 365 tools installed from the Azure DevOps marketplace. If you got it right you probably don’t need to change anything. If you have the same issue as me, just add a new step and select the “Update Model Version” task and change the fields so it looks like this:

Update Model Version
Azure hosted build: Update Model Version

Build solution

Azure hosted build for Dynamics 365 Finance & SCM 1
Build solution step

In the build solution step, you have a wildcard in the solution field: **\\*.sln. If you leave this wildcard it will build all the projects you have in the repo and, depending on the number of projects you have, the build could time out.

I solve this by selecting a solution, that contains all the models I have, that I have placed in the Build folder in my repo, and update that solution if you add or remove any model.

Thanks to Ievgen Miroshnikov for pointing this out!

There could be an additional issue with the rnrproj files as Josh Williams points out in a comment. If your project was created pre-PU27 try creating a new solution to avoid problems.

Create Deployable Package

This is another one of the steps that are not loading correctly for me. Again, add it and change as needed:

2020 04 24 14 55 32
Azure hosted build: Create Deployable Package

Add Licenses to Deployable Package

Another step with issues. Do the same as with the others:

2020 04 24 14 57 35
Azure hosted build: Add Licenses to Deployable Package

And that’s all. You can queue the build to test if it’s working. For the first runs you can disable the steps after the “Build solution” one to see if the nugets are downloaded correctly and your code built. After that try generating the DP and publishing the artifact.

You’ve configured your Azure hosted build, now it’s your turn to decide in which cases will you use the self-hosted or the azure hosted build.

Subscribe!

Receive an email when a new post is published

41 Comments

  1. Pingback: Azure hosted build for Dynamics 365 Finance & SCM - Dynamics 365 Finance Community

  2. Pingback: Azure hosted build for Dynamics 365 Finance & SCM - 365 Community

    • Adrià Ariste Santacreu Reply

      Thank you Tommy! I’m really enjoying this AX10 trip…

  3. Michael Cronqvist Reply

    Is the nuget packages missing some assemblies used for building reports? We get this error:
    Error: AxReport/xxxxxx – “An unhandled exception was thrown while validating xxxxxx with callstack System.IO.FileNotFoundException: Business Logic assembly not found at location d:\a\45\NuGets\Microsoft.Dynamics.AX.Platform.CompilerPackage\Microsoft.Dynamics.ApplicationSuite.Reporting.BusinessLogic.dll

    • Adrià Ariste Santacreu Reply

      During the private preview there was an issue with reports and there was a workaround but I haven’t found it with the new nuget packages, our reports are being compiled. You should ask in the Dev ALM group in the feedback program Yammer.

  4. Erik Norell Reply

    When installing the CredentialsProvider I had to run the following: .\installcredprovider.ps1 -AddNetfx

    Otherwise I would just get asked over and over again to provide username/password to connect to the feed when pushing the packages.

  5. Hi,
    i am getting an error regarding the Build task directory
    can you share what did you put on the extract the NuGet packages location ?
    i used this -ExcludeVersion -OutputDirectory “$(Pipeline.Workspace)\NuGets”
    and this parameter on the build task
    /p:BuildTasksDirectory=”$(Pipeline.Workspace)\NuGets\Microsoft.Dynamics.AX.Platform.CompilerPackage\DevAlm”
    the error is
    Error MSB4226: The imported project “C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Microsoft\Dynamics\AX\Microsoft.Dynamics.Framework.Tools.BuildTasks.targets” was not found.

    • Adrià Ariste Santacreu Reply

      I don’t have access to an Azure-hosted pipeline right now, but check if the path $(Pipeline.Workspace) is where the nugets have been installed or you’re using a different location for them and that’s why the build fails.

      • @Adria @Gill if it isn’t the nuget path, it’s also possible you have an .rnrproj that was generated pre-PU27. Open it in a notepad and double check the line

        exists. If the import line for BuildTasks.targets is prefixed with “$(MSBuildExtensionsPath32)\Microsoft\Dynamics\AX\Microsoft…” then you are probably on an outdated rnrproj file. Try generating a new one from a recently deployed VM – that helped me recently.

        • Adrià Ariste Santacreu Reply

          Thanks, Josh, I’ve updated the DevOps page and the post with your remarks.

  6. Søren P. Christensen Reply

    Hi
    I´m running this to “push” a nuget package:
    PS C:\nuget> ./nuget.exe push -Source “Build” -ApiKey az microsoft.dynamics.ax.platform.compilerpackage.7.0.5746.35600.nupkg
    MSBuild auto-detection: using msbuild version ‘4.0’ from ‘C:\Windows\Microsoft.NET\Framework64\v4.0.30319’.
    Please provide credentials for: https://MYSTUFF.pkgs.visualstudio.com/MYCODE/_packaging/Build/nuget/v3/index.json

    But nothing happens!? I supposed a login prompt would show…

    SPC

    • Adrià Ariste Santacreu Reply

      Yes, for the first nuget upload you should get an upload prompt. Could an antivirus be blocking it or that the login window stayed behind the active one?

  7. Søren P. Christensen Reply

    Oops “-AddNetfx” was the solution to my question

    • Adrià Ariste Santacreu Reply

      Ahhh, then the issue was on the credential provider install! Glad you could fix it.

  8. Søren P. Christensen Reply

    The VS solution: should that just contain projects referring to each module to build?
    So just an empty project with no elements?

    • Adrià Ariste Santacreu Reply

      Yes, that’s correct. You need a solution and a project inside it, one project for each of the models you want the build process to compile. The in Azure DevOps, in the build step, you select that solution from source control and it’ll build the models of those projects.

  9. Søren P. Christensen Reply

    Maybe not the right forum, but where can I get the log file generated here? :

    D:\a\14\NuGets\Microsoft.Dynamics.AX.Platform.CompilerPackage\LabelC.exe -metadata=D:\a\14\s\Metadata -modelmodule=MYSTUFF -output=D:\a\14\b\MYSTUFF\Resources\ -outlog=D:\a\14\s\Project\Costing\Dynamics.AX.MYSTUFF.labelc.log -errlog=D:\a\14\s\Project\Costing\Dynamics.AX.MYSTUFF.labelc.err -compilerpath=C:\Windows\Microsoft.NET\Framework\v4.0.30319\
    Label compilation did not succeed.
    Review the output and error logs for more details from ResGen.exe, Csc.exe or Al.exe.
    Returning result: -1

    • Adrià Ariste Santacreu Reply

      The LabelC issue happened during the preview days and shouldn’t be happening now, but I’ve also seen some people having this same issue on the Dev ALM Yammer group. Try adding a PowerShell script task before compiling with this:

      $netfxPath = (Get-ItemProperty -Path “HKLM:\SOFTWARE\WOW6432Node\Microsoft\Microsoft SDKs\NETFXSDK\4.6.1\WinSDK-NetFx40Tools”).InstallationFolder
      $frameworkPath = (Get-ItemProperty -Path “HKLM:\SOFTWARE\WOW6432Node\Microsoft\NET Framework Setup\NDP\v4\Full”).InstallPath
      Write-Host “##vso[task.setvariable variable=PATH;]$($env:Path);$netfxPath;$frameworkPath”

      But as I said it shouldn’t be happening and maybe you could report it on Yammer.

  10. Hi Ariste,

    Thanks for your helpful documentation.

    I have an issue on “Update Model Version” step. The error is following “Container path not found: ‘D:\a\8\s\Metadata’ “

    • Adrià Ariste Santacreu Reply

      Have you changed any of the path mappings? This step runs fine if nothing is changed.

    • Finally I found the cause of my issue. You should put a empty value on “Local path under $(build.sourcesDirectory” field on mapping for your branch on Get Sources step.

  11. Pingback: Add and build .NET projects to your Dynamics 365 pipeline - ariste.info

  12. Pingback: Tier 1 Microsoft managed VMs will be removed - ariste.info

  13. Pingback: Microsoft Kendi Yönettiği Tier 1 Ortamları Kaldırıyor!

  14. Hi Adrià, how do I add a project in the solution for an ISV model which does not show up in the list (locked)?

    • Adrià Ariste Santacreu Reply

      I haven’t tried this case. Have you tried adding a PowerShell step that will copy the binaries to your output directory. You should be able to get the path for the ISV binaries in your repo and copy all its contents before the build step is run.

      • thanks Adrià, copying ISV binaries from MetadataPath to Build.BinariesDirectory just before the build task worked!
        By the way great post, I finally got it to work now 🙂

  15. Hi Adrià,
    thank you for this awesome post!

    I have an issue in the Build solution step:

    ” ##[error]Trunk\Development\Projects\DLX_Build\DEVCommon\DEVCommon.rnrproj(36,3): Error MSB4019: The imported project “D:\a\9\NuGets\Microsoft.Dynamics.AX.Platform.CompilerPackage\DevAlm\Microsoft.Dynamics.Framework.Tools.BuildTasks.targets” was not found. Confirm that the path in the declaration is correct, and that the file exists on disk.”

    I have a solution with one project for each custom module I have.
    I also checked that I have the right version of nuget packages (PU36).

    • Adrià Ariste Santacreu Reply

      Thank you!!

      Do you see any error during the nuget install step? If it takes like 8-10 seconds (or under 3 minutes) you might see the errors in that step.

      • nuget install step takes 3minutes and 50 sec…
        and I found no error but 2 warning.

        ##[warning]Can\’t find loc string for key: Info_ResolvedToolFromCache
        Info_ResolvedToolFromCache 3.3.0
        ##[warning]Can\’t find loc string for key: Info_UsingVersion

        • Adrià Ariste Santacreu Reply

          And all 3 nuget packages have been uploaded to the artifacts and are being referenced in the packages.config file, right?

  16. Right!
    I have uploaded the following:
    – Microsoft.Dynamics.AX.Application.DevALM.BuildXpp 10.0.507.10008
    – Microsoft.Dynamics.AX.Platform.CompilerPackage 7.0.5688.35573
    – Microsoft.Dynamics.AX.Platform.DevALM.BuildXpp 7.0.5688.35573

    The project I specified has the following definition:

    It seams that in the BuildTasksDirectory [/p:BuildTasksDirectory=”$(Pipeline.Workspace)\NuGets\Microsoft.Dynamics.AX.Platform.CompilerPackage\DevAlm”] there isn’t the file [Microsoft.Dynamics.Framework.Tools.BuildTasks.targets]

  17. Hi Adrià,
    Brilliant blog 🙂

    I was getting an error which was something like this:
    Error: AxFormExtension/DocuParameters.MyExtension/Controls/FormExtensionControl41jm1jgc1/PreviousSibling – For form extension control ‘FormExtensionControl41jm1jgc1’, its previous sibling ‘TST_Security’ was not found as a child control of ‘Design’.

    TST_Security is a Control in another extension (which was also added to the build project).
    To fix this, i had to change the Id for description file to be in sequence. i.e. the model that has the control TST_Security should be lesser than the model “MyExtension”

    • Adrià Ariste Santacreu Reply

      Thanks Shashi! Yes, this is a known issue but I don’t know if it’s documented. Thanks for sharing it!

Write A Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Do NOT follow this link or you will be banned from the site!