Using NUKE for Cross-Platform Build Scripts

Making Complex Build Scripts More Intuitive and Easier to Maintain

NUKE is the most intuitive and productive build automation system for C#/.NET that runs cross-platform on .NET Core, .NET Framework, and Mono.

Ever had to rig up a build script that felt more like a Rube Goldberg machine. Build this project, run this script, move these files, now publish that site, reset the app pool and then upload some changes, etc. In a good CI server it may be as simple as putting in the steps one by one, and then hitting save. The display shows what will happen and the build server does the rest. But what happens when the build server goes down and someone needs to manually push a change?

In comes NUKE build scripts to save the day. The runner is packaged as a dotnet tool. It runs your builds using a series of libraries and console applications written in pure .Net. And the build scripts you write in it are just .Net console applications. This means your build scripts can live in your solution, in your source control repo, and in your IDE. No more worrying if that syntax was right or switching context for msbuild tasks.

Define Targets and their relationships that are executed.

    Target BuildProject => _ => _
        .DependsOn(Restore)
        .Executes(() =>
        {
            DotNetBuild(s => s
                .SetProjectFile(Solution)
                .SetConfiguration(Configuration)
                .SetAssemblyVersion(GitVersion.AssemblySemVer)
                .SetFileVersion(GitVersion.AssemblySemFileVer)
                .SetInformationalVersion(GitVersion.InformationalVersion)
                .EnableNoRestore()
                .SetProperty("PackageVersion", GitVersion.NuGetVersionV2));
        });
//... any other tasks such as Restore

public static int Main() => Execute<Build>(x => x.BuildProject);

One of my own personal uses is setting up or resetting testing environment resources (copying/deleting/downloading files or publishing websites) prior to running the build and it's tests.

The Nuclear Option

You have the option of getting rid of most of your CI server's build scripts and rewriting everything in C#. Changes to the build scripts can go through code review and slow steps or things that can be done in parallel can be handled just as you would when optimizing any other piece of code.

If you're still stuck on a legacy build server like Cruise Control. NUKE can offer a way around the many limitations imposed by those systems reducing the entire script down to a readable glob of C#.

Only For Manual Builds

Not ready to switch things over entirely? You can write up build scripts for individuals to use when testing their code or when a special deploy is needed. Perhaps it's currently a manual process that you don't want eating up your build server minutes? Save those minutes and avoid downtime and human errors with a reliably engineered build script.

Open Source Projects

Open Source projects greatly benefit from having a simple build script. Not having to look up msbuild options and download specific resources prior to a build can make things much easier for new contributors. In fact the .Net Foundation requires a reproducible build script:

The project contains a build script that can produce deployable artifacts that are identical to the official deployable artifacts, with the exception of code signing (Exception may be granted for strong name keys, though strongly encouraged to be committed. Exception relies on OSS signing being in the build script for public builds).

This can be especially important for testing as well. If you require them to run all the applicable tests prior to merging a PR (and you don't have a CI option that will run their PR for you) you can provide a target through NUKE that enables running the scripts first and eases your confirmation of this result.

The Catch

Currently NUKE does not inherently support parallel build targets (see PR 526 and Issue 162 ). To get something in paralle you will need to use a feature such as tasks to do this:

    Target Build => _ => _
        .DependsOn(Restore)
        .Executes(() =>
        {
            var BuildTask = Task.Run(() => DotNetBuild(s => s
                .SetProjectFile(Solution)
                .SetConfiguration(Configuration)
                .SetAssemblyVersion(GitVersion.AssemblySemVer)
                .SetFileVersion(GitVersion.AssemblySemFileVer)
                .SetInformationalVersion(GitVersion.InformationalVersion)
                .EnableNoRestore()
                .SetProperty("PackageVersion", GitVersion.NuGetVersionV2)));

            var GetFilesForPublish = Task.Run(() => Task.Delay(5)); ///Some Arbitrary task that needs to happen before package can be deployed
            BuildTask.Wait();
            GetFilesForPublish.Wait();
        });

Support This Project

NUKE is provided as an Open Source project. If NUKE makes your life easier, consider sponsoring matkoch the maintainer.

Did you find this article valuable?

Support Curtis Carter by becoming a sponsor. Any amount is appreciated!