Opinion: What and why YAML Azure Pipelines

In the last days I have had several conversations around YAML Azure pipelines, some people asking me whya they should go from old “moving boxes” mode to YAML Azure Pipelines. So here goes my opinion on this, disclaimer, this is just and opinion post, don’t expect here instructions, but just my one (not event two) cent.

What are YAML pipelines? this is the new model for build pipelines, instead of using the visual designer, we go directly with configuration as code, using YAML language to define our build process. YAML has been around for some time, it is widely used for Docker, Kubernetes, and other build systems like Appveyor, so let’s just say it is an standarized way to define “things” in code. So it seems like the natural evolution to go for our builds, as more and more people and companies are going into this, making it a “natural” language to express. Is it difficult? for sure, it has it’s problems, usually around the spaces and tabbing issues, but more and more tools (you have plugins for VS Code and other tools in example) comes in our help.

Why YAML pipelines? Configuration as code.  Our code evolves, and our build configuration usually evolves, not at the same pace for sure, but it evolves, so we must keep configuration tied to code, and which method could be better than represnting oour configuration as code?. So we end up storing our way to build right next to the code (another opinion: keep your code in the same repo as your YAML builds). So when we make changes to our structure code, adding or removing projects, new ways to build, the way to build is right with the code, in the case we need to build and older version, we will have the exact build configuration right with it, therefore we won’t have to make fancy things like recover and old version of the build from the definion history like with the “boxes” approach.

Is it ready for use? Yet I can agree sometimes the documentaion is not up to date, we should really go with the YAML builds, it is easy to start with. In any build definition we can get the YAML, clicking this button:


And also, for each of the tasks we have in and old model definition, we can also export YAML, so we can start learning from here:


I’m not saying you just go right away and modify all your existing builds and move them yo YAML, but next build definition you create, go with YAML and start using configuration as code.

Environment variables and Azure Pipelines

Some days ago talking with Sergio Navarro (if you don’t follow him you should) he raised a question about setting environment variables in an Azure Pipeline so a container can use it in the build. The answer was easy, the great news are: all variables declared in an Azure Pipeline are “executed” (I couldn’t find a better word) as environment variables in the agent, and not only that, all environment variables in an agent can be retrieved as simple variables in the pipeline.

This is easier to understand with a very simple example, I’m using a Windows agent and just plain Powershell, but this can be adapted to Linux/Mac agents using bash, just one important thing to take care: Linux/MAc environment variables are case sensitive, Windows are not case sensitive.

We have this YAML build (hmmm the coloring on the second line is not correct):


It is just a simple build with one Powershell task, printing out the usual PATH environment variable, using the common syntax of Pipelines variables $(variable-name) and then printing out. We also configured the variables in the properties of the Azure Pipeline with a Demo variable:


When we run the build, we obtain the following output:


Check it out:

  • The first Write-Host, has printed out the PATH environment variable without any problem, and using it as it was a simple Pipeline variable.
  • The second Write-Host has printed out the content of the demo Pipeline variable but using it as a computer environment variable on the agent.

With this simple demo I hope it gets more clear, and you are ready to use this feature in your Azure Pipelines.

Universal packages with Azure DevOps Artifacts

If you are already familiar with Azure Artifacts in Azure DevOps probaly you know about Nuget, Maven, or NPM. But there is another kind of artifact less known, and which is really useful, the Universal Packages.

Surely you have need to share a set of files with different projects, we are not talking of assemblies, nodejs packages, just plain files like for example an HTML, images, or what-ever-the-file, some people will go with git submodules for example, but we know this is usually painful. So here comes Universal Packages (Disclaimer: at the time of publishing this post this is in public preview).

Universal Packages is just a type of package which store any set of files, and when downloaded it just unpack this files locally. Let’s imagine we want to share a couple of files in our repo which we cant to share with other projects and repositories:


Of course this files will change over time (probably …), so we keep them in a repository, but also, we will keep the Universal Package versioned, so we just create a new build definition in Azure Pipelines to publish the package, and we will use the Universal Packages task which comes with Azure Artifacts extension. With this definition (for this demo scenario):


In this task definition, apart from the obvious display name, we have several other values:

  • Command: Which command we want to execute agains the Universal Package, it can be Publish, when we are publishing a new version of the package or Download to download it locally during the build for use it in another project.
  • Path to file(s) to publish: It points to the folder or particular file in the repository to generate the package with this files. (If we are downloading this changes to the folder in which to download the package files).
  • Feed location: Just to use with this or another Azure DevOps collection.
  • Destionantion feed: which feed we will use to publish the package.
  • Package name: name of the package to publish. If it does not exists it will create a new one with this name.
  • Version: how we want to generate the new version to publish, I highly recommend to use SemVer package versioning.
  • Description: just a description for the package listing.

Once executed the build pipeline, if everything is correct we will see the Universal Package in the feed:


So, now, how we consume it locally? for use in pipelines we have already seen we can use the same task as Publish, but for download, so let’s see how to consume it locally. For this we will need:

  1. Latest version of Azure CLI
  2. Azure DevOps extension of Azure CL(install with this command line: az extension add –name azure-devops)

Now we will login to Azure DevOps from the Azure CLI, we have to run two commands (NOTICE: depending on your url for your Azure Devops subscription it can change to https:/[your-org].visualstudio.com more info):

  1. az login
  2. az devops configure –defaults organization=https://dev.azure.com/[your-organization] project=ContosoWebApp

Next step, if everything has gone correctly, we can download locally the package to a folder with this command line:

And the package will download locally with the version you just set in the folder, showing the two files we published.

Try it out and let me know how it goes, I’m find it particular useful to avoid sharing files with submodules or whatever other tricks, and keep them versioned.

More info here.

Azure DevOps from Hosted XML process to inherited process

Migrating a Team Foundation Server Azure Devops Server from on-premises to cloud, it is common we have done some customizations to the process templates, which can’t be migrated directly to any of the existing templates in Azure DevOps Services.

When this happens, for every project with customizations, a new Hosted XML process is created in the Azure Devops Services destination, if navigate to: https://dev.azure.com/organization/_settings/process?_a=all you will see something like this, with the list of all the projects:


As you can see in the figure we have the three basic process template of the inherited process and then a line for every project with its own process which are known as Hosted XML processes. To get full advantage of the new customization UI we can migrate from the Hosted XML to the inherited process. But before proceed review first this article, as some of the process customizations that can be done in the old Hosted XML process are not preserved when migrating to inherited process: https://docs.microsoft.com/en-us/azure/devops/organizations/settings/work/upgrade-support-hosted-to-inherited?view=vsts

The migration to inherited process is done in two steps: clone the process as inherited process, move the existing process to the inherited process.

Clone process

To clone the process, click on the ellipsis icon in the selected project and click on Clone process to inherited:


This will show a summary of what is going to do and what will be migrated and what will be lost, on of the most important things which will be lost is any workflow restriction you set up in the old process, as the new process model allows Work Items to go from any state to any state:


When you click on continue, it will ask for a new name to the inherited process template and which of the main templates to be set up as parent:


Just click on Ok and after a while we will have the new inherited process template:


Migrate projects

To finish the migration process, now we have to go to each of the projects we want to apply the new inherited process, click on the name Hosted XML project you want to migrate to see its details, and go to Projects tab where you must see the project belonging to this Hosted XML process template:


If you click on the ellipsis on the dropdown menu you will see an option to change process (is the only option available) and if you click it a screen asking to select the destination template will be shown, in which you will be able to select the previously migrated inherited process template, just click ok and you are done.

Now you will have the process using the new inherited process template, and you can start doing customizations with the new model, using the UI directly from Azure DevOps Services rather than using the old XML customization process.

Hope this helps you.