NuGet.org Publishing

Build and publish .NET packages to the public NuGet.org gallery.

Overview

NuGet.org is the primary package repository for .NET libraries. This example shows how to build, pack, and publish NuGet packages as part of your ANDO build pipeline.

Basic Package Publishing

Build and publish a package to NuGet.org:

var publish = DefineProfile("publish");

var project = Dotnet.Project("./src/MyLibrary/MyLibrary.csproj");
var tests = Dotnet.Project("./tests/MyLibrary.Tests/MyLibrary.Tests.csproj");

// Build and test
Dotnet.SdkInstall();
Dotnet.Restore(project);
Dotnet.Build(project);
Dotnet.Test(tests);

if (publish)
{
    // Pack with Release configuration
    Dotnet.Pack(project, o => o
        .WithConfiguration(Configuration.Release)
        .Output(Root / "packages"));

    // Push to NuGet.org
    Nuget.Push(
        Root / "packages" / "*.nupkg",
        Env("NUGET_API_KEY"),
        "https://api.nuget.org/v3/index.json"
    );

    Log.Info("Package published to NuGet.org");
}

Versioned Publishing

Use Git tags for package versioning:

var publish = DefineProfile("publish");

var project = Dotnet.Project("./src/MyLibrary/MyLibrary.csproj");
var version = Git.GetVersion();

Log.Info($"Building version {version}");

Dotnet.Restore(project);
Dotnet.Build(project, o => o.WithProperty("Version", version));
Dotnet.Test(Dotnet.Project("./tests/MyLibrary.Tests/MyLibrary.Tests.csproj"));

if (publish)
{
    // Pack with explicit version
    Dotnet.Pack(project, o => o
        .WithConfiguration(Configuration.Release)
        .WithProperty("Version", version)
        .Output(Root / "packages"));

    // Push versioned package
    Nuget.Push(
        Root / "packages" / $"MyLibrary.{version}.nupkg",
        Env("NUGET_API_KEY")
    );

    Log.Info($"Published MyLibrary {version} to NuGet.org");
}

Pre-release Packages

Publish pre-release versions for testing:

var publish = DefineProfile("publish");
var prerelease = DefineProfile("prerelease");

var project = Dotnet.Project("./src/MyLibrary/MyLibrary.csproj");
var baseVersion = Git.GetVersion();

string version;
if (prerelease)
{
    // Pre-release: 1.2.3-beta.45
    var buildNumber = Env("BUILD_NUMBER", "0");
    version = $"{baseVersion}-beta.{buildNumber}";
}
else
{
    version = baseVersion;
}

Log.Info($"Building version {version}");

Dotnet.Restore(project);
Dotnet.Build(project, o => o.WithProperty("Version", version));
Dotnet.Test(Dotnet.Project("./tests/MyLibrary.Tests/MyLibrary.Tests.csproj"));

if (publish)
{
    Dotnet.Pack(project, o => o
        .WithConfiguration(Configuration.Release)
        .WithProperty("Version", version)
        .Output(Root / "packages"));

    Nuget.Push(
        Root / "packages" / $"MyLibrary.{version}.nupkg",
        Env("NUGET_API_KEY")
    );

    Log.Info($"Published {version}");
}

Usage:

# Publish stable release
ando -p publish

# Publish pre-release
BUILD_NUMBER=45 ando -p publish,prerelease

Multi-Package Solution

Publish multiple packages from a solution:

var publish = DefineProfile("publish");

var packages = new[]
{
    Dotnet.Project("./src/MyLibrary.Core/MyLibrary.Core.csproj"),
    Dotnet.Project("./src/MyLibrary.Extensions/MyLibrary.Extensions.csproj"),
    Dotnet.Project("./src/MyLibrary.AspNetCore/MyLibrary.AspNetCore.csproj"),
};

var version = Git.GetVersion();

// Build all packages
Dotnet.SdkInstall();
foreach (var project in packages)
{
    Dotnet.Restore(project);
    Dotnet.Build(project, o => o.WithProperty("Version", version));
}

// Run all tests
Dotnet.Test(Dotnet.Project("./tests/MyLibrary.Tests/MyLibrary.Tests.csproj"));

if (publish)
{
    // Pack all
    foreach (var project in packages)
    {
        Dotnet.Pack(project, o => o
            .WithConfiguration(Configuration.Release)
            .WithProperty("Version", version)
            .Output(Root / "packages"));
    }

    // Push all packages
    Nuget.Push(
        Root / "packages" / "*.nupkg",
        Env("NUGET_API_KEY")
    );

    Log.Info($"Published {packages.Length} packages at version {version}");
}

With Symbol Packages

Include debug symbols for better debugging:

var publish = DefineProfile("publish");

var project = Dotnet.Project("./src/MyLibrary/MyLibrary.csproj");
var version = Git.GetVersion();

Dotnet.Restore(project);
Dotnet.Build(project, o => o.WithProperty("Version", version));
Dotnet.Test(Dotnet.Project("./tests/MyLibrary.Tests/MyLibrary.Tests.csproj"));

if (publish)
{
    // Pack with symbol package
    Dotnet.Pack(project, o => o
        .WithConfiguration(Configuration.Release)
        .WithProperty("Version", version)
        .WithProperty("IncludeSymbols", "true")
        .WithProperty("SymbolPackageFormat", "snupkg")
        .Output(Root / "packages"));

    // Push both .nupkg and .snupkg
    Nuget.Push(
        Root / "packages" / $"MyLibrary.{version}.nupkg",
        Env("NUGET_API_KEY")
    );

    Log.Info($"Published {version} with symbols");
}

Enable source link for debugging into source:

var publish = DefineProfile("publish");

var project = Dotnet.Project("./src/MyLibrary/MyLibrary.csproj");
var version = Git.GetVersion();

Dotnet.Restore(project);
Dotnet.Build(project, o => o
    .WithProperty("Version", version)
    .WithProperty("ContinuousIntegrationBuild", "true"));

Dotnet.Test(Dotnet.Project("./tests/MyLibrary.Tests/MyLibrary.Tests.csproj"));

if (publish)
{
    Dotnet.Pack(project, o => o
        .WithConfiguration(Configuration.Release)
        .WithProperty("Version", version)
        .WithProperty("ContinuousIntegrationBuild", "true")
        .WithProperty("EmbedUntrackedSources", "true")
        .WithProperty("IncludeSymbols", "true")
        .WithProperty("SymbolPackageFormat", "snupkg")
        .Output(Root / "packages"));

    Nuget.Push(
        Root / "packages" / $"MyLibrary.{version}.nupkg",
        Env("NUGET_API_KEY")
    );

    Log.Info($"Published {version} with Source Link");
}

Your .csproj should include:

<PropertyGroup>
  <PublishRepositoryUrl>true</PublishRepositoryUrl>
</PropertyGroup>

<ItemGroup>
  <PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All"/>
</ItemGroup>

Validate Before Publishing

Dry-run and validate package:

var publish = DefineProfile("publish");
var validate = DefineProfile("validate");

var project = Dotnet.Project("./src/MyLibrary/MyLibrary.csproj");
var version = Git.GetVersion();

Dotnet.Restore(project);
Dotnet.Build(project, o => o.WithProperty("Version", version));
Dotnet.Test(Dotnet.Project("./tests/MyLibrary.Tests/MyLibrary.Tests.csproj"));

// Always pack for validation
Dotnet.Pack(project, o => o
    .WithConfiguration(Configuration.Release)
    .WithProperty("Version", version)
    .Output(Root / "packages"));

if (validate || publish)
{
    // Validate package metadata
    Nuget.Verify(Root / "packages" / $"MyLibrary.{version}.nupkg");
    Log.Info("Package validation passed");
}

if (publish)
{
    Nuget.Push(
        Root / "packages" / $"MyLibrary.{version}.nupkg",
        Env("NUGET_API_KEY")
    );

    Log.Info($"Published {version}");
}

Usage:

# Validate only
ando -p validate

# Validate and publish
ando -p publish

Key Operations

OperationPurpose
Dotnet.Pack()Create NuGet package
Nuget.Push()Push to NuGet feed
Nuget.Verify()Validate package
Git.GetVersion()Get version from tags

Tips

  • API key security - Store NUGET_API_KEY as a secret, never in code
  • Semantic versioning - Follow semver for predictable updates
  • Test before publish - Always run tests before packaging
  • Symbol packages - Include .snupkg for better debugging
  • Source Link - Enable for debugging into source code

See Also