diff --git a/localization/strings/en-US/Resources.resw b/localization/strings/en-US/Resources.resw
index ff843e40e..3e9587df5 100644
--- a/localization/strings/en-US/Resources.resw
+++ b/localization/strings/en-US/Resources.resw
@@ -2294,6 +2294,12 @@ On first run, creates the file with all settings commented out at their defaults
Settings reset to defaults.
+
+ Show version information.
+
+
+ Show version information for this tool.
+
Show all regardless of state.
diff --git a/src/windows/wslc/commands/RootCommand.cpp b/src/windows/wslc/commands/RootCommand.cpp
index 6c63c7e15..732c19404 100644
--- a/src/windows/wslc/commands/RootCommand.cpp
+++ b/src/windows/wslc/commands/RootCommand.cpp
@@ -18,6 +18,7 @@ Module Name:
#include "ImageCommand.h"
#include "SessionCommand.h"
#include "SettingsCommand.h"
+#include "VersionCommand.h"
using namespace wsl::windows::wslc::execution;
using namespace wsl::shared;
@@ -47,6 +48,7 @@ std::vector> RootCommand::GetCommands() const
commands.push_back(std::make_unique(FullName()));
commands.push_back(std::make_unique(FullName()));
commands.push_back(std::make_unique(FullName()));
+ commands.push_back(std::make_unique(FullName()));
return commands;
}
@@ -71,7 +73,7 @@ void RootCommand::ExecuteInternal(CLIExecutionContext& context) const
{
if (context.Args.Contains(ArgType::Version))
{
- wsl::windows::common::wslutil::PrintMessage(std::format(L"{} v{}", s_ExecutableName, WSL_PACKAGE_VERSION));
+ VersionCommand::PrintVersion();
return;
}
diff --git a/src/windows/wslc/commands/VersionCommand.cpp b/src/windows/wslc/commands/VersionCommand.cpp
new file mode 100644
index 000000000..eba4c565f
--- /dev/null
+++ b/src/windows/wslc/commands/VersionCommand.cpp
@@ -0,0 +1,39 @@
+/*++
+
+Copyright (c) Microsoft. All rights reserved.
+
+Module Name:
+
+ VersionCommand.cpp
+
+Abstract:
+
+ Implementation of the version command.
+
+--*/
+#include "VersionCommand.h"
+
+using namespace wsl::windows::wslc::execution;
+
+namespace wsl::windows::wslc {
+std::wstring VersionCommand::ShortDescription() const
+{
+ return Localization::WSLCCLI_VersionDesc();
+}
+
+std::wstring VersionCommand::LongDescription() const
+{
+ return Localization::WSLCCLI_VersionLongDesc();
+}
+
+void VersionCommand::PrintVersion()
+{
+ wsl::windows::common::wslutil::PrintMessage(std::format(L"{} {}", s_ExecutableName, WSL_PACKAGE_VERSION));
+}
+
+void VersionCommand::ExecuteInternal(CLIExecutionContext& context) const
+{
+ UNREFERENCED_PARAMETER(context);
+ PrintVersion();
+}
+} // namespace wsl::windows::wslc
diff --git a/src/windows/wslc/commands/VersionCommand.h b/src/windows/wslc/commands/VersionCommand.h
new file mode 100644
index 000000000..be700f550
--- /dev/null
+++ b/src/windows/wslc/commands/VersionCommand.h
@@ -0,0 +1,31 @@
+/*++
+
+Copyright (c) Microsoft. All rights reserved.
+
+Module Name:
+
+ VersionCommand.h
+
+Abstract:
+
+ Declaration of the VersionCommand.
+
+--*/
+#pragma once
+#include "Command.h"
+
+namespace wsl::windows::wslc {
+struct VersionCommand final : public Command
+{
+ constexpr static std::wstring_view CommandName = L"version";
+ VersionCommand(const std::wstring& parent) : Command(CommandName, parent)
+ {
+ }
+ static void PrintVersion();
+ std::wstring ShortDescription() const override;
+ std::wstring LongDescription() const override;
+
+protected:
+ void ExecuteInternal(CLIExecutionContext& context) const override;
+};
+} // namespace wsl::windows::wslc
diff --git a/test/windows/wslc/CommandLineTestCases.h b/test/windows/wslc/CommandLineTestCases.h
index ed1025fba..7a7b7008f 100644
--- a/test/windows/wslc/CommandLineTestCases.h
+++ b/test/windows/wslc/CommandLineTestCases.h
@@ -115,6 +115,10 @@ COMMAND_LINE_TEST_CASE(L"image list -q", L"list", true)
COMMAND_LINE_TEST_CASE(L"image pull ubuntu", L"pull", true)
COMMAND_LINE_TEST_CASE(L"pull ubuntu", L"pull", true)
+// Version command tests
+COMMAND_LINE_TEST_CASE(L"version", L"version", true)
+COMMAND_LINE_TEST_CASE(L"version --help", L"version", true)
+COMMAND_LINE_TEST_CASE(L"version extraarg", L"version", false)
// Settings command
COMMAND_LINE_TEST_CASE(L"settings", L"settings", true)
COMMAND_LINE_TEST_CASE(L"settings reset", L"reset", true)
diff --git a/test/windows/wslc/WSLCCLICommandUnitTests.cpp b/test/windows/wslc/WSLCCLICommandUnitTests.cpp
index f72c63df3..e707c909c 100644
--- a/test/windows/wslc/WSLCCLICommandUnitTests.cpp
+++ b/test/windows/wslc/WSLCCLICommandUnitTests.cpp
@@ -20,6 +20,7 @@ Module Name:
#include "RootCommand.h"
#include "ContainerCommand.h"
#include "SessionCommand.h"
+#include "VersionCommand.h"
using namespace wsl::windows::wslc;
using namespace WSLCTestHelpers;
@@ -95,6 +96,48 @@ class WSLCCLICommandUnitTests
VERIFY_IS_NOT_NULL(subcmd.get());
}
}
+
+ // Test: Verify VersionCommand has the correct name
+ TEST_METHOD(VersionCommand_HasCorrectName)
+ {
+ auto cmd = VersionCommand(L"wslc");
+ VERIFY_ARE_EQUAL(std::wstring_view(L"version"), cmd.Name());
+ }
+
+ // Test: Verify VersionCommand has no subcommands
+ TEST_METHOD(VersionCommand_HasNoSubcommands)
+ {
+ auto cmd = VersionCommand(L"wslc");
+ VERIFY_ARE_EQUAL(0u, cmd.GetCommands().size());
+ }
+
+ // Test: Verify VersionCommand has no arguments (only the auto-added --help)
+ TEST_METHOD(VersionCommand_HasNoArguments)
+ {
+ auto cmd = VersionCommand(L"wslc");
+ VERIFY_ARE_EQUAL(0u, cmd.GetArguments().size());
+ // Test out that auto added help command is the only one
+ VERIFY_ARE_EQUAL(1u, cmd.GetAllArguments().size());
+ }
+
+ // Test: Verify RootCommand contains VersionCommand as a subcommand
+ TEST_METHOD(RootCommand_ContainsVersionCommand)
+ {
+ auto root = RootCommand();
+ auto subcommands = root.GetCommands();
+
+ bool found = false;
+ for (const auto& subcmd : subcommands)
+ {
+ if (subcmd->Name() == VersionCommand::CommandName)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ VERIFY_IS_TRUE(found, L"RootCommand should contain VersionCommand");
+ }
};
} // namespace WSLCCLICommandUnitTests
\ No newline at end of file
diff --git a/test/windows/wslc/e2e/WSLCE2EGlobalTests.cpp b/test/windows/wslc/e2e/WSLCE2EGlobalTests.cpp
index c4486ffc7..ae5fc2c57 100644
--- a/test/windows/wslc/e2e/WSLCE2EGlobalTests.cpp
+++ b/test/windows/wslc/e2e/WSLCE2EGlobalTests.cpp
@@ -51,6 +51,11 @@ class WSLCE2EGlobalTests
RunWslcAndVerify(L"INVALID_CMD", {.Stdout = GetHelpMessage(), .Stderr = L"Unrecognized command: 'INVALID_CMD'\r\n", .ExitCode = 1});
}
+ TEST_METHOD(WSLCE2E_VersionCommand)
+ {
+ WSL2_TEST_ONLY();
+ RunWslcAndVerify(L"version", {.Stdout = GetVersionMessage(), .Stderr = L"", .ExitCode = 0});
+ }
TEST_METHOD(WSLCE2E_Session_DefaultElevated)
{
WSL2_TEST_ONLY();
@@ -400,6 +405,11 @@ class WSLCE2EGlobalTests
return output.str();
}
+ std::wstring GetVersionMessage() const
+ {
+ return std::format(L"wslc {}\r\n", WSL_PACKAGE_VERSION);
+ }
+
std::wstring GetDescription() const
{
return L"WSLC is the Windows Subsystem for Linux Container CLI tool. It enables management and interaction with WSL "
@@ -435,6 +445,7 @@ class WSLCE2EGlobalTests
{L"save", Localization::WSLCCLI_ImageSaveDesc()},
{L"start", Localization::WSLCCLI_ContainerStartDesc()},
{L"stop", Localization::WSLCCLI_ContainerStopDesc()},
+ {L"version", Localization::WSLCCLI_VersionDesc()},
};
size_t maxLen = 0;