Publish to NuGet feeds

Azure Pipelines | TFS 2018 | TFS 2017

Note

In Microsoft Team Foundation Server (TFS) 2018 and previous versions, build and release pipelines are called definitions, service connections are called service endpoints, stages are called environments, and jobs are called phases.

You can publish NuGet packages from your build to NuGet feeds. You can publish these packages to

  • Azure Artifacts or the TFS Package Management service
  • Other NuGet services such as NuGet.org
  • Your internal NuGet repository

Before you read this topic, you should understand the kind of build pipeline you're creating: designer or YAML.

Create a NuGet package

There are a variety of ways to create NuGet packages during a build. If you're already using MSBuild or some other task to create your packages, skip this section to go ahead and publish your packages. Otherwise, add a NuGet task:

To create a package, add the following snippet to your azure-pipelines.yml file.

- task: NuGetCommand@2
  inputs:
    command: pack
    packagesToPack: '**/*.csproj'

The NuGet task supports a number of options. Some of the key ones are described below. The rest are described in the task documentation.

  • packagesToPack: The path to the files that describe the package you want to create. If you don't have these, see the NuGet documentation to get started.
  • configuration: The default is $(BuildConfiguration) unless you wish to always build either Debug or Release packages, or unless you have a custom build configuration.
  • packDestination: The default is $(Build.ArtifactStagingDirectory). If you set this, make a note of the location so you can use it in the publish task.

YAML is not supported in TFS.

Package versioning

In NuGet, a particular package is identified by its name and version number. A recommended approach to versioning packages is to use semantic versioning. Semantic version numbers have 3 numeric components, Major.Minor.Patch. When you fix a bug, you increment the patch (1.0.0 ? 1.0.1). When you release a new backwards-compatible feature, you increment minor and reset patch to 0 (1.4.17 ? 1.5.0). When you make a backwards-incompatible change, you increment major and reset minor and patch to 0 (2.6.5 ? 3.0.0).

In addition to Major.Minor.Patch, semantic versioning provides for a prerelease label. Prerelease labels are a “-” 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, semantic versioning specifies that when you sort by version number, those prerelease versions fit exactly where you’d expect: 0.99.999 < 1.0.0-alpha < 1.0.0 < 1.0.1-beta.

When you create a package in CI, you can use semantic versioning with prerelease labels. The NuGet task can be used for this purpose, and supports the following formats:

  • Use the same versioning scheme for your builds and packages, provided that scheme has at least three parts separated by periods. The following build pipeline formats are examples of versioning schemes that are compatible with NuGet.

    • $(Major).$(Minor).$(rev:.r), where Major and Minor are two variables defined in the build pipeline. This will automatically increment the build number and the package version with a new patch number keeping the major and minor versions constant, until you change them manually in the build pipeline.
    • $(Major).$(Minor).$(Patch).$(date:yyyyMMdd), where Major, Minor, and Patch are variables defined in the build pipeline. This will create a new prerelease label for the build and package while keeping the major, minor, and patch versions constant.
  • Use a version that is different from the build number. You can customize the major, minor, and patch versions for your packages in the NuGet task, and let the task generate a unique prerelease label based on date and time.

  • Use a script in your build pipeline to generate the version.

This example shows how to use the date and time as the prerelease label.

variables:
  Major: '1'
  Minor: '0'
  Patch: '0'

steps:
- task: NuGetCommand@2
  inputs:
    command: pack
    versioningScheme: byPrereleaseNumber
    majorVersion: '$(Major)'
    minorVersion: '$(Minor)'
    patchVersion: '$(Patch)'

For a list of other possible values for versioningScheme, see the NuGet task.

YAML is not supported in TFS.

While semantic versioning with prerelease labels is a good solution for packages produced in CI builds, including a prerelease label is not ideal when you want to release a package to your users. The challenge is that packages once produced are immutable and so cannot be updated or replaced. When you’re producing a package in build, you can’t know whether it will be the version that you aim to release to your users or just a step along the way towards that release. While none of the following solutions are ideal, you can use one of these depending on your preference:

  • Once you validate a package and decide to release it, produce another package without the prerelease label and publish it. The drawback of this approach is that you have to validate the new package again, and it may uncover new issues.

  • Publish only packages that you wish to release. In this case, you will not use a prerelease label for every build. Instead, you will reuse the same package version for all packages. Since you do not publish packages from every build, you do not cause a conflict.

Publish your packages

In the previous section, you learned how to create a package with every build. When you are ready to share the changes to your package with your users, you can publish it.

To publish to an Azure Artifacts feed, set the Project Collection Build Service identity to be a Contributor on the feed. To learn more about permissions to Package Management feeds, see Secure and share packages using feed permissions. Add the following snippet to your azure-pipelines.yml file.

steps:
- task: NuGetCommand@2
  displayName: 'NuGet push'
  inputs:
    command: push
    publishVstsFeed: 'af432f1b-f4b2-4a4f-bc9c-fef924f8f823'
    allowPackageConflicts: true

To publish to a external NuGet feed, you must first create a service connection to point to that feed. You can do this by going to Project settings, then choosing Service connections, and then creating a New service connection. Select the NuGet option for the service connection. Fill in feed URL and the API key or token to connect to the feed.

To publish a package to a NuGet feed, add the following snippet to your azure-pipelines.yml file.

- task: NuGetCommand@2
  inputs:
    command: push
    nuGetFeedType: external
    publishFeedCredentials: '<Name of the NuGet service connection>'
    versioningScheme: byEnvVar
    versionEnvVar: Version

YAML is not supported in TFS.

Publish symbols for your packages

When you push packages to a Package Management feed, you can also publish symbols.

Q&A

Where can I learn more about Azure Artifacts and the TFS Package Management service

Package Management in Azure Artifacts and TFS