如何记录蛋糕构建参数?

How can cake build arguments be documented?

在蛋糕构建脚本中,使用任务的 .Description() 扩展可以非常简洁地记录任务。使用 -showdescription 参数调用构建脚本时会显示这些描述。

我的构建脚本中有几个自定义参数,我想以某种方式记录下来。目前我添加了一个任务,输出类似于 manual page style 的描述文本,用于看起来像这样的可用参数:

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");

这工作正常,但工作量很大,尤其是当文本格式应正确以便在命令行中可读时。

所以当我打电话给 ./build.ps1 -Target MyDocTask 我得到了一个不错的结果:

ARGUMENTS

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

        --nextParameter                 Next description

...

是否有另一种方法或最佳实践来为参数添加文档,以便它可以在类似于任务描述的命令行中显示?

编辑: 或者,我可以在我的构建脚本中找到所有可用的参数来遍历它们并生成这样的描述,而不是为每个参数手动编写吗?

"registering" 参数目前没有内置的功能来寻求帮助,这将是一个很好的补充,所以请提出一个问题。

也就是说可以实现,因为 Cake 只是 .NET,您可以利用 NuGet 上可用的命令行解析器之一来实现这一点。一种这样的解析器是 CommandLineParser.

程序集可以使用 #addin 指令从 NuGet 引用,对于 CommandLineParser,它看起来如下

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

因为它不是 "native" Cake 插件,所以您需要使用完全限定的类型名称,或者就像普通的 C# 添加这样的 using 语句

using CommandLine;

CommandLineParser 使用 class 和属性上的特性来提供规则和帮助。在下面移植您的示例将如下所示

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; }
}

通常 CommandLineParser 会输出帮助到控制台,但如果你想在任务中显示它,你可以使用 TextWriter

捕获输出
var helpWriter = new StringWriter();
var parser = new Parser(config => config.HelpWriter = helpWriter);

然后解析参数,如果指定了 "MyDocTask" 则将帮助渲染到 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
);

和任务

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);

MyDocTask会输出帮助

>> 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.

Default任务将只输出解析参数的值

>> cake .\commandline.cake

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

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

这将以相当简单的方式为您提供强类型和记录的参数。

下面是完整的 Cake 脚本:

#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);