{"id":15997,"date":"2016-05-03T00:56:53","date_gmt":"2016-05-02T17:56:53","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/visualstudioalm\/?p=15997"},"modified":"2019-02-14T17:34:04","modified_gmt":"2019-02-15T01:34:04","slug":"versioning-nuget-packages-cd-1","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/devops\/versioning-nuget-packages-cd-1\/","title":{"rendered":"Versioning NuGet packages in a continuous delivery world: part 1"},"content":{"rendered":"<p>On the Package Management team, we\u2019re frequently asked how to think about versioning packages. Conceptually, it\u2019s simple: <a href=\"http:\/\/docs.nuget.org\/Create\/Versioning\">NuGet<\/a> (like many package managers) prefers semantic versioning (<a href=\"http:\/\/semver.org\">SemVer<\/a>), which describes a release in terms of its backwards-compatibility with the last release. But for teams that have adopted continuous delivery, there\u2019s tension between this simple concept and the reality of publishing packages.<\/p>\n<p>This series of blog posts will cover strategies for resolving the tension. In this first one, we\u2019ll cover SemVer, immutability of packages, and a really simple versioning strategy. Later posts will talk about some <a title=\"Versioning NuGet packages in a continuous delivery world: part 2\" href=\"https:\/\/blogs.msdn.microsoft.com\/visualstudioalm\/2016\/05\/18\/versioning-nuget-packages-cd-2\/\">future thinking<\/a> we\u2019re doing in the versioning space, as well as a <a title=\"Versioning NuGet packages in a continuous delivery world: part 3\" href=\"https:\/\/blogs.msdn.microsoft.com\/visualstudioalm\/2016\/05\/26\/versioning-nuget-packages-cd-3\/\">tool\u00a0for Git users<\/a> that seems to work really well.<\/p>\n<h2>The tension between SemVer and CD<\/h2>\n<p>With continuous delivery, we recommend that you produce and publish packages as an output of your CI build. Put those CI packages through your validation steps (automated testing, user acceptance testing, or whatever) and, when a particular package is deemed ready, you promote it to release status.<\/p>\n<p>Did you spot the conflict? Each CI package produced needs a unique version number, so you must automatically increment the version number as you produce packages. As <a href=\"http:\/\/www.xavierdecoster.com\/semantic-versioning-auto-incremented-nuget-package-versions\">Xavier Decoster wrote<\/a> a few years ago, this is a contradiction in terms: You\u2019re \u201cauto-versioning a yet unknown semantic version\u201d. Put another way, we have a paradox: We need to pick a version number before we\u2019ve had a chance to determine what the version number ought to be based on the contents of the package.<\/p>\n<h2>Brief intro to SemVer<\/h2>\n<p>Semantic version numbers have 3 numeric components, Major.Minor.Patch. When you fix a bug, increment patch (1.0.0 \u2192\u00a01.0.1). When you release a new backwards-compatible feature, increment minor and reset patch to 0 (1.4.17 \u2192 1.5.0). When you make a backwards-incompatible change, increment major and reset minor and patch to 0 (2.6.5 \u2192 3.0.0).<\/p>\n<h2>Immutability and unique version numbers<\/h2>\n<p>In NuGet, a particular package is identified by its name and version number. Once you publish a package at a particular version, you can <a href=\"https:\/\/visualstudio.com\/get-started\/package\/feeds\/immutability\">never change its contents<\/a>. But when you\u2019re producing a CI package, you can\u2019t know whether it will be version 1.2.3 or just a step along the way towards 1.2.3. You don\u2019t want to burn the 1.2.3 version number on a package that still needs a few bug fixes.<\/p>\n<p>SemVer to the rescue! In addition to Major.Minor.Patch, SemVer provides for a prerelease label. Prerelease labels are a \u201c-\u201d followed by whatever letters and numbers you want. Version 1.0.0-alpha, 1.0.0-beta, and 1.0.0-foo12345 are all prerelease versions of 1.0.0. Even better, SemVer specifies that when you sort by version number, those prerelease versions fit exactly where you\u2019d expect: 0.99.999 &lt; 1.0.0-alpha &lt; 1.0.0 &lt; 1.0.1-beta.<\/p>\n<h2>Producing CI packages<\/h2>\n<p>Xavier\u2019s blog post describes \u201chijacking\u201d the prerelease tag to use for CI. We don\u2019t think it\u2019s hijacking, though. This is exactly what we do on Visual Studio Team Services to create our CI packages. We\u2019ll overcome the paradox by picking a version number, then producing prereleases of that version. Does it matter that we leave a prerelease tag in the version number? For most use cases, not really. If you\u2019re pinning to a specific version number of a dependent package, there will be no impact, and if you use floating version ranges with <a href=\"http:\/\/docs.nuget.org\/consume\/ProjectJson-Intro\">project.json<\/a>, it will mean a small change to the version range you specify.<\/p>\n<p>I\u2019m going to assume you\u2019ve got a small component you want to package up. Make sure the repo\u2019s in your Visual Studio Team Services account. If you don\u2019t, you can create a new class library called \u201cMyComponent\u201d in Visual Studio. Let the IDE add the solution to version control, then push the repo to Visual Studio Team Services. Also, if you haven\u2019t installed <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=ms.feed\">Package Management<\/a> in your account, do that now and create a feed to use.<\/p>\n<p>Create a new Visual Studio build for the repo. You can do that from the Build hub or from the \u201csetup a build now\u201d badge in the repo. Add two new steps to the build: NuGet Packager and NuGet Publisher. Move the Packager step up to right after the Visual Studio Test step, and under <strong>Automatic package versioning<\/strong>, choose <strong>Use the date and time<\/strong>. Enter the version number you want to build, for example, 1.0.0.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/6\/2019\/05\/packager.png\"><img decoding=\"async\" class=\"alignnone size-mediumlarge wp-image-16005\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2016\/05\/packager-415x350.png\" alt=\"NuGet Packager step\" width=\"415\" height=\"350\" \/><\/a><\/p>\n<p>Leave the NuGet Publisher step at the bottom. Change its <strong>Feed type<\/strong> to <strong>Internal NuGet Feed<\/strong>. Paste in the NuGet URL from the feed you want to use.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/6\/2019\/05\/publisher.png\"><img decoding=\"async\" class=\"alignnone size-mediumlarge wp-image-16015\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2016\/05\/publisher-500x289.png\" alt=\"NuGet Publisher step\" width=\"500\" height=\"289\" \/><\/a><\/p>\n<p>The list of steps should look like the screenshot below.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/6\/2019\/05\/steps.png\"><img decoding=\"async\" class=\"alignnone size-mediumlarge wp-image-16025\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2016\/05\/steps-323x350.png\" alt=\"Build steps for versioning\" width=\"323\" height=\"350\" \/><\/a><\/p>\n<p>When you save and choose <strong>Queue a build<\/strong>, the build system will create a package with a version number like \u201c1.0.0-ci-20160502-100256\u201d. That\u2019s the version number you selected followed by an ever-increasing prerelease section, in this case based on date and time.<\/p>\n<h2>Sharing the package with others<\/h2>\n<p>Once you put a particular version of a package through its paces and decide it\u2019s ready to release, you need to share it with others. The NuGet Publisher task works in Release Management just as they work in Team Build. While a full walkthrough is out of scope for this post, I recommend that you create a release definition that contains a NuGet Publisher task. You can point it either to another internal feed, or if you\u2019re open-source-oriented, point it at NuGet.org. Queue a release off the build which produced your desired package \u2013 there, you\u2019ve just released your first package from a CI stream!<\/p>\n<p>Clarification\u00a0[added May 5]:\u00a0NuGet.org is\u00a0<em>not<\/em> a good place to point your CI builds directly. It&#8217;s only for package versions you&#8217;re ready to release to the world. That&#8217;s what the previous paragraph intended to say, but it&#8217;s a little ambiguous.<\/p>\n<p>See the next post, with\u00a0more details about <a title=\"Versioning NuGet packages in a continuous delivery world: part 2\" href=\"https:\/\/blogs.msdn.microsoft.com\/visualstudioalm\/2016\/05\/18\/versioning-nuget-packages-cd-2\/\">future investments that make versioning and releasing easier<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>On the Package Management team, we\u2019re frequently asked how to think about versioning packages. Conceptually, it\u2019s simple: NuGet (like many package managers) prefers semantic versioning (SemVer), which describes a release in terms of its backwards-compatibility with the last release. But for teams that have adopted continuous delivery, there\u2019s tension between this simple concept and the [&hellip;]<\/p>\n","protected":false},"author":719,"featured_media":45953,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1,225,223],"tags":[],"class_list":["post-15997","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","category-git","category-package-management"],"acf":[],"blog_post_summary":"<p>On the Package Management team, we\u2019re frequently asked how to think about versioning packages. Conceptually, it\u2019s simple: NuGet (like many package managers) prefers semantic versioning (SemVer), which describes a release in terms of its backwards-compatibility with the last release. But for teams that have adopted continuous delivery, there\u2019s tension between this simple concept and the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/15997","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/users\/719"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/comments?post=15997"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/15997\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media\/45953"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media?parent=15997"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/categories?post=15997"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/tags?post=15997"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}