Publish to NuGet feeds (YAML/Classic)
Azure Pipelines | Azure DevOps Server 2020 | Azure DevOps Server 2019 | TFS 2018 | TFS 2017
In Microsoft Team Foundation Server (TFS) 2018 and previous versions, build and release pipelines are called definitions, runs are called builds, 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 using the Pipeline tasks as well as the Classic user interface. 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.
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
Releasepackages, 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.
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,
When you fix a bug, you increment the patch (
1.0.1). When you release a new backward-compatible feature, you increment the minor version and reset the patch version to 0 (
1.5.0). When you make a backward-incompatible change, you increment the major version and reset the minor and patch versions to 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-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:
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:
Minorare 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.
Patchare 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.
Please note that
DotNetStandard packages should be packaged with the
DotNetCoreCLI@2 task to avoid System.InvalidCastExceptions. See the .NET Core CLI task for more details.
task: DotNetCoreCLI@2 displayName: 'dotnet pack $(buildConfiguration)' inputs: command: pack versioningScheme: byPrereleaseNumber majorVersion: '$(Major)' minorVersion: '$(Minor)' patchVersion: '$(Patch)'
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
steps: - task: NuGetAuthenticate@0 displayName: 'NuGet Authenticate' - task: NuGetCommand@2 displayName: 'NuGet push' inputs: command: push publishVstsFeed: '<projectName>/<feed>' allowPackageConflicts: true
Artifact feeds that were created through the classic user interface are project scoped feeds. You must include the project name in the
publishVstsFeed: '<projectName>/<feed>'. See Project-scoped feeds vs. Organization-scoped feeds to learn about the difference between the two types.
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
- task: NuGetAuthenticate@0 inputs: nuGetServiceConnections: '<Name of the NuGet service connection>' - task: NuGetCommand@2 inputs: command: push nuGetFeedType: external 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.