Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can cake build arguments be documented?

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?

like image 879
Philipp Grathwohl Avatar asked Jul 31 '17 10:07

Philipp Grathwohl


1 Answers

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);
like image 59
devlead Avatar answered Nov 09 '22 04:11

devlead