Automating NuGet deployment with AppVeyor

This entry is part of a 10 part series: Exploring modern .NET development with ConTabs

In the past, I’ve blogged about using AppVeyor for Continuous Integration (CI), but up to now, I’ve been manually uploading NuGet packages to NuGet.org. In this post – the 10th in the ConTabs series – I explain the steps I took to automate the packaging and deployment of ConTabs to NuGet.org. Or, in other words, how I’m using AppVeyor for my Continuous Deployment.

Photo of a Chinook helicopter carrying a shipping container

Original photo by Capt. Peter Smedberg (U.S. Army)

Since I set it up AppVeyor to perform Continuous Integration for ConTabs back in November last year, it’s been working like a charm. Whenever anyone pushes to GitHub or opens a pull request, AppVeyor will busily set to work building ConTabs and running the unit tests. By reporting the build status back to GitHub, we can easily see whether the build is currently working or not. (I also hooked AppVeyor up to Coveralls to monitor test coverage, but I digress…)

Whilst free, automated CI is great, I wanted to take it a step further. Every time I decide to release a new version of ConTabs, I have to manually package it up, and upload that package to NuGet.org. Doesn’t take too long admittedly, but it’s a dull trivial task that feels like it ought to be automated.

Selective build processes

My aim was to use the master branch to trigger NuGet deployments. As stated in the ConTabs contributor guidelines, development happens on develop, but master should reflect the publicly released product. This was the source of my first headache – how can I tell AppVeyor to use a different process for the master branch only?

AppVeyor does support conditional build configs that can be applied based on tags or branches, but it felt like this would mean repeating a lot of the same content. (DRY and all that…)

Luckily, there also seems to be a new-ish feature, which allows for a common config to be selectively overridden as needed. This looked like the way to go. Setting it up was simple. I just had to add a section to the bottom of my appveyor.yml configuration:

Any settings specified in this new section will be applied on top of the main config, overriding whenever there’s a clash. In my case, I’d be implementing the packaging and deployment in this section, so I can ensure it only takes place for my master branch.

Unfortunately, a bug means that including this for section currently seems to restrict the main build process to branches/tags explicitly in the for section. In my case, this meant that the build process wasn’t firing when I pushed changes to the develop branch. I spent quite a while troubleshooting this (and learning more about GitHub webhooks in the process!), but eventually, I raised a white flag and was alerted to the bug.

I have to hand it to AppVeyor, their support is incredible. Despite me bring a dirty open-source freeloader, I got a personal response from Ilya within hours of my post. The suggested remedy is to also include an empty for section targeting the other branches:

This ensures that all branches can trigger a build, even if they don’t need any additional specific settings.

Packaging and deploying

Once I’d got my conditional build process sorted, it was time to tackle the main problem: packaging the ConTabs library and deploying this package to NuGet.org.

In order to connect AppVeyor, I first needed to get an API key from NuGet.org. There’s an option in the account menu on NuGet.org. From there it’s possible to tightly define the scope in terms of the capabilities and the packages they apply to. So that the world and his dog can’t see my API key (and potentially publish rogue versions of ConTabs), I put the API key through AppVeyor’s handy encryption tool. I can then reference this encrypted value securely within my appveyor.yml.

Persuading AppVeyor to use this API key to deploy ConTabs to NuGet required some guesswork. After some trial and error, I got the result I wanted on the third attempt. The documentation on this subject (packaging artefacts and NuGet deployment) is almost too comprehensive: it lists a lot of fields which seem like they’d be useful, but aren’t actually needed.

In the end, all I needed was the following:

As far as I can tell, setting publish_nuget to true automatically created the NuGet package and registers it as an artefact. When I tried to do these manually, I got some strange errors about artefacts not being found, despite subsequently appearing in my artefacts list. The other effect of this magic setting seems to be that the NuGet deployment can automatically work out what to deploy. Note that in the YAML above I don’t specify an artefact name or filename.

In other words, I didn’t need to explicitly tell AppVeyor to do a dotnet pack or to register the artefact with an artifacts YAML section. It was all just taken care of behind the scenes.

The end result looks like this:

Screenshot of AppVeyor console output showing a successful deployment to NuGet

I know, I know… This doesn’t actually show a new deployment. I did have some changes queued up, but the AppVeyor bug rattled me, so I published them the old-fashioned way. What this does show is that AppVeyor is successfully talking to NuGet and is able to ascertain that this version already exists.

The main thing is the next new update to ConTabs will be automated. All I’ll have to do is merge develop into master and the new version will be automatically packaged and deployed to NuGet.org, ready for download.

This means it’ll be important to update the .csproj file before pushing master to GitHub. As my dry run shows, however, NuGet is smart enough not to let us overwrite an existing version of a package.

Summary

So we’ve seen how it’s possible to tell AppVeyor to apply different built processes based on Git branches and tags. And, with the assistance of AppVeyor’s excellent support, I was able to overcome a small bug. AppVeyor is pretty well geared up for publishing packages to NuGet services and I was able to succinctly tell it to deploy ConTabs to NuGet.org.

It took a lot of fiddling (that blasted bug didn’t help!), but I’m confident that my final appveyor.yml file will do what I need. Next time I push to master, I’ll be able to sit back whilst AppVeyor packages and deploys ConTabs to the NuGet gallery.

Leave a Reply

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