Announcing Petabridge.Templates 2.0 - Professional Akka.NET Application and Library Templates
Ready-made Akka.NET application and library dotnet new templates for creating professional-quality projects!
We’ve prepared a set of three professional-grade dotnet new
templates (Petabridge.Templates
) for use with your projects - these will help you get started right away with Akka.NET or developing your own NuGet libraries that you wish to distribute. We’ve built and maintained these for years in order to create our own internal and external projects here at Petabridge.
But first, I should probably tell you a personal story, about how I improved the professionalism on my projects with build automation. Before I had the opportunity to work on a build system, I have always known the advantage of them and envied projects that had them.
On Twitter I read tweets from different .NET developers about creating a powerful build automations; I felt like it was a rocket science and secretly wished to be doing something like that. I was stuck, I needed a boost to move me out of that state.
For instance, my first ever NuGet package was released from my machine using NuGet CLI and the unit tests were executed manually, locally. For an open source project, you want to be very transparent and one way to do that is to have a build automation setup that everyone can see!
In late 2020, I was given an opportunity to work on Akka.NET’s build system; and, “Ah, may the force be with me”, I exclaimed! That was the opportunity I needed to get into the world of build automation - that was the force I needed! That force has remained with me ever since!
Maybe I “Was” You!
When it comes to creating professional grade software, you may belong to the category of developers who know what it takes but aren’t sure about the best practices or how to learn them. You want to write unit tests, add documentation, automate builds, but need an example to work from - Petabridge.Templates
, which we’re releasing 2.0 of today, is that example.
The goal of Petabridge.Templates
is to help you get started with a “best practices” .NET project structures quickly.
To install these templates, you’ll need to use the dotnet
command line:
dotnet new -i "Petabridge.Templates::*"
This will make all of the templates included in this package (read on) available as options via the dotnet new
command.
What Is Petabridge.Templates
?
.NET Core brought about some dramatic tooling changes to the typical .NET experience with heavy emphasis now placed on the dotnet
command line. .NET Core was created to be cross-platform and the command line is a great fit for this purpose. dotnet new
is part of dotnet
CLI - the entry point to all of .NET core goodness, which is mainly used to create projects driven from existing templates like console
(console
templates provide the ability to create a console application from the dotnet new
command).
Petabridge.Templates
is a collection of open source dotnet new
templates maintained by Petabridge - and they’re designed for use by Petabridge’s own teams and end-users to create professional grade libraries, Akka.Cluster applications, and Akka.Cluster + ASP.NET integrations:
pb-lib
- a professional .NET 6 project setup including build scripts, documentation, unit tests, and performance tests for a class library project.pb-akka-cluster
- creates a headless .NET 6 service that includes full Akka.NET clustering support, and Docker support.pb-akka-web
- does the same aspb-akka-cluster
, but hosts Akka.NET inside an ASP.NET Core 6 simple web application.
You can read more about how these templates work by clicking on “source link” and reading the README.md
for each individual project.
To use one of these templates, you can use the dotnet new
command followed by the name or short-name.
dotnet new pb-lib [-n name] [other arguments]
So for instance, if I execute dotnet new pb-lib -n "MyProject"
the following output will appear in my working directory:
D:\MyProject\.nuke
D:\MyProject\build.cmd
D:\MyProject\build.ps1
D:\MyProject\build.sh
D:\MyProject\MyProject.sln
D:\MyProject\README.md
D:\MyProject\CHANGELOG.md
D:\MyProject\gitversion.yml
D:\MyProject\build
D:\MyProject\build\_build.csproj
D:\MyProject\build\Build.CI.GitHubActions.cs
D:\MyProject\build\Build.cs
D:\MyProject\build\Configuration.cs
D:\MyProject\build\Directory.Build.props
D:\MyProject\build\Directory.Build.targets
D:\MyProject\docs
D:\MyProject\docs\api
D:\MyProject\docs\articles
D:\MyProject\docs\docfx.json
D:\MyProject\docs\images
D:\MyProject\docs\index.md
D:\MyProject\docs\toc.yml
D:\MyProject\docs\api\index.md
D:\MyProject\docs\articles\index.md
D:\MyProject\docs\articles\toc.yml
D:\MyProject\docs\images\icon.png
D:\MyProject\src
D:\MyProject\src\Directory.Build.props
D:\MyProject\src\MyProject
D:\MyProject\src\MyProject.Tests
D:\MyProject\src\MyProject.Tests.Performance
D:\MyProject\src\MyProject\Class1.cs
D:\MyProject\src\MyProject\MyProject.csproj
D:\MyProject\src\MyProject.Tests\MyProject.Tests.csproj
D:\MyProject\src\MyProject.Tests\UnitTest1.cs
D:\MyProject\src\MyProject.Tests.Performance\MyProject.Tests.Performance.csproj
D:\MyProject\src\MyProject.Tests.Performance\UnitTest1.cs
I’ll have a new .NET 6 library project complete with a cross-platform build system, documentation, unit tests, performance tests, and a README explaining how all of the above work ready to go from day one.
What’s Included?
Each templates within Petabridge.Templates
has a build automation setup with it for GitHub Actions - and the templates have the following benefits:
- Robust .NET Solution Hygiene - all dependency versions are synchronized across all projects using
Directory.Build.props
, as are .NET runtime versions, version data, and project metadata. - Easy Version Management - to bump the version on a NuGet package or Docker image, simply update the
RELEASE_NOTES.md
with your new version number (SemVer is supported) and run the appropriate build action either locally or on GitHub Actions. - Testing - each template has a standardized convention for discovering and running xUnit test projects.
- Documentation: -you can generate DocFx documentation in a single command.
- Benchmarks - each template has a performance project for writing and executing performance tests.
- NuGet Publication - for the
pb-lib
template the build script has aPublishNuget
with which NuGet packages can be built and published. - Code Signing - for the
pb-lib
template only, we have built-in support for using SignService to Authenticode sign NuGet packages with a certificate prior to NuGet publication. This is an optional step in thePublishNuGet
build step. - Docker Image Creation - for the
pb-akka-cluster
andpb-akka-web
templates we support automatically discoveringDockerfile
instances anddotnet publish
-ing the binaries for your applications and then executing the pre-baked build instructions inside theDockerfile
. Uses the version data from theRELEASE_NOTES.md
. - Shovel-Ready Akka.NET - the
pb-akka-cluster
andpb-akka-web
templates are built with Akka.NET hosting best practices from the start, so no guesswork needed to get up and running.
The previous version, 1.2.0, and earlier build automation was built on FAKE. In version 2, we rewrote the build automation from scratch, replacing FAKE with NUKE. Let me have a good laugh before saying this😂: for those that like tech wars, in this case FAKE vs NUKE, 14 reasons for adopting Nuke as your next build automation tool, will be a good use of your time!
When we decided to adopt NUKE, it was for two reasons and two reasons only (Nuke Build support). The sum, of the two reasons, is to greatly improve developers’ experience:
- The cross-platform build automation solution for .NET with C# DSL: What this mean is C# developer can start automating builds almost immediately. With FAKE, aside learning how to use it, there is also the burden of having to learn F# first.
- Overcoming YAML hell: NUKE can generates the CI (TeamCity, Azure Pipelines, AppVeyor, GitHub Actions and more) configuration from the C# build implementation itself.
You can start using these templates right away - but if you’re curious to learn more about how they’re implemented, read on!
For Geeks: Implementation Details
C# DSL
In the past, we used FAKE 4 - which is an F#-based build system.
Our syntax for running a project’s unit tests before looked like this:
Target "RunTests" (fun _ ->
let projects =
match (isWindows) with
| true -> !! "./src/**/*.Tests.csproj"
| _ -> !! "./src/**/*.Tests.csproj" // if you need to filter specs for Linux vs. Windows, do it here
let runSingleProject project =
let arguments =
match (hasTeamCity) with
| true -> (sprintf "test -c Release --no-build --logger:trx --logger:\"console;verbosity=normal\" --results-directory %s -- -parallel none -teamcity" (outputTests))
| false -> (sprintf "test -c Release --no-build --logger:trx --logger:\"console;verbosity=normal\" --results-directory %s -- -parallel none" (outputTests))
let result = ExecProcess(fun info ->
info.FileName <- "dotnet"
info.WorkingDirectory <- (Directory.GetParent project).FullName
info.Arguments <- arguments) (TimeSpan.FromMinutes 30.0)
ResultHandling.failBuildIfXUnitReportedError TestRunnerErrorLevel.Error result
projects |> Seq.iter (log)
projects |> Seq.iter (runSingleProject)
)
Now, it looks like this using NUKE and C#:
Target RunTests => _ => _
.Description("Runs all the unit tests")
.DependsOn(Compile)
.Executes(() =>
{
var projects = Solution.GetProjects("*.Tests");
foreach (var project in projects)
{
Information($"Running tests from {project}");
foreach (var fw in project.GetTargetFrameworks())
{
Information($"Running for {project} ({fw}) ...");
DotNetTest(c => c
.SetProjectFile(project)
.SetConfiguration(Configuration.ToString())
.SetFramework(fw)
.SetResultsDirectory(OutputTests)
.SetProcessWorkingDirectory(Directory.GetParent(project).FullName)
.SetLoggers("trx")
.SetVerbosity(verbosity: DotNetVerbosity.Normal)
.EnableNoBuild());
}
}
});
Auto-Generation of YAML
Suppose we have the following C# in our NUKE files:
[CustomGitHubActions("pr_validation",
GitHubActionsImage.WindowsLatest,
GitHubActionsImage.UbuntuLatest,
AutoGenerate = true,
OnPushBranches = new[] { "master", "dev" },
OnPullRequestBranches = new[] { "master", "dev" },
InvokedTargets = new[] { nameof(All) },
PublishArtifacts = true,
EnableGitHubContext = true)
]
The code above will generate the build configuration YAML below. This is what comes out of the box with the templates.
# ------------------------------------------------------------------------------
# <auto-generated>
#
# This code was generated.
#
# - To turn off auto-generation set:
#
# [CustomGitHubActions (AutoGenerate = false)]
#
# - To trigger manual generation invoke:
#
# nuke --generate-configuration GitHubActions_pr_validation --host GitHubActions
#
# </auto-generated>
# ------------------------------------------------------------------------------
name: pr_validation
on:
push:
branches:
- master
- dev
pull_request:
branches:
- master
- dev
jobs:
windows-latest:
name: windows-latest
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- name: Make build.sh executable
run: chmod +x ./build.sh
- name: Make build.cmd executable
run: chmod +x ./build.cmd
- uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.*
- uses: actions/setup-dotnet@v1
with:
dotnet-version: 6.0.*
- name: Cache .nuke/temp, ~/.nuget/packages
uses: actions/cache@v2
with:
path: |
.nuke/temp
~/.nuget/packages
key: $-$
- name: Run './build.cmd All'
run: ./build.cmd All
env:
GITHUB_CONTEXT: $
ubuntu-latest:
name: ubuntu-latest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Make build.sh executable
run: chmod +x ./build.sh
- name: Make build.cmd executable
run: chmod +x ./build.cmd
- uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.*
- uses: actions/setup-dotnet@v1
with:
dotnet-version: 6.0.*
- name: Cache .nuke/temp, ~/.nuget/packages
uses: actions/cache@v2
with:
path: |
.nuke/temp
~/.nuget/packages
key: $-$
- name: Run './build.cmd All'
run: ./build.cmd All
env:
GITHUB_CONTEXT: $
Extending the Default Build Configuration
The above code will generate GitHub workflow configuration for Windows
and Ubuntu
OSes. What if you want to run pr_validation
on MacOS
too? Well you can as shown below (AutoGenerate
is false
by default):
[CustomGitHubActions("pr_validation",
.........
GitHubActionsImage.MacOsLatest,
AutoGenerate = true,
.........)
]
This will generate a build configuration for MacOS
if I run build.cmd compile
in the root folder, the build configuration will be update:
.....................................
macOS-latest:
name: macOS-latest
runs-on: macOS-latest
steps:
- uses: actions/checkout@v1
- name: Make build.sh executable
run: chmod +x ./build.sh
- name: Make build.cmd executable
run: chmod +x ./build.cmd
- uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.*
- uses: actions/setup-dotnet@v1
with:
dotnet-version: 6.0.*
- name: Cache .nuke/temp, ~/.nuget/packages
uses: actions/cache@v2
with:
path: |
.nuke/temp
~/.nuget/packages
key: $-$
- name: Run './build.cmd All'
run: ./build.cmd All
env:
GITHUB_CONTEXT: $
Conclusion
Our aim with this release is to improve developers experience when working with Petabridge.Templates
- and we are just getting started. We open to suggestion and requests for additional templates. Please file an issue or a suggestion here: https://github.com/petabridge/petabridge-dotnet-new
- Read more about:
- Akka.NET
- Case Studies
- Videos
Observe and Monitor Your Akka.NET Applications with Phobos
Did you know that Phobos can automatically instrument your Akka.NET applications with OpenTelemetry?
Click here to learn more.