You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vk...@apache.org on 2020/12/23 23:51:16 UTC

[ignite-3] branch main updated: IGNITE-13894 - Improve look&feel of the CLI tool (#12)

This is an automated email from the ASF dual-hosted git repository.

vkulichenko pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new 0688e1d  IGNITE-13894 - Improve look&feel of the CLI tool (#12)
0688e1d is described below

commit 0688e1dd8c4d1e3a46e21e1f0e536dda972d18bd
Author: Valentin Kulichenko <va...@gmail.com>
AuthorDate: Wed Dec 23 15:51:06 2020 -0800

    IGNITE-13894 - Improve look&feel of the CLI tool (#12)
---
 modules/cli-demo/cli/pom.xml                       |   6 --
 .../progressbar/IgniteProgressBarRenderer.java     |  19 +++-
 .../org/apache/ignite/cli/HelpFactoryImpl.java     |   4 +-
 .../org/apache/ignite/cli/IgniteProgressBar.java   |   2 +-
 .../src/main/java/org/apache/ignite/cli/Table.java |   2 +-
 .../cli/builtins/config/ConfigurationClient.java   |  12 ++-
 .../cli/builtins/init/InitIgniteCommand.java       |  29 ++++--
 .../cli/builtins/module/MavenArtifactResolver.java |   2 +
 .../cli/builtins/module/MavenCoordinates.java      |   2 +-
 .../ignite/cli/builtins/module/ModuleManager.java  |  33 ++++--
 .../ignite/cli/builtins/node/NodeManager.java      |   7 ++
 .../apache/ignite/cli/spec/ConfigCommandSpec.java  |  41 ++++----
 .../ignite/cli/spec/InitIgniteCommandSpec.java     |   4 +-
 .../apache/ignite/cli/spec/ModuleCommandSpec.java  | 113 +++++++++++++++------
 .../apache/ignite/cli/spec/NodeCommandSpec.java    |  89 +++++++++++-----
 .../cli/src/main/resources/builtin_modules.conf    |   8 +-
 .../apache/ignite/cli/IgniteCliInterfaceTest.java  |  97 ++++++++++--------
 .../cli/builtins/init/InitIgniteCommandTest.java   |   7 +-
 18 files changed, 311 insertions(+), 166 deletions(-)

diff --git a/modules/cli-demo/cli/pom.xml b/modules/cli-demo/cli/pom.xml
index 90b92ca..4c1b786 100644
--- a/modules/cli-demo/cli/pom.xml
+++ b/modules/cli-demo/cli/pom.xml
@@ -105,12 +105,6 @@
         </dependency>
 
         <dependency>
-            <groupId>com.github.freva</groupId>
-            <artifactId>ascii-table</artifactId>
-            <version>1.1.0</version>
-        </dependency>
-
-        <dependency>
             <groupId>me.tongfei</groupId>
             <artifactId>progressbar</artifactId>
             <version>0.9.0</version>
diff --git a/modules/cli-demo/cli/src/main/java/me/tongfei/progressbar/IgniteProgressBarRenderer.java b/modules/cli-demo/cli/src/main/java/me/tongfei/progressbar/IgniteProgressBarRenderer.java
index 48f865d..95133c3 100644
--- a/modules/cli-demo/cli/src/main/java/me/tongfei/progressbar/IgniteProgressBarRenderer.java
+++ b/modules/cli-demo/cli/src/main/java/me/tongfei/progressbar/IgniteProgressBarRenderer.java
@@ -17,6 +17,8 @@
 
 package me.tongfei.progressbar;
 
+import picocli.CommandLine.Help.Ansi;
+
 /**
  * Custom renderer for the {@link ProgressBar}.
  *
@@ -31,13 +33,22 @@ public class IgniteProgressBarRenderer implements ProgressBarRenderer {
 
         sb.append("=".repeat(completed));
 
-        if (completed < 100)
+        String percentage;
+        int percentageLen;
+
+        if (completed < 100) {
             sb.append('>').append(" ".repeat(99 - completed));
 
-        String percentage = completed + "%";
+            percentage = completed + "%";
+            percentageLen = percentage.length();
+        }
+        else {
+            percentage = "@|green,bold Done!|@";
+            percentageLen = 5;//percentageText.getCJKAdjustedLength();
+        }
 
-        sb.append("|").append(" ".repeat(5 - percentage.length())).append(percentage);
+        sb.append("|").append(" ".repeat(6 - percentageLen)).append(percentage);
 
-        return sb.toString();
+        return Ansi.AUTO.string(sb.toString());
     }
 }
diff --git a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/HelpFactoryImpl.java b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/HelpFactoryImpl.java
index e2f1583..b8bd0f4 100644
--- a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/HelpFactoryImpl.java
+++ b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/HelpFactoryImpl.java
@@ -99,7 +99,7 @@ public class HelpFactoryImpl implements CommandLine.IHelpFactory {
                     }
                 }
 
-                return table.toString();
+                return table.toString() + "\n";
             });
         }
         else if (hasParameters || hasOptions) {
@@ -136,7 +136,7 @@ public class HelpFactoryImpl implements CommandLine.IHelpFactory {
                     }
                 }
 
-                return table.toString();
+                return table.toString() + "\n";
             });
         }
 
diff --git a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/IgniteProgressBar.java b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/IgniteProgressBar.java
index a6bb0a0..2375c94 100644
--- a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/IgniteProgressBar.java
+++ b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/IgniteProgressBar.java
@@ -47,7 +47,7 @@ public class IgniteProgressBar implements AutoCloseable {
             0,
             Duration.ZERO,
             new IgniteProgressBarRenderer(),
-            new ConsoleProgressBarConsumer(System.out, 107)
+            new ConsoleProgressBarConsumer(System.out, 150)
         );
     }
 
diff --git a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/Table.java b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/Table.java
index cc4cffb..277fd93 100644
--- a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/Table.java
+++ b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/Table.java
@@ -109,7 +109,7 @@ public class Table {
 
         appendLine(sb);
 
-        return sb.toString();
+        return sb.toString().stripTrailing();
     }
 
     private void appendLine(StringBuilder sb) {
diff --git a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/config/ConfigurationClient.java b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/config/ConfigurationClient.java
index 26a07c0..919ac92 100644
--- a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/config/ConfigurationClient.java
+++ b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/config/ConfigurationClient.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.cli.builtins.config;
 
 import java.io.IOException;
+import java.io.PrintWriter;
 import java.net.HttpURLConnection;
 import java.net.URI;
 import java.net.http.HttpClient;
@@ -32,6 +33,7 @@ import com.typesafe.config.ConfigFactory;
 import com.typesafe.config.ConfigRenderOptions;
 import org.apache.ignite.cli.IgniteCLIException;
 import org.jetbrains.annotations.Nullable;
+import picocli.CommandLine.Help.ColorScheme;
 
 @Singleton
 public class ConfigurationClient {
@@ -75,7 +77,7 @@ public class ConfigurationClient {
         }
     }
 
-    public String set(String host, int port, String rawHoconData) {
+    public void set(String host, int port, String rawHoconData, PrintWriter out, ColorScheme cs) {
         var request = HttpRequest
             .newBuilder()
             .POST(HttpRequest.BodyPublishers.ofString(renderJsonFromHocon(rawHoconData)))
@@ -85,8 +87,12 @@ public class ConfigurationClient {
 
         try {
             HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
-            if (response.statusCode() == HttpURLConnection.HTTP_OK)
-                return "";
+            if (response.statusCode() == HttpURLConnection.HTTP_OK) {
+                out.println("Configuration was updated successfully.");
+                out.println();
+                out.println("Use the " + cs.commandText("ignite config get") +
+                    " command to view the updated configuration.");
+            }
             else
                 throw error("Fail to set configuration", response);
         }
diff --git a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/init/InitIgniteCommand.java b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/init/InitIgniteCommand.java
index 71d5a7e..cb98ae0 100644
--- a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/init/InitIgniteCommand.java
+++ b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/init/InitIgniteCommand.java
@@ -31,9 +31,12 @@ import org.apache.ignite.cli.CliPathsConfigLoader;
 import org.apache.ignite.cli.CliVersionInfo;
 import org.apache.ignite.cli.IgniteCLIException;
 import org.apache.ignite.cli.IgnitePaths;
+import org.apache.ignite.cli.Table;
 import org.apache.ignite.cli.builtins.SystemPathResolver;
 import org.apache.ignite.cli.builtins.module.ModuleManager;
 import org.jetbrains.annotations.NotNull;
+import picocli.CommandLine.Help.Ansi;
+import picocli.CommandLine.Help.ColorScheme;
 
 public class InitIgniteCommand {
 
@@ -51,26 +54,30 @@ public class InitIgniteCommand {
         this.cliPathsConfigLoader = cliPathsConfigLoader;
     }
 
-    public void init(PrintWriter out) {
+    public void init(PrintWriter out, ColorScheme cs) {
         moduleManager.setOut(out);
         Optional<IgnitePaths> ignitePathsOpt = cliPathsConfigLoader.loadIgnitePathsConfig();
         if (ignitePathsOpt.isEmpty()) {
-            File cfgFile = initConfigFile();
-            out.println("Configuration file initialized: " + cfgFile);
+            initConfigFile();
         }
         IgnitePaths cfg = cliPathsConfigLoader.loadIgnitePathsConfig().get();
-        out.println("Init ignite directories...");
+        out.print("Creating directories... ");
         cfg.initOrRecover();
-        out.println("Download and install current ignite version...");
+        out.println(Ansi.AUTO.string("@|green,bold Done!|@"));
+
+        Table table = new Table(0, cs);
+
+        table.addRow("@|bold Binaries Directory|@", cfg.binDir);
+        table.addRow("@|bold Work Directory|@", cfg.workDir);
+
+        out.println(table);
+        out.println();
+
         installIgnite(cfg);
-        out.println("Init default Ignite configs");
         initDefaultServerConfigs(cfg.serverDefaultConfigFile());
         out.println();
-        out.println("Apache Ignite version " + cliVersionInfo.version + " successfully installed");
-        out.println(
-            "Configuration file: " + cliPathsConfigLoader.configFilePath() + "\n" +
-            "Ignite binaries dir: " + cfg.binDir + "\n" +
-            "Ignite work dir: " + cfg.workDir);
+        out.println("Apache Ignite is successfully initialized. Use the " +
+            cs.commandText("ignite node start") + " command to start a new local node.");
     }
 
     private void initDefaultServerConfigs(Path serverCfgFile) {
diff --git a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/module/MavenArtifactResolver.java b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/module/MavenArtifactResolver.java
index f20e846..809d1ef 100644
--- a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/module/MavenArtifactResolver.java
+++ b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/module/MavenArtifactResolver.java
@@ -81,6 +81,8 @@ public class MavenArtifactResolver {
     ) throws IOException {
         Ivy ivy = ivyInstance(customRepositories); // needed for init right output logger before any operations
 
+        out.println("Installing " + String.join(":", grpId, artifactId, version) + "...");
+
         try (IgniteProgressBar bar = new IgniteProgressBar(100)) {
             ivy.getEventManager().addIvyListener(event -> {
                 if (event instanceof EndResolveEvent) {
diff --git a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/module/MavenCoordinates.java b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/module/MavenCoordinates.java
index a405855..0dd0eb3 100644
--- a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/module/MavenCoordinates.java
+++ b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/module/MavenCoordinates.java
@@ -30,7 +30,7 @@ public class MavenCoordinates {
         this.version = version;
     }
 
-    static MavenCoordinates of(String mvnString) {
+    public static MavenCoordinates of(String mvnString) {
         String[] coords = mvnString.split(":");
 
         if (coords.length == 4)
diff --git a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/module/ModuleManager.java b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/module/ModuleManager.java
index c829d6d..823fe22 100644
--- a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/module/ModuleManager.java
+++ b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/module/ModuleManager.java
@@ -30,9 +30,10 @@ import javax.inject.Singleton;
 import com.typesafe.config.ConfigFactory;
 import com.typesafe.config.ConfigObject;
 import com.typesafe.config.ConfigValue;
-import org.apache.ignite.cli.IgnitePaths;
-import org.apache.ignite.cli.IgniteCLIException;
 import org.apache.ignite.cli.CliVersionInfo;
+import org.apache.ignite.cli.IgniteCLIException;
+import org.apache.ignite.cli.IgnitePaths;
+import picocli.CommandLine.Help.ColorScheme;
 
 @Singleton
 public class ModuleManager {
@@ -44,6 +45,9 @@ public class ModuleManager {
 
     public static final String INTERNAL_MODULE_PREFIX = "_";
 
+    private PrintWriter out;
+    private ColorScheme cs;
+
     @Inject
     public ModuleManager(
         MavenArtifactResolver mavenArtifactResolver, CliVersionInfo cliVersionInfo,
@@ -55,9 +59,15 @@ public class ModuleManager {
     }
 
     public void setOut(PrintWriter out) {
+        this.out = out;
+
         mavenArtifactResolver.setOut(out);
     }
 
+    public void setColorScheme(ColorScheme cs) {
+        this.cs = cs;
+    }
+
     public void addModule(String name, IgnitePaths ignitePaths, List<URL> repositories) {
         Path installPath = ignitePaths.libsDir();
         if (name.startsWith("mvn:")) {
@@ -71,21 +81,26 @@ public class ModuleManager {
                     mavenCoordinates.version,
                     repositories
                 );
+
+                String mvnName = String.join(":", mavenCoordinates.groupId,
+                    mavenCoordinates.artifactId, mavenCoordinates.version);
+
                 moduleStorage.saveModule(new ModuleStorage.ModuleDefinition(
-                    mavenCoordinates.groupId + ":" + mavenCoordinates.artifactId + ":" + mavenCoordinates.version,
+                    mvnName,
                     resolveResult.artifacts(),
                     new ArrayList<>(),
                     ModuleStorage.SourceType.Maven,
                     name
                 ));
+
+                out.println();
+                out.println("New Maven dependency successfully added. To remove, type: " +
+                    cs.commandText("ignite module remove ") + cs.parameterText(mvnName));
             }
             catch (IOException e) {
-                throw new IgniteCLIException("Error during resolving maven module " + name, e);
+                throw new IgniteCLIException("\nFailed to install " + name, e);
             }
-
         }
-        else if (name.startsWith("file://"))
-            throw new RuntimeException("File urls is not implemented yet");
         else if (isStandardModuleName(name)) {
             StandardModuleDefinition moduleDescription = readBuiltinModules()
                 .stream()
@@ -104,7 +119,7 @@ public class ModuleManager {
                     ));
                 }
                 catch (IOException e) {
-                    throw new IgniteCLIException("Error during resolving standard module " + name, e);
+                    throw new IgniteCLIException("\nFailed to install an Ignite module: " + name, e);
                 }
             }
 
@@ -121,7 +136,7 @@ public class ModuleManager {
                     ));
                 }
                 catch (IOException e) {
-                    throw new IgniteCLIException("Error during resolving module " + name, e);
+                    throw new IgniteCLIException("\nFailed to install a module " + name, e);
                 }
             }
 
diff --git a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/node/NodeManager.java b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/node/NodeManager.java
index 4f4e992..3a00310 100644
--- a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/node/NodeManager.java
+++ b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/builtins/node/NodeManager.java
@@ -139,6 +139,13 @@ public class NodeManager {
             .collect(Collectors.joining(":"));
     }
 
+    public List<String> classpathItems() throws IOException {
+        return moduleStorage.listInstalled().modules.stream()
+            .flatMap(m -> m.artifacts.stream())
+            .map(m -> m.getFileName().toString())
+            .collect(Collectors.toList());
+    }
+
     public void createPidFile(String consistentId, long pid,Path pidsDir) {
         if (!Files.exists(pidsDir)) {
             if (!pidsDir.toFile().mkdirs())
diff --git a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/spec/ConfigCommandSpec.java b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/spec/ConfigCommandSpec.java
index abd5bb1..551dd47 100644
--- a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/spec/ConfigCommandSpec.java
+++ b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/spec/ConfigCommandSpec.java
@@ -24,59 +24,64 @@ import picocli.CommandLine;
 
 @CommandLine.Command(
     name = "config",
-    description = "Inspect and update Ignite cluster configuration.",
+    description = "Inspects and updates Ignite cluster configuration.",
     subcommands = {
         ConfigCommandSpec.GetConfigCommandSpec.class,
         ConfigCommandSpec.SetConfigCommandSpec.class
     }
 )
 public class ConfigCommandSpec extends CategorySpec {
-    @CommandLine.Command(name = "get", description = "Get current Ignite cluster configuration values.")
+    @CommandLine.Command(name = "get", description = "Gets current Ignite cluster configuration values.")
     public static class GetConfigCommandSpec extends CommandSpec {
 
         @Inject private ConfigurationClient configurationClient;
 
         @CommandLine.Mixin CfgHostnameOptions cfgHostnameOptions;
 
-        @CommandLine.Option(names = {"--subtree"},
-            description = "any text representation of hocon for querying considered subtree of config " +
-                "(example: local.baseline)")
-        private String subtree;
+        @CommandLine.Option(
+            names = "--selector",
+            description = "Configuration selector (example: local.baseline)"
+        )
+        private String selector;
 
         @Override public void run() {
             spec.commandLine().getOut().println(
-                configurationClient.get(cfgHostnameOptions.host(), cfgHostnameOptions.port(), subtree));
+                configurationClient.get(cfgHostnameOptions.host(), cfgHostnameOptions.port(), selector));
         }
     }
 
     @CommandLine.Command(
         name = "set",
-        description = "Update Ignite cluster configuration values."
+        description = "Updates Ignite cluster configuration values."
     )
     public static class SetConfigCommandSpec extends CommandSpec {
 
         @Inject private ConfigurationClient configurationClient;
 
-        @CommandLine.Parameters(paramLabel = "hocon-string", description = "any text representation of hocon config")
+        @CommandLine.Parameters(paramLabel = "hocon", description = "Configuration in Hocon format")
         private String config;
 
         @CommandLine.Mixin CfgHostnameOptions cfgHostnameOptions;
 
         @Override public void run() {
-            spec.commandLine().getOut().println(
-                configurationClient
-                    .set(cfgHostnameOptions.host(), cfgHostnameOptions.port(), config));
+            configurationClient.set(cfgHostnameOptions.host(), cfgHostnameOptions.port(), config,
+                spec.commandLine().getOut(), spec.commandLine().getColorScheme());
         }
     }
 
     private static class CfgHostnameOptions {
 
-        @CommandLine.Option(names = "--node-endpoint", required = true,
-            description = "host:port of node for configuration")
-        String cfgHostPort;
-
+        @CommandLine.Option(
+            names = "--node-endpoint",
+            description = "Ignite server node's REST API address and port number",
+            paramLabel = "host:port"
+        )
+        String endpoint;
 
         int port() {
+            if (endpoint == null)
+                return 8080;
+
             var hostPort = parse();
 
             try {
@@ -87,11 +92,11 @@ public class ConfigCommandSpec extends CategorySpec {
         }
 
         String host() {
-            return parse()[0];
+            return endpoint != null ? parse()[0] : "localhost";
         }
 
         private String[] parse() {
-            var hostPort = cfgHostPort.split(":");
+            var hostPort = endpoint.split(":");
             if (hostPort.length != 2)
                 throw new IgniteCLIException("Incorrect host:port pair provided " +
                     "(example of valid value 'localhost:8080')");
diff --git a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/spec/InitIgniteCommandSpec.java b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/spec/InitIgniteCommandSpec.java
index 488bd88..b53d430 100644
--- a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/spec/InitIgniteCommandSpec.java
+++ b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/spec/InitIgniteCommandSpec.java
@@ -22,14 +22,14 @@ import org.apache.ignite.cli.common.IgniteCommand;
 import org.apache.ignite.cli.builtins.init.InitIgniteCommand;
 import picocli.CommandLine;
 
-@CommandLine.Command(name = "init", description = "Install Ignite core modules locally.")
+@CommandLine.Command(name = "init", description = "Installs Ignite core modules locally.")
 public class InitIgniteCommandSpec extends CommandSpec implements IgniteCommand {
 
     @Inject
     InitIgniteCommand command;
 
     @Override public void run() {
-        command.init(spec.commandLine().getOut());
+        command.init(spec.commandLine().getOut(), spec.commandLine().getColorScheme());
     }
 
 }
diff --git a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/spec/ModuleCommandSpec.java b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/spec/ModuleCommandSpec.java
index 827d9c3..4739039 100644
--- a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/spec/ModuleCommandSpec.java
+++ b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/spec/ModuleCommandSpec.java
@@ -17,25 +17,26 @@
 
 package org.apache.ignite.cli.spec;
 
+import java.io.PrintWriter;
 import java.net.URL;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.stream.Collectors;
 import javax.inject.Inject;
-import com.github.freva.asciitable.AsciiTable;
-import com.github.freva.asciitable.Column;
-import com.github.freva.asciitable.HorizontalAlign;
 import org.apache.ignite.cli.CliPathsConfigLoader;
+import org.apache.ignite.cli.Table;
+import org.apache.ignite.cli.builtins.module.MavenCoordinates;
 import org.apache.ignite.cli.builtins.module.ModuleManager;
 import org.apache.ignite.cli.builtins.module.ModuleStorage;
 import org.apache.ignite.cli.builtins.module.StandardModuleDefinition;
 import org.apache.ignite.cli.common.IgniteCommand;
 import picocli.CommandLine;
+import picocli.CommandLine.Help.ColorScheme;
 
 @CommandLine.Command(
     name = "module",
-    description = "Manage optional Ignite modules and external artifacts.",
+    description = "Manages optional Ignite modules and additional Maven dependencies.",
     subcommands = {
         ModuleCommandSpec.ListModuleCommandSpec.class,
         ModuleCommandSpec.AddModuleCommandSpec.class,
@@ -43,7 +44,10 @@ import picocli.CommandLine;
     }
 )
 public class ModuleCommandSpec extends CategorySpec implements IgniteCommand {
-    @CommandLine.Command(name = "add", description = "Add an optional Ignite module or an external artifact.")
+    @CommandLine.Command(
+        name = "add",
+        description = "Adds an optional Ignite module or an additional Maven dependency."
+    )
     public static class AddModuleCommandSpec extends CommandSpec {
 
         @Inject private ModuleManager moduleManager;
@@ -51,41 +55,59 @@ public class ModuleCommandSpec extends CategorySpec implements IgniteCommand {
         @Inject
         private CliPathsConfigLoader cliPathsConfigLoader;
 
-        @CommandLine.Option(names = "--repo",
-            description = "Url to custom maven repo")
+        @CommandLine.Option(
+            names = "--repo",
+            description = "Additional Maven repository URL"
+        )
         public URL[] urls;
 
-        @CommandLine.Parameters(paramLabel = "module",
-            description = "can be a 'builtin module name (see module list)'|'mvn:groupId:artifactId:version'")
+        @CommandLine.Parameters(
+            paramLabel = "module",
+            description = "Optional Ignite module name or Maven dependency coordinates (mvn:groupId:artifactId:version)"
+        )
         public String moduleName;
 
         @Override public void run() {
             var ignitePaths = cliPathsConfigLoader.loadIgnitePathsOrThrowError();
+
             moduleManager.setOut(spec.commandLine().getOut());
+            moduleManager.setColorScheme(spec.commandLine().getColorScheme());
+
             moduleManager.addModule(moduleName,
                 ignitePaths,
                 (urls == null)? Collections.emptyList() : Arrays.asList(urls));
         }
     }
 
-    @CommandLine.Command(name = "remove", description = "Add an optional Ignite module or an external artifact.")
+    @CommandLine.Command(
+        name = "remove",
+        description = "Removes an optional Ignite module or an additional Maven dependency."
+    )
     public static class RemoveModuleCommandSpec extends CommandSpec {
 
         @Inject private ModuleManager moduleManager;
 
-        @CommandLine.Parameters(paramLabel = "module",
-            description = "can be a 'builtin module name (see module list)'|'mvn:groupId:artifactId:version'")
+        @CommandLine.Parameters(
+            paramLabel = "module",
+            description = "Optional Ignite module name or Maven dependency coordinates (groupId:artifactId:version)"
+        )
         public String moduleName;
 
         @Override public void run() {
+            PrintWriter out = spec.commandLine().getOut();
+            ColorScheme cs = spec.commandLine().getColorScheme();
+
             if (moduleManager.removeModule(moduleName))
-                spec.commandLine().getOut().println("Module " + moduleName + " was removed successfully");
+                out.println("Module " + cs.parameterText(moduleName) + " was removed successfully.");
             else
-                spec.commandLine().getOut().println("Module " + moduleName + " is not found");
+                out.println("Nothing to do: module " + cs.parameterText(moduleName) + " is not yet added.");
         }
     }
 
-    @CommandLine.Command(name = "list", description = "Show the list of available optional Ignite modules.")
+    @CommandLine.Command(
+        name = "list",
+        description = "Shows the list of Ignite modules and Maven dependencies."
+    )
     public static class ListModuleCommandSpec extends CommandSpec {
 
         @Inject private ModuleManager moduleManager;
@@ -101,31 +123,58 @@ public class ModuleCommandSpec extends CategorySpec implements IgniteCommand {
                 installedModules.put(m.name, m);
             }
 
+            PrintWriter out = spec.commandLine().getOut();
+            ColorScheme cs = spec.commandLine().getColorScheme();
+
             var builtinModules = moduleManager.builtinModules()
                 .stream()
                 .filter(m -> !m.name.startsWith(ModuleManager.INTERNAL_MODULE_PREFIX))
-                .map(m -> new StandardModuleView(m, installedModules.containsKey(m.name)));
+                .map(m -> new StandardModuleView(m, installedModules.containsKey(m.name)))
+                .collect(Collectors.toList());
+
+            out.println(cs.text("@|bold Optional Ignite Modules|@"));
+
+            if (builtinModules.isEmpty()) {
+                out.println("    Currently, there are no optional Ignite modules available for installation.");
+            }
+            else {
+                Table table = new Table(0, cs);
+
+                table.addRow("@|bold Name|@", "@|bold Description|@", "@|bold Installed?|@");
 
-            String table = AsciiTable.getTable(builtinModules.collect(Collectors.toList()), Arrays.asList(
-                new Column().header("Name").dataAlign(HorizontalAlign.LEFT).with(m -> m.standardModuleDefinition.name),
-                new Column().header("Description").dataAlign(HorizontalAlign.LEFT).with(m -> m.standardModuleDefinition.description),
-                new Column().header("Installed").dataAlign(HorizontalAlign.LEFT).with(m -> (m.installed) ? "+":"-")
-            ));
-            spec.commandLine().getOut().println("Official Ignite modules:");
-            spec.commandLine().getOut().println(table);
+                for (StandardModuleView m : builtinModules) {
+                    table.addRow(m.standardModuleDefinition.name, m.standardModuleDefinition.description,
+                        m.installed ? "Yes" : "No");
+                }
+
+                out.println(table);
+            }
+
+            out.println();
+            out.println(cs.text("@|bold Additional Maven Dependencies|@"));
 
             var externalInstalledModules = installedModules.values().stream()
                 .filter(m -> !(m.type == ModuleStorage.SourceType.Standard))
                 .collect(Collectors.toList());
-            if (!externalInstalledModules.isEmpty()) {
-                String externalModulesTable = AsciiTable.getTable(
-                    externalInstalledModules,
-                    Arrays.asList(
-                        new Column().header("Name").dataAlign(HorizontalAlign.LEFT).with(m -> m.name)
-                    ));
-                spec.commandLine().getOut().println();
-                spec.commandLine().getOut().println("External modules:");
-                spec.commandLine().getOut().println(externalModulesTable);
+
+            if (externalInstalledModules.isEmpty()) {
+                out.println("    No additional Maven dependencies installed. Use the " +
+                    cs.commandText("ignite module add") + " command to add a dependency.");
+            }
+            else {
+                Table table = new Table(0, cs);
+
+                table.addRow("@|bold Group ID|@", "@|bold Artifact ID|@", "@|bold Version|@");
+
+                for (ModuleStorage.ModuleDefinition m :externalInstalledModules){
+                    MavenCoordinates mvn = MavenCoordinates.of("mvn:" + m.name);
+
+                    table.addRow(mvn.groupId, mvn.artifactId, mvn.version);
+                }
+
+                out.println(table);
+                out.println("Type " + cs.commandText("ignite module remove") + " " +
+                    cs.parameterText("<groupId>:<artifactId>:<version>") + " to remove a dependency.");
             }
         }
 
diff --git a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/spec/NodeCommandSpec.java b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/spec/NodeCommandSpec.java
index 00f4b21..8903dee 100644
--- a/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/spec/NodeCommandSpec.java
+++ b/modules/cli-demo/cli/src/main/java/org/apache/ignite/cli/spec/NodeCommandSpec.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.cli.spec;
 
 import java.io.IOException;
+import java.io.PrintWriter;
 import java.nio.file.Path;
 import java.util.List;
 import javax.inject.Inject;
@@ -27,10 +28,12 @@ import org.apache.ignite.cli.IgnitePaths;
 import org.apache.ignite.cli.Table;
 import org.apache.ignite.cli.builtins.node.NodeManager;
 import picocli.CommandLine;
+import picocli.CommandLine.Help.Ansi;
+import picocli.CommandLine.Help.ColorScheme;
 
 @CommandLine.Command(
     name = "node",
-    description = "Start, stop and manage locally running Ignite nodes.",
+    description = "Manages locally running Ignite nodes.",
     subcommands = {
         NodeCommandSpec.StartNodeCommandSpec.class,
         NodeCommandSpec.StopNodeCommandSpec.class,
@@ -39,55 +42,77 @@ import picocli.CommandLine;
     }
 )
 public class NodeCommandSpec extends CategorySpec {
-    @CommandLine.Command(name = "start", description = "Start an Ignite node locally.")
+    @CommandLine.Command(name = "start", description = "Starts an Ignite node locally.")
     public static class StartNodeCommandSpec extends CommandSpec {
 
         @Inject private CliPathsConfigLoader cliPathsConfigLoader;
 
         @Inject private NodeManager nodeManager;
 
-        @CommandLine.Parameters(paramLabel = "consistent-id", description = "ConsistentId for new node")
+        @CommandLine.Parameters(paramLabel = "consistent-id", description = "Consistent ID of the new node")
         public String consistentId;
 
-        @CommandLine.Option(names = {"--config"},
-            description = "path to configuration file")
+        @CommandLine.Option(names = "--config", description = "Configuration file to start the node with")
         public Path configPath;
 
         @Override public void run() {
             IgnitePaths ignitePaths = cliPathsConfigLoader.loadIgnitePathsOrThrowError();
 
+            PrintWriter out = spec.commandLine().getOut();
+            ColorScheme cs = spec.commandLine().getColorScheme();
+
+            out.println("Starting a new Ignite node...");
+
             NodeManager.RunningNode node = nodeManager.start(consistentId, ignitePaths.workDir,
                 ignitePaths.cliPidsDir(),
                 configPath);
 
-            spec.commandLine().getOut().println("Started ignite node.\nPID: " + node.pid +
-                "\nConsistent Id: " + node.consistentId + "\nLog file: " + node.logFile);
+            out.println();
+            out.println("Node is successfully started. To stop, type " +
+                cs.commandText("ignite node stop ") + cs.parameterText(node.consistentId));
+            out.println();
+
+            Table table = new Table(0, cs);
+
+            table.addRow("@|bold Consistent ID|@", node.consistentId);
+            table.addRow("@|bold PID|@", node.pid);
+            table.addRow("@|bold Log File|@", node.logFile);
+
+            out.println(table);
         }
     }
 
-    @CommandLine.Command(name = "stop", description = "Stop a locally running Ignite node.")
+    @CommandLine.Command(name = "stop", description = "Stops a locally running Ignite node.")
     public static class StopNodeCommandSpec extends CommandSpec {
 
         @Inject private NodeManager nodeManager;
         @Inject private CliPathsConfigLoader cliPathsConfigLoader;
 
-        @CommandLine.Parameters(arity = "1..*", paramLabel = "consistent-ids",
-            description = "consistent ids of nodes to start")
+        @CommandLine.Parameters(
+            arity = "1..*",
+            paramLabel = "consistent-ids",
+            description = "Consistent IDs of the nodes to stop (space separated list)"
+        )
         public List<String> consistentIds;
 
         @Override public void run() {
             IgnitePaths ignitePaths = cliPathsConfigLoader.loadIgnitePathsOrThrowError();
 
+            PrintWriter out = spec.commandLine().getOut();
+            ColorScheme cs = spec.commandLine().getColorScheme();
+
             consistentIds.forEach(p -> {
+                out.print("Stopping locally running node with consistent ID " + cs.parameterText(p) + "... ");
+
                 if (nodeManager.stopWait(p, ignitePaths.cliPidsDir()))
-                    spec.commandLine().getOut().println("Node with consistent id " + p + " was stopped");
+                    out.println(cs.text("@|bold,green Done!|@"));
                 else
-                    spec.commandLine().getOut().println("Stop of node " + p + " was failed");
+                    out.println(cs.text("@|bold,red Failed|@"));
             });
         }
     }
 
-    @CommandLine.Command(name = "list", description = "Show the list of currently running local Ignite nodes.")
+    @CommandLine.Command(name = "list", description = "Shows the list of currently running local Ignite nodes.")
     public static class ListNodesCommandSpec extends CommandSpec {
 
         @Inject private NodeManager nodeManager;
@@ -96,33 +121,51 @@ public class NodeCommandSpec extends CategorySpec {
         @Override public void run() {
             IgnitePaths paths = cliPathsConfigLoader.loadIgnitePathsOrThrowError();
 
-            List<NodeManager.RunningNode> nodes = nodeManager
-                .getRunningNodes(paths.workDir, paths.cliPidsDir());
+            List<NodeManager.RunningNode> nodes = nodeManager.getRunningNodes(paths.workDir, paths.cliPidsDir());
 
-            if (nodes.isEmpty())
-                spec.commandLine().getOut().println("No running nodes");
+            PrintWriter out = spec.commandLine().getOut();
+            ColorScheme cs = spec.commandLine().getColorScheme();
+
+            if (nodes.isEmpty()) {
+                out.println("Currently, there are no locally running nodes.");
+                out.println();
+                out.println("Use the " + cs.commandText("ignite node start")
+                    + " command to start a new node.");
+            }
             else {
-                Table table = new Table(0, spec.commandLine().getColorScheme());
+                out.println("Currently, there are " +
+                    cs.text("@|bold " + nodes.size() + "|@") + " locally running nodes.");
+                out.println();
 
-                table.addRow("@|bold PID|@", "@|bold Consistent ID|@", "@|bold Log|@");
+                Table table = new Table(0, cs);
+
+                table.addRow("@|bold Consistent ID|@", "@|bold PID|@", "@|bold Log File|@");
 
                 for (NodeManager.RunningNode node : nodes) {
-                    table.addRow(node.pid, node.consistentId, node.logFile);
+                    table.addRow(node.consistentId, node.pid, node.logFile);
                 }
 
-                spec.commandLine().getOut().println(table);
+                out.println(table);
             }
         }
     }
 
-    @CommandLine.Command(name = "classpath", description = "Show the current classpath used by the Ignite nodes.")
+    @CommandLine.Command(name = "classpath", description = "Shows the current classpath used by the Ignite nodes.")
     public static class NodesClasspathCommandSpec extends CommandSpec {
 
         @Inject private NodeManager nodeManager;
 
         @Override public void run() {
             try {
-                spec.commandLine().getOut().println(nodeManager.classpath());
+                List<String> items = nodeManager.classpathItems();
+
+                PrintWriter out = spec.commandLine().getOut();
+
+                out.println(Ansi.AUTO.string("@|bold Current Ignite node classpath:|@"));
+
+                for (String item : items) {
+                    out.println("    " + item);
+                }
             }
             catch (IOException e) {
                 throw new IgniteCLIException("Can't get current classpath", e);
diff --git a/modules/cli-demo/cli/src/main/resources/builtin_modules.conf b/modules/cli-demo/cli/src/main/resources/builtin_modules.conf
index c7f4e80..4cea4e2 100644
--- a/modules/cli-demo/cli/src/main/resources/builtin_modules.conf
+++ b/modules/cli-demo/cli/src/main/resources/builtin_modules.conf
@@ -3,11 +3,5 @@ modules : {
         description: "Collection of base modules, which needed for start ignite server",
         artifacts: ["mvn:org.apache.ignite:ignite-runner"],
         cli-artifacts: []
-    },
-
-    ignite-demo-cli {
-        description: "Demo Ignite module with additional cli command 'snapshot'",
-        artifacts: ["mvn:org.apache.ignite:ignite-demo-module"],
-        cli-artifacts: ["mvn:org.apache.ignite:ignite-demo-module-cli"]
     }
-}
\ No newline at end of file
+}
diff --git a/modules/cli-demo/cli/src/test/java/org/apache/ignite/cli/IgniteCliInterfaceTest.java b/modules/cli-demo/cli/src/test/java/org/apache/ignite/cli/IgniteCliInterfaceTest.java
index 6d60b72..692c050 100644
--- a/modules/cli-demo/cli/src/test/java/org/apache/ignite/cli/IgniteCliInterfaceTest.java
+++ b/modules/cli-demo/cli/src/test/java/org/apache/ignite/cli/IgniteCliInterfaceTest.java
@@ -70,8 +70,9 @@ public class IgniteCliInterfaceTest {
         void init() {
             var initIgniteCommand = mock(InitIgniteCommand.class);
             applicationContext.registerSingleton(InitIgniteCommand.class, initIgniteCommand);
-            assertEquals(0, commandLine(applicationContext).execute("init"));
-            verify(initIgniteCommand).init(any());
+            CommandLine cli = commandLine(applicationContext);
+            assertEquals(0, cli.execute("init"));
+            verify(initIgniteCommand).init(any(), any());
         }
     }
 
@@ -143,7 +144,7 @@ public class IgniteCliInterfaceTest {
                 commandLine(applicationContext).execute("module remove builtin-module".split(" "));
             verify(moduleManager).removeModule(moduleName);
             assertEquals(0, exitCode);
-            assertEquals("Module " + moduleName + " was removed successfully\n", out.toString());
+            assertEquals("Module " + moduleName + " was removed successfully.\n", out.toString());
         }
 
         @Test
@@ -156,7 +157,7 @@ public class IgniteCliInterfaceTest {
                 commandLine(applicationContext).execute("module remove unknown-module".split(" "));
             verify(moduleManager).removeModule(moduleName);
             assertEquals(0, exitCode);
-            assertEquals("Module " + moduleName + " is not found\n", out.toString());
+            assertEquals("Nothing to do: module " + moduleName + " is not yet added.\n", out.toString());
         }
 
         @Test
@@ -186,21 +187,22 @@ public class IgniteCliInterfaceTest {
             verify(moduleManager).builtinModules();
             assertEquals(0, exitCode);
 
-            var expectedOutput = "Official Ignite modules:\n" +
-                "+---------+--------------+-----------+\n" +
-                "| Name    | Description  | Installed |\n" +
-                "+---------+--------------+-----------+\n" +
-                "| module1 | description1 | +         |\n" +
-                "+---------+--------------+-----------+\n" +
-                "| module2 | description2 | -         |\n" +
-                "+---------+--------------+-----------+\n" +
+            var expectedOutput = "Optional Ignite Modules\n" +
+                "+---------+--------------+------------+\n" +
+                "| Name    | Description  | Installed? |\n" +
+                "+---------+--------------+------------+\n" +
+                "| module1 | description1 | Yes        |\n" +
+                "+---------+--------------+------------+\n" +
+                "| module2 | description2 | No         |\n" +
+                "+---------+--------------+------------+\n" +
                 "\n" +
-                "External modules:\n" +
-                "+----------------------------------+\n" +
-                "| Name                             |\n" +
-                "+----------------------------------+\n" +
-                "| org.apache.ignite:snapshot:2.9.0 |\n" +
-                "+----------------------------------+\n";
+                "Additional Maven Dependencies\n" +
+                "+-------------------+-------------+---------+\n" +
+                "| Group ID          | Artifact ID | Version |\n" +
+                "+-------------------+-------------+---------+\n" +
+                "| org.apache.ignite | snapshot    | 2.9.0   |\n" +
+                "+-------------------+-------------+---------+\n" +
+                "Type ignite module remove <groupId>:<artifactId>:<version> to remove a dependency.\n";
             assertEquals(expectedOutput, out.toString());
         }
     }
@@ -234,10 +236,15 @@ public class IgniteCliInterfaceTest {
 
             assertEquals(0, exitCode);
             verify(nodeManager).start(nodeName, ignitePaths.workDir, ignitePaths.cliPidsDir(), Path.of("conf.json"));
-            assertEquals("Started ignite node.\n" +
-                "PID: 1\n" +
-                "Consistent Id: node1\n" +
-                "Log file: logfile\n", out.toString());
+            assertEquals("Starting a new Ignite node...\n\nNode is successfully started. To stop, type ignite node stop " + nodeName + "\n\n" +
+                "+---------------+---------+\n" +
+                "| Consistent ID | node1   |\n" +
+                "+---------------+---------+\n" +
+                "| PID           | 1       |\n" +
+                "+---------------+---------+\n" +
+                "| Log File      | logfile |\n" +
+                "+---------------+---------+\n",
+                out.toString());
         }
 
         @Test
@@ -256,7 +263,8 @@ public class IgniteCliInterfaceTest {
 
             assertEquals(0, exitCode);
             verify(nodeManager).stopWait(nodeName, ignitePaths.cliPidsDir());
-            assertEquals("Node with consistent id " + nodeName + " was stopped\n", out.toString());
+            assertEquals("Stopping locally running node with consistent ID " + nodeName + "... Done!\n",
+                out.toString());
         }
 
         @Test
@@ -275,7 +283,8 @@ public class IgniteCliInterfaceTest {
 
             assertEquals(0, exitCode);
             verify(nodeManager).stopWait(nodeName, ignitePaths.cliPidsDir());
-            assertEquals("Stop of node " + nodeName + " was failed\n", out.toString());
+            assertEquals("Stopping locally running node with consistent ID " + nodeName + "... Failed\n",
+                out.toString());
         }
 
         @Test
@@ -296,13 +305,15 @@ public class IgniteCliInterfaceTest {
 
             assertEquals(0, exitCode);
             verify(nodeManager).getRunningNodes(ignitePaths.workDir, ignitePaths.cliPidsDir());
-            assertEquals("+-----+---------------+----------+\n" +
-                "| PID | Consistent ID | Log      |\n" +
-                "+-----+---------------+----------+\n" +
-                "| 1   | new1          | logFile1 |\n" +
-                "+-----+---------------+----------+\n" +
-                "| 2   | new2          | logFile2 |\n" +
-                "+-----+---------------+----------+\n\n", out.toString());
+            assertEquals("Currently, there are 2 locally running nodes.\n\n" +
+                "+---------------+-----+----------+\n" +
+                "| Consistent ID | PID | Log File |\n" +
+                "+---------------+-----+----------+\n" +
+                "| new1          | 1   | logFile1 |\n" +
+                "+---------------+-----+----------+\n" +
+                "| new2          | 2   | logFile2 |\n" +
+                "+---------------+-----+----------+\n",
+                out.toString());
         }
 
         @Test
@@ -320,21 +331,20 @@ public class IgniteCliInterfaceTest {
 
             assertEquals(0, exitCode);
             verify(nodeManager).getRunningNodes(ignitePaths.workDir, ignitePaths.cliPidsDir());
-            assertEquals("No running nodes\n", out.toString());
+            assertEquals("Currently, there are no locally running nodes.\n\n" +
+                "Use the ignite node start command to start a new node.\n", out.toString());
         }
 
         @Test
         @DisplayName("classpath")
         void classpath() throws IOException {
-            when(nodeManager.classpath())
-                .thenReturn("classpath");
+            when(nodeManager.classpathItems()).thenReturn(Arrays.asList("item1", "item2"));
 
-            var exitCode =
-                commandLine(applicationContext).execute("node classpath".split(" "));
+            var exitCode = commandLine(applicationContext).execute("node classpath".split(" "));
 
             assertEquals(0, exitCode);
-            verify(nodeManager).classpath();
-            assertEquals("classpath\n", out.toString());
+            verify(nodeManager).classpathItems();
+            assertEquals("Current Ignite node classpath:\n    item1\n    item2\n", out.toString());
         }
     }
 
@@ -375,7 +385,7 @@ public class IgniteCliInterfaceTest {
         }
 
         @Test
-        @DisplayName("get --node-endpoint localhost:8081 --subtree local.baseline")
+        @DisplayName("get --node-endpoint localhost:8081 --selector local.baseline")
         void getSubtree() throws IOException, InterruptedException {
             when(response.statusCode()).thenReturn(HttpURLConnection.HTTP_OK);
             when(response.body()).thenReturn("{\"autoAdjust\":{\"enabled\":true}}");
@@ -383,7 +393,7 @@ public class IgniteCliInterfaceTest {
 
             var exitCode =
                 commandLine(applicationContext).execute(("config get --node-endpoint localhost:8081 " +
-                    "--subtree local.baseline").split(" "));
+                    "--selector local.baseline").split(" "));
 
             assertEquals(0, exitCode);
             verify(httpClient).send(
@@ -418,7 +428,8 @@ public class IgniteCliInterfaceTest {
                     r.bodyPublisher().get().contentLength() == expectedSentContent.getBytes().length &&
                     r.headers().firstValue("Content-Type").get().equals("application/json")),
                 any());
-            assertEquals("\n", out.toString());
+            assertEquals("Configuration was updated successfully.\n\n" +
+                "Use the ignite config get command to view the updated configuration.\n", out.toString());
         }
 
         @Test
@@ -442,8 +453,8 @@ public class IgniteCliInterfaceTest {
                     r.bodyPublisher().get().contentLength() == expectedSentContent.getBytes().length &&
                     r.headers().firstValue("Content-Type").get().equals("application/json")),
                 any());
-            assertEquals("\n", out.toString());
-
+            assertEquals("Configuration was updated successfully.\n\n" +
+                "Use the ignite config get command to view the updated configuration.\n", out.toString());
         }
     }
 }
diff --git a/modules/cli-demo/cli/src/test/java/org/apache/ignite/cli/builtins/init/InitIgniteCommandTest.java b/modules/cli-demo/cli/src/test/java/org/apache/ignite/cli/builtins/init/InitIgniteCommandTest.java
index c9e708e..654440e 100644
--- a/modules/cli-demo/cli/src/test/java/org/apache/ignite/cli/builtins/init/InitIgniteCommandTest.java
+++ b/modules/cli-demo/cli/src/test/java/org/apache/ignite/cli/builtins/init/InitIgniteCommandTest.java
@@ -20,6 +20,7 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.junit.jupiter.api.io.TempDir;
 import org.mockito.junit.jupiter.MockitoExtension;
+import picocli.CommandLine.Help.ColorScheme;
 
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -48,7 +49,7 @@ public class InitIgniteCommandTest {
             .thenReturn(new ResolveResult(Arrays.asList()));
 
         var out = new ByteArrayOutputStream();
-        initIgniteCommand.init(new PrintWriter(System.out, true));
+        initIgniteCommand.init(new PrintWriter(System.out, true), new ColorScheme.Builder().build());
 
         var ignitePaths = cliPathsConfigLoader.loadIgnitePathsConfig().get();
         assertTrue(ignitePaths.validateDirs());
@@ -63,14 +64,14 @@ public class InitIgniteCommandTest {
             .thenReturn(new ResolveResult(Collections.emptyList()));
 
         var out = new PrintWriter(System.out, true);
-        initIgniteCommand.init(out);
+        initIgniteCommand.init(out, new ColorScheme.Builder().build());
 
         var ignitePaths = cliPathsConfigLoader.loadIgnitePathsOrThrowError();
         recursiveDirRemove(ignitePaths.binDir);
 
         assertFalse(ignitePaths::validateDirs);
 
-        initIgniteCommand.init(out);
+        initIgniteCommand.init(out, new ColorScheme.Builder().build());
         assertTrue(ignitePaths::validateDirs);
     }