How can cake build arguments be documented?
Asked Answered
D

1

5

In a cake build script there is a very neat way of documenting the tasks using the .Description() extension on the Task. These descriptions are displayed when calling the build script with the -showdescription argument.

I have several custom arguments in my build script that I'd like to document somehow. Currently I added a task that outputs a description text similar to the manual page style for the available arguments that looks something like this:

var nextLineDescription = "\n\t\t\t\t\t"; // for formatting 
Console.WriteLine("ARGUMENTS");
Console.WriteLine("");

Console.WriteLine("\t--someparameter=<number>\t\t" +
                "Description of the parameter" + nextLineDescription +
                "that can span multiple lines" + nextLineDescription +
                "and defaults to 5.\n");

This works fine but is a lot of work, especially if the text should be properly formatted so it's readable in the command line.

So when I call ./build.ps1 -Target MyDocTask I get a nice result:

ARGUMENTS

        --someparameter=number          Description of the parameter
                                        that can span multiple lines
                                        and defaults to 5

        --nextParameter                 Next description

...

Is there another way or a best practice to add documentation for arguments so it can be displayed in the command line similar to the tasks descriptions?

Edit: Alternatively, can I find all available parameters in my build script to loop over them and generate such a description instead of writing it manually for each parameter?

Dicotyledon answered 31/7, 2017 at 10:34 Comment(1)
I'm writing as comment because you specifically asked about Cake. However, Nuke provides this as a feature: nuke.build/command-line.html (I am the maintainer).Redd
W
6

There's currently no built-in feature for "registering" arguments for help, would be an great addition though so please raise an issue about that.

That said it can be achieved, as Cake is just .NET you could utilize one of the command line parsers available on NuGet to achieve this. One such parser is CommandLineParser.

Assemblies can be references from NuGet using the #addin directive, for CommandLineParser it looks below

#addin "nuget:?package=CommandLineParser&version=2.1.1-beta&prerelease=true"

As it's not an "native" Cake addin you'll need to use fully qualified type names or just like regular C# add a using statement like this

using CommandLine;

CommandLineParser uses a class and attributes on the properties to provide rules and help. Porting your example below would look something like below

class Options
{
    [Option("someparameter",
        HelpText = "Description of the parameter, that can span multiple lines",
        Default = 5)]
    public int SomeParameter { get; set; }

    [Option("nextParameter", HelpText = "Next description")]
    public string NextParameter { get; set; }

    [Option("target", HelpText = "Target", Default = "Default")]
    public string Target { get; set; }
}

Normally CommandLineParser will output help to the console, but if you want to display it in a task, you can capture the output with a TextWriter

var helpWriter = new StringWriter();
var parser = new Parser(config => config.HelpWriter = helpWriter);

Then parsing arguments and if "MyDocTask" is specified render help to the helpWriter

Options options = parser
    .ParseArguments<Options>(
        StringComparer.OrdinalIgnoreCase.Equals(Argument("target", "Default"), "MyDocTask")
            ? new []{ "--help" }
            : System.Environment.GetCommandLineArgs()
    )
    .MapResult(
        o => o,
        errors=> new Options { Target = "MyDocTask"} // TODO capture errors here
);

and tasks

Task("MyDocTask")
    .Does(() => {
        Information(helpWriter.ToString());
}
);

Task("Default")
    .Does(() => {
        Information("SomeParameter: {0}", options.SomeParameter);
        Information("NextParameter: {0}", options.NextParameter);
        Information("Target: {0}", options.Target);
}
);

then executed

RunTarget(options.Target);

The MyDocTask will output the help

>> cake .\commandline.cake --Target="MyDocTask"

========================================
MyDocTask
========================================
Cake 0.20.0+Branch.main.Sha.417d1eb9097a6c71ab25736687162c0f58bbb74a
Copyright (c) .NET Foundation and Contributors

  --someparameter    (Default: 5) Description of the parameter, that can span multiple lines

  --nextParameter    Next description

  --target           (Default: Default) Target

  --help             Display this help screen.

  --version          Display version information.

and Default task will just output values of the parsed arguments

>> cake .\commandline.cake

========================================
Default
========================================
SomeParameter: 5
NextParameter: [NULL]
Target: Default

Task                          Duration
--------------------------------------------------
Default                       00:00:00.0133265
--------------------------------------------------
Total:                        00:00:00.0133265

This will give you strongly typed and documented arguments in a fairly easy way.

The complete Cake script below:

#addin "nuget:?package=CommandLineParser&version=2.1.1-beta&prerelease=true"
using CommandLine;
class Options
{
    [Option("someparameter",
        HelpText = "Description of the parameter, that can span multiple lines",
        Default = 5)]
    public int SomeParameter { get; set; }

    [Option("nextParameter", HelpText = "Next description")]
    public string NextParameter { get; set; }

    [Option("target", HelpText = "Target", Default = "Default")]
    public string Target { get; set; }
}

var helpWriter = new StringWriter();
var parser = new Parser(config => config.HelpWriter = helpWriter);

    Options options = parser
        .ParseArguments<Options>(
            StringComparer.OrdinalIgnoreCase.Equals(Argument("target", "Default"), "MyDocTask")
                ? new []{ "--help" }
                : System.Environment.GetCommandLineArgs()
        )
        .MapResult(
            o => o,
            errors=> new Options { Target = "MyDocTask"} // could capture errors here
    );


    Task("MyDocTask")
        .Does(() => {
            Information(helpWriter.ToString());
    }
    );

    Task("Default")
        .Does(() => {
            Information("SomeParameter: {0}", options.SomeParameter);
            Information("NextParameter: {0}", options.NextParameter);
            Information("Target: {0}", options.Target);
    }
    );


RunTarget(options.Target);
Wineglass answered 31/7, 2017 at 12:42 Comment(4)
Thanks for this detailed description. It seems like a nice option. I just played around with it and it looks good when using the cake executable directly. When using the bootstrap powershell file, then it calle cake with explicitly named parameters -target -configuration -verbosity. Note that it is called with only one -. This causes the CommandLineParser to always go to the error path because it says that parameters t,c and v are not found. It expects the parameters with double dash. As suggested I created an issue for cake directly: github.com/cake-build/cake/issues/1708Dicotyledon
Actually cake supports double dash too and likely what will be standard in future, double dash for full command and single for short i.e. -t or --targetWineglass
Yeah, I use double dashes for my custom parameters also. I just wanted to hint, that the powershell script uses the single dashes atm. :)Dicotyledon
so you could change the bootrapper to do --target --configuration --verbosity and everything would still work.Wineglass

© 2022 - 2024 — McMap. All rights reserved.