Create a plugin to register a command

You can use a plugin to register a command for use with the Content Hub CLI. In this example, you'll create a command called echo and then create a plugin to register it. The echo command outputs the string values that are passed in as arguments.

This walkthrough describes how to:

Note

The following examples use the .NET CLI, but you can achieve the same results in your preferred integrated development environment (IDE).

Create a project

To create a project:

  1. To create a class library, run the following commands:

    RequestResponse
     mkdir Walkthrough
    
    RequestResponse
    cd Walkthrough
    RequestResponse
    dotnet new classlib --framework net6.0
  2. To add a reference to the core CLI functionality, run the following command :

    RequestResponse
    dotnet add package Sitecore.CH.Cli.Core --source https://nuget.sitecore.com/resources/v3/index.json
    

Sitecore.CH.Cli.Core provides access to the plugin infrastructure, useful utilities around file system access, configuration management, and console output. It also adds a dependency to the Web Client SDK.

Create the plugin

While starting up the application, the CLI scans the plugin search paths for any types that inherit from Sitecore.CH.Cli.Core.Abstractions.Infrastructure.IPlugin.

To create the plugin:

  • Rename the file Class1.cs to Plugin.cs and add the following code

    RequestResponse
    using Sitecore.CH.Cli.Core.Abstractions.Infrastructure;
    
    namespace Walkthrough
    {
      public class WalkthroughPlugin : IPlugin
      {
        public void ConfigureServices(IServiceCollection services)
        {
        }
    
        public void RegisterCommands(ICommandRegistry registry)
        {
        }
      }
    }
    

This class contains the following methods:

  • ConfigureServices - lets you register custom services in the shared service collection and resolve them again later during the command execution.

  • RegisterCommands - registers new commands that are being delivered as part of this plugin, and makes them available through the CLI.

Create and register a command

In this example, you create a command called echo. There are two methods you can use to do this:

  • Use a separate command declaration and command handling. This is the preferred approach as it allows for better and easier unit testing of the command handler implementation.

  • Specify options and command handling in the same class 

To create and register a command:

The value echo that is passed to the base constructor is the name under which the command will be made available later.

Arguments are passed into the function. IHost contains a reference to the service provider that resolves previously registered services. The value echo that is passed to the base constructor is the name under which the command will be made available later.

New commands can be added to existing groups, or to new groups created specifically for them. Several command groups are available as standard, including:

  • delivery 

  • serialization 

  • tenant 

  1. Create a file called EchoCommand.cs and add a separate command declaration and command handling as shown in the following code:

    RequestResponse
    using System.CommandLine;
    using System.CommandLine.Invocation;
    using Sitecore.ContentHub.Cli.Shared.Abstractions.Commands;
    using Sitecore.ContentHub.Cli.Shared.Abstractions.Rendering;
    
    namespace Walkthrough;
    
    public class EchoCommand : BaseCommand <EchoCommandHandler> 
    {
      public EchoCommand() : base("echo", "Echo a value")
      {
        // Options
        AddOption(new Option <string> (new[] {"--value", "-v"}, "Value to echo")
        {
          IsRequired = true
        });
      }
    }
    
    public class EchoCommandHandler : BaseCommandHandler
    {
      // Inject services from service provider
      public EchoCommandHandler(IOutputRenderer renderer) : base(renderer)
      {
      }
    
      public string Value { get; set; }
    
      // Command handling
      public override Task <int> InvokeDefaultAsync(InvocationContext context)
      {
        Renderer.WriteLine(Value);
    
        // Return exit code to indicate success or failure
        return Task.FromResult(0);
      }
    }
    
  2. Or, use a separate class for arguments and options, as shown in the following code:

    RequestResponse
    using System.CommandLine;
    using System.CommandLine.Invocation;
    using Microsoft.Extensions.Options;
    using Sitecore.ContentHub.Cli.Shared.Abstractions.Commands;
    using Sitecore.ContentHub.Cli.Shared.Abstractions.Rendering;
    
    namespace Walkthrough;
    
    public class EchoCommandParameters
    {
      public string Value { get; set; }
    }
    
    public class EchoCommand : BaseCommand <EchoCommandHandler> 
    {
      public EchoCommand() : base("echo", "Echo a value")
      {
        // Options
        AddOption(new Option <string> (new[] {"--value", "-v"}, "Value to echo")
        {
          IsRequired = true
        });
      }
    }
    
    public class EchoCommandHandler : BaseCommandHandler <EchoCommandParameters> 
    {
      // Inject services from service provider
      public EchoCommandHandler(
        IOutputRenderer renderer, 
        IOptions <EchoCommandParameters> parameters) : base(renderer, parameters)
      {
      }
    
      // Command handling
      public override Task <int> InvokeDefaultAsync(InvocationContext context)
      {
        Renderer.WriteLine(Parameters.Value);
    
        // Return exit code to indicate success or failure
        return Task.FromResult(0);
      }
    }
    
  3. Specify options and command handling in the same class, as shown in the following code:

    RequestResponse
      using System.CommandLine;
      using System.CommandLine.NamingConventionBinder;
      using Microsoft.Extensions.DependencyInjection; 
      using Microsoft.Extensions.Hosting;
      using Sitecore.ContentHub.Cli.Shared.Abstractions.Commands;
      using Sitecore.ContentHub.Cli.Shared.Abstractions.Rendering;       
    
      namespace Walkthrough
      {
          public class EchoCommand : BaseCommand
        {
          public EchoCommand() : base("echo", "Echo a value")
          {
            // Options
            AddOption(new Option <string> (new[] {"--value", "-v"}, "Value to echo")
            {
              IsRequired = true
            });
    
            Handler = CommandHandler.Create <string>, IHost ((value, host) = 
            {
              host.Services.GetService <IOutputRenderer> ().WriteLine(value);
            });
        }
      }
    
  4. To connect the plugin class and the command, modify the Plugin.cs file updating the RegisterCommands method as follows:

    RequestResponse
    public class WalkthroughPlugin : IPlugin
    {
      ...
    
      public void RegisterCommands(ICommandRegistry registry)
      {
        // register the command to an existing command group
        registry.RegisterCommand("walkthrough", new EchoCommand());
    
        // register a new command group and its commands
        registry.RegisterCommandGroup(
          "walkthrough", new List <Command> { new EchoCommand() }, "Walkthrough plugin for demonstration purposes only");
      }
    
      ...
    }
    

After they are compiled and copied to a discoverable plugin search path, the walkthrough command group and echo command are included in the CLI. You can now run several commands to verify that everything has been set up correctly.

The following command starts from the walkthrough command group and verifies that the new echo command has been added:

RequestResponse
ch-cli walkthrough --help

You can run the echo command as follows:

RequestResponse
ch-cli walkthrough echo --value Hello

Do you have some feedback for us?

If you have suggestions for improving this article,