Skip to content

Commit 715ce52

Browse files
ptrivediPooja TrivediclaudeCopilot
authored
[WSLC] Add 'wslc version' subcommand (#14547)
* [WSLC] Add 'wslc version' subcommand Adds a 'version' subcommand to the WSLC CLI as an alternative to the existing '--version' flag, following the subcommand pattern used by other WSLC commands. Includes unit tests for command structure and command-line parsing. Co-authored-by: Pooja Trivedi <trivedipooja@microsoft.com> Co-Authored-By: Claude Sonnet 4.6 * [WSLC] Fix E2E help/invalid-command tests after version subcommand addition Update expected help output in WSLCE2EGlobalTests to include the newly added 'version' subcommand, fixing WSLCE2E_HelpCommand and WSLCE2E_InvalidCommand_DisplaysErrorMessage test failures. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * [WSLC] Add E2E version command test and strengthen unit test - Add WSLCE2E_VersionCommand E2E test in WSLCE2EGlobalTests verifying stdout, empty stderr, and exit code for 'wslc version' - Add assertion to VersionCommand_HasNoArguments unit test to verify only the auto-added --help argument is present Authored-By: Pooja Trivedi <trivedipooja@microsoft.com> Co-Authored-By: Claude Sonnet 4.6 * Mark 'context' as UNREFERENCED_PARAMETER in VersionCommand::ExecuteInternal to avoid build issues * Address PR feedback on wslc version command - Use Localization::WSLCCLI_VersionDesc/LongDesc instead of hard-coded strings; add entries to en-US Resources.resw - Centralize version printing in VersionCommand::PrintVersion(); reuse from RootCommand --version flag - Drop 'v' prefix from version output per OneBlue's feedback - Add 'version' entry to E2E GetAvailableCommands() to fix WSLCE2E_HelpCommand and WSLCE2E_InvalidCommand_DisplaysErrorMessage Co-Authored-By: Pooja Trivedi * Fix build: add missing using namespace wsl::shared Localization::WSLCCLI_VersionDesc() and WSLCCLI_VersionLongDesc() live in wsl::shared::Localization. Without this using directive the compiler cannot resolve the unqualified Localization:: references in VersionCommand.cpp. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Pooja Trivedi <trivedipooja@microsoft.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent c223800 commit 715ce52

7 files changed

Lines changed: 138 additions & 1 deletion

File tree

localization/strings/en-US/Resources.resw

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2313,6 +2313,12 @@ On first run, creates the file with all settings commented out at their defaults
23132313
<data name="WSLCCLI_SettingsResetConfirm" xml:space="preserve">
23142314
<value>Settings reset to defaults.</value>
23152315
</data>
2316+
<data name="WSLCCLI_VersionDesc" xml:space="preserve">
2317+
<value>Show version information.</value>
2318+
</data>
2319+
<data name="WSLCCLI_VersionLongDesc" xml:space="preserve">
2320+
<value>Show version information for this tool.</value>
2321+
</data>
23162322
<data name="WSLCCLI_AllArgDescription" xml:space="preserve">
23172323
<value>Show all regardless of state.</value>
23182324
</data>

src/windows/wslc/commands/RootCommand.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Module Name:
1818
#include "ImageCommand.h"
1919
#include "SessionCommand.h"
2020
#include "SettingsCommand.h"
21+
#include "VersionCommand.h"
2122

2223
using namespace wsl::windows::wslc::execution;
2324
using namespace wsl::shared;
@@ -47,6 +48,7 @@ std::vector<std::unique_ptr<Command>> RootCommand::GetCommands() const
4748
commands.push_back(std::make_unique<ImageSaveCommand>(FullName()));
4849
commands.push_back(std::make_unique<ContainerStartCommand>(FullName()));
4950
commands.push_back(std::make_unique<ContainerStopCommand>(FullName()));
51+
commands.push_back(std::make_unique<VersionCommand>(FullName()));
5052
return commands;
5153
}
5254

@@ -71,7 +73,7 @@ void RootCommand::ExecuteInternal(CLIExecutionContext& context) const
7173
{
7274
if (context.Args.Contains(ArgType::Version))
7375
{
74-
wsl::windows::common::wslutil::PrintMessage(std::format(L"{} v{}", s_ExecutableName, WSL_PACKAGE_VERSION));
76+
VersionCommand::PrintVersion();
7577
return;
7678
}
7779

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*++
2+
3+
Copyright (c) Microsoft. All rights reserved.
4+
5+
Module Name:
6+
7+
VersionCommand.cpp
8+
9+
Abstract:
10+
11+
Implementation of the version command.
12+
13+
--*/
14+
#include "VersionCommand.h"
15+
16+
using namespace wsl::shared;
17+
using namespace wsl::windows::wslc::execution;
18+
19+
namespace wsl::windows::wslc {
20+
std::wstring VersionCommand::ShortDescription() const
21+
{
22+
return Localization::WSLCCLI_VersionDesc();
23+
}
24+
25+
std::wstring VersionCommand::LongDescription() const
26+
{
27+
return Localization::WSLCCLI_VersionLongDesc();
28+
}
29+
30+
void VersionCommand::PrintVersion()
31+
{
32+
wsl::windows::common::wslutil::PrintMessage(std::format(L"{} {}", s_ExecutableName, WSL_PACKAGE_VERSION));
33+
}
34+
35+
void VersionCommand::ExecuteInternal(CLIExecutionContext& context) const
36+
{
37+
UNREFERENCED_PARAMETER(context);
38+
PrintVersion();
39+
}
40+
} // namespace wsl::windows::wslc
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*++
2+
3+
Copyright (c) Microsoft. All rights reserved.
4+
5+
Module Name:
6+
7+
VersionCommand.h
8+
9+
Abstract:
10+
11+
Declaration of the VersionCommand.
12+
13+
--*/
14+
#pragma once
15+
#include "Command.h"
16+
17+
namespace wsl::windows::wslc {
18+
struct VersionCommand final : public Command
19+
{
20+
constexpr static std::wstring_view CommandName = L"version";
21+
VersionCommand(const std::wstring& parent) : Command(CommandName, parent)
22+
{
23+
}
24+
static void PrintVersion();
25+
std::wstring ShortDescription() const override;
26+
std::wstring LongDescription() const override;
27+
28+
protected:
29+
void ExecuteInternal(CLIExecutionContext& context) const override;
30+
};
31+
} // namespace wsl::windows::wslc

test/windows/wslc/CommandLineTestCases.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ COMMAND_LINE_TEST_CASE(L"image list -q", L"list", true)
125125
COMMAND_LINE_TEST_CASE(L"image pull ubuntu", L"pull", true)
126126
COMMAND_LINE_TEST_CASE(L"pull ubuntu", L"pull", true)
127127

128+
// Version command tests
129+
COMMAND_LINE_TEST_CASE(L"version", L"version", true)
130+
COMMAND_LINE_TEST_CASE(L"version --help", L"version", true)
131+
COMMAND_LINE_TEST_CASE(L"version extraarg", L"version", false)
128132
// Settings command
129133
COMMAND_LINE_TEST_CASE(L"settings", L"settings", true)
130134
COMMAND_LINE_TEST_CASE(L"settings reset", L"reset", true)

test/windows/wslc/WSLCCLICommandUnitTests.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Module Name:
2020
#include "RootCommand.h"
2121
#include "ContainerCommand.h"
2222
#include "SessionCommand.h"
23+
#include "VersionCommand.h"
2324

2425
using namespace wsl::windows::wslc;
2526
using namespace WSLCTestHelpers;
@@ -126,6 +127,48 @@ class WSLCCLICommandUnitTests
126127
VERIFY_IS_NOT_NULL(subcmd.get());
127128
}
128129
}
130+
131+
// Test: Verify VersionCommand has the correct name
132+
TEST_METHOD(VersionCommand_HasCorrectName)
133+
{
134+
auto cmd = VersionCommand(L"wslc");
135+
VERIFY_ARE_EQUAL(std::wstring_view(L"version"), cmd.Name());
136+
}
137+
138+
// Test: Verify VersionCommand has no subcommands
139+
TEST_METHOD(VersionCommand_HasNoSubcommands)
140+
{
141+
auto cmd = VersionCommand(L"wslc");
142+
VERIFY_ARE_EQUAL(0u, cmd.GetCommands().size());
143+
}
144+
145+
// Test: Verify VersionCommand has no arguments (only the auto-added --help)
146+
TEST_METHOD(VersionCommand_HasNoArguments)
147+
{
148+
auto cmd = VersionCommand(L"wslc");
149+
VERIFY_ARE_EQUAL(0u, cmd.GetArguments().size());
150+
// Test out that auto added help command is the only one
151+
VERIFY_ARE_EQUAL(1u, cmd.GetAllArguments().size());
152+
}
153+
154+
// Test: Verify RootCommand contains VersionCommand as a subcommand
155+
TEST_METHOD(RootCommand_ContainsVersionCommand)
156+
{
157+
auto root = RootCommand();
158+
auto subcommands = root.GetCommands();
159+
160+
bool found = false;
161+
for (const auto& subcmd : subcommands)
162+
{
163+
if (subcmd->Name() == VersionCommand::CommandName)
164+
{
165+
found = true;
166+
break;
167+
}
168+
}
169+
170+
VERIFY_IS_TRUE(found, L"RootCommand should contain VersionCommand");
171+
}
129172
};
130173

131174
} // namespace WSLCCLICommandUnitTests

test/windows/wslc/e2e/WSLCE2EGlobalTests.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ class WSLCE2EGlobalTests
5151
RunWslcAndVerify(L"INVALID_CMD", {.Stdout = GetHelpMessage(), .Stderr = L"Unrecognized command: 'INVALID_CMD'\r\n", .ExitCode = 1});
5252
}
5353

54+
TEST_METHOD(WSLCE2E_VersionCommand)
55+
{
56+
WSL2_TEST_ONLY();
57+
RunWslcAndVerify(L"version", {.Stdout = GetVersionMessage(), .Stderr = L"", .ExitCode = 0});
58+
}
5459
TEST_METHOD(WSLCE2E_Session_DefaultElevated)
5560
{
5661
WSL2_TEST_ONLY();
@@ -400,6 +405,11 @@ class WSLCE2EGlobalTests
400405
return output.str();
401406
}
402407

408+
std::wstring GetVersionMessage() const
409+
{
410+
return std::format(L"wslc {}\r\n", WSL_PACKAGE_VERSION);
411+
}
412+
403413
std::wstring GetDescription() const
404414
{
405415
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
435445
{L"save", Localization::WSLCCLI_ImageSaveDesc()},
436446
{L"start", Localization::WSLCCLI_ContainerStartDesc()},
437447
{L"stop", Localization::WSLCCLI_ContainerStopDesc()},
448+
{L"version", Localization::WSLCCLI_VersionDesc()},
438449
};
439450

440451
size_t maxLen = 0;

0 commit comments

Comments
 (0)