Building C# using C#
Having your own pet project gives you the great possibility to try things you would not want to explore in a serious project. One of my latest experiments made me rethink how I create build scripts (which I have mentioned before in a previous blog post): What if I would use C# as a "scripting language" in order to create a build script. Or even better: What if I could create a CLI tool which deals with all my build tasks? The advantages are rather nice:
- Using a single languages makes changing the build process as approachable as working on the main project itself
- I can use my IDE with all its features (e.g. a debugger)
- A command line interface makes it easy to pass variables into the build process
- I can install and use NuGet packages (e.g. commandlineparser to create CLIs)
Here's an example of a class which contains all command line interface verbs
such as clean
, build
, or test
. Most of the methods found in this class
simply call the git
or the dotnet
CLI with parameters. You can run the tool
using dotnet run
:
dotnet run --project MyProject.Build.csproj -- clean -c Debug dotnet run --project MyProject.Build.csproj -- build -c Debug dotnet run --project MyProject.Build.csproj -- clean dotnet run --project MyProject.Build.csproj -- build
Using dotnet run
to run a C# program which in turn calls dotnet build
to
build some other C# program might be weird in the beginning, but we can use
wrapper scripts in PowerShell or Bash to forget about these messy details.
Here's an example written in PowerShell:
$root = git rev-parse --show-toplevel if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } try { Push-Location $root $project = git ls-files '*.Build.csproj' if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } dotnet run --project $project -- $args if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } } finally { Pop-Location }
This script (let's call it make.ps1
) changes the above dotnet run
command to
something like this:
./make.ps1 clean ./make.ps1 build
You could even copy this script to a place which is in your PATH variable so
that you could call it from anywhere inside your project/repository. This is why
the above script changes the root directory using a call to git rev-parse
.
Some experiments give you an opportunity to learn. Some may end up nowhere. This one sparks joy. Well, at least for me.