Dynamically adding a MyGet feed to your VSTS build process

Overview

Some history: when it was launched for the first time, Visual Studio Team Services (formerly Visual Studio Online or Team Foundation Server Online) had no support for hosting your NuGet packages into the same platform as your code. Later on, they added a very basic support in the form of a NuGet Packages feed. It lacked lots of features, but it worked. And it was nicely integrated with VSTS. So we all rushed and adopted this “free” feature. And everything was easy and beautiful.

But suddenly, one dark night, Microsoft did what we knew it would eventually do. Visual Studio Package Management ended its beta stage and was launched as General Availability. That means, more or less, that you had to pay to continue using the service. At this point, we had to choose whether to continue using Microsoft’s package Management or move to a different solution.

Setting up an on-premise service was out of question. We wanted something easy to set up that required no manteinance. After all, we don’t want to reinvent the wheel. And of course, we wanted it to be free or cheap. Then we stumbled upon MyGet.

MyGet features

MyGet offers lots of functionalities and costs less than Microsoft’s package management solution. Here’s a succint list of features:

  • It’s fast: one of the problems we had with VSTS Package manager it’s that it was slow. Very slow.
  • Symbols: we can publish symbols packages. This solves one of the typical headaches when dealing with the pubishing of symbols, namely debugging our own libraries.
  • Other kind of packages: npm, bower and vsix. I don’t use them currently, but I eventually will.
  • Reliable: VSTS Package Manager suffered from fails from time to time. MyGet is well tested and robust,
  • Cheaper: it’s not free, but it’s ~30% cheaper than Microsoft
  • Allows statistics, quotas, package cleanup, galleries and several other features not present on VSTS.
  • It’s nicer: overall, it looks a lot sexier.

Migration process

Considering what I need, talking to MyGet support and reading the docs, I managed to set up a VSTS environment that had little impact on current developers.

Set up the new MyGet feed

Create a new MyGet feed with the name of your company

https://acme.myget.org/F/myfeed/api/v3/index.json

Then, the current VSTS feed is added as an Upstream source. This means that you can add packages from the VSTS feed and the packages downloaded are automatically added to the MyGet feed.

To make things simpler, I added all the latest versions of existing packages in the newly created feed, so existing developers can still use the new feed without changes.

A new user is created to access the feed from VSTS.

We will need the URLs for pushing packages and symbols and the API key. Both can be found in the Feed Details tab

Configure releases to publish to MyGet

Once we have the feed created, we need our Release Definitions to publish to it. We intend to publish normal packages and symbols packages. Symbol packages are created by invoking NuGet.exe with the -Symbols parameter. This creates two package files: .nupkg and .symbols.nupkg. So, we need to:

  • Modify nuspec packages to include PDB files
  • Add MyGet endpoints to VSTS
  • Make NuGet pack command to include the -Symbols parameter

Add PDB files in .nuspec files

We have to modify the .nuspec files so that PDB files are included in the package. Let’s see an example:

<?xml version="1.0" encoding="utf-16"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
  <metadata>
    <id>Acme.Marketing.Tracking</id>
    <version>1.3.0.0</version>
    <title>ACMEMarketing Tracking</title>
[...]
  </metadata>
  <files>
    <file src="BaseTypes\bin\Release\Acme.Tracking.BaseTypes.dll" target="lib\net451" />   
    <file src="Tracking\bin\Release\Acme.Marketing.Tracking.dll" target="lib\net451" />
  </files>
</package>

As you can see, we are only including the assembly files in package. If we also want to include the PDB files, we can change the file to something like this:

<?xml version="1.0" encoding="utf-16"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
  <metadata>
    <id>Acme.Marketing.Tracking</id>
    <version>1.3.0.0</version>
    <title>ACMEMarketing Tracking</title>
[...]
  </metadata>
  <files>
    <file src="BaseTypes\bin\Release\Acme.Tracking.BaseTypes.dll" target="lib\net451" />   
    <file src="Tracking\bin\Release\Acme.Marketing.Tracking.dll" target="lib\net451" />
    <file src="BaseTypes\bin\Release\Acme.Tracking.BaseTypes.pdb" target="lib\net451" />
    <file src="Tracking\bin\Release\Acme.Marketing.Tracking.pdb" target="lib\net451" />   
  </files>
</package>

Add new endpoints for MyGet

Next, we add two new endpoints to each Team Project that needs to publish to MyGet, one for normal packages and the other for symbol packages. This is done by browsing to Project Settings → Services and adding generic endpoints.

We need the following endpoints:

To set the credentials for both endpoints, we simply use an empty string as the username and the API Key as the password.

Change Release definition to publish to MyGet

The next step is to change the Release Definitions so that the two packages are published to MyGet. For this purpose, we have created a Group Task that we share among the different definitions. The Task Group has two steps, one to push normal packages and other to push symbol packages.

The first step is a NuGet publish task that gets all packages except symbol packages and pushes them to MyGet

  • Path/pattern to nupkg: $(NuPackagesFolder)/*.nupkg;-:$(NuPackagesFolder)/*.symbols.nupkg
  • Feed Type: External NuGet feed
  • NuGet Server Endpoint: the feed endpoint created in previous step

The second step is a NuGet publish task that gets all symbol packages and pushes them to MyGet

  • Path/pattern to nupkg: $(NuPackagesFolder)/*.symbols.nupkg
  • Feed Type: External NuGet feed
  • NuGet Server Endpoint: the symbols feed endpoint created in previous step

IMPORTANT: in both steps, make sure you change the NuGet.exe version to 3.5. Otherwise you’ll face an error when pushing packages.