ariste.info
  • MSDyn365 & Azure DevOps ALM
  • Get my book!
  • Services
  • About me
    • About me
    • Events
    • Subscribe
    • Contact
  • Logo
  • LinkedIn

Unified experience ALM

  • Welcome to the new ALM guide
    • Introduction
    • Prerequisites
  • Create and prepare Azure DevOps organization and project
    • Create an Azure DevOps organization
    • Create an Azure DevOps project
    • Enable TFVC projects in Azure DevOps
    • Add CI/CD agents with an Azure subscription
  • Unified development environment
    • What are unified developer environments?
    • Transition to a capacity-based model
    • Deploying a unified developer environment using PowerShell
    • Deploy an UDE environment from PPAC
    • Upgrade version in a Unified Development Environment
    • Useful links
  • Using Visual Studio
    • Connect Visual Studio to your UDE
    • Deploy code to a Unified Development Environment
  • Git basics for the unified experience
    • Add X++ code to a new Git repo
    • Configure your Git repository
  • Pipelines
    • What’s new in the pipelines?
    • YAML Pipelines
    • YAML Structure
    • Understanding YAML triggers
    • Create a YAML build pipeline
    • Create a classic release pipeline
    • Create a YAML Build and Release Pipeline With Stages

Legacy Guide

  • Welcome
    • Welcome!
  • Dynamics 365 for Finance & Operations & Azure DevOps
    • Intro
    • Package and model planning
    • Azure DevOps
    • First steps
    • The build server
    • Visual Studio
    • Some advice
    • Branching strategies
  • Azure Pipelines
    • Builds
    • Continuous integration
    • Gated check-ins
    • Set up the new Azure DevOps tasks for Packaging and Model Versioning
  • Azure hosted build for Dynamics 365 Finance & SCM
    • Intro
    • Azure agents
    • How does it work?
    • What do I need?
    • Azure DevOps artifacts
    • Prepare Azure DevOps
    • Configure pipeline
    • Update for version 10.0.18 and greater
  • Azure DevTest Labs powered builds
    • Intro
    • Azure DevTest Labs
    • Getting and preparing the VHD
    • Create a DevTest Labs account
    • Creating the VM
    • Preparing the VM
    • Create a new image
    • Azure DevOps pipelines
    • Run the build
    • Times
    • Show me the money
    • Some final remarks
  • Add and build .NET projects
    • Intro
    • Build .NET in your pipeline
    • Add a C# project to FnO
    • Build pipelinebui
    • Things I don’t like/understand/need to investigate
  • Release Pipelines
    • Intro
    • Setting up Release Pipeline in Azure DevOps for Dynamics 365 for Finance and Operations
    • AAD app creation
    • Create the release pipeline in DevOps
    • Creating the LCS connection
    • New Azure DevOps release tasks: MSAL authentication and ADAL deprecation
  • Automation
    • Update VMs using pipelines and d365fo.tools
    • Builds
    • Releases
    • But I like to add some human touch to it
    • Extra bonus
    • Update a variable in a release
  • LCS DB API
    • Call the LCS Database Movement API from your Azure DevOps Pipelines
    • Automating Prod to Dev DB copies
    • Restore a data package with Azure DevOps Pipelines
  • Secure your Azure Pipelines with Azure Key Vault
    • Azure Key Vault
    • Securing your Azure DevOps Pipelines
View Categories
  • ariste.info
  • Dynamics 365 F&O Dev ALM guide
  • Unified experience ALM
  • Pipelines
  • Create a YAML Build and Release Pipeline With Stages

Create a YAML Build and Release Pipeline With Stages

To me this is one of the biggest improvements we get from using Git in our repos.

While we can still use different classic build and classic release pipelines, with the YAML pipelines we can have pipelines with different stages that will first build and then release.

What are Stages? #

Imagine you’re running a mini factory for your code. Each stage is like a station on the assembly line where something specific happens before your code is ready to be deployed.

For example:

  • You might start with a Build stage, where your code is compiled and a package is created.
  • Then comes a Deploy UAT stage, where you deploy the code to the UAT environment.
  • After that, you could have a Deploy Production stage that pushes your changes to production. Yes, production!

Each Azure DevOps stage can have multiple jobs and tasks, and you can decide when and how each stage runs, like “only deploy to production if someone approves it”.

Template pipeline #

To speed things up a little bit, I’ve created a template pipeline with a build stage, a UAT release stage, and a Prod release stage.

You can download it here: https://raw.githubusercontent.com/aariste/Unified-Experience-ALM/refs/heads/main/build-release.yml

Now let’s go through it and learn something. I will use line numbers as a reference, but I will also post pieces of the file.

From lines 1 to 26 we have this:

# Sample YML pipeline for X++ builds (multi-stage)
# https://docs.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/dev-tools/hosted-build-automation

name: $(Date:yy.MM.dd)$(Rev:.r)

trigger:
  - none

schedules:
  - cron: "0 6 * * *"           # 8:00 every day
    displayName: Daily Build at 08:00
    branches:
      include:
        - main
    always: false

# Global variables stay as-is
variables:
  App1Package: 'Microsoft.Dynamics.AX.Application1.DevALM.BuildXpp'
  App2Package: 'Microsoft.Dynamics.AX.Application2.DevALM.BuildXpp'
  AppSuitePackage: 'Microsoft.Dynamics.AX.ApplicationSuite.DevALM.BuildXpp'
  PlatPackage: 'Microsoft.Dynamics.AX.Platform.DevALM.BuildXpp'
  ToolsPackage: 'Microsoft.Dynamics.AX.Platform.CompilerPackage'
  MetadataPath: '$(Build.SourcesDirectory)\Metadata'
  NugetConfigsPath: '$(Build.SourcesDirectory)\Tools\Build'
  NugetsPath: '$(Pipeline.Workspace)\NuGets'

You can see it has no CI trigger, but it has a schedule. In this case it will run at 8am (CET) every day, only for the main branch (include), and only if there have been any changes to the codebase (always: false).

Build stage #

Next we have the first stage, which builds the code:

stages:
# ---------- Stage 1: Build ----------
- stage: Build
  displayName: X++ Build & Package
  jobs:
  - job: BuildXpp
    pool:
      vmImage: 'windows-latest'
      demands:
        - msbuild
        - visualstudio
    displayName: Build solution and create deployable package
    
    steps:
      # Install NuGet and use -ExcludeVersion option
      - task: NuGetCommand@2
        displayName: 'NuGet custom install Packages'
        inputs:
          command: custom
          arguments: 'install -Noninteractive $(NugetConfigsPath)\packages.config -ConfigFile $(NugetConfigsPath)\nuget.config -Verbosity Detailed -ExcludeVersion -OutputDirectory "$(NugetsPath)"'

This is marked by the stages keyword to signal that the pipeline has stages, and the -stage keyword for each stage.

Then, for every stage, we still have jobs. This is exactly the same as pipelines with no stages.

For each job, we have a pool with the VM image definition, and also steps and -tasks. Each of these tasks is a single operation inside the stage.

Deploy UAT stage #

After building, we’ve got the package ready to be applied.

# ---------- Stage 2: Deploy UAT ----------
- stage: DeployUAT
  displayName: Deploy to UAT
  dependsOn: Build
  condition: succeeded()
  jobs:
  - deployment: DeployToUAT
    timeoutInMinutes: 360
    pool:
      vmImage: 'windows-latest'
    displayName: Deploy package to UAT
    environment: 'D365-UAT'   # create this Environment in Azure DevOps and add approvals/checks as needed
    strategy:
      runOnce:
        deploy:
          steps:
            - task: PowerPlatformToolInstaller@2
              displayName: 'Power Platform Tool Installer '

            - task: PowerPlatformWhoAmi@2
              displayName: 'Power Platform WhoAmI '
              inputs:
                authenticationType: PowerPlatformSPN
                PowerPlatformSPN: 'CSNA-UAT'

            - task: PowerPlatformDeployPackage@2
              displayName: 'Power Platform Deploy Package '
              inputs:
                authenticationType: PowerPlatformSPN
                PowerPlatformSPN: 'CSNA-UAT'
                PackageFile: '$(Pipeline.Workspace)/drop/CloudDeployablePackage/TemplatePackage.dll'

Again, the stage has a jobs part and steps that run. These steps are the same as the ones used in the classic release pipeline.

What I want you to remember from this is the environment in the deployment.

jobs:
  - deployment: DeployToUAT
    timeoutInMinutes: 360
    pool:
      vmImage: 'windows-latest'
    displayName: Deploy package to UAT
    environment: 'D365-UAT'   # create this Environment in Azure DevOps and add approvals/checks as needed

For the UAT stage, it’s called D365-UAT. We’ll talk about the environment in a minute.

Before that I want to remark on the dependsOn and condition on the stage:

- stage: DeployUAT
  displayName: Deploy to UAT
  dependsOn: Build
  condition: succeeded()

What does that mean? First, the dependsOn item tells us that running the DeployUAT stage depends on the Build stage. It was clear without an explanation.

Then the condition expected is succeeded(). This means that if the Build stage fails, the DeployUAT won’t run.

Deploy Prod stage #

And, finally, the deploy to prod stage, which essentially is the same as the UAT but for another environment.

Regarding the PowerPlatformSPN value, this is the service connection. In the YAML pipeline case, you need to create the service connection beforehand. There’s no new button here.

About Deploying to Production #

Yes, there are no guardrails here. We can deploy code directly to prod; no need to go through a sandbox environment first.

Does that mean that we should do it? Hell no! Even if Microsoft allows us to deploy code to production, we’re the owners and final responsible parties for our custom code.

We still need to adhere to best practices, code with quality in mind, and do proper testing, both technical and functional, before deploying anything to prod.

Environments #

So what are environments? In Azure DevOps, environments are the places your code gets deployed to, like UAT or Prod.

When you add an environment to a YAML file, it gets automatically created on DevOps:

Environments
Environments

Each environment can have its own approvals, checks, and permissions, so you can control who and what gets deployed where.

Environment approvals
Environment approvals

And it’s here where you MUST add approvals for your environments, especially the production one!

You don’t want to start servicing the production environment in the middle of the workday, right? There’s the business hours approval for that!

With great power, comes great responsibility
With great power, comes great responsibility

Please, use this new superpower with care.

And to end this, here’s how the pipeline run with stages looks like:

Pipeline run with stages
Pipeline run with stages

Timeouts #

And of course, we have a limitation! One that we can overcome easily and that you might’ve noticed already.

In the deploy stages, I have set a manual timeout:

timeoutInMinutes: 360

The Azure-hosted pipelines’ jobs can run for up to 60 minutes, and deploying using the Power Platform tools is taking a bit over an hour.

To avoid hitting the timeout, we need to purchase an additional agent job and set the timeoutInMinutes value in the stage.

Subscribe! #

Receive an email when a new post is published
What are your Feelings

Share This Article :

  • Facebook
  • X
  • LinkedIn
  • Pinterest
Still stuck? How can I help?

How can I help?

Create a classic release pipeline

Write A Comment Cancel Reply

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

Table of Contents
  • What are Stages?
  • Template pipeline
    • Build stage
    • Deploy UAT stage
    • Deploy Prod stage
  • About Deploying to Production
  • Environments
  • Timeouts
  • Dynamics 365 Community
  • Subscribe!
  • Microsoft MVP
  • LinkedIn
  • Privacy Policy
  • Contact
  • About me

© 2024 ariste.info. Designed by CazaPelusas.

Top

    Type above and press Enter to search. Press Esc to cancel.