Show / Hide Table of Contents

    CI Integration

    Eventually, builds are supposed to be executed in a continuous integration environment. That means that every push will trigger a build to verify committed changes. NUKE aims to seamlessly integrate with those CI systems, for instance by allowing to have typed access to environment variables, reporting warnings and errors in the required format, or publishing artifacts via method calls.

    Configuration Generation

    Supported for TeamCity, Azure Pipelines, AppVeyor, GitHub Actions.

    NUKE goes one step further and allows to conveniently generate the related configuration files, for instance YML files, by using configuration generation attributes. Typically, these attributes are applied to the build class:

    [TeamCity(
        TeamCityAgentPlatform.Windows,
        DefaultBranch = DevelopBranch,
        VcsTriggeredTargets = new[] { nameof(Pack), nameof(Test) },
        NightlyTriggeredTargets = new[] { nameof(Test) })]
    [AzurePipelines(
        AzurePipelinesImage.UbuntuLatest,
        AzurePipelinesImage.WindowsLatest,
        AzurePipelinesImage.MacOsLatest,
        InvokedTargets = new[] { nameof(Test), nameof(Pack) })]
    class Build : NukeBuild
    {
    }
    

    Using the nameof operator for targets and parameters ensures refactoring-safety and that the configuration files are always up-to-date with the actual implementation. After changing the build configuration (e.g., renaming targets), the build must be triggered once, for instance by calling nuke --help. If any of the configuration files have changed, a warning is reported:

    $ nuke --help
    
    NUKE Execution Engine version 1.0.0 (OSX,.NETStandard,Version=v2.0)
    
    Configuration files for TeamCity have changed.
    Configuration files for AzurePipelines have changed.
    
    Note

    In TeamCity, the Import settings from .teamcity/settings.kts option must be chosen during project creation. Afterwards, Versioned Settings must be enabled as follows: TeamCity Versioned Settings This approach still allows to apply manual changes to the configurations, like adding triggers, failure conditions, report tabs, and more. In this case, TeamCity will commit a patch file to .teamcity/patches in the repository.

    For TeamCity and Azure Pipelines, the generated configuration takes advantage of the target dependency model. That means that for every target, a separate build configuration (TeamCity) or job (Azure Pipelines) is created. This provides a better overview for individual target behavior:

    Azure Pipelines Stages

    Artifacts

    Supported for TeamCity, Azure Pipelines, AppVeyor, GitHub Actions.

    Usually, builds are supposed to publish some kind of artifacts, like NuGet packages or test results. Using the Produces call, artifact paths can be defined per target:

    Target Pack => _ => _
        .Produces(OutputDirectory / "*.nupkg")
        .Executes(() =>
        {
            DotNetPack(s => s
                .SetProject(Solution)
                .SetOutputDirectory(OutputDirectory));
        });
    

    Defining artifact paths with absolute paths is the recommended approach. In the resulting configuration files, they are automatically converted to relative paths.

    For multi-staged builds with TeamCity, a target can consume the artifacts from another target by using Produces and Consumes in combination:

    Target Restore => _ => _
        .Produces(SourceDirectory / "*/obj/**/*")
        .Executes(() =>
        {
        });
    
    Target Compile => _ => _
        .Consumes(Restore)
        .Executes(() =>
        {
        });
    

    Partitioning

    Supported for TeamCity, Azure Pipelines.

    Many targets are well-suited to be split into multiple partitions. For instance, think of a target that executes tests for several test assemblies. NUKE introduces an easy way to run those tests in parallel on different agents:

    [Partition(2)] readonly Partition TestPartition;
    
    Target Test => _ => _
        .DependsOn(Compile)
        .Partition(() => TestPartition)
        .Executes(() =>
        {
            var projects = Solution.GetProjects("*.Tests");
            var relevantProjects = TestPartition.GetCurrent(projects);        
            DotNetTest(s => s
                .SetConfiguration(Configuration)
                .CombineWith(
                    relevantProjects, (cs, v) => cs
                        .SetProjectFile(v)));
        });
    

    Adding the Partition attribute on the TestPartition field will automatically split the execution in to the specified amount of partitions. A partition can be associated with a target via Partition(() => Partition). Calling TestPartition.GetCurrent(enumerable) inside the target implementation returns only the relevant items for the current partition. In terms of configuration files, this is implemented by adding the --test-partition n parameter. For local executions, the TestPartition has a size of 1.

    In TeamCity, the resulting build chain would look like this:

    TeamCity Build Chain

    Parameters

    Supported for TeamCity.

    All properties and fields having the ParameterAttribute applied, will automatically be exposed to the Run Build Type dialog.

    TeamCity Dialog

    Required parameters are marked with red asterisks. Default values are read from the initializers. Enumeration parameters can be picked from a drop-down.

    Serialization

    Work in progress. This will allow state to be shared when targets are executed on different agents.

    Copyright © Matthias Koch
    MIT License
    Slack | Gitter | GitHub | Twitter
    Back to top