public DeploymentExecutor(ILog log, IHelpWriter helpWriter, IVersionWriter versionWriter, IExecCommand execCommand)
 {
     _log           = log;
     _helpWriter    = helpWriter;
     _versionWriter = versionWriter;
     _execCommand   = execCommand;
 }
 public static void GetAdditionalHelpText(IHelpWriter formatter, CommandLineApplication application, int firstColumnWidth)
 {
     formatter.WriteOnNewLine(null);
     formatter.WriteSectionTitle("HOW TO");
     formatter.WriteOnNewLine($"Start by reading the manual for this tool: {typeof(ManCommand).GetFullCommandLine<MainCommand>().PrettyQuote()}.");
     formatter.WriteOnNewLine($"Get a full list of commands available: {typeof(ManCommandListCommand).GetFullCommandLine<MainCommand>().PrettyQuote()}.");
 }
        public ConsoleRunner(
            [NotNull] IGenerationService generationService,
            [NotNull] IConsoleWriter consoleWriter,
            [NotNull] IHelpWriter helpWriter,
            [NotNull] IResultWriter resultWriter)
        {
            if (generationService == null)
            {
                throw new ArgumentNullException(nameof(generationService));
            }
            if (consoleWriter == null)
            {
                throw new ArgumentNullException(nameof(consoleWriter));
            }
            if (resultWriter == null)
            {
                throw new ArgumentNullException(nameof(resultWriter));
            }
            if (helpWriter == null)
            {
                throw new ArgumentNullException(nameof(helpWriter));
            }

            _generationService = generationService;
            _consoleWriter     = consoleWriter;
            _helpWriter        = helpWriter;
            _resultWriter      = resultWriter;
        }
        public JiraAutomation(IHelpWriter helpWriter, IActionManager actionManager)
        {
            Argument.IsNotNull(() => helpWriter);
            Argument.IsNotNull(() => actionManager);

            _helpWriter = helpWriter;
            _actionManager = actionManager;
        }
Exemple #5
0
        public JiraAutomation(IHelpWriter helpWriter, IActionManager actionManager)
        {
            Argument.IsNotNull(() => helpWriter);
            Argument.IsNotNull(() => actionManager);

            _helpWriter    = helpWriter;
            _actionManager = actionManager;
        }
 public ChangeCommandLineArguments(ICmdArguments cmdArguments, IOutput output, IInput input, IHelpWriter helpWriter, ICommandLine cmdLine, IArgumentsValidator argumentsValidator)
 {
     _cmdArguments = cmdArguments;
     _output = output;
     _input = input;
     _helpWriter = helpWriter;
     _cmdLine = cmdLine;
     _argumentsValidator = argumentsValidator;
 }
Exemple #7
0
        public HelpWriterTests()
        {
            var sp = ConfigureServices(services =>
            {
                services.AddModule(new GitVersionExeModule());
            });

            helpWriter = sp.GetService <IHelpWriter>();
        }
        public static void WriteToolUsage(IHelpWriter formatter, CommandLineApplication app, int firstColumnWidth)
        {
            formatter.WriteOnNewLine(null);
            formatter.WriteSectionTitle("WHAT IS THIS TOOL");
            formatter.WriteOnNewLine(app.Parent?.Description);

            formatter.WriteOnNewLine(null);
            WriteGenericToolUsage(formatter, app, firstColumnWidth);
        }
        public GitVersionApplication(IFileSystem fileSystem, IEnvironment environment, ILog log, IConfigFileLocator configFileLocator)
        {
            this.fileSystem        = fileSystem;
            this.environment       = environment;
            this.log               = log;
            this.configFileLocator = configFileLocator;

            versionWriter = new VersionWriter();
            helpWriter    = new HelpWriter(versionWriter);
        }
Exemple #10
0
 private static void ListCommands(IHelpWriter formatter, List <CommandLineApplication> subCommands)
 {
     foreach (var subCommand in subCommands.OrderBy(c => c.Name))
     {
         subCommand.ShowHelp();
         if (subCommand.Commands != null && subCommand.Commands.Count > 0)
         {
             ListCommands(formatter, subCommand.Commands);
         }
     }
 }
 public GitVersionExecutor(ILog log, IConfigFileLocator configFileLocator, IVersionWriter versionWriter, IHelpWriter helpWriter,
                           IExecCommand execCommand, IConfigProvider configProvider, IBuildServerResolver buildServerResolver, IGitPreparer gitPreparer)
 {
     this.log = log ?? throw new ArgumentNullException(nameof(log));
     this.configFileLocator   = configFileLocator ?? throw new ArgumentNullException(nameof(configFileLocator));
     this.versionWriter       = versionWriter ?? throw new ArgumentNullException(nameof(versionWriter));
     this.helpWriter          = helpWriter ?? throw new ArgumentNullException(nameof(helpWriter));
     this.execCommand         = execCommand ?? throw new ArgumentNullException(nameof(execCommand));
     this.configProvider      = configProvider ?? throw new ArgumentNullException(nameof(configFileLocator));
     this.buildServerResolver = buildServerResolver ?? throw new ArgumentNullException(nameof(buildServerResolver));
     this.gitPreparer         = gitPreparer;
 }
        /// <summary>
        /// Write the generic usage of this CLI.
        /// </summary>
        /// <param name="formatter"></param>
        /// <param name="app"></param>
        /// <param name="firstColumnWidth"></param>
        public static void WriteGenericToolUsage(IHelpWriter formatter, CommandLineApplication app, int firstColumnWidth)
        {
            formatter.WriteSectionTitle("COMMAND LINE USAGE");
            formatter.WriteOnNewLine(@"How to use this command line interface tool:
  - Each command is well documented on its own, don't be afraid to use the `--" + AExecutionCommand.HelpLongName + @"` option.
  - Some commands and options have aliases (shortcuts). For instance the following option:
    `-");
            formatter.Write("-opt", ConsoleColor.Green);
            formatter.Write(@"ion` can also be written as `");
            formatter.Write("-opt", ConsoleColor.Green);
            formatter.Write($@"` (mind the highlighted letters).");
            formatter.WriteOnNewLine($@"  - Every single option can also be passed to this tool using an environment variable; the variable should be named like the option (in capital letters) and prefixed by `{app.GetRootCommandLineApplication().Name?.ToUpper()}_`.
    For instance, you can pass the value of the option named `--myoption` through an environment variable named `{app.GetRootCommandLineApplication().Name?.ToUpper()}_MYOPTION`.
  - You can escape white spaces in argument/option values by using double quotes (i.e. ""my value"").
  - If you need to use a double quote within a double quote, you can do so by double quoting the double quotes (i.e. ""my """"special"""" value"").
  - If an extra layer is needed, just double the doubling (i.e. -opt ""-mysubopt """"my special """"""""value"""""""""""""").
  - In the 'USAGE' help section, arguments between brackets (i.e. []) are optionals.");

            formatter.WriteOnNewLine(null);
            formatter.WriteSectionTitle("RESPONSE FILE PARSING");
            formatter.WriteOnNewLine($@"Instead of using a long command line (which is limited in size on every platform), you can use a response file that contains each argument/option that should be used.

Everything that is usually separated by a space in the command line should be separated by a new line in the file.
In response files, you do not have to double quote arguments containing spaces, they will be considered as a whole as long as they are on a separated line.

  `{app.GetRootCommandLineApplication().Name} @responsefile.txt`");

            formatter.WriteOnNewLine(null);
            formatter.WriteSectionTitle("EXIT CODE");
            formatter.WriteOnNewLine(@"The convention followed by this tool is the following.
  - 0 : used when a command completed successfully, without errors nor warnings.
  - 1-8 : used when a command completed but with warnings, the level can be used to pinpoint different kinds of warnings.
  - 9 : used when a command does not complete and ends up in error.");

            if (app.Commands.Count > 0)
            {
                formatter.WriteOnNewLine(null);
                formatter.WriteSectionTitle("LEARN MORE");
                formatter.WriteOnNewLine("Learn more about specific topics using the command:");
                formatter.WriteOnNewLine(null);
                formatter.WriteOnNewLine($"{app.GetFullCommandLine()} <TOPIC>".PrettyQuote());

                formatter.WriteOnNewLine(null);
                formatter.WriteSectionTitle("TOPICS");
                foreach (var command in app.Commands.ToList().OrderBy(c => c.Name))
                {
                    formatter.WriteOnNewLine(command.Name?.PadRight(30));
                    formatter.Write(command.Description, padding: 30);
                }
            }

            formatter.WriteOnNewLine(null);
        }
Exemple #13
0
        public static void GetAdditionalHelpText(IHelpWriter formatter, CommandLineApplication app, int firstColumnWidth)
        {
            formatter.WriteOnNewLine(null);
            app.Parent.Commands.Remove(app);
            var rootCommand = app;

            while (rootCommand.Parent != null)
            {
                rootCommand = rootCommand.Parent;
            }
            ListCommands(formatter, rootCommand.Commands);
            formatter.WriteOnNewLine(null);
        }
        public static void GetAdditionalHelpText(IHelpWriter formatter, CommandLineApplication app, int firstColumnWidth)
        {
            formatter.WriteOnNewLine(null);
            formatter.WriteSectionTitle("LIST OF ALL THE COMMANDS");
            var rootCommand = app;

            while (rootCommand.Parent != null)
            {
                rootCommand = rootCommand.Parent;
            }
            formatter.WriteOnNewLine(rootCommand.Name);
            ListCommands(formatter, rootCommand.Commands, "");
            formatter.WriteOnNewLine(null);
        }
Exemple #15
0
        public GitVersionExecutor(ILog log, IConsole console,
                                  IConfigFileLocator configFileLocator, IConfigProvider configProvider, IGitVersionTool gitVersionTool,
                                  IVersionWriter versionWriter, IHelpWriter helpWriter)
        {
            this.log               = log ?? throw new ArgumentNullException(nameof(log));
            this.console           = console ?? throw new ArgumentNullException(nameof(console));
            this.configFileLocator = configFileLocator ?? throw new ArgumentNullException(nameof(configFileLocator));
            this.configProvider    = configProvider ?? throw new ArgumentNullException(nameof(configFileLocator));

            this.gitVersionTool = gitVersionTool ?? throw new ArgumentNullException(nameof(gitVersionTool));

            this.versionWriter = versionWriter ?? throw new ArgumentNullException(nameof(versionWriter));
            this.helpWriter    = helpWriter ?? throw new ArgumentNullException(nameof(helpWriter));
        }
        private static void ListCommands(IHelpWriter formatter, List <CommandLineApplication> subCommands, string linePrefix)
        {
            var i = 0;

            foreach (var subCommand in subCommands.OrderBy(c => c.Name))
            {
                formatter.WriteOnNewLine($"{linePrefix}{(i == subCommands.Count - 1 ? "└─ " : "├─ ")}{subCommand.Name}".PadRight(30));
                var linePrefixForNewLine = $"{linePrefix}{(i == subCommands.Count - 1 ? "   " : "│  ")}";
                formatter.Write(subCommand.Description, padding: 30, prefixForNewLines: linePrefixForNewLine);
                if (subCommand.Commands != null && subCommand.Commands.Count > 0)
                {
                    ListCommands(formatter, subCommand.Commands, linePrefixForNewLine);
                }
                i++;
            }
        }
        /// <summary>
        /// Additional help
        /// </summary>
        public static void GetAdditionalHelpText(IHelpWriter formatter, CommandLineApplication application, int firstColumnWidth)
        {
            formatter.WriteOnNewLine(null);
            formatter.WriteSectionTitle("BUILD PROPERTIES");

            foreach (var property in GetAvailableBuildProperties().OrderBy(p => p.Key))
            {
                formatter.WriteOnNewLine($"* -p \"{property.Key}={property.Value ?? ""}\"");
            }
            formatter.WriteOnNewLine(null);
            formatter.WriteTip($"Display the full documentation of each build property by running {$"{application.GetFullCommandLine()} {PropertyHelpLongName}".PrettyQuote()}.");

            formatter.WriteOnNewLine(null);
            formatter.WriteSectionTitle("EXTRA CONFIG");
            formatter.WriteOnNewLine($"The example below illustrate the usage of the --{ExtraConfigOption} option:");
            formatter.WriteOnNewLine(@"We have 2 project files (p1 and p2) containing build configurations as described below:

p1" + OeBuilderConstants.OeProjectExtension + @"
├─ Configuration1
└─ Configuration2

p2" + OeBuilderConstants.OeProjectExtension + @"
└─ Configuration3
   ├─ Configuration4
   │  ├─ Configuration5
   │  └─ Configuration6
   └─ Configuration7

We use the following command line to start a build:");
            formatter.WriteOnNewLine(null);
            formatter.WriteOnNewLine($"{application.GetFullCommandLine()} p1 {ConfigurationNameLongName} Configuration1 --{ExtraConfigOption} p2=Configuration6 --{ExtraConfigOption} Configuration2".PrettyQuote(), padding: 2);
            formatter.WriteOnNewLine(null);
            formatter.WriteOnNewLine(@"Below is the equivalent of how build configurations are nested in this scenario:

Configuration1
└─ Configuration3
   └─ Configuration4
      └─ Configuration6
         └─ Configuration2

This allow a lot of flexibility for organizing and partitioning your build process.");

            formatter.WriteOnNewLine(null);
            formatter.WriteSectionTitle("NOTES");
            formatter.WriteOnNewLine($"Create a new project file using the command: {typeof(ProjectInitCommand).GetFullCommandLine<MainCommand>().PrettyQuote()}.");
            formatter.WriteOnNewLine($"Get a more in-depth help and learn about the concept of a build (in sakoe) using the command: {typeof(BuildManCommand).GetFullCommandLine<MainCommand>().PrettyQuote()}.");
        }
    public GitVersionExecutor(ILog log, IConsole console,
                              IConfigFileLocator configFileLocator, IConfigProvider configProvider,
                              IGitVersionCalculateTool gitVersionCalculateTool, IGitVersionOutputTool gitVersionOutputTool,
                              IVersionWriter versionWriter, IHelpWriter helpWriter, IGitRepositoryInfo repositoryInfo)
    {
        this.log               = log.NotNull();
        this.console           = console.NotNull();
        this.configFileLocator = configFileLocator.NotNull();
        this.configProvider    = configProvider.NotNull();

        this.gitVersionCalculateTool = gitVersionCalculateTool.NotNull();
        this.gitVersionOutputTool    = gitVersionOutputTool.NotNull();

        this.versionWriter  = versionWriter.NotNull();
        this.helpWriter     = helpWriter.NotNull();
        this.repositoryInfo = repositoryInfo.NotNull();
    }
Exemple #19
0
        public GitVersionExecutor(ILog log, IConsole console,
                                  IConfigFileLocator configFileLocator, IConfigProvider configProvider,
                                  IGitVersionCalculateTool gitVersionCalculateTool, IGitVersionOutputTool gitVersionOutputTool,
                                  IVersionWriter versionWriter, IHelpWriter helpWriter, IGitRepositoryInfo repositoryInfo)
        {
            this.log               = log ?? throw new ArgumentNullException(nameof(log));
            this.console           = console ?? throw new ArgumentNullException(nameof(console));
            this.configFileLocator = configFileLocator ?? throw new ArgumentNullException(nameof(configFileLocator));
            this.configProvider    = configProvider ?? throw new ArgumentNullException(nameof(configFileLocator));

            this.gitVersionCalculateTool = gitVersionCalculateTool ?? throw new ArgumentNullException(nameof(gitVersionCalculateTool));
            this.gitVersionOutputTool    = gitVersionOutputTool ?? throw new ArgumentNullException(nameof(gitVersionOutputTool));

            this.versionWriter  = versionWriter ?? throw new ArgumentNullException(nameof(versionWriter));
            this.helpWriter     = helpWriter ?? throw new ArgumentNullException(nameof(helpWriter));
            this.repositoryInfo = repositoryInfo ?? throw new ArgumentNullException(nameof(repositoryInfo));
        }
        public static void GetAdditionalHelpText(IHelpWriter formatter, CommandLineApplication app, int firstColumnWidth)
        {
            formatter.WriteOnNewLine(null);
            formatter.WriteSectionTitle("OVERVIEW");
            formatter.WriteOnNewLine(@"With sakoe, you can 'build' your project. A build process is a succession of tasks that (typically) transform your source files into a deliverable format, usually called a release or package.

In sakoe, you describe a build process using a 'build configuration'. A build configuration holds 'properties' of the build (for instance, the path to the openedge installation directory $DLC). It also holds the list of 'tasks' that will be executed successively during the build process.

To illustrate this, here is a possible build process:
  - Task 1: compile all your .p files to a `procedures` directory.
  - Task 2: compile all your .w files into a pro-library `client.pl`.
  - Task 3: zip the `procedures` and `client.pl` together into an archive file `release.zip`.

In order to store these build configurations, sakoe uses project files: " + OeBuilderConstants.OeProjectExtension.PrettyQuote() + @".
You can create them with the command: " + typeof(ProjectInitCommand).GetFullCommandLine <MainCommand>().PrettyQuote() + @".");
            formatter.WriteOnNewLine(null);
            formatter.WriteOnNewLine(OeIncrementalBuildOptions.GetDefaultEnabledIncrementalBuild() ? "By default, a build is 'incremental'." : "A build can be 'incremental'.");
            formatter.WriteOnNewLine("An incremental build is the opposite of a full build. In incremental mode, only the files that were added/modified/deleted since the previous build are taken into account. Unchanged files are simply not rebuilt.");
            formatter.WriteOnNewLine(null);
            formatter.WriteOnNewLine("The chapters below contain more details about a project, build configuration, properties and tasks. ");

            // TODO: list all the node and their documentation, use a tree

            formatter.WriteOnNewLine(null);
            formatter.WriteSectionTitle("PROJECT");
            formatter.WriteOnNewLine(BuilderHelp.GetPropertyDocumentation(typeof(OeProject).GetXmlName()));

            formatter.WriteOnNewLine(null);
            formatter.WriteSectionTitle("BUILD CONFIGURATION");
            formatter.WriteOnNewLine(BuilderHelp.GetPropertyDocumentation(typeof(OeProject).GetXmlName(nameof(OeProject.BuildConfigurations))));

            formatter.WriteOnNewLine(null);
            formatter.WriteSectionTitle("BUILD CONFIGURATION VARIABLES");
            formatter.WriteOnNewLine(BuilderHelp.GetPropertyDocumentation(typeof(OeBuildConfiguration).GetXmlName(nameof(OeBuildConfiguration.Variables))));

            formatter.WriteOnNewLine(null);
            formatter.WriteSectionTitle("BUILD CONFIGURATION PROPERTIES");
            formatter.WriteOnNewLine(BuilderHelp.GetPropertyDocumentation(typeof(OeBuildConfiguration).GetXmlName(nameof(OeBuildConfiguration.Properties))));

            formatter.WriteOnNewLine(null);
            formatter.WriteSectionTitle("BUILD STEPS");
            formatter.WriteOnNewLine(BuilderHelp.GetPropertyDocumentation(typeof(OeBuildConfiguration).GetXmlName(nameof(OeBuildConfiguration.BuildSteps))));

            formatter.WriteOnNewLine(null);
        }
Exemple #21
0
 public BuildRunner(ITaskRegistrationValidator taskRegistrationValidator, 
                    IArgumentsValidator argumentsValidator,
                    IOutput output, 
                    ITaskDirector taskDirector, 
                    ICommandLine commandLine, 
                    IHelpWriter helpWriter,
                    IKnownCmdArguments knownCmdArguments,
                    IDryrun dryrun,
                    IInteractiveMode interactiveMode)
 {
     _taskRegistrationValidator = taskRegistrationValidator;
     _argumentsValidator = argumentsValidator;
     _output = output;
     _taskDirector = taskDirector;
     _commandLine = commandLine;
     _helpWriter = helpWriter;
     _knownCmdArguments = knownCmdArguments;
     _dryrun = dryrun;
     _interactiveMode = interactiveMode;
 }
Exemple #22
0
 public HandleSpecialOptions(IHelpWriter helpTextWriter)
 {
     _helpTextWriter = helpTextWriter;
 }
Exemple #23
0
 public static void GetAdditionalHelpText(IHelpWriter writer, CommandLineApplication application, int firstColumnWidth)
 {
     writer.WriteOnNewLine(null);
     writer.WriteSectionTitle("HOW TO");
     writer.WriteOnNewLine($"Here, you could write some piece of documentation.");
 }
Exemple #24
0
        public HelpWriterTests()
        {
            var versionWriter = new VersionWriter();

            helpWriter = new HelpWriter(versionWriter);
        }
 public HelpWriterTests(IHelpWriter helpWriter)
 {
     this.helpWriter = helpWriter;
 }
Exemple #26
0
 private void WriteHelpWhenNoCommandAreSpecified(IEnumerable <ICommandTypeProvider> commandTypeProviders, IHelpWriter helpWriter)
 {
     if (All)
     {
         var commands = commandTypeProviders.GetAllVisibleCommandsTypes();
         helpWriter.WriteHelpForCommand(commands.ToArray());
     }
     else
     {
         helpWriter.WriteCommandListing();
     }
 }
Exemple #27
0
    public HelpWriterTests()
    {
        var sp = ConfigureServices(services => services.AddModule(new GitVersionAppModule()));

        this.helpWriter = sp.GetService <IHelpWriter>();
    }
Exemple #28
0
 /// <summary>
 /// Sets the helpwriter to be used with the command. Only the helpwriter applied to the root command is used.
 /// </summary>
 /// <param name="helpWriter"></param>
 /// <returns></returns>
 public Command Use(IHelpWriter helpWriter)
 {
     _helpWriter = helpWriter;
     return(this);
 }
 /// <summary>
 /// Creates a new instance.
 /// </summary>
 /// <param name="helpWriter">Help writer</param>
 /// <param name="helpContentProvider">Provider for content</param>
 internal HelpProgram(IHelpWriter helpWriter, IProvider <IReadOnlyCollection <string> > helpContentProvider)
 {
     _helpWriter          = helpWriter;
     _helpContentProvider = helpContentProvider ?? throw ConfigurationExceptions.NoHelpContentProviderDefined();
 }
Exemple #30
0
        public static void GetAdditionalHelpText(IHelpWriter formatter, CommandLineApplication app, int firstColumnWidth)
        {
            formatter.WriteOnNewLine(null);
            formatter.WriteSectionTitle("WHAT IS THIS TOOL");
            formatter.WriteOnNewLine(app.Parent?.Description);

            formatter.WriteOnNewLine(null);
            formatter.WriteSectionTitle("ABOUT THIS MANUAL");
            formatter.WriteOnNewLine(@"The goal of this manual is to provide KEY concepts that are necessary to understand to use this tool to its fullest.

Each command is well documented on its own, don't be afraid to use the " + MainCommand.HelpLongName.PrettyQuote() + " option.");

            formatter.WriteOnNewLine(null);
            formatter.WriteSectionTitle("COMMAND LINE USAGE");
            formatter.WriteOnNewLine(@"How to use this command line interface tool:
  - You can escape white spaces in argument/option values by using double quotes (i.e. ""my value"").
  - If you need to use a double quote within a double quote, you can do so by double quoting the double quotes (i.e. ""my """"special"""" value"").
  - If an extra layer is needed, just double the doubling (i.e. -opt ""-mysubopt """"my special """"""""value"""""""""""""").
  - In the 'USAGE' help section, arguments between brackets (i.e. []) are optionals.");

            formatter.WriteOnNewLine(null);
            formatter.WriteSectionTitle("RESPONSE FILE PARSING");
            formatter.WriteOnNewLine(@"Instead of using a long command line (which is limited in size on every platform), you can use a response file that contains each argument/option that should be used.

Everything that is usually separated by a space in the command line should be separated by a new line in the file.
In response files, you do not have to double quote arguments containing spaces, they will be considered as a whole as long as they are on a separated line.

  `sakoe @responsefile.txt`");

            formatter.WriteOnNewLine(null);
            formatter.WriteSectionTitle("EXIT CODE");
            formatter.WriteOnNewLine(@"The convention followed by this tool is the following.
  - 0 : used when a command completed successfully, without errors nor warnings.
  - 1-8 : used when a command completed but with warnings, the level can be used to pinpoint different kinds of warnings.
  - 9 : used when a command does not complete and ends up in error.");

            formatter.WriteOnNewLine(null);
            formatter.WriteSectionTitle("WEBSITE");
            formatter.WriteOnNewLine(@"The official page of this tool is:
  https://jcaillon.github.io/Oetools.Sakoe/.

You are invited to STAR the project on github to increase its visibility!");

            if (app.Commands != null && app.Commands.Count > 0)
            {
                formatter.WriteOnNewLine(null);
                formatter.WriteSectionTitle("LEARN MORE");
                formatter.WriteOnNewLine("Learn more about specific topics using the command:");
                formatter.WriteOnNewLine(null);
                formatter.WriteOnNewLine($"{app.GetFullCommandLine()} <TOPIC>".PrettyQuote());

                formatter.WriteOnNewLine(null);
                formatter.WriteSectionTitle("TOPICS");
                foreach (var command in app.Commands.ToList().OrderBy(c => c.Name))
                {
                    formatter.WriteOnNewLine(command.Name.PadRight(30));
                    formatter.Write(command.Description, padding: 30);
                }
            }

            formatter.WriteOnNewLine(null);
        }