Skip to main content

Sitecore CLI: Extend the Command Line Interface with NuGet

 Sitecore CLI: Extend the Command Line Interface with NuGet




Sitecore Command Line Interface (CLI) allows console communication with a Sitecore instance.  Sitecore CLI allows adding commands by writing custom plugins. Sitecore provides some plugins like Publishing and Serialization.

The purpose of this blog is to create a simple Sitecore CLI plugin which will print any message which you pass as parameter or print a default message.

Sitecore CLI Document

Prerequisites

Code Repository

Usages

dotnet sitecore plugin [subcommand] [options]

Below are some subcommands:

Create a custom CLI plugin command

  1. Create a blank new Solution “CustomCLI” in Visual Studio, then add a class library with .Net core 3.1 with the name “CLI.DevEX.Extensibility.Custom”.
  2. PackageSources node contains all package sources. Plugin sources need to be specified in Nuget.Config, Local package source will take the package from “Build/nugets” folder which we  have generated in the previous step. 
    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
    <packageSources>
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
    <add key="Sitecore" value="https://sitecore.myget.org/F/sc-packages/api/v3/index.json" />
    <add key="Local" value="_Build\nugets"></add>
    </packageSources>
    <packageRestore>
    <add key="enabled" value="True" />
    <add key="automatic" value="True" />
    </packageRestore>
    <activePackageSource>
    <add key="All" value="(Aggregate source)" />
    </activePackageSource>
    </configuration>
    view raw Nuget.Config hosted with ❤ by GitHub
  3. Add NuGet references to Sitecore.Devex.Client.Cli.Extensibility and Spectre.Console in the class library.
  4. Create a class named RegisterExtension and inherit it from ISitecoreCliExtension class. AddCommands method allows the plugin to add a command to the RootCommand of the System.CommandLine processor. AddConfiguration method will allow the plug-in to add configuration to a config builder. AddServices method will allow the plug-in to service to the IOC container.
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Sitecore.Devex.Client.Cli.Extensibility;
    using Sitecore.Devex.Client.Cli.Extensibility.Subcommands;
    using CLI.DevEX.Extensibility.Custom.Commands;
    using System;
    using System.Collections.Generic;
    namespace CLI.DevEX.Extensibility.Custom
    {
    public class RegisterExtension : ISitecoreCliExtension
    {
    public IEnumerable<ISubcommand> AddCommands(IServiceProvider container)
    {
    if (container == null)
    {
    throw new ArgumentNullException(nameof(container));
    }
    CustomCommand customCommand = new CustomCommand("Custom", "This is a custom command");
    PrintCommand printCommand = container.GetRequiredService<PrintCommand>();
    customCommand.AddCommand(printCommand);
    return new ISubcommand[] { customCommand };
    }
    public void AddConfiguration(IConfigurationBuilder configBuilder)
    {
    }
    public void AddServices(IServiceCollection serviceCollection)
    {
    serviceCollection.AddSingleton<CustomCommand>().AddSingleton<PrintCommand>();
    }
    }
    }
  5. Create a subfolder named Commands and add a class CustomCommand inside the Commands folder which will inherit Command and ISubcommand class.
    using Sitecore.Devex.Client.Cli.Extensibility.Subcommands;
    using System.CommandLine;
    namespace CLI.DevEX.Extensibility.Custom.Commands
    {
    public class CustomCommand: Command, ISubcommand
    {
    public CustomCommand(string name, string description = null)
    : base(name, description)
    {
    }
    }
    }
  6. Now create a class named PrintCommand inside the Commands folder. SubcommandBase class will handle exceptions for Sitecore CLI subcommands.
    using Sitecore.Devex.Client.Cli.Extensibility.Subcommands;
    using CLI.DevEX.Extensibility.Custom.Tasks;
    using System;
    using System.Threading.Tasks;
    namespace CLI.DevEX.Extensibility.Custom.Commands
    {
    public class PrintCommand : SubcommandBase<PrintTask, PrintTaskOptions>
    {
    public PrintCommand(IServiceProvider container) : base("Print", "Print test message", container)
    {
    AddOption(PrintArgOptions.Message);
    }
    protected override async Task<int> Handle(PrintTask task, PrintTaskOptions args)
    {
    args.Validate();
    await task.Execute(args).ConfigureAwait(false);
    return 0;
    }
    }
    }
    view raw PrintCommand hosted with ❤ by GitHub
  7. Add a class named PrintArgOptions inside the Tasks folder.
    using System.CommandLine;
    namespace CLI.DevEX.Extensibility.Custom.Tasks
    {
    public class PrintArgOptions
    {
    public static readonly Option Message = new Option(new[] {
    "--message",
    "-m" },
    "Name to be displayed. Default: Swati Gupta")
    {
    Argument = new Argument<string>(() => "Swati Gupta")
    };
    }
    }
  8. Add a new subfolder named Tasks and create a class PrintTask inside this folder.
    using Spectre.Console;
    using System.Threading.Tasks;
    namespace CLI.DevEX.Extensibility.Custom.Tasks
    {
    public class PrintTask
    {
    public async Task Execute(PrintTaskOptions options)
    {
    await PrintMessage(options);
    }
    private async Task PrintMessage(PrintTaskOptions options)
    {
    AnsiConsole.Write(new FigletText(options.Message).LeftAligned().Color(Color.Red));
    }
    }
    }
    view raw PrintTask.cs hosted with ❤ by GitHub
  9. Create PrintTaskOptions which inherit TaskOptionsBase. This class will validate the utility of the task option class.
    using Sitecore.DevEx.Client.Tasks;
    namespace CLI.DevEX.Extensibility.Custom.Tasks
    {
    public class PrintTaskOptions : TaskOptionsBase
    {
    public string Message { get; set; }
    public override void Validate()
    {
    Require(nameof(Message));
    }
    }
    }
  10. Open CLI.DevEX.Extensibility.Custom.csproj file and update the below settings:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<PackageVersion>1.0.0</PackageVersion>
<PackageOutputPath>..\..\_Build\nugets</PackageOutputPath>
<OutputPath>.\bin\</OutputPath>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);CustomBuildOutputTarget</TargetsForTfmSpecificContentInPackage>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Sitecore.Devex.Client.Cli.Extensibility" Version="4.1.1" />
<PackageReference Include="Spectre.Console" Version="0.43.0" />
</ItemGroup>
<Target Name="CustomBuildOutputTarget">
<ItemGroup>
<TfmSpecificPackageFile Include="$(OutputPath)CLI.DevEX.Extensibility.Custom.dll" PackagePath="plugin" />
<TfmSpecificPackageFile Include="$(OutputPath)Spectre.Console.dll" PackagePath="plugin" />
</ItemGroup>
</Target>
</Project>


PackageOutputPath

Determines the output path in which the packed package will be dropped. Default is $(OutputPath). To make Sitecore CLI able to find our Nuget without publishing it to the public feed we instead use a local Nuget folder. “$(SolutionDir)_Build/nugets”. In the csproj file we can set the ‘PackageOutputPath’ property to output our package to this folder.

CopyLocalLockFileAssemblies

The CopyLocalLockFileAssemblies property is useful for plugin projects that have dependencies on other libraries. If you set this property to true, any NuGet package dependencies are copied to the output directory. That means you can use the output of dotnet build to run your plugin on any machine.

AppendTargetFrameworkToOutputPath

Setting AppendTargetFrameworkToOutputPath to false prevents the target framework moniker from being appended to the output path.

PackageReference

Package references, using the PackageReference node, manage NuGet dependencies directly within project files. 

TargetsForTfmSpecificContentInPackage

TargetsForTfmSpecificContentInPackage write a custom target. PackagePath where the file should be output in the package.

Plugin assembly needs to be placed inside a plugin folder so that’s why PackagePath is mentioned as a plugin.

How to Run Custom CLI Plugin

  • Open terminal, Run as Administrator.
  • Run the below command to restore:
    • dotnet tool restore
  • Run below command to add your custom plugin:
    • dotnet sitecore plugin add -n CLI.DevEx.Extensibility.Custom --version 1.0.0                
  • Run “dotnet sitecore -h” command to check available commands:
  • To check the custom command run “dotnet sitecore Custom -h”.
  • Now finally when you will run “dotnet sitecore Custom Print” command, it will print the default name.
  • You can pass some message like this “dotnet sitecore Custom print -m Sitecore”.

Note: Extensions/customizations to the CLI and Sitecore Management Services module are unsupported by Sitecore.

Comments

Popular posts from this blog

Sitecore 10.2 - “Failed to start service ‘Sitecore Marketing Automation Engine’” on Windows 11

Sitecore 10.2 - “Failed to start service ‘Sitecore Marketing Automation Engine' ” on Windows 11 Today I started to install Sitecore 10.2 using Sitecore Instance Manager on Windows 11 and I got this issue “Failed to start service ‘Sitecore Marketing Automation Engine' ” . Error : On event viewer it was showing the below error: I also tried to run ‘ Sitecore.MAEngine.exe ’ like this C:\Windows\system32>C:\inetpub\wwwroot\sclocal102xconnect.dev.local\App_Data\jobs\continuous\AutomationEngine\Sitecore.MAEngine.exe Which was throwing below error: Starting Marketing Automation Engine... 2022-01-29 22:21:11 ERR Error initializing XConnect client. System.AggregateException: One or more errors occurred. ---> Sitecore.XConnect.XdbCollectionUnavailableException: An error occurred while sending the request. ---> System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: The underlying connection was closed: An unexpected err...

Azure AD Integration with Sitecore 10.2

 Azure AD Integration with Sitecore 10.2 Sitecore identity server that comes with Sitecore 9.1 allows you to log in through an external identity provider like Azure Active Directory, Facebook, Apple, or Google. It is built on Federation Authentication. What is Federation Authentication? Federation authentication is a technology to allows users to access multiples application, tools, and domains using one credential. Using one set of credential user can access multiple applications, and resources after authentication.  Federation authentication consists of two systems, the Identity provider and the Service provider. Identity providers that maintain/create/manage identity information like name, email address, device, and location. Some examples of identity providers are Azure AD, Google, Facebook, and Apple. Service providers basically refer to a website, software, or app that the user is trying to access and SP basically relies on the identity provider to authenticate the user ...

Sitecore 9 Forms: Google reCaptcha field

Sitecore 9 Forms: Google reCaptcha field  Re-Captcha is the most important part of any form’s submission. Google reCaptcha run internet bot detector and determined whether a user is a bot or not.  Sitecore Forms does not provide Google reCaptcha field, which was available in WFFM before, so I have created my custom Google reCaptcha.   Below you can find step by step process to create Google reCaptcha field. Create patch config for reCaptcha Sitekey and SecretKey <?xml version="1.0"?> <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/"> <sitecore> <settings> <setting name="ReCaptchaSiteKey" value="site-key" /> <setting name="ReCaptchaSecretKey" value="secret-key" /> </settings> </sitecore> </configuration> Create new viewmodel class RecaptchaViewMode...