Cannot queue a new build on Azure DevOps Server 2019.1 due to the way a SQL cluster was setup

I have recently been doing a TFS 2015 to Azure DevOps Server 2019.1 upgrade for a client. The first for a while, I have been working with Azure DevOps Service mostly of late. Anyway I saw an issue I had never seen before with any version of TFS, and I could find no information on the Internet.

The Problem

The error occurred when I tried to queue a new build after the upgrade, the build instantly failed with the error

‘The module being executed is not trusted, Either the owner of the database of the module need to be granted authenticate permission, or the module needs to be digitally signed. Warning: Null value is eliminated by an aggregate or other SET operation, The statement has been terminated’.

The Solution

It turns out the issue was the the client was using a enterprise wide SQL cluster to host the tfs_ databases. After the Azure DevOps upgrade the DBAs has enabled a trigger based logging system to monitor the databases and this was causing the error.

As soon as this logging was switched off everything worked as expected.

I would not recommend using such a logging tool for any ‘out the box’ database for a product such as TFS/Azure DevOps Server where the DBA team don’t own the database schema’s changes, as these databases will only occur if the product is upgraded

Release of my video on ‘Introduction to GitHub Actions’

I recently posted on my initial experiences with GitHub Actions. I had hoped to deliver a session on this subject a DDD 14 in Reading , I even got so far as to propose a session.

However, life happened and I found I could not make it to the event. So I decided to do the next best thing and recorded a video of the session. I event went as far as to try to get the ‘DDD event feel’ by recording in front of a ‘live audience’ at Black Marble’s offices.

A first look at GitHub Action – converting my Azure DevOps tasks to GitHub Actions

Introduction

GitHub Actions open up an interesting new way to provide CI/CD automation for your GitHub projects, other than the historic options of Jenkins, Bamboo, Team City, Azure DevOps Pipelines etc. No longer do you have to leave the realm of GitHub to create a powerful CI/CD process or provision a separate system.

For people familiar with Azure DevOps YAML based Pipelines you will notice some common concepts in GitHub Actions. However, GitHub Action’s YAML syntax is different and Actions are not Tasks.You can’t just re-use your old Azure DevOps tasks.

So my mind quickly went to the question ‘how much work is involved to allow me to re-use my Azure DevOps Pipeline Tasks?’. I know I probably won’t be moving them to Docker, but surely I can reuse my Node based ones somehow?

The Migration Process

The first thing to consider is ‘are they of any use?’.

Any task that used the Azure DevOps API was going to need loads of work, if even relevant on GitHub. But, my Versioning tasks seemed good candidates. They still needed some edits, such as the logic to extract a version number from a the build number needed to be removed. This is because GitHub Actions have no concept of build numbers (it is recommended that versioning is done using SemVer and branching).

Given all this I picked one for migration, my JSONVersioner

The first step was to create a new empty GitHub repo for my new Action. I did this using the JavaScript template and followed the Getting Started instructions. This allowed me to make sure I had a working starting point.

I then copied in my JSON file versioner task into the repo bit by bit

  • Renamed my entry ApplyVersionToJSONFile.ts file to main.ts to keep inline with the template standard
  • Copied over the AppyVersionToJSONFuncitons.js
  • I removed any Azure DevOps specific code that was not needed.
  • In both files swapped the references to “vsts-task-lib/task” to “@actions/core” and update the related function calls to use
    • core.getInput()
    • core.debug()
    • core.warning()
    • core.SetFailed()
  • Altered my handling of input variables defaults to use the GitHub Actions as opposed to Azure DevOps Pipeline variables (to find the current working folder)
  • Migrated the manifest from the task.json
    to the action.yaml
  • Updated the readme.md with suitable usage details.

And that was basically it, the Action just worked, I could call my Action from a test workflow in another GitHub repo

However, I did decided to do a bit more work

  • I moved my Mocha/Chai based tests over to use Jest, again to keep inline with the template example. This was actually the main area of effort for me. Jest runs it’s tests async, and this caused me problem with my temporary file handling that had to be reworked. I also took the chance to improve the tests handing of the JSON comparison, making it more resilient for cross platform testing.
  • I also added TSLint to the npm build process, something I do for all my TypeScript based projects to keep up code quality

Summary

So the basic act of migration from Azure DevOps Pipeline Extension to GitHub Actions is not that hard if you take it step by step.

The difficultly will be with what your tasks do, are they even relevant to GitHub Actions? And are any APIs you need available?

So migration of Azure DevOps Extension Tasks to GitHub Actions is not an impossible task, have a look at my source at JSONFileVersioner or in the actual task in the GitHub Marketplace with the usage

jobs:

build:

runs-on: ubuntu-latest

strategy:

matrix:

node-version: [12.x]

steps:

     - uses: actions/checkout@v1

    - uses: rfennell/JSONFileVersioner@v1

with:

Path: ''

Field: 'version'

FilenamePattern: '.json'

Recursion: 'true'

    - name: Use Node.js ${{ matrix.node-version }}

uses: actions/setup-node@v1

with:

node-version: ${{ matrix.node-version }}

    - name: npm install, build, and test

run: |

npm install

npm run build --if-present

npm test

env:

CI: true




There is a nice series of posts on Actions from Microsoft’s Abel Wang – Github Actions 2.0 Is Here!!!

Strange issue with multiple calls to the same REST WebClient in PowerShell

Hit a strange problem today trying to do a simple Work Item update via the Azure DevOps REST API.

To do a WI update you need to call the REST API

  • Using the verb PATCH
  • With the Header “Content-Type” set to “application/json-patch+json”
  • Include in the Body the current WI update revision (to make sure you are updating the current version)

So the first step is to get the current WI values to find the current revision.

So my update logic was along the lines of

  1. Create new WebClient with the Header “Content-Type” set to “application/json-patch+json”
  2. Do a Get call to API to get the current work item
  3. Build the update payload with my updated fields and the current revision.
  4. Do a PATCH call to API using the client created in step 1 to update the current work item

Problem was at Step 4 I got a 400 error. A general error, not too helpful

After much debugging I spotted the issue was that after Step 2. my WebClient’s Headers had changed, I had lost the content type – no idea why.

It all started to work if I recreated my WebClient after Step 2, so something like (in PowrShell)

Function Get-WebClient

{

param
(

[string]$pat,
[string]$ContentType = "application/json"

)

$wc = New-Object System.Net.WebClient
$pair = ":${password}"
$bytes = [System.Text.Encoding]::ASCII.GetBytes($pair)
$base64 = [System.Convert]::ToBase64String($bytes)
$wc.Headers.Add(“Authorization”,"Basic $base64")
$wc.Headers["Content-Type"] = $ContentType
$wc

}


function Update-WorkItemTitle {

param

(

$baseUri ,
$teamproject,
$workItemID,
$pat,
$title

)

$wc = Get-WebClient -pat $pat -ContentType "application/json-patch+json"
$uri = "$($baseUri)/$teamproject/_apis/wit/workitems/$($workItemID)?api-version=5.1"

# you can only update a work item if you also pass in the rev, this makes sure you are updating lastest version
$jsondata = $wc.DownloadString($uri) | ConvertFrom-Json

$wc = Get-WebClient -pat $pat -ContentType "application/json-patch+json"

$data = @(
@{
            op    = "test";
            path  = "/rev";
            value = $jsondata.Rev
},
@{
            op    = "add";
            path  = "/fields/System.Title";
            value = $title
}
) | ConvertTo-Json

$jsondata = $wc.UploadString($uri, "PATCH", $data) | ConvertFrom-Json
$jsondata

}

Authentication loops swapping organisations in Azure DevOps

I have recently been getting a problem swapping between different organisations in Azure DevOps. It happens when I swap between Black Mable ones and customer ones, where each is back by different Azure Active Directory (AAD) but I am using the same credentials; because I am either a member of that AAD or a guest.

The problem is I get into an authentication loop. It happens to be in Chrome, but you might find the same problem in other browsers.

It seems to be a recent issue, maybe related to MFA changes in AAD?

I used to be re-promoted for my ID when I swapped organisations in a browser tab, but not asked for further authentication

However, now the following happens

  • I login to an organisation without a problem e.g https://dev.azure.com/someorg using ID, password and MFA
  • In the same browser window, when I connect to another organisation e.g. https://dev.azure.com/someotherorg 
  • I am asked to pick an account, then there is the MFA challenge, but then go back to the login
  • …. and repeat.

The fix is to go in the browser tab to https://dev.azure.com. As you are already authenticated you will be able to sign out, then all is OK, you can login again.

The other options is to make even more use of Chrome People; one ‘person’ per customer, as opposed to my current usage on one ‘person’ per ID

You can’t use Azure DevOps Pipeline Gates to check services behind a firewall

I have recently be working on a release pipeline that deploys to a server behind a corporate firewall. This is done using an Azure DevOps private build agent and works fine.

As the service is a basic REST service and takes a bit of time to start-up I though a gate was a perfect way to pause the release pipeline until service was ready for the automated tests.

However, I hit a problem, the gates always failed as the internal server could not be resolved.

After a bit of thought I realised why. Gates as actual agentless tasks, they don’t run on the agent but on the server, so are outside the firewall. They could never connect to the private service without ports being opened, which was never going to happen.

So at this point in time I can’t use gates on this pipeline. Any similar logic to do the same job would have to be developed as scripts I can run on an agent.

Review of ‘Azure DevOps Server 2019 Cookbook’ – well worth getting

It always amazes me that people find time to write tech books whilst having a full time job. So given the effort I know it will have been, it is great to see an update to  Tarun Arora and Utkarsh Sigihalli’s book ‘Azure DevOps Server 2019 Cookbook’.

Azure DevOps Server 2019 Cookbook - Second Edition

I do like their format of ‘recipes’  that walk through common requirements. I find it particularly interesting that for virtually each recipes there is an associated Azure DevOps Extension that enhances the experience. It speaks well of the research the authors have done and the richness and variety of the 3rd party extensions in the Azure DevOps Marketplaces

I think because of this format there is something in this book for everyone, whether new to Azure DevOps Server 2019 or someone who has been around the product since the days of TFS 2005.

In my opinion, it is well worth having a copy on your shelf, whether physical or virtual

Azure DevOps Repos branch build policies not triggering when expected in PRs – Solved

I recently hit a problem with builds triggered by branch policies in Azure DevOps Repos. With the help of Microsoft I found out the problem and I thought it worth writing up uncase others hit the issue.

Setup

Folders

Assume you have a Git repo with source for the UI, backend Services and common code in sub folders

/ [root]
     UI
     Services
     Common

Branch Policies

On the Master branch there are a policies of running

  • one build for anything in the UI folder/project or common folder/project
  • and a different build for anything in the Services folder/project or common folder/project

These build were filtered by path using the filters

/UX; /Common
/Services; /Common

The Issue

I discovered the problem by doing the following

  • Create a PR for some work that effects the UI project
  • As expected the UI build triggers
  • Update the PR with a second commit for the Services code
  • The Service build is not triggered

The Solution

The fix was simple it turns out. Remove the spaces from the filter paths so they become

/UX;/Common
/Services;/Common

Once this was done the builds triggered as expected.

Thanks again to the Azure DevOps Product Group for the help

Regex issues in Node

I have been trying to use Regex to select a block of an XML based .NET Core CSPROJ file, and yes before you say know I could use XPATH, but why am not is another story.

I was trying to use the Regex

content.match(/<PropertyGroup>((.|\n)*)<\/PropertyGroup>/gmi)

The strange thing was this selection string worked in online Regex testers and in online Javascript IDEs, but failed inside my Node based Azure DevOps Pipeline extension.

After much experimentation I found that the following line worked

content.match(/<PropertyGroup>([\s\S]*?)<\/PropertyGroup>/gmi)


Well that a a good few hours of my life I won’t get back. No idea why Node handles the wildcards differently

A fix for Error: SignerSign() failed." (-2146958839/0x80080209) with SignTool.exe

I have spent too long recently trying to sign a UWP .MSIXBUNDLE generated from an Azure DevOps build using the SignTool.exe and our code signing certificate. I kept getting the error

Done Adding Additional Store
Error information: "Error: SignerSign() failed." (-2146958839/0x80080209)

From past experience, SignTool errors are usually due to the publisher details in the XML manifest files (in this case unpack the bundle with MakeAppx.exe and look in AppxMetadata\AppxBundleManifest.xml, and also check the manifest in the bundled .MSIX files) does not match the subject details for the PFX file being used for signing. 

Or so I thought…..

Turns out you can get this error too if you use the wrong version of the SignTool, but it give no clue to this fact.

So the top tip is …

Make sure you use the SignTool.exe from the same folder as the MakeAppx.exe tool. In  my case in “C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x64\”

Once I did this, after of course updating all the manifest files with the correct publisher details, I was able to sign my bundle as I wanted.