Dr. Neil's Notes
Using GitHub Packages with NuGet
This note introduces using GitHub to manage and maintain packages. As most of the work, and hobby, projects I do are in .NET, the contents of this note are focussed on NuGet packages. Packaging is a common, and standard, way to enable code to be shared between projects that are not in the same distributed output. For example in these notes the code for the Azure Key Vault could be compiled into a DLL that is shared by different products that require secret keys. Packaging also supports versioning of the code, and shared component. This provides the facility for different products to be working with different versions of the shared code.
Building the Package
When building a .NET project that you desire to distribute as a package, you can define the details of the package in the
.csproj file. Previously this was often done in a
.nuspec file, and you can still find
.nuspec files in folders of many projects.
For example the
.csproj file for a project named
CoolProject could contain a
PropertyGroup as follows
<PropertyGroup> <IsPackable>true</IsPackable> <Authors>DrNeil</Authors> <Description>A .NET library for using doing cool things</Description> <PackageLicenseExpression>NONE</PackageLicenseExpression> <PackageProjectUrl>https://github.com/ORGANIZATION_NAME/CoolProject</PackageProjectUrl> <RepositoryUrl>https://github.com/ORGANIZATION_NAME/CoolProject</RepositoryUrl> <PackageReadmeFile>README.md</PackageReadmeFile> </PropertyGroup> <ItemGroup> <None Include="README.md" Pack="true" PackagePath="\" /> </ItemGroup>
For a package you want to publish outside of your organization, the
PackageLicenseExpression should be set to reflects the license you wish to use for distribution.
Obviously, replace the
ORGANIZATION_NAME with your GitHub organization name, or if you are not an organization it will be the GitHub name where you have your repositories, for example my account is
DrNeil so the the
RepositoryUrl would be
PackageReadmeFile element is used to set the file used to describe the package, and here is set to a
README.md file in the project folder. The
ItemGroup at the end indicates the
README.md file should not be compiled and is purely for packing in the NuGet package.
When you build this project you can package it. Normally you would only want to package a release build and so from a command line build this would be achieved as follows:
dotnet pack -c Release CoolProject.csproj
Pushing the package
Typically publishing a package should be done from the CI (Continuous Integration) process, for example an Azure DevOps PipeLine or GitHub Action. However for a hobby project, like many of those in these Notes publishing from a local build is fine, and GitHub actions is beyond the scope of this Note.
In order to write a package to GitHub you will need a Classic Personal Access Token (PAT) with the scope write:packages. To create a Classic PAT see the GitHub docs here
Once you have a PAT you can use it from a PowerShell script as follows:
$ghKey = Read-Host -Prompt "Enter your github PAT" dotnet nuget push "bin/Release/CoolProject.1.0.0.nupkg" --api-key $ghKey --source https://nuget.pkg.github.com/<ORGANIZATION_NAME>/index.json
Consuming the package
In order to restore any private packages from GitHub you will need a Classic Personal Access Token (PAT) with the scope
To create a Classic PAT see the GitHub docs here
Then in the project folder where you desire to restore the package, add the GitHub packages folder for your organization to the
nuget.config file. If you do not have a
nuget.config file you may need to create one.
packageSources define the locations from which to retrieve packages when the .NET compiler tries to restore the packages to your local hard drive in order to build the project.
It is possible to have many
packageSources, sometimes, many from different GitHub organizations.
<configuration> <packageSources> <clear /> <!-- `key` can be any identifier for your source. --> <add key="nuget.org" value="https://api.nuget.org/v3/index.json" /> <add key="github" value="https://nuget.pkg.github.com/<ORGANIZATION_NAME>/index.json" /> </packageSources> <!-- Define mappings by adding package patterns beneath the target source. --> <!-- Contoso.* packages and NuGet.Common will be restored from contoso.com, everything else from nuget.org. --> <packageSourceMapping> <!-- key value for <packageSource> should match key values from <packageSources> element --> <packageSource key="nuget.org"> <package pattern="*" /> </packageSource> <packageSource key="github"> <package pattern="*" /> </packageSource> </packageSourceMapping> </configuration>
Then you can add the package to your
.csproj file using the
<ItemGroup> <PackageReference Include="CoolProject" Version="1.0.0" /> </ItemGroup>
To restore (retrieve) the packages you can either do a build
dotnet build, or explicitly run
When you restore the packages, if the package has not been made public, you will be asked for the GitHub credentials, You will need to enter your GitHub username and the PAT for the password.
Packaging components to be shared amongst products is a great way of sharing code between different deliverables. As packaging also supports versioning, it enables you to have different versions of the shared code used by different products, enabling you to roll out updates across products over time, and not forcing every product to always be on the latest version of the packaged code.
Created: July 23, 2023 00:13:22