Using CI/CD Tools to Enforce SemVer When Migrating NuGet Packages to .NET 

When pre-release packages end up in Production, you risk bugs, breaks, and even security breaches. Poor package naming schemes make this all too easy. With a .NET 5+ migration likely in your future, now is the best time to use repackaging to enforce SemVer on your private NuGet packages.

.NET 5 can’t use your .NET Framework Libraries and vice versa, so you can’t just use them as-is. We discovered five methods for migrating NuGet packages between .NET Framework and .NET 5 when migrating our own private packages. While each application and library is unique and must be treated accordingly, these five methods are a great start. 

Learn how to enforce semantic versioning inside ProGet and BuildMaster as you migrate your .NET Framework libraries using any of the five methods.

Jump to the tutorial 

Five Ways to Migrate

As we said in a previous article, we’ve uncovered five methods for migrating your first-party .NET Framework NuGet packages as you prepare to move to .NET 5+. From easiest to hardest, they are abandon, update, fork, multi-target, and bridge. 

Method When to Use How to Execute 
Abandon Libraries using deprecated technologies Update the code as needed for security patches and bug fixes and release with CI/CD 
Update Most applications will use .NET 5+ but some old applications using .NET Framework endure Use a wide gap in the SemVer numbers to leave room between the .NET Framework library’s last version number and the first .NET 5+ version number. Release using CI/CD 
Fork Framework and 5+ applications that will coexist in the mid-to-long-term Copy the library, retarget to .NET 5+, fix the code errors, and use CI/CD to publish the package with a new, semantically versioned name 
Multi-target Efficiently supporting multiple applications on different .NET platforms and keeping libraries in sync Compile your C# code, pick the assembly type (.NET Framework or .NET 5+). Since NuGet packages have libraries under a subfolder named after the type of assembly, your package can have both a .NET Framework library (under the .net452 folder to specify version 4.5.2) or a .NET 5+ library (under the net5.0 folder). Use CI/CD to enforce SemVer 
Bridge Buy time before making another choice (only if your code supports it) Use .NET Standard as a bridge between .NET Framework and .NET 5; use CI/CD to semantically version 

You must assess each package in context and make the best decision for each, but some general advice is: 

1. Assess how many applications use each library. 
2. Assess when (if ever) those applications will migrate to .NET 5 
3. Rule out methods that will NOT work for your code
4. And for every method, enforce SemVer 

NuGet is built using SemVer, and repackaging helps you enforce SemVer

As we’ve said in a previous article

What distinguishes a “package” from a random zip file is that, once a package has been created, it should never be modified. Since the version number is part of the embedded metadata of a package, editing the same version will create confusion or even conflicts. Instead, use a new version number to indicate when a package has been altered.  

NuGet itself was built on a semantically versioned naming system and its dependencies rely on SemVer. If this wasn’t reason enough to use a SemVer naming scheme, it’s also nearly impossible to confuse because its rules are strict and numerical. 

Semantic Versioning (or SemVer) is a software naming system indicating backwards (in)compatibility. SemVer requires three digits: Major.Minor.Patch. 

Major

3.0.0 

changes that will be incompatible with previous versions 

Minor 

3.1.0 

added functionality that will still be backward-compatible (in this example 3.1.0 will be compatible with 3.0.0)

Patch

3.1.4 

minor bug fixes or security patches that should always be fully backward-compatible  

Further quality can be indicated with prerelease tags like -ci or -rc, which should never be used in production. 

No matter which of the 5 migration methods you choose, using repackaging to enforce SemVer is the way to do the job right the first time, and using DevOps tools helps you do this automatically. Repackaging is the process of creating a new packages from an existing one, changing only the name to indicate quality or approval. Repackaging is a simple way to enforce SemVer for your private NuGet packages via automation tools. 

Using BuildMaster and ProGet to Enforce SemVer 

Before you begin, you’ll need: 

We also recommend having Windows clipboard enabled, so that when you hit Windows Key v, you’ll have a history of your copied items. This is not a necessity, however. 

Once these are installed, follow these steps: 

Whether you create a new NuGet feed in ProGet or use an existing one, copy the API URL from the top right corner. You’ll need it so BuildMaster and ProGet can communicate. 

Next, navigate to ProGet’s settings by clicking the gear icon and select ‘API Keys’ and ‘Create API Key.’  

Name it as you like, and select the boxes ‘Grant Access to Feed API’ and ‘Grant Access to Repackaging API,’ then save. Note that you can limit the users who may access the API key with the ‘Impersonate User’ field; otherwise, it’s a global key. ProGet can also auto-generate a key. 

Now go into BuildMaster. Create a new application using the NuGet CI/CD application template. Name it as you like, and save. 

After the template is applied, you’ll need to create a secure resource to clear the first warning shield.  

To do this, click on ‘Secure Resources’ at the top right of the set-up template, select ‘Create Secure Resource,’ and select ‘NuGet Package Feed,’ then ‘Create…’ near the bottom of the pop-up.  

Create a new API key/token and name it, then save. Back on the ‘Create Secure Resource’ window, name it and paste the Feed URL you grabbed from ProGet. Then, use the dropdown to select the new API key you just created, and save. 

Return to the application set-up template by clicking “Application Setup.’ Clear the warning shields by adding the secure resource name you just created and adding your package name. If you’re just testing this, copy the example package from the description line, ProfitCalc.NuGet (see image). 

Your NuGet CI/CD pipeline is now ready to use, so create a new build in BuildMaster. You’ll be prompted to create a release, and then a new build. 

If you’ve configured everything correctly, when you go back to ProGet, you’ll see a new package with -ci ending in the ProGet feed. 

ProGet clearly indicates that it’s a prerelease version, and you can view the metadata, files, and more by clicking the package name. 

As you deploy your package through this NuGet CI/CD pipeline, BuildMaster will continue to push pre-release and finally the stable version of your package to ProGet. 

You can customize the BuildMaster pipeline to meet your team’s needs, from adding automated executions to extra manual approvals and more. 

Get More Value by Using Both Tools

While ProGet is doing the actual repackaging, combining the two tools is a great way to live the ‘CI/CD lifestyle.’ BuildMaster adds communication and security features to the repackaging process like: