Skip to content

v2.0.0

Compare
Choose a tag to compare
@mayuki mayuki released this 11 Jan 00:34
· 87 commits to master since this release
3f3f3ee

Features

Introduce Minimal API (#43, #45)

This release introduces ASP.NET Core-like Minimal API. It's an enhancement for .NET 6 and C# 10.

Minimal API supports most of the expressions that were possible with the previous Class-based style.
Please refer to the updated documentation for more details and see CoconaSample.MinimalApi.InAction.

CoconaApp.Run and CoconaApp.RunAsync

Run and RunAsync is a shortcut that makes it easy to build command line applications.

await CoconaApp.RunAsync((string? name) => Console.WriteLine($"Hello {(name ?? "Guest")}!"));

This is equivalent to the following code using Minimal API Builder.

var builder = CoconaApp.CreateBuilder(args);
var app = builder.Build();
app.AddCommand((string? name) => Console.WriteLine($"Hello {(name ?? "Guest")}!"));
app.Run();

CoconaApp.CreateBuilder() and CoconaApp.Create()

CreateBuilder and Create provide builders to configure services and register/configure multiple commands.

var builder = CoconaApp.CreateBuilder();
builder.Services.AddTransient<IMyService, MyService>();
builder.Configuration.AddJsonFile("path/to/additonalsettings.json");

var app = builder.Build();
app.AddCommand("hello", (string? name) => Console.WriteLine($"Hello {(name ?? "Guest")}!"));
app.AddSubCommand("server", x =>
{
    x.UseFilter(new RequirePrivilege());
    x.AddCommand("start", () => Console.WriteLine("Start"));
    x.AddCommand("stop", () => Console.WriteLine("Stop"));
});
app.AddSubCommand("client", x =>
{
    x.AddCommand("connect", () => Console.WriteLine("Connect"));
    x.AddCommand("disconnect", () => Console.WriteLine("Disconnect"));
});
app.AddComands<CommandType>();

await app.RunAsync();

Add a command and configure using the builder

var app = CoconaApp.Create(); // Shorthand for CoconaApp.CreateBuilder().Build();

// Add a command and configure.
app.AddCommand("hello", (string? name) => Console.WriteLine($"Hello {(name ?? "Guest")}!"))
    // Sets a description to the command.
    .WithDescription("Say hello");
    // Sets aliases to the command.
    .WithAliases(new[] { "hey" })
    // Sets a metadata (attribute) to the command.
    .WithMetadata(new HiddenAttribute());

// Use a user-defined command filter.
app.UseFilter(new MyFilterAttribute());

// Configure filters per command.
app.AddCommand("konnichiwa", (string name) => Console.WriteLine($"Konnichiwa {name}!"))
    .WithFilter(new MyFilterAttribute())
    .WithFilter(async (ctx, next) =>
    {
        if (Environment.UserName != "Administrator")
        {
            throw new CommandExitedException("Insufficient Permissions");
        }
        return next(ctx);
    })
    .CommandLikeOption(x =>
    {
        // CommandLikeOption: konnichiwa --info
        x.Add("info", () => Console.WriteLine("Show Information"));
    });
New APIs
  • CoconaAppBuilder
    • Services
    • Build()
  • CoconaApp (ICoconaCommandsBuilder)
    • Static methods
      • Create: Shorthand for CoconaApp.CreateBuilder().Build()
      • CreateBuilder: Creates CoconaAppBuilder instance.
      • CreateHostBuilder: Creates CoconaAppHostBuilder instance. (former CoconaApp.Create())
    • Instance methods
      • AddCommand(Delegate)
      • AddCommand(string, Delegate)
      • AddCommands(Type)
      • AddCommands<T>()
      • AddSubCommand(string, Action<ICoconaCommandsBuilder>)
      • UseFilter
      • Run / RunAsync

Introduce [Option(StopParsingOptions = true)] (#36)

[Option(StopParsingOptions = true)] enables to stop parsing options after a option on a command line.

public void A([Option]int a, [Option(StopParsingOptions = true)]string b, [Argument]string arg0, [Argument]string[] args)
{
   // $ ./myapp --a 123 --b valueB -c -d --e f
   // a = 123
   // b = "valueB"
   // arg0 = "-c"
   // args = new [] { "d", "--e", "f" }
}

Handle shutdown timeout (#57)

Cocona waits for a timeout before shutting down when canceling with Ctrl+C. This will allow you to perform a graceful shutdown.

Applied to Cocona

var builder = CoconaApp.CreateBuilder();
builder.Services.Configure<HostOptions>(options =>
{
     options.ShutdownTimeout = TimeSpan.FromSeconds(15);
});

Applied to Cocona.Lite

CoconaLiteApp.Create(options =>
{
    options.ShutdownTimeout = TimeSpan.FromSecond(15);
});

Localization (#44)

This release introduces localization mechanism for user-defined commands and add built-in ja-jp localization of messages.

image

New APIs

  • ICoconaLocalizer interface: Provides a localized description of the command. (see CoconaSample.Advanced.Localization)

Help Wanted: Contributions are welcome! 🤝

  • English: Since I (@mayuki) am not a native English speaker, this project has some problems such as lack of documentation and grammatical errors. Contributions of XML Doc comments, exception messages and README improvements would be welcome!
  • Non-English: Contributions of non-English language (ja-jp, ko-kr, ...) resources are also welcome!

Breaking changes

Disable support for shell completion by default (#50)

Support for Shell completion feature is now disabled by default.
If you want to continue to enable it, set the EnableShellCompletionSupport option to true.

CoconaApp Host APIs (#43)

  • Rename CoconaApp.Create() -> CoconaApp.CreateHostBuilder()
  • Rename IHostBuilder.UseCocona -> IHostBuilder.ConfigureCocona
  • Remove CommandTypes from CoconaAppOptions and CoconaLiteAppOptions

Changes

Improvements

  • Adopt to .NET 6 (#41)
  • Add scope support for ServiceProvider (#56)
  • Handle static methods marked as commands. (#35)

Fixes

  • Update NuGet package info (#55)
  • Throw exceptions in Run when building the application (#51)
  • Throw an exception if a sub-command name is duplicated (#52)

Full Changelog: v1.6.0...v2.0.0