Skip to content

Adding a CLI command

Ahmed ElSayed edited this page Aug 16, 2018 · 1 revision

The way the cli commands are structures are

func [context] [sub-context] <action> [options]

# [context], [sub-context] and [options] are optional
# <action> is required. 

For example:

say you want to add a command like func durable sync --version 3.5 --output csv --blah anotherValue

Then you need a class like

// The name is the [action] part on the command line
// Context and SubContext are also defined here if you need them.
// You can also alias commands by having multiple [Action] attributes
// For example if you want to also have `func durable show` to be an alias for this command
// you can just add
// [Action(Name = "show", Context = Context.Durable, HelpText = "")]
[Action(Name = "sync" Context = Context.Durable, HelpText = "This will show up in the help next to your command")]
class DurableSyncAction : IAction
{
    // I usually have actions define their properties public like this
    // That way actions can instantiate and run each others if needed
    // Some actions already do that, like extensions install, calling extensions sync after words
    public string Version { get; set; }

    public string Output { get; set; }

    public string Blah { get; set; }


    private readonly ISecretsManager _secretsManager;

    // The constructor supports DI for objects defined here https://github.com/Azure/azure-functions-core-tools/blob/master/src/Azure.Functions.Cli/Program.cs#L44
    public DurableSyncAction(ISecretsManager secretsManager)
    {
        _secretsManager = secretsManager;
    }

    // ParseArgs(string[] args) gets the args after action on the command line. 
    // So in the example below args is an array of [ "--version", "3.5", "--output", "csv", "--blah", "anotherValue" ]
    public ICommandLineParserResult ParseArgs(string[] args)
    {
        var parser = new FluentCommandLineParser();
        parser
            .Setup<string>("version")
            .WithDescription("This shows up in the help next to the version option.")
            .SetDefault(string.Empty)
            // This is a call back with the value you can use it however you like
            .Callback(v => Version = v);

        parser
            .Setup<string>("output")
            .WithDescription("")
            .SetDefault(string.Empty)
            .Callback(o => Output = o);

        parser
            .Setup<string>("blah")
            .WithDescription("")
            .SetDefault(string.Empty)
            .Callback(v => {});

        return parser.Parse(args);
    }

    public Task RunAsync()
    {
        return Task.CompletedTask;
    }
}

You can see the implementation of any action from the cli here I usually base all on the BaseAction class that sets up the parser. You don't have to use the parser, but it just keeps all the arguments consistent.

The help is built automatically from the attributes and ICommandLineParserResult.