Publish to NuGet feeds

Azure Pipelines | Azure DevOps Server 2019 | 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 various 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 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. The following list describes some of the key ones. The task documentation describes the rest.

  • 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 want 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 three numeric components, Major.Minor.Patch.

When you fix a bug, you increment the patch (1.0.0 to 1.0.1). When you release a new backward-compatible feature, you increment the minor version and reset the patch version to 0 (1.4.17 to 1.5.0). When you make a backward-incompatible change, you increment the major version and reset the minor and patch versions to 0 (2.6.5 to 3.0.0).

In addition to Major.Minor.Patch, Semantic Versioning provides for a prerelease label. Prerelease labels are a hyphen (-) 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 continuous integration (CI), you can use Semantic Versioning with prerelease labels. You can use the NuGet task for this purpose. It supports the following formats:

  • Use the same versioning scheme for your builds and packages, if 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 format will automatically increment the build number and the package version with a new patch number. It will keep 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 format will create a new prerelease label for the build and package while keeping the major, minor, and patch versions constant.
  • Use a version that's 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.

Although 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 after packages are produced, they're immutable. They can't be updated or replaced.

When you’re producing a package in a 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 toward that release. Although none of the following solutions are ideal, you can use one of these depending on your preference:

  • After 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 might uncover new issues.

  • Publish only packages that you want to release. In this case, you won't use a prerelease label for every build. Instead, you'll reuse the same package version for all packages. Because 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're 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: '<feedName>'
    allowPackageConflicts: true

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

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: <VersionVariableName>

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