Sharpliner 1.4.12

.NET 5.0
dotnet add package Sharpliner --version 1.4.12
NuGet\Install-Package Sharpliner -Version 1.4.12
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Sharpliner" Version="1.4.12" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Sharpliner --version 1.4.12
#r "nuget: Sharpliner, 1.4.12"
#r directive can be used in F# Interactive, C# scripting and .NET Interactive. Copy this into the interactive tool or source code of the script to reference the package.
// Install Sharpliner as a Cake Addin
#addin nuget:?package=Sharpliner&version=1.4.12

// Install Sharpliner as a Cake Tool
#tool nuget:?package=Sharpliner&version=1.4.12

Sharpliner is a .NET library that lets you use C# for Azure DevOps pipeline definition instead of YAML. Exchange YAML indentation problems for the type-safe environment of C# and let the intellisense speed up your work!

Getting started

All you have to do is reference our NuGet package in your project, override a class with your definition and dotnet build the project! Dead simple!

For more detailed steps, check our documentation.

Example

// Just override prepared abstract classes and `dotnet build` the project, nothing else is needed!
// For a full list of classes you can override
//    see https://github.com/sharpliner/sharpliner/blob/main/src/Sharpliner/AzureDevOps/PublicDefinitions.cs
// You can also generate collections of definitions dynamically
//    see https://github.com/sharpliner/sharpliner/blob/main/docs/AzureDevOps/DefinitionCollections.md
class PullRequestPipeline : SingleStagePipelineDefinition
{
    // Say where to publish the YAML to
    public override string TargetFile => "eng/pr.yml";
    public override TargetPathType TargetPathType => TargetPathType.RelativeToGitRoot;

    public override SingleStagePipeline Pipeline => new()
    {
        Pr = new PrTrigger("main"),

        Variables =
        {
            // YAML ${{ if }} conditions are available with handy macros that expand into the
            // expressions such as comparing branch names. We also have "else"
            If.IsBranch("net-6.0")
                .Variable("DotnetVersion", "6.0.100")
                .Group("net6-keyvault")
            .Else
                .Variable("DotnetVersion", "5.0.202"),
        },

        Jobs =
        {
            new Job("Build")
            {
                Pool = new HostedPool("Azure Pipelines", "windows-latest"),
                Steps =
                {
                    // Many tasks have helper methods for shorter notation
                    DotNet.Install.Sdk(variables["DotnetVersion"]),

                    // You can also specify any pipeline task in full too
                    Task("DotNetCoreCLI@2", "Build and test") with
                    {
                        Inputs = new()
                        {
                            { "command", "test" },
                            { "projects", "src/MyProject.sln" },
                        }
                    },

                    // Frequently used ${{ if }} statements have readable macros
                    If.IsPullRequest
                        // You can load script contents from a .ps1 file and inline them into YAML
                        // This way you can write scripts with syntax highlighting separately
                        .Step(Powershell.FromResourceFile("New-Report.ps1", "Create build report")),
                }
            }
        },
    };
}

Sharpliner features

Apart from the obvious benefits of using static type language with IDE support, not having to have to deal with indentation problems ever again, being able to split the code easily or the ability to generate YAML programatically, there are several other benefits of using Sharpliner.

Intellisense

One of the best things when using Sharpliner is that you won't have to go the YAML reference every time you're adding a new piece of your pipeline. Having everything strongly typed will make your IDE give you hints all the way!

Example intellisense for pipeline variables

Nice APIs

Imagine you want to install the .NET SDK. For that, Azure Pipelines have the DotNetCoreCLI@2 task. However, this task's specification is quite long since the task does many things:

# .NET Core
# Build, test, package, or publish a dotnet application, or run a custom dotnet command
# https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops
- task: DotNetCoreCLI@2
  inputs:
    command: 'build' # Options: build, push, pack, publish, restore, run, test, custom
    publishWebProjects: true # Required when command == Publish
    projects: # Optional
    custom: # Required when command == Custom
    arguments: # Optional
    publishTestResults: true # Optional
    testRunTitle: # Optional
    zipAfterPublish: true # Optional
    versioningScheme: 'off' # Options: off, byPrereleaseNumber, byEnvVar, byBuildNumber
    versionEnvVar: # Required when versioningScheme == byEnvVar
    majorVersion: '1' # Required when versioningScheme == ByPrereleaseNumber
    minorVersion: '0' # Required when versioningScheme == ByPrereleaseNumber
    patchVersion: '0' # Required when versioningScheme == ByPrereleaseNumber
    buildProperties: # Optional
    verbosityPack: 'Detailed' # Options: -, quiet, minimal, normal, detailed, diagnostic
    workingDirectory:

Notice how some of the properties are only valid in a specific combination with other. With Sharpliner, we remove some of this complexity using nice fluent APIs:

DotNet.Install.Sdk(parameters["version"]),

DotNet.Restore.FromFeed("dotnet-7-preview-feed", includeNuGetOrg: false) with
{
    ExternalFeedCredentials = "feeds/dotnet-7",
    NoCache = true,
    RestoreDirectory = ".packages",
},

DotNet.Build("src/MyProject.csproj") with
{
    Timeout = TimeSpan.FromMinutes(20)
},

Useful macros

Some very common pipeline patterns such as comparing the current branch name or detecting pull requests are very cumbersome to do in YAML (long conditions full of complicated ${{ if }} syntax). For many of these, we have handy macros so that you get more readable and shorter code.

For example this YAML

${{ if eq(variables['Build.SourceBranch'], 'refs/heads/production') }}:
    name: rg-suffix
    value: -pr
${{ if ne(variables['Build.SourceBranch'], 'refs/heads/production') }}:
    name: rg-suffix
    value: -prod

can become this C#

If.IsBranch("production")
    .Variable("rg-suffix", "-pr")
.Else
    .Variable("rg-suffix", "-prod")

Re-usable pipeline blocks

Sharpliner lets you re-use code more easily than YAML templates do. Apart from obvious C# code re-use, you can also define sets of C# building blocks and re-use them in your pipelines:

class ProjectBuildSteps : StepLibrary
{
    public override List<Conditioned<Step>> Steps => new()
    {
        DotNet.Install.Sdk("6.0.100"),

        If.IsBranch("main")
            .Step(DotNet.Restore.Projects("src/MyProject.sln")),

        DotNet.Build("src/MyProject.sln"),
    };
}

You can then reference this library in between build steps and it will get expanded into the pipeline's YAML:

...
    new Job("Build")
    {
        Steps =
        {
            Script.Inline("echo 'Hello World'"),

            StepLibrary<ProjectBuildSteps>(),

            Script.Inline("echo 'Goodbye World'"),
        }
    }
...

More about this feature can be found here (DefinitionLibraries.md).

Sourcing scripts from files

When you need to add cmd, PowerShell or bash steps into your pipeline, mainatining these bits inside YAML can be error prone. With Sharpliner you can keep scripts in their own files (.ps1, .sh..) where you get the natural environment you're used to such as syntax highlighting. Sharpliner gives you APIs to load these on build time and include them inline:

Steps =
{
    Bash.FromResourceFile("embedded-script.sh") with
    {
        DisplayName = "Run post-build clean-up",
        Timeout = TimeSpan.FromMinutes(5),
    }
}

Correct variable/parameter types

Frequent struggle people have with Azure pipelines is using the right type of variable in the right context. Be it a ${{ compile time parameter }}, a variable['used in runtime'] or a $(macro) syntax, with Sharpliner you won't have to worry about which one to pick as it understands the context and selects the right one for you.

Pipeline validation

Your pipeline definition can be validated during publishing and you can uncover issues, such as typos inside dependsOn, you would only find by trying to run the pipeline in CI. This gives you a faster dev loop and greater productivity.

We are continuosly adding new validations as we find new error-prone spots. Each validation can be individually configured/silenced in case you don't wish to take advantage of these:

class YourCustomConfiguration : SharplinerConfiguration
{
    public override void Configure()
    {
        // You can set severity for various validations
        Validations.DependsOn = ValidationSeverity.Off;
        Validations.Name = ValidationSeverity.Warning;

        // You can also further customize serialization
        Serialization.PrettifyYaml = false;
        Serialization.UseElseExpression = true;
        Serialization.IncludeHeaders = false;

        // You can add hooks that execute during the publish process
        Hooks.BeforePublish = (definition, path) => {};
        Hooks.AfterPublish = (definition, path) => {};
    }
}
Product Versions
.NET net5.0 net5.0-windows net6.0 net6.0-android net6.0-ios net6.0-maccatalyst net6.0-macos net6.0-tvos net6.0-windows net7.0 net7.0-android net7.0-ios net7.0-maccatalyst net7.0-macos net7.0-tvos net7.0-windows
Compatible target framework(s)
Additional computed target framework(s)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories (1)

Showing the top 1 popular GitHub repositories that depend on Sharpliner:

Repository Stars
sharpliner/sharpliner
Use C# instead of YAML to define your Azure DevOps pipelines
Version Downloads Last updated
1.4.12 47 1/31/2023
1.4.11 46 1/31/2023
1.4.10 62 1/30/2023
1.4.9 124 12/29/2022
1.4.8 147 11/20/2022
1.4.7 1,215 10/28/2022
1.4.6 175 10/28/2022
1.4.5 224 10/18/2022
1.4.4 239 9/16/2022
1.4.3 226 9/7/2022
1.4.2 225 9/1/2022
1.4.1 223 8/31/2022
1.3.7 225 8/26/2022
1.3.6 248 8/14/2022
1.3.5 256 7/11/2022
1.3.4 272 5/13/2022
1.3.3 305 4/17/2022
1.3.2 253 4/3/2022
1.3.1 349 3/15/2022
1.3.0 260 3/13/2022
1.2.9 280 3/5/2022
1.2.8 263 2/26/2022
1.2.7 272 2/17/2022
1.2.6 2,888 2/14/2022
1.2.5 265 2/11/2022
1.2.4 200 12/15/2021
1.2.3 193 12/5/2021
1.2.1 1,478 11/28/2021
1.2.0 1,222 11/28/2021
1.1.2 5,334 11/23/2021
1.1.1 233 11/18/2021
1.1.0 225 11/15/2021
1.0.2 250 11/8/2021
1.0.0 301 11/6/2021
0.3.9 250 11/4/2021
0.3.8 236 11/1/2021
0.3.7 268 10/24/2021
0.3.6 314 10/20/2021
0.3.5 248 10/20/2021
0.3.4 249 10/17/2021
0.3.3 292 10/16/2021
0.3.2 252 10/14/2021
0.3.1 210 10/14/2021
0.3.0 252 10/14/2021
0.2.2 235 8/30/2021
0.2.1 256 8/22/2021
0.2.0 248 8/22/2021
0.1.1 355 7/24/2021
0.1.0 268 7/24/2021