Development
Dev Ops

Moving all our projects to Azure Devops

At the end of 2018, we switched over to Microsoft's Azure Devops product. Here is a breakdown of some of the challenges we faced and the outcome of the project.

Why we did it

We have many different projects, which are implemented in a few different technologies. We had these in an older system but this was starting to show its age, and we weren't enjoying the process of hosting this on a physical server. We also have many libraries which are shared between projects. These libraries were referenced in our Visual Studio projects directly as DLL's. Some of our products were being deployed using continuous integration, but the CI system was crashing. Our automated testing was carried out in a non formal way and we wanted to leverage our unit tests more heavily.

Numerous things needed a CI pipeline; we needed to build and release some of our web applications, and we have nuget packages which we needed to build, package up. We've currently got a few web applications to build and deploy with this system and we needed to keep certain things such as database credentials secure.

In 2018 we had decided that Angular was going to be the main front end technology on all of our products, with future developments using it. Angular has been designed around continuous integration, being based around Webpack and Node - the build server needed to support these things and nobody wanted the task of coaxing our old CI system into doing this. We were also starting to use .net core which was another technology our old system didn't understand.

With our development team growing, the problems started to become more apparent. Updates to our shared libraries became more and more frequent, so it was clear that we needed a Nuget feed to help us synchronise these. We needed a fresh start in for our Continuous Integration system because it wasn't handling newer technologies. Releases were becoming more frequent, and required too much manual work - our future plans involve a service oriented architecture which means a larger number of smaller projects - complicating all of the above.

Continuous Integration

Build and release pipelines are of course the most complex aspect of this setup. To create a new CI pipeline, you need a good understanding of all the tools that are being used - build agents are hosted on a headless VM so you also need to understand the command line for a tool if you want to customise it. If you've only ever used something through an IDE such as Visual Studio this means more research which may be out of some people's comfort zone. 

The UI in Azure Devops build pipelines will try to push you in a YAML direction, but if you are new to the system you stand little chance of knowing the YAML format. The system comes with templates but these are for default setups, any legacy application will have additional steps you'll need to research and implement - although marketing people will always claim their tool is 100% seamless, the reality is you will need to work to move a project over and the older the project, the more work. Generally you can start with one of the templates but you will almost always have to customise your pipeline.

If your continuous integration is based on source control, you can use this to get the YAML code. Otherwise, you're better off using the drag and drop editor.
– If your continuous integration is based on source control, you can use this to get the YAML code. Otherwise, you're better off using the drag and drop editor.
An example of a drag and drop build pipeline
– An example of a drag and drop build pipeline

Challenge - Automating Angular in a .net MVC build

Angular was one of the more troublesome things to automate. There are many considerations, including the npm version that the build depends on, and what kind of build to use. Out of the box, Angular wants to be a single page application with an HTML file served directly from the web server in which all the magic happens. In practice, we had to add in custom steps to install specific versions of Angular, and create the right kind of build.

To make angular work, we needed to first add in some of the standard tools - the npm installer and a version switch. Then we were able to add a manual command line to build angular. 

Key Takeaways

The biggest thing we learned from this was that one needs a very good understanding of how a tool works under the hood. Through research, we were able to learn any aspect of MSBuild which we were not familiar with at the start of this project - its quite surprising how much an IDE like Visual Studio hides.

Creating a Nuget feed

For this part of the project, Azure Artifacts is the solution on offer. We could have hosted a service somewhere else, but this seemed the most cost effective. Initially we weren't so familiar with the workings of Nuget, the package manager for .net - so a few things came as a surprise. We were able to figure out how to push build artifacts from our CI pipelines into Azure Artifacts, which was where we ran into the first oddity which had to be resolved.

Challenge: Creating packages which use semantic versioning

Normally in Nuget a package is given a semantic version. Version 1.0.0 is the first ever stable version, and the version usually follows the format <Major Version>.<Minor Version>.<Patch>[possible other stuff] For example, 2.0.3.1202. If your package is a pre-release package, you might append -rc1 or -beta. The reason this is important is that each number has a meaning - for example, minor version changes are expected to maintain backward compatibility.

The Nuget Pack task does have a feature which looks like it should do the job - you can set the version numbers in variables, and on the Nuget Pack command you can choose the pack option "Use the build number".

For our pre-release packages, we set our variables, and set our build number format to Major.Minor.Patch.Revision-beta and for release, we set Major.Minor.Patch.Revision

But unfortunately, in that pipeline step, "build number" means "an internal build number". No matter what we put as our build number format, it would always use Major.Minor.Patch.Revision. We couldn't distinguish between release and pre-release packages and we certainly didn't want to ship a beta package to a live site.

This option was tempting - it seems to work until you change the build number format. Its at this point that you'll realise that it uses its own internal formatting macro which can not be changed.
– This option was tempting - it seems to work until you change the build number format. Its at this point that you'll realise that it uses its own internal formatting macro which can not be changed.

Eventually we found that the best way to approach this problem was to tell the Nuget Pack command to use an environment variable - Build.BuildNumber to be precise.

Setting the pack option "use an environment variable". If you do this, it will use the same "build number" as the rest of the pipeline.
– Setting the pack option "use an environment variable". If you do this, it will use the same "build number" as the rest of the pipeline.

Key Takeaways

We realised from this that many of the labels in the UI in Azure Devops should be taken with a pinch of salt. Not everything means what one would initially assume. In the case of "Use the build number" the difference was subtle, but its advisable to test a new setting fully before trying to rely on it.

Another example of this effect is the term "Preview" and "Release" in the listing screen for nuget packages. These are absolutely nothing to do with nuget's definition of a preview or release version. They seem to be there just to help you filter within the UI.

According to nuget, due to the suffix, Package2 is a pre-release package, while Package1 has no no suffix - its a live package, even though both are tagged as Release and Prerelease.
– According to nuget, due to the suffix, Package2 is a pre-release package, while Package1 has no no suffix - its a live package, even though both are tagged as Release and Prerelease.

Conclusions

Powerful, but rough around the edges. For anything non-standard it can be fiddly and time consuming. It's still getting some big revisions by Microsoft, so even they know it isn't a finished product. Once set up though it works very well.
– Mark Windle

The project took a few weeks in all, and after that there were some further follow-up steps to be taken, but once everything is setup and the nuances of each project have been worked out, everything works brilliantly. 

 
An Article by Gavin Burton

As a core member of our development team, Gavin draws on his spectrum of experience in web application development for a variety of industries to play a key role in the build of RDC's innovative products.