Defra.Example.Greetings
0.1.6
Prefix Reserved
dotnet add package Defra.Example.Greetings --version 0.1.6
NuGet\Install-Package Defra.Example.Greetings -Version 0.1.6
<PackageReference Include="Defra.Example.Greetings" Version="0.1.6" />
<PackageVersion Include="Defra.Example.Greetings" Version="0.1.6" />
<PackageReference Include="Defra.Example.Greetings" />
paket add Defra.Example.Greetings --version 0.1.6
#r "nuget: Defra.Example.Greetings, 0.1.6"
#:package Defra.Example.Greetings@0.1.6
#addin nuget:?package=Defra.Example.Greetings&version=0.1.6
#tool nuget:?package=Defra.Example.Greetings&version=0.1.6
Defra NuGet Example
An example .NET 10 package that returns friendly greetings.
Install
dotnet add package Defra.Example.Greetings
Usage
using Defra.Example.Greetings;
Console.WriteLine(Greeting.Hello("John"));
// Hello, John!
Publishing NuGet packages to the Defra organisation
This repository is an example of how to create, package and publish a .NET NuGet package to the Defra NuGet.org organisation using Trusted Publishing from GitHub Actions.
Trusted Publishing allows GitHub Actions to publish packages to NuGet.org without storing a long-lived NuGet API key in GitHub secrets.
Who this is for
This guidance is for Defra teams who want to publish public NuGet packages under the Defra NuGet.org organisation.
It covers:
- how to request access to the Defra NuGet.org organisation
- what a NuGet organisation collaborator can do
- what Defra NuGet organisation admins need to do
- how to create a new package
- how to publish using GitHub Actions Trusted Publishing
- how to choose an appropriate package ID
- how Trusted Publishing supports succession planning
Requesting access to the Defra NuGet organisation
To publish a package to the Defra NuGet.org organisation, you need to be added as a Collaborator.
To request access:
Create or sign in to your NuGet.org account.
Make sure your NuGet.org account uses a secure Microsoft account with MFA enabled.
Find your NuGet.org username.
Contact
#nuget-supportin Slack.Include:
- your NuGet.org username
- your team name
- the GitHub repository that will publish the package
- the proposed package ID
- whether this is a new package or an existing package
- confirmation that the package is suitable for public publishing
Example Slack request:
Hi, please can I be added as a Collaborator to the Defra NuGet.org organisation?
NuGet username: <your-nuget-username>
Team: <team-name>
GitHub repository: <github-org>/<repo-name>
Proposed package ID: Defra.<PackageName>
Reason: We want to publish a public NuGet package using GitHub Actions Trusted Publishing.
What Defra NuGet organisation admins need to do
When someone requests access via #github-support, a Defra NuGet organisation admin should:
- Confirm the request is from an appropriate Defra team or maintainer.
- Confirm the package is intended to be public.
- Confirm the proposed package ID is appropriate.
- Ask the requester for their NuGet.org username if they have not provided it.
- Sign in to NuGet.org.
- Go to the Defra organisation.
- Open the organisation members area.
- Invite the requester by their NuGet.org username.
- Add them as a Collaborator.
- Confirm in
#github-supportonce they have been added.
Package ID naming
The Defra package ID prefix is reserved on NuGet.org for the Defra organisation.
Publish packages using a combination of Defra and a team or product name that is unlikely to conflict with other packages.
Defra.Farming.Greetings
Defra.Farming.Grants.Utilities
Defra.Trade.Greetings
Before publishing, check that the package ID is:
- globally unique on NuGet.org
- clearly associated with the owning team or product
- unlikely to conflict with another Defra, ALB or external package
- suitable for public use
- stable enough to keep long term
NuGet package IDs are immutable once published. You cannot rename a package after publishing; you would need to publish a new package with a different ID.
What this example repository includes
This example repository demonstrates a minimal .NET package publishing setup.
It includes:
- a .NET class library project
- a test project
- package metadata in the
.csproj - a package README
- a package licence file
- GitHub Actions CI with version bump enforcement
- GitHub Actions NuGet publishing
- Trusted Publishing with NuGet.org
- package versioning via
<Version>in the.csproj - publishing without storing a NuGet API key in GitHub secrets
The example package contains a simple greeting helper so the publishing process can be tested end to end without introducing application-specific logic.
Example package structure:
repo-root/
├─ .github/
│ └─ workflows/
│ ├─ check-pull-request.yml
│ └─ publish.yml
├─ Defra.Example.Greetings/
│ ├─ Greetings.cs
│ └─ Defra.Example.Greetings.csproj
├─ Defra.Example.Greetings.
│ ├─ Greeting.cs
│ └─ Defra.Example.Greetings.Tests.csproj
├─ README.md
├─ LICENCE
└─ Defra.Example.Greetings.slnx
Creating a new package
Create a new repository for your package.
Then create a solution, class library and test project:
mkdir Defra.Example.Greetings
cd Defra.Example.Greetings
dotnet new sln --name Defra.Example.Greetings
dotnet new classlib \
--name Defra.Example.Greetings \
--output Defra.Example.Greetings
dotnet new xunit \
--name Defra.Example.Greetings.Tests \
--output Defra.Example.Greetings.Tests
dotnet sln add Defra.Example.Greetings/Defra.Example.Greetings.csproj
dotnet sln add Defra.Example.Greetings.Defra.Example.Greetings.Tests.csproj
dotnet add Defra.Example.Greetings.Defra.Example.Greetings.Tests.csproj \
reference Defra.Example.Greetings/Defra.Example.Greetings.csproj
Replace Defra.Example.Greetings with your actual package ID.
Adding package metadata
Add NuGet package metadata to your project file. See Defra.Example.Greetings.csproj for a full example.
The key metadata properties to set are:
<PackageId>Defra.Example.Greetings</PackageId>
<Version>0.1.0</Version>
<Authors>Authors</Authors>
<Company>Defra</Company>
<Description>A short description of what the package does.</Description>
<PackageTags>defra;dotnet;example</PackageTags>
<PackageProjectUrl>https://github.com/DEFRA/repo-name</PackageProjectUrl>
<RepositoryUrl>https://github.com/DEFRA/repo-name</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageLicenseFile>LICENCE</PackageLicenseFile>
<PackageReadmeFile>README.md</PackageReadmeFile>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
Include the licence and README in the package:
<ItemGroup>
<None Include="../LICENCE" Pack="true" PackagePath="\" />
<None Include="../README.md" Pack="true" PackagePath="\" />
</ItemGroup>
Do not use PackageLicenseExpression unless the licence is accepted by NuGet.org as an approved licence expression. For licences not accepted as NuGet licence expressions, include the licence as a file instead.
The <Version> element controls the published package version. It is read directly at pack time by both local builds and the GitHub Actions publish workflow. Increment it in every pull request that should result in a new published version. The CI check enforces this before merging.
Building and packing locally
Build, test and pack the package locally before publishing:
dotnet restore
dotnet build --configuration Release
dotnet test --configuration Release --no-build
dotnet pack Defra.Example.Greetings/Defra.Example.Greetings.csproj \
--configuration Release \
--output artifacts
The package file will be created in the artifacts directory:
artifacts/Defra.Example.Greetings.0.1.0.nupkg
You can test the package locally from another project (run this command from the consuming project directory, adjusting the source path to where your artifacts folder is):
dotnet add package Defra.Example.Greetings \
--source /path/to/Defra.Example.Greetings/artifacts
GitHub Actions CI workflow
The CI workflow builds, tests and checks that the package version has been incremented on every pull request to main.
See .github/workflows/check-pull-request.yml for the full workflow.
Key steps:
- name: Restore
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Test
run: dotnet test --configuration Release --no-build
The workflow also enforces that the <Version> in the .csproj is higher than the version on main before the pull request can be merged. This is the mechanism that controls which version is published next.
Why version bumping matters
The package version is read directly from <Version> in the .csproj at pack time. There is no tag-based or automatic versioning. This means:
- every change merged to
mainthat should result in a new published version must include a version increment in the.csproj - if you merge without bumping the version, the publish workflow will attempt to push a version that already exists on NuGet.org and will fail
- NuGet package versions are immutable, so you cannot overwrite a published version
The CI check in .github/workflows/check-pull-request.yml prevents merging if the version has not been incremented:
- name: Check version incremented
run: |
CURRENT="${{ steps.current-version.outputs.version }}"
BASE="${{ steps.base-version.outputs.version }}"
# fails if CURRENT is not greater than BASE
This means every merged pull request is guaranteed to carry a new version, and the publish workflow can push it to NuGet.org immediately.
GitHub Actions publish workflow
See .github/workflows/publish.yml for the full workflow.
The workflow is triggered on every push to main (i.e. when a pull request is merged) and can also be run manually:
on:
workflow_dispatch:
push:
branches:
- main
It requires id-token: write for Trusted Publishing:
permissions:
contents: read
id-token: write
The pack step uses the <Version> from the .csproj directly:
- name: Pack
run: dotnet pack Defra.Example.Greetings/Defra.Example.Greetings.csproj --configuration Release --no-build --output artifacts
Replace Defra.Example.Greetings with your package ID and project path.
GitHub repository secret
Add a GitHub Actions secret named:
NUGET_USERNAME
The value must be the NuGet.org username of the person who created the Trusted Publishing policy.
It should be a NuGet.org username, not:
- the NuGet organisation name
- an email address
- a Microsoft account login
- a GitHub username, unless that is also the NuGet.org username
Example:
my-nuget-username
Setting up Trusted Publishing in NuGet.org
A NuGet organisation collaborator or admin should create the Trusted Publishing policy.
In NuGet.org:
- Sign in as the NuGet.org user that will be used in
NUGET_USERNAME. - Go to Trusted Publishing.
- Add a new policy.
- Choose the package owner as the Defra organisation.
- Enter the GitHub repository details.
- Enter the workflow file name.
- Enter the GitHub environment name, if one is used.
Example policy values:
Package owner: Defra
Repository owner: DEFRA
Repository: defra-nuget-example
Workflow file: publish.yml
The workflow file should be only the file name:
publish.yml
Do not enter the full path:
.github/workflows/publish.yml
Leave the environment field blank if the publish workflow does not specify a GitHub environment.
Publishing a package
Publishing happens automatically when a pull request is merged to main. Before merging, ensure the <Version> in the .csproj has been incremented. The CI check will block the merge if it has not.
For example, to publish version 0.1.1:
- Update
<Version>in the.csprojto0.1.1. - Open a pull request.
- The CI check confirms the version is higher than
main. - Merge the pull request.
The publish workflow will then:
- build the project
- run the tests
- create a NuGet package using the version from the
.csproj - use GitHub OIDC to authenticate with NuGet.org
- receive a short-lived NuGet API key
- push the package to NuGet.org
NuGet package versions are immutable. Once a version has been published, it cannot be overwritten. If you merge without bumping the version, the push step will fail because the version already exists on NuGet.org. Increment the version in a follow-up pull request to recover.
Trusted Publishing and succession planning
Trusted Publishing helps with succession planning because publishing is tied to:
- the Defra NuGet.org organisation
- a GitHub repository
- a GitHub Actions workflow
- a NuGet.org policy
It avoids depending on a long-lived NuGet API key stored in a single repository secret.
This has several benefits:
- no permanent NuGet API key needs to be shared
- no individual needs to keep a personal API key alive
- access can be managed through NuGet organisation membership
- responsibility can move between maintainers without rotating package API keys
- organisation admins can add or remove collaborators as teams change
Recommended succession setup:
NuGet.org organisation: Defra
Organisation admins: 2 or more trusted support/admin users
Package maintainers: added as Collaborators
Publishing identity: GitHub Actions Trusted Publishing
When a maintainer leaves a team:
- Remove them from the relevant GitHub repository or team.
- Remove or update their NuGet organisation membership if they no longer need it.
- Confirm another maintainer can create releases.
- Confirm the Trusted Publishing policy still points to the correct repository and workflow.
- Confirm the
NUGET_USERNAMEsecret still refers to the NuGet.org user who created the policy, or recreate the policy with a different user if needed.
For long-lived packages, avoid having only one person able to manage the package or its release process.
Troubleshooting
No matching trust policy owned by user was found
Check that NUGET_USERNAME is the NuGet.org username of the person who created the Trusted Publishing policy.
It must not be the organisation name.
For example, use:
my-nuget-username
not:
Defra
The package ID is reserved
The package ID probably uses a name already in use or that is reserved.
For example:
Defra.Example.Greetings
may fail because the Defra.Example.Greetings package already exists.
Use another appropriate package name instead.
License expression must only contain licences that are approved
If NuGet.org rejects your licence expression, use a packaged licence file instead:
<PackageLicenseFile>LICENCE</PackageLicenseFile>
and include the file in the package:
<ItemGroup>
<None Include="../LICENCE" Pack="true" PackagePath="\" />
</ItemGroup>
Package already exists
NuGet package versions are immutable.
If this version has already been published, increment <Version> in the .csproj and open a new pull request.
Package does not appear in search immediately
NuGet.org may take some time to validate and index a package.
Check the package directly using:
https://www.nuget.org/packages/<PackageId>
For example:
https://www.nuget.org/packages/Defra.Example.Greetings
Licence
THIS INFORMATION IS LICENSED UNDER THE CONDITIONS OF THE OPEN GOVERNMENT LICENCE found at:
http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3
The following attribution statement MUST be cited in your products and applications when using this information.
Contains public sector information licensed under the Open Government license v3
About the licence
The Open Government Licence (OGL) was developed by the Controller of Her Majesty's Stationery Office (HMSO) to enable information providers in the public sector to license the use and re-use of their information under a common open licence.
It is designed to encourage use and re-use of information freely and flexibly, with only a few conditions.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.