CLI: Fix image --quiet to output truncated ids instead of repository:tag (#40855)
David Bennett committed
Jun 19, 2026 at 22:24 UTC
83effc5b485475adcc140b8c290914b38dae498d
5 files changed
+63
-25
src/windows/wslc/tasks/ImageTasks.cpp
+2
-2
@@ -118,10 +118,10 @@ void ListImages(CLIExecutionContext& context)
118
119
if (context.Args.Contains(ArgType::Quiet))
120
{
121
- // Print only the image names.
121
+ bool trunc = !context.Args.Contains(ArgType::NoTrunc);
122
for (const auto& image : images)
123
{
124
- PrintMessage(MultiByteToWide(image.Repository.value_or("<untagged>") + ":" + image.Tag.value_or("<untagged>")));
124
+ context.Reporter.Output(L"{}\n", trunc ? TruncateId(image.Id, true) : image.Id);
125
}
126
127
return;
test/windows/wslc/e2e/WSLCE2EHelpers.cpp
+11
-9
@@ -358,13 +358,14 @@ void EnsureImageContainersAreDeleted(const TestImage& image)
358
359
void EnsureImageIsDeleted(const TestImage& image)
360
{
361
- auto result = RunWslc(L"image list -q");
361
+ auto result = RunWslc(L"image list --format json");
362
result.Verify({.Stderr = L"", .ExitCode = 0});
363
364
- auto outputLines = result.GetStdoutLines();
365
- for (const auto& line : outputLines)
364
+ auto images = wsl::shared::FromJson<std::vector<wsl::windows::wslc::models::ImageInformation>>(result.Stdout.value().c_str());
365
+ for (const auto& img : images)
366
{
367
- if (line.find(image.NameAndTag()) != std::wstring::npos)
367
+ if (img.Repository == wsl::shared::string::WideToMultiByte(image.Name) &&
368
+ img.Tag == wsl::shared::string::WideToMultiByte(image.Tag))
369
{
370
EnsureImageContainersAreDeleted(image);
371
auto deleteResult = RunWslc(std::format(L"image delete --force {}", image.NameAndTag()));
@@ -376,19 +377,20 @@ void EnsureImageIsDeleted(const TestImage& image)
377
378
void EnsureImageIsLoaded(const TestImage& image, const std::wstring& sessionName)
379
{
379
- std::wstring listCommand = L"image list -q";
380
+ std::wstring listCommand = L"image list --format json";
381
if (!sessionName.empty())
382
{
382
- listCommand = std::format(L"--session \"{}\" image list -q", sessionName);
383
+ listCommand = std::format(L"--session \"{}\" image list --format json", sessionName);
384
}
385
386
auto result = RunWslc(listCommand);
387
result.Verify({.Stderr = L"", .ExitCode = 0});
388
388
- auto outputLines = result.GetStdoutLines();
389
- for (const auto& line : outputLines)
389
+ auto images = wsl::shared::FromJson<std::vector<wsl::windows::wslc::models::ImageInformation>>(result.Stdout.value().c_str());
390
+ for (const auto& img : images)
391
{
391
- if (line.find(image.NameAndTag()) != std::wstring::npos)
392
+ if (img.Repository == wsl::shared::string::WideToMultiByte(image.Name) &&
393
+ img.Tag == wsl::shared::string::WideToMultiByte(image.Tag))
394
{
395
return;
396
}
test/windows/wslc/e2e/WSLCE2EImageDeleteTests.cpp
+3
-3
@@ -134,12 +134,12 @@ class WSLCE2EImageDeleteTests
134
135
VerifyImageIsListed(DebianImage);
136
137
- auto listAfter = RunWslc(L"image list -q");
137
+ auto listAfter = RunWslc(L"image list");
138
listAfter.Verify({.Stderr = L"", .ExitCode = 0});
139
for (const auto& line : listAfter.GetStdoutLines())
140
{
141
- VERIFY_IS_TRUE(
142
- line.find(NoPruneTaggedImage.NameAndTag()) == std::wstring::npos,
141
+ VERIFY_IS_FALSE(
142
+ line.find(NoPruneTaggedImage.Name) != std::wstring::npos && line.find(NoPruneTaggedImage.Tag) != std::wstring::npos,
143
L"Secondary tag should have been removed by `image delete --no-prune`");
144
}
145
}
test/windows/wslc/e2e/WSLCE2EImageListTests.cpp
+44
-9
@@ -19,7 +19,7 @@ Abstract:
19
20
namespace WSLCE2ETests {
21
using namespace wsl::shared;
22
-
22
+using namespace wsl::windows::common::string;
23
using namespace wsl::windows::wslc::models;
24
25
class WSLCE2EImageListTests
@@ -61,22 +61,57 @@ class WSLCE2EImageListTests
61
VERIFY_FAIL(L"Failed to find the loaded image in the output");
62
}
63
64
- WSLC_TEST_METHOD(WSLCE2E_Image_List_QuietOption_OutputsNamesOnly)
64
+ WSLC_TEST_METHOD(WSLCE2E_Image_List_QuietOption_OutputsIdsOnly)
65
{
66
- const auto result = RunWslc(L"image list --quiet");
67
- result.Verify({.Stderr = L"", .ExitCode = 0});
66
+ // Get the expected image ID from JSON output.
67
+ auto jsonResult = RunWslc(L"image list --format json");
68
+ jsonResult.Verify({.Stderr = L"", .ExitCode = 0});
69
+ const auto images = wsl::shared::FromJson<std::vector<ImageInformation>>(jsonResult.Stdout.value().c_str());
70
69
- bool imageFound = false;
70
- for (const auto& line : result.GetStdoutLines())
71
+ std::string debianId;
72
+ for (const auto& image : images)
73
{
72
- if (line == DebianImage.NameAndTag())
74
+ if (image.Repository == wsl::shared::string::WideToMultiByte(DebianImage.Name) &&
75
+ image.Tag == wsl::shared::string::WideToMultiByte(DebianImage.Tag))
76
{
74
- imageFound = true;
77
+ debianId = image.Id;
78
break;
79
}
80
}
81
+ VERIFY_ARE_NOT_EQUAL(std::string{}, debianId, L"Debian image was not present in `image list --format json` output");
82
+
83
+ const auto truncatedDebianId = wsl::shared::string::MultiByteToWide(TruncateId(debianId, true));
84
+ const auto fullDebianIdW = wsl::shared::string::MultiByteToWide(debianId);
85
+
86
+ // Default --quiet truncates to 12 chars.
87
+ auto truncResult = RunWslc(L"image list --quiet");
88
+ truncResult.Verify({.Stderr = L"", .ExitCode = 0});
89
79
- VERIFY_IS_TRUE(imageFound);
90
+ bool truncatedFound = false;
91
+ for (const auto& line : truncResult.GetStdoutLines())
92
+ {
93
+ if (line == truncatedDebianId)
94
+ {
95
+ truncatedFound = true;
96
+ break;
97
+ }
98
+ }
99
+ VERIFY_IS_TRUE(truncatedFound, L"Truncated image ID not found in --quiet output");
100
+
101
+ // --quiet --no-trunc shows the full id with sha256: prefix.
102
+ auto noTruncResult = RunWslc(L"image list --quiet --no-trunc");
103
+ noTruncResult.Verify({.Stderr = L"", .ExitCode = 0});
104
+
105
+ bool fullFound = false;
106
+ for (const auto& line : noTruncResult.GetStdoutLines())
107
+ {
108
+ if (line == fullDebianIdW)
109
+ {
110
+ fullFound = true;
111
+ break;
112
+ }
113
+ }
114
+ VERIFY_IS_TRUE(fullFound, L"Full image ID not found in --quiet --no-trunc output");
115
}
116
117
WSLC_TEST_METHOD(WSLCE2E_Image_List_InvalidFormatOption)
test/windows/wslc/e2e/WSLCE2EPushPullTests.cpp
+3
-2
@@ -77,10 +77,11 @@ class WSLCE2EPushPullTests
77
result.Verify({.Stderr = L"", .ExitCode = 0});
78
79
// Verify the image is now present.
80
- result = RunWslc(L"image list -q");
80
+ auto registryRepo = registryImage.substr(0, registryImage.rfind(L':'));
81
+ result = RunWslc(L"image list --format json");
82
result.Verify({.Stderr = L"", .ExitCode = 0});
83
VERIFY_IS_TRUE(result.Stdout.has_value());
83
- VERIFY_IS_TRUE(result.Stdout->find(registryImage) != std::wstring::npos);
84
+ VERIFY_IS_TRUE(result.Stdout->find(registryRepo) != std::wstring::npos);
85
}
86
}
87