Table of Contents

Publish your library

Introduction

This article will guide you through the process of publishing a package on NuGet.org and GitHub packages using GitHub actions. This will enable you to share your library with the world.

NuGet is a package manager for .NET that allows you to share your code with the world. It is a great way to share your library with the community and to make it easy for others to use your code.

Prerequisites

Setup workspace

We will take the example project of the Introduction section and we will publish it on NuGet.org and GitHub packages as an example.

As a reminder, here is the file structure of the project:

Example_project  <-- root
└───MyApp
    ├───bin
    ├───MyApp.csproj
    └───Program.cs

README.md & LICENSE

This part is not mandatory but highly recommended.

Readme files are a great way to introduce your project to the world. It is the first thing people will see when they visit your repository. It is a good practice to include a README file in your project. Learn more

The license file is also important. It is a way to tell people what they can and cannot do with your project. The default license is the MIT license that let the user a lot a freedom with your code. Learn more

Here is an example of a README file:

# MyApp

> A simple console app for demonstration purposes

## Installation

Describe how to install your project

## Usage

Describe how to use your project

## Contributing

Describe how to contribute to your project

## License

MIT

And here is an example of a LICENSE file:

MIT License

Copyright (c) 2024 YourName

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

MyApp.csproj

C# project files (.csproj) are the files that contain all the information about your project. It is where you define the target framework, the dependencies, the version of your project, and much more. Learn more

Here is a template for a .csproj file made for publishing a package:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
    <!-- Project Info-->
    <TargetFrameworks>net8.0</TargetFrameworks>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <PropertyGroup>
    <Title>MyApp</Title>
    <!-- Change this by the name of your package, it must be unique -->
    <PackageId>MyFirstApp1234</PackageId>
    <!-- Change this by the name of the publisher on nuget.org -->
    <Authors>YourNugetAccountName</Authors>
    <!-- Change this by the description of your package -->
    <Description>Descriptive description to describe the package use</Description>
    <PackageLicenseExpression>MIT</PackageLicenseExpression>
    <!-- Change this by the tags of your package -->
    <PackageTags>Test, Discovery</PackageTags>
    <!-- Change this by the url of your repository on GitHub -->
    <RepositoryUrl>https://github.com/MorganKryze/ConsoleAppVisuals</RepositoryUrl>
    <RepositoryType>git</RepositoryType>
    <PackageReadmeFile>README.md</PackageReadmeFile>
    <PackageLicenseFile>LICENSE</PackageLicenseFile>
  </PropertyGroup>

  <PropertyGroup>
    <!-- NuGet Package Explorer health standards -->
    <EmbedUntrackedSources>true</EmbedUntrackedSources>
    <PublishRepositoryUrl>true</PublishRepositoryUrl>
    <IncludeSymbols>true</IncludeSymbols>
    <SymbolPackageFormat>snupkg</SymbolPackageFormat>
  </PropertyGroup>

    <!-- This condition let you build locally, and on a test github action without issue. Only the action CD.yml (see later) will enable this condition. this is part of the package health standards for deterministic build. -->
  <PropertyGroup
    Condition="'$(GITHUB_ACTIONS)' == 'true' AND '$(GITHUB_ACTION)' == 'publish'">
    <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
  </PropertyGroup>

  <PropertyGroup>
    <!-- Publishing Settings -->
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
    <PublishRelease>true</PublishRelease>
    <PackRelease>true</PackRelease>
  </PropertyGroup>

  <ItemGroup>
    <!-- Assets load-->
    <!-- MANDATORY: give the filepath to the files declared -->
    <!-- OPTIONAL: give a custom path to store them inside your package -->
    <None Include="..\README.md" Pack="true" PackagePath=""/>
    <None Include="..\LICENSE" Pack="true" PackagePath=""/>
  </ItemGroup>

  <ItemGroup>
    <!-- Dependencies if you have-->
    <PackageReference Include="yamldotnet" Version="15.1.2" />
  </ItemGroup>
</Project>

Consider checking that the filepaths are accurate. Here is the file structure of the project updated:

Example_project  <-- root
├───MyApp
│   ├───bin
│   ├───MyApp.csproj
│   └───Program.cs
├───LICENSE
└───README.md

Learn more about making your project deterministic.

Build the project

Now we will be able to build your project including the metadata for the package.

cd MyApp
dotnet build -c Release

Optional: You can also run the tests to make sure everything is working as expected by creating a local package:

dotnet pack -c Release

You will then find the NuGet package in the bin/Release folder of your project.

Publish your package

API keys

API keys are a way to authenticate yourself to a service. Using those keys will enable you to create automation to deploy and publish packages for example. You will need to create an API key for NuGet and GitHub.

Go to Nuget.org and sign in. Then jump to the API keys page and create a new API key. Copy it to your clipboard (I recommend you to store it somewhere safe afterward like in a password manager).

Important

Set your API key as a secret of your repository on GitHub and name it NUGET_API_KEY. Paste your API key in the value field.

To create a GitHub personal API key, go to this page and create a classic token. You will need to check the "write:packages" scope. Copy it to your clipboard (I recommend you to store it somewhere safe afterward like in a password manager).

Automation

Now we will set up a github action to automate the process of publishing your package.

Create two folders in the root of your project: .github then workflows inside.

Create a new file in the .github/workflows folder and name it CD.yml.

name: Publish package

on:
  push:
    tags:
      - 'v[0-9]+.[0-9]+.[0-9]+'

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - name: Verify commit exists in origin/main
        run: git branch --remote --contains | grep origin/main
      - name: Extract release notes
        run: |
          git log --pretty=format:'%d %s' ${GITHUB_REF} | perl -pe 's| \(.*tag: v(\d+.\d+.\d+(-preview\d{3})?)(, .*?)*\)|\n## \1\n|g' > RELEASE-NOTES
      - name: Set VERSION variable from tag
        run: echo "VERSION=${GITHUB_REF/refs\/tags\/v/}" >> $GITHUB_ENV
      - name: Pack library
      run: dotnet pack <your_path_from_your_project_file.csproj> /p:Version=${VERSION} /p:ContinuousIntegrationBuild=true --output .
      env:
        GITHUB_ACTIONS: true
        GITHUB_ACTION: 'publish'
      - name: Push to GitHub Packages
      run: dotnet nuget push <name_of_your_app>.${VERSION}.nupkg --source https://nuget.pkg.github.com/<nuget_username>/index.json --api-key ${GITHUB_TOKEN}
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    - name: Push to NuGet.org
      run: dotnet nuget push <name_of_your_app>.${VERSION}.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{secrets.NUGET_API_KEY}}
Important

Check that you updated:

  • <your_path_from_your_project_file.csproj> by the path to your .csproj file
  • <name_of_your_app> by the name of your app
  • <nuget_username> by your NuGet username (on the same line as the dotnet nuget push command)

Then, commit your changes and push them to your repository.

Finally, create a new release and add a tag to it as follow "vX.X.X" where X is a number representing the version of your package. Learn more

Tip

Wait a few minutes and you will find your package on NuGet.org and GitHub packages, you will be notified by email.

Clean up

If that project was indeed for you for demo purposes, you cannot delete it from NuGet.org, but you can hide it by unlisting it: Go to Manage Packages > select the package > click on the Edit button > Listing category > unchecked the "List in search results" checkbox > Save.

Bonus: Prefix ID

To protect the uniqueness of your package name, you can reserve a prefix for your package. This will prevent someone else from using the same name as your package. That way, I reserved "ConsoleAppVisuals" and "ConsoleAppVisuals.*" (meaning that "ConsoleAppVisuals" and "ConsoleAppVisuals.MyApp" will be reserved for example).

To do so, you only need to send an email to account@nuget.org with the subject "Package ID prefix reservation" and give your NuGet username (or organization, or other name of collaborators) and the prefixes you want to reserve. The criteria are given in this page.

Resources


Have a question, give a feedback or found a bug? Feel free to open an issue or start a discussion on the GitHub repository.