Notes regarding the development of Energinet-DataHub NuGet packages, also called libraries. The packages contain reusable types, supporting the development of Energinet DataHub.
- NuGet package bundle
- Multiple NuGet packages in mono repository
- Workflows
- Preparations for a new release
- Testing a package locally
- Debugging a released package
- Developing a new package bundle
In the following we will use the term NuGet package bundle when referring to a group of related NuGet packages, between which we want to use project references during development of the packages, and NuGet package references when they are published.
It is important to read and understand this section before changing anything. The fundamental idea behind the organization of this repository, and how everything works together, is to support:
- KISS principle
- Project references between related packages (NuGet package bundle)
- Easy and faster update between related packages (NuGet package bundle)
- Only releasing NuGet package bundles where the content has been changed
Packages must be created in subfolders to the source
folder, where each subfolder contains a NuGet package bundle.
All project files belonging to a NuGet package bundle must be added to a <bundle>.sln
solution, and organized similar to existing projects and files, with regards to solution folders.
Each bundle has its own:
documentation.md
file for documentation the bundle content and possible usage.- (optional)
development.md
file for additional information (e.g. setup local environment) necessary to be able to develop the specific package or bundle. release-notes.md
file for documentation of changes between each version.- Source code and tests.
- (optional)
.editorconfig
as mentioned in theREADME.md
some bundles have their own because we needed to migrate to another set of rules, which we didn't want to do for all at once. - (optional)
Directory.Build.props
as mentioned in theREADME.md
some bundles have their own because we needed to migrate to another set of properties, which we didn't want to do for all at once.
The following are shared:
development.md
(this) file for documenting how to develop the packages and bundles in general.Directory.Build.props
(some bundles have their own)stylecop.json
Here is an example of the package folder structure using the existing TestCommon
and a MyNewBundle
bundle:
<root>
│
├───docs
│ development.md
│
└───source
│ Directory.Build.props
│ stylecop.json
│
├───TestCommon
| | .editorconfig
| | Directory.Build.props
│ │ TestCommon.sln
│ │
│ ├───documents
│ │ │ development.md
│ │ │ documentation.md
│ │ │
│ │ └───release-notes
│ │ release-notes.md
│ │
│ └───source
│ └───FunctionApp.TestCommon
│ └───FunctionApp.TestCommon.Tests
│ └───TestCommon
│ └───TestCommon.Tests
│
└───MyNewBundle
│ MyNewBundle.sln
│
├───documents
│ │ documentation.md
│ │
│ └───release-notes
│ release-notes.md
│
└───source
└───MyNewPackage
└───MyNewPackage.Tests
This workflow type handles test, build, pack and publish of a bundle.
If any of the packages in the bundle has changes, all must be updated with regards to version.
Before publishing anything an action verifies that there is no released version existing with the current version number. This is to help detect if we forgot to update the version number in packages.
If the workflow is triggered:
- Manually (
workflow_dispatch
), a prerelease version of the packages are published. - By
pull_request
, then the packages are not published. - By
push
to main, the a release version of the packages are published.
Only packages that have changes should be published as new versions.
To prepare any given package for a new release, do the following:
- Open the
*.csproj
file and update the propertyPackageVersion
.Don't edit the property from the editor, it will not work correctly.
- Update the
release-notes.md
file following the existing style and structure. - If we need to describe any migration steps required to move from one version to the next, then do one of the following:
- If the description in short: put it in the
release-notes.md
. - If the description requires more than a few lines: put it in a separate
.md
file and link to it from therelease-notes.md
. Name the new.md
file following the formatversion_<major>_<minor>_<patch>.md
, and place it in therelease-notes
folder.
- If the description in short: put it in the
The NuGet packages must use Semantic Versioning
The version format is:
<major>.<minor>.<patch>$(VersionSuffix)
Packaging a prerelease version can be done by ensuring the $(VersionSuffix)
build variable is set to a value.
The following example will use -alpha-01
as version suffix:
dotnet pack --configuration Release /p:versionsuffix=-alpha-01
The following is a walkthrough of how we can test a NuGet package locally, before we publish it to others.
The following expects us to use a PowerShell console or similar, where the current directory is the location of the <bundle>.sln
file:
-
Create a folder to use as the local NuGet source.
Here we will use
C:\Projects\LocalNuGet
. -
Build the NuGet packages.
The following creates each NuGet package as prerelease versions in the specified
--output
location.dotnet pack --output C:\Projects\LocalNuGet --configuration Release /p:versionsuffix=-alpha-01
-
(Optional) Investigate package content.
We can rename a
*.nupkg
file to*.zip
and open it to investigate its content.
Using e.g. Visual Studio, we can now install the local NuGet packages to other projects for verification:
-
Add a new NuGet package source to Visual Studio:
Important: Do not check-in changes this might cause to any
nuget.config
files.- Select menu item Tools | NuGet Package Manager | Package Manager Settings.
- Choose Package Sources.
- Press the "+" (plus) button to add a new source and specify the following:
- Name:
LocalNuGet
- Source:
C:\Projects\LocalNuget
- Name:
- Close the dialog by pressing "OK" button.
-
Use local NuGet package.
Add NuGet packages as usual, but be sure to select the
LocalNuGet
asPackage source
to see the local packages. If the package is a prerelease we must also ensure to checkInclude prerelease
, otherwise it will not show up on the list.
For another walkthrough, see How to test NuGet packages locally.
Some IDE's support downloading symbol (*.pdb
) files for NuGet packages, to allow developers a rich debugging experience where they can debug into release builds of packages.
To support this feature our builds must pack and push .snupkg
files to NuGet.org symbol server.
For details, see Improved package debugging experience with the NuGet.org symbol server.
To download and use symbols for debugging in Visual Studio, you must enable NuGet.org symbol server, and enable certain debugger features. See Debug with symbols in Visual Studio.
Notice Unchecking "Enable Just My Code" will cause the download and load of lots of symbols when you run your debugging session, so it can impact your performance. But you can have it checked by default, and only uncheck it in those situations where you need to dig into the libraries.
If you have "Enable Just My Code" checked then, when you step into code, you will get a dialog asking if you want to download the source. It is possible to set breakpoints in the downloaded source as well.
Projects within a bundle must use Project References when depending on each other. When doing so, developers must be careful, and seriously consider the best modularization of code into projects, and the impact it has on dependencies.
However, preferable only packages that has changes are actually published, and hence requires an updated version. If only the tests, or *.md
files for a package has changes, then the package should not have to be published.
All packages must start with Energinet.DataHub.Core
in their output name, namespace and package id.
Consider using shorter project file names and folders (see TestCommon example), and instead ensure to set the full names using project properties:
<PropertyGroup>
<AssemblyName>Energinet.DataHub.Core.MyPackageName</AssemblyName>
<RootNamespace>Energinet.DataHub.Core.MyPackageName</RootNamespace>
...
<PackageId>Energinet.DataHub.Core.MyPackageName</PackageId>
</PropertyGroup>
In all packages we should aim for documenting types using XML documentation comments.
When a new package is added to the repository, it is important that the project file has the necessary properties for the new package.
Example of what project properties that should be set:
<PropertyGroup>
<PackageId>Energinet.DataHub.Core.(library_name).(package_name)</PackageId>
<PackageVersion>1.0.0$(VersionSuffix)</PackageVersion>
<Title>insert_title</Title>
<Company>Energinet-DataHub</Company>
<Authors>Energinet-DataHub</Authors>
<PackageProjectUrl>https://github.com/Energinet-DataHub</PackageProjectUrl>
<RepositoryUrl>https://github.com/Energinet-DataHub/geh-core</RepositoryUrl>
<!-- PackageReleaseNotes:
Is shown in Azure DevOps artifacts Release Notes section.
-->
<PackageReleaseNotes>
[Release Notes](https://github.com/Energinet-DataHub/geh-core/blob/master/source/(library_name)/documents/release-notes/release-notes.md)
[Documentation](https://github.com/Energinet-DataHub/geh-core/blob/master/source/(library_name)/documents/documentation.md)
</PackageReleaseNotes>
<!-- PackageDescription:
Is shown in GitHub packages "About this package" section,
and in Visual Studio package manager view.
-->
<PackageDescription>
[Release Notes](https://github.com/Energinet-DataHub/geh-core/blob/master/source/(library_name)/documents/release-notes/release-notes.md)
[Documentation](https://github.com/Energinet-DataHub/geh-core/blob/master/source/(library_name)/documents/documentation.md)
</PackageDescription>
<Description>package_description</Description>
<PackageTags>energinet;datahub</PackageTags>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
</PropertyGroup>
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
<!-- Disable warning on your public types/methods for not having added full documentation tags -->
<NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>
We use SourceLink
to allow debugging.
Install nuget package: Microsoft.SourceLink.GitHub
Add the following properties in the project file:
<!-- Enable Source Link (https://github.com/dotnet/sourcelink/blob/master/README.md) -->
<PropertyGroup>
<!-- Publish the repository URL in the built .nupkg (in the NuSpec <Repository> element) -->
<PublishRepositoryUrl>true</PublishRepositoryUrl>
</PropertyGroup>