Converting Existing pipeline to YAML, how to avoid double builds

Actually YAML build is the preferred way to create Azure DevOps Build Pipeline and converting existing build is really simple thanks to the “View YAML” button that can simply convert every existing pipeline in a YAML definition.

image

figure 1: Converting existing Pipeline in YAML is easy with the View YAML button present in editor page.

The usual process is, start a new feature branch to test pipeline conversion to YAML, create the YAML file and a Pipeline based on it, then start testing. Now a problem arise: until the YAML definition is not merged in ANY branch of your Git repository, you should keep the old UI Based Build and the new YAML build togheter.

What happens if a customer calls you because it has a bug in an old version, you create a support branch and then realize that in that branch the YAML build definition is not present. What if the actual YAML script is not valid for that code? The obvious solution is to keep the old build around until you are 100% sure that the build is not needed anymore.

During conversion from legacy build to YAML it is wise to keep the old build around for a while.

This usually means that you start to gradually remove triggers for branches until you merge all the way to master or the last branch, then you leave the definition around without trigger for a little while, finally you delete it.

The real problem is that usually there is a transition phase where you want both the old pipeline definition to run in parallel with the YAML one, but this will create a trigger for both the build at each publish.

SNAGHTML64e597

Figure 2: After a push both build, the old UI Based and the new based on YAML were triggered.

From figure 2 you can understand the problem: each time I push, I have two build that were spinned. Clearly you can start setting up triggers for build to handle this situation, but it is usually tedious.

The very best situation would be, trigger the right build based on the fact that the YAML definition file is present or not.

A viable solution is: abort the standard build if the corresponding YAML Build file is present in the source. This will perfectly work until YAML build file reach the last active branch, after that moment you can disable the trigger on the original Task based build or completely delete the build because all the relevant branches have now the new YAML definition.

To accomplish this, you can simple add a PowerShell Task in the original build, with a script that checks if the YAML file exists and if the test is positive aborts current build. Luckly enough I’ve found a script ready to use: Many tanks for the original author of the script. You can find the original script in GitHub and you can simply take the relevant part putting inside a standard PowerShell task.

SNAGHTMLb575bc

Figure 3: Powershell inline task to simply abort the build.

The script is supposed to work if you have a variable called Token where you place a Personal Access Token with sufficient permission to cancel the build, as explained in the original project on GitHub.

Here is my version of the script

if (Test-Path Assets/Builds/BaseCi.yaml) 
{
    Write-Host "Abort the build because corresponding YAML build file is present"
    $url = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/build/builds/$($env:BUILD_BUILDID)?api-version=2.0"
    $pat = "$(token)" 
    $pair = ":${pat}"
    $b  = [System.Text.Encoding]::UTF8.GetBytes($pair)
    $token = [System.Convert]::ToBase64String($b)
    $body = @{ 'status'='Cancelling' } | ConvertTo-Json
    
    $pipeline = Invoke-RestMethod -Uri $url -Method Patch -Body $body -Headers @{
        'Authorization' = "Basic $token";
        'Content-Type' = "application/json"
    }
    Write-Host "Pipeline = $($pipeline)"
}
else
{
   write-host "YAML Build is not present, we can continue"
}

This is everything you need, after this script is added to the original build definition, you can try to queue a build for a branch that has the YAML build definition on it and wait for the execution to be automatically canceled, as you can see in Figure 4:

image

Figure 4: Build cancelled because YAML definition file is present.

With this workaround we still have double builds triggered, but at least when the branch contains the YAML file, the original build definition will imeediately cancel after check-out, because it knows that a corresponding YAML build was triggered. If the YAML file is not present, the build runs just fine.

This is especially useful because it avoid human error, say that a developer manually trigger the old build to create a release or to verify something, if he trigger the old build on a branch that has the new YAML definition, the build will be automatically aborted, so the developer can trigger the right definition.

Gian Maria.

How to edit a YAML Azure DevOps Pipeline

I cannot stress you enough on how better is the experience of having builds defined in code than having build definition on the server, so I’m here to convince you to move to the new YAML build system in Azure DevOps :).

Having build definition in Code gives you many benefits, the first is that builds evolve with code branches.

If you still think that editing a YAML file is a daunting experience because you have tons of possible tasks and configuration to use, take a peek to the Azure Pipeline extension Visual Studio Code Addin, that brings intellisense for your pipeline editing in Visual Studio Code. I strongly encourage you to have a look at the YAML schema reference to have a complete knowledge of the syntax, but for most people a quick approach to the tool is enough, leaving the deep dive for when they need to do complex stuff.

With the extension enabled, after you opened a YAML Build definition in Visual Studio Code, you can click on the YAML button in the lower right part of visual studio code editor to change language

image

Figure 1: Language mode selection of Visual Studio Code

That area is the Language Mode Selection, and it is where you specify to Visual Studio Code what is the language of the file you are editing. If you simply open a YAML file, VS Code recognize the yaml extension and helps using standard YAML syntax, but it does not know anything about Azure DevOps Pipeline.

When you tell Visual Studio Code that the file is a YAML pipeline, intellisense kicks out and allows you to quickly edit the file

Thanks to the Language Mode Selector, we can now specify that the file is a Azure Pipeline file and not a standard YAML file.

image

Figure 2: Selecting the right language type allows VS Code to give you tremendous help in editing the file.

This is everything you need to do, from now on, VS Code will give you helps in the context of Azure DevOps pipeline syntax. Even if the file is completely empty the editor shows you possible choices for the first level nodes

image

Figure 3: Suggestions on empty file

Since I usually start specifying the pool, I can simply choose pool, then let VS Code guide me in the compilation of all properties

image

Figure 4: Intellisense in action editing the file

In real scenario you usually starts from some template file (another advantage of having build in code), you already prepared with standard build for you project, but even in that scenario having intellisense to refine the build will help you in choosing tasks.

image

Figure 5: Help in choosing tasks

I can assure that, after some usage, it is far more powerful and quick to edit a build with VS Code than to edit a standard build made with tasks in the Web based editor. Graphical editor are powerful and are a good entry point for those who does not know the instrument, but intellisense powered editors are more productive and powerful.

image

Figure 6: You do not have only intellisense to choose the task, but it will shows you also information about the task

The only drawback I found is using custom tasks that were not recognized by the intellisense, as my GitVersion Task, that was marked as wrong because VS Code does not know it.

image

Figure 7: Custom tasks were not automatically recognized by VS Code

Intellisense will completely remove the need of the old trick of creating a build with the old editor, place tasks in the pipeline and then letting the tool generates YAML definition based on how you configured the task in graphical editor. I assure you that it is faster to directly copy a reference build and then add needed tasks with intellisense in VS Code than using UI editor.

If you are really a UI Oriented person, in the latest release of Azure DevOps (at the time of writing the feature is rolling out so it is not available on all accounts) you can use the YAML Task Assistant

Badge

Figure 8: YAML Task assistant in action

The assistant allows you to configure the Task with the very same UI experience you have in UI Based pipeline, once the task is configured you can simply add corresponding YAML to the definition.

Task assistant gives you the same add experience for tasks of the old UI editor, so you can configure the task with graphic editor, then add corresponding YAML syntax to the definition.

I think that with Task Assistant there are no more excuses not to move to YAML based definition.

Gian Maria

YAML Build in Azure DevOps

I’ve blogged in the past about YAML build in azure DevOps, but in that early days, that kind of build was a little bit rough and many people still preferred the old build based on visual editing in a browser. One of the main complaint was that the build was not easy to edit and there were some glitch, especially when it is time to access external services.

After months from the first version, the experience is really improved and I strongly suggest you to start trying to migrate existing build to this new system, to take advantage of having definition of build directly in the code, a practice that is more DevOps oriented and that allows you to have different build tasks for different branches.

YAML Build is now a first class citized in Azure DevOps and it is time to plan switching old build to the new engine.

You can simply start with an existing build, just edit it, select one of the phases (or the entire process) then press View YAML button to grab generated YAML build.

SNAGHTML2fecbc

Figure 1: Generate YAML definition from an existing build created with the standard editor

Now you can simply create a yaml file in any branch of your repository, paste the content in the file, commit to the branch and create a new build based on that file. I can clearly select not only AzDO repositories, but I can build also GitHub and GitHub enterprise

image

Figure 2: I can choose GitHub as source repository, not only azure repos

Then I can choose the project searching in all the project I have access to with my access token used to connect GitHub

image

Figure 3: Accessing GitHub repositories is simple, once you connected the acount with an access token AzDO can search in repositories

Just select a repository and select the option Existing Azure Pipelines, if you are starting from scratch you can create a starter pipeline.

image

Figure 4: Choose the option to use an existing pipeline.

You are ready to go, just choose branch and yaml file and the game is done.

image

Figure 5: You can directly specify the build file in the pipeline creation wizard.

Converting an existing build pipeline to YAML it is matter of no more than 10 minutes of your time.

Now you can simply run and edit your build directly from the browser, the whole process took no more than 10 minutes, including connecting my AzDO account to GitHub

image

Figure 6: Your build is ready to run inside Azure DevOPS.

Your build is now ready to run without any problem. If you specified triggers as in Figure 6 you can just push to the repository to have the build automatically kicks in and being executed. You can also directly edit the build in the browser, and pressing the Run button (Figure 6) you can trigger a run of the build without the need to push anything.

But the coolness of actual YAML build editor starts to shine when you start editing your build in the web editor, because you have intellisense, as you can see in Figure 7.

image

Figure 7: YAML build web editor has now intellisense.

As you can see the YAML build editor allows you to edit with full intellisense support, if you want to add a task, you can simply start writing task followed by a semicolon and the editor will suggest you all the tasks-available. When it is time to edit properties, you have intellisense and help for each task parameters, as well as help for the entire task. This is really useful because it immediately spots deprecated tasks (Figure 9)

image

Figure 8: All parameters can be edited with fully intellisense and help support

image

Figure 9: Helps gives you helps for the deprecation of old task that should not be used.

With the new web editor with intellisense, maintaining a YAML build is now easy and not more difficult than the standard graphical editor.

Outdated tasks are underlined in green, so you can immediately spot where the build definition is not optimal, as an example if I have a task that have a new version, the old version is underlined in green, and the intellisense suggests me that the value is  not anymore supported. This area still need some more love, but it works quite well.

There is no more excuses to still use the old build definition based on web editor, go and start converting everything to YAML definition, your life as bulid maintainer will be better :)

Gian Maria.

Converting PowerShell Task in YAML

YAML Builds have many advantages over traditional build definitions, especially because YAML build definitions follows branching of code, a killer feature that is fantastic if you use GitFlow.

YAML Build definitions are stored in code, this allows them to follow branches, minimizing the need to maintain builds that should build code in different moment in time.

As an example I have a build where I have tasks to publish some Web Sites, if I had a new Web Site to publish, I can add another task in YAML build, but the build still work for older branches, especially for the master branch that represent my code in production.

To minimize impacts, I tend to use PowerShell scripts stored inside code repository to perform build tasks, this was an old trick  useful when YAML build was not present. Scripts allows you to create a generic build, add some tasks to run PowerShell scripts, and the result is that scripts follow branches.

Now that YAML Build is available, I started converting everything to YAML build, a task that is made simple tanks to a nice feature of VSTS, in the UI there is a nice View YAML button that convert all of my build definition with new YAML syntax.

image

Figure 1: Ui functionality to show the current standard build definition translated to new YAML build definition.

As you can see from Figure 1, PowerShell tasks is not converted as a task, but with a node of type powershell, followed by parameters. This is perfectly valid, because YAML build can contain a powershell node, but in my specific situation the build failed, because the conversion failed to setup working directory.

Even if YAML build allows direct call of PowerShell scripts, if you convert a working build that uses PowerShell task it is better to use the same Task inside YAML definition.

To solve my problem I simply changed generated YAML build definition to use a standard PowerShell task, this is the declaration of the task.

- task: PowerShell@2
  displayName: Pack Release
  inputs:
    targetType: filePath
    filePath: 'tools\packrelease.ps1'
    arguments: '-Configuration $(BuildConfiguration) -DestinationDir $(Build.ArtifactStagingDirectory) -StandardZipFormat $false -SkipZip $false -SkipConfigRename $false -compressionLevel 5'
    workingDirectory: 'tools'

As usual you specify a task and the type, in this example PowerShell@2. It is important the version after the @ character, it should be equal to the version of the task in the standard build, as shown in Figure 2.

image

Figure 2: Pay attention to version Task when you convert to YAML build.

To know input parameter name of the tasks (Es. targetType, arguments, workingDirectory, etc), the most immediate solution is looking in the working directory of an agent and find the task definition.

image

Figure 3: Tasks inside working folder of an agent.

Inside the folder of the chosen task there are all latest version for any major version, and inside each version folder there is a task.json file that can be inspected to know the exact version of the parameter.

After modifying YAML build to use PowerShell task the build started working as usual.

Gian Maria.