Add --format option to wslc version command (#41078)

* Add --format option to wslc version command

ggarzia-MSFT committed Jul 14, 2026 at 18:42 UTC 66abe46667b8f847a5f3a2c553eeee8e22bc3f19
5 files changed +64 -7
src/windows/wslc/commands/VersionCommand.cpp
+32 -2
@@ -12,11 +12,22 @@ Abstract:
12
13 --*/
14 #include "VersionCommand.h"
15 +#include "ArgumentValidation.h"
16 +#include "JsonUtils.h"
17
18 using namespace wsl::shared;
19 +using namespace wsl::shared::string;
20 using namespace wsl::windows::wslc::execution;
21 +using namespace wsl::windows::wslc::models;
22
23 namespace wsl::windows::wslc {
24 +std::vector<Argument> VersionCommand::GetArguments() const
25 +{
26 + return {
27 + Argument::Create(ArgType::Format),
28 + };
29 +}
30 +
31 std::wstring VersionCommand::ShortDescription() const
32 {
33 return Localization::WSLCCLI_VersionDesc();
@@ -34,7 +45,26 @@ void VersionCommand::PrintVersion()
45
46 void VersionCommand::ExecuteInternal(CLIExecutionContext& context) const
47 {
37 - UNREFERENCED_PARAMETER(context);
38 - PrintVersion();
48 + FormatType format = FormatType::Table;
49 + if (context.Args.Contains(ArgType::Format))
50 + {
51 + format = validation::GetFormatTypeFromString(context.Args.Get<ArgType::Format>());
52 + }
53 +
54 + switch (format)
55 + {
56 + case FormatType::Json:
57 + {
58 + nlohmann::json root;
59 + root["Client"]["Version"] = std::string{WSL_PACKAGE_VERSION};
60 + wsl::windows::common::wslutil::PrintMessage(MultiByteToWide(root.dump(c_jsonPrettyPrintIndent)));
61 + break;
62 + }
63 + case FormatType::Table:
64 + PrintVersion();
65 + break;
66 + default:
67 + THROW_HR(E_UNEXPECTED);
68 + }
69 }
70 } // namespace wsl::windows::wslc
src/windows/wslc/commands/VersionCommand.h
+1
@@ -22,6 +22,7 @@ struct VersionCommand final : public Command
22 {
23 }
24 static void PrintVersion();
25 + std::vector<Argument> GetArguments() const override;
26 std::wstring ShortDescription() const override;
27 std::wstring LongDescription() const override;
28
test/windows/wslc/CommandLineTestCases.h
+3
@@ -300,6 +300,9 @@ COMMAND_LINE_TEST_CASE(L"image rm cont1 cont2 cont3 --force --no-prune", L"remov
300 // Version command tests
301 COMMAND_LINE_TEST_CASE(L"version", L"version", true)
302 COMMAND_LINE_TEST_CASE(L"version --help", L"version", true)
303 +COMMAND_LINE_TEST_CASE(L"version --format json", L"version", true)
304 +COMMAND_LINE_TEST_CASE(L"version --format table", L"version", true)
305 +COMMAND_LINE_TEST_CASE(L"version --format invalid", L"version", false)
306 COMMAND_LINE_TEST_CASE(L"version extraarg", L"version", false)
307 // Settings command
308 COMMAND_LINE_TEST_CASE(L"settings", L"settings", true)
test/windows/wslc/WSLCCLICommandUnitTests.cpp
+13 -5
@@ -162,13 +162,21 @@ class WSLCCLICommandUnitTests
162 VERIFY_ARE_EQUAL(0u, cmd.GetCommands().size());
163 }
164
165 - // Test: Verify VersionCommand has no arguments (only the auto-added --help)
166 - TEST_METHOD(VersionCommand_HasNoArguments)
165 + // Test: Verify VersionCommand exposes the --format argument (plus the auto-added --help)
166 + TEST_METHOD(VersionCommand_HasFormatArgument)
167 {
168 auto cmd = VersionCommand(L"wslc");
169 - VERIFY_ARE_EQUAL(0u, cmd.GetArguments().size());
170 - // Test out that auto added help command is the only one
171 - VERIFY_ARE_EQUAL(1u, cmd.GetAllArguments().size());
169 +
170 + auto args = cmd.GetArguments();
171 + VERIFY_ARE_EQUAL(1u, args.size());
172 +
173 + const auto& format = args[0];
174 + VERIFY_ARE_EQUAL(ArgType::Format, format.Type());
175 + VERIFY_ARE_EQUAL(Kind::Value, format.Kind());
176 + VERIFY_IS_FALSE(format.Required());
177 +
178 + // GetAllArguments also includes the auto-added --help.
179 + VERIFY_ARE_EQUAL(2u, cmd.GetAllArguments().size());
180 }
181
182 // Test: Verify RootCommand contains VersionCommand as a subcommand
test/windows/wslc/e2e/WSLCE2EGlobalTests.cpp
+15
@@ -113,6 +113,21 @@ class WSLCE2EGlobalTests
113 RunWslcAndVerify(L"--version", {.Stdout = GetVersionMessage(), .Stderr = L"", .ExitCode = 0});
114 }
115
116 + WSLC_TEST_METHOD(WSLCE2E_VersionCommand_FormatJson)
117 + {
118 + auto result = RunWslc(L"version --format json");
119 + result.Verify({.Stderr = L"", .ExitCode = 0});
120 + VERIFY_IS_TRUE(result.Stdout.has_value());
121 + const auto root = nlohmann::json::parse(wsl::shared::string::WideToMultiByte(result.Stdout.value()));
122 + VERIFY_ARE_EQUAL(std::string{WSL_PACKAGE_VERSION}, root["Client"]["Version"].get<std::string>());
123 + }
124 +
125 + WSLC_TEST_METHOD(WSLCE2E_VersionCommand_FormatTable)
126 + {
127 + // Explicit table format matches the default plain-text output.
128 + RunWslcAndVerify(L"version --format table", {.Stdout = GetVersionMessage(), .Stderr = L"", .ExitCode = 0});
129 + }
130 +
131 WSLC_TEST_METHOD(WSLCE2E_Session_DefaultElevated)
132 {
133 // Run container list to create the default elevated session