Add repository, tag, ID and created columns to image list output#40043
Conversation
There was a problem hiding this comment.
Pull request overview
This PR enhances the wslc image ls/list output to surface more Docker-like image metadata (repository, tag, image ID, created time, size) across table, quiet, and JSON formats, and updates E2E tests accordingly.
Changes:
- Extends
ImageInformationto includeRepository,Tag,Id, andCreatedand updates JSON serialization accordingly. - Updates
wslc image listtable/quiet output formatting (new columns, short ID rendering, relative “CREATED” time). - Adjusts E2E tests/helpers to work with the new output format and validates the new table header columns.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| test/windows/wslc/e2e/WSLCE2EImageListTests.cpp | Updates image list assertions; adds a header/columns check for table output. |
| test/windows/wslc/e2e/WSLCE2EHelpers.cpp | Adjusts image existence checks used by E2E setup/cleanup. |
| src/windows/wslc/tasks/ImageTasks.cpp | Updates CLI formatting for image list (quiet + table) and adds created/ID formatting. |
| src/windows/wslc/services/ImageService.cpp | Populates the expanded ImageInformation fields using ParseImage() and WSLC image metadata. |
| src/windows/wslc/services/ImageModel.h | Expands the image model and updates nlohmann JSON mapping. |
Comments suppressed due to low confidence (1)
test/windows/wslc/e2e/WSLCE2EHelpers.cpp:214
EnsureImageIsDeleted()now checksimage listoutput with a substring match onimage.Name. This can trigger cleanup logic even when the specificNameAndTag()image isn't present (e.g., another repo containing the substring), leading to an attempted delete ofimage.NameAndTag()and a potential cleanup failure.
Consider switching the existence check to wslc image list --quiet (exact match) or --format json and match repository+tag explicitly.
auto outputLines = result.GetStdoutLines();
for (const auto& line : outputLines)
{
if (line.find(image.Name) != std::wstring::npos)
{
EnsureImageContainersAreDeleted(image);
auto deleteResult = RunWslc(std::format(L"image delete --force {}", image.NameAndTag()));
deleteResult.Verify({.Stderr = L"", .ExitCode = 0});
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
test/windows/wslc/e2e/WSLCE2EImageListTests.cpp:61
WSLCE2E_Image_List_DisplayLoadedImagenow only checks forDebianImage.Nameas a substring in the table output. This can yield false positives (e.g., if a different tag of the same repository, or another repository containing the substring, is present) and allow the test to pass even when the expectedName:Tagisn’t listed. Prefer asserting on the exactNameAndTag()by usingimage list --quiet(line equality) or by parsing--format jsonand matching bothRepositoryandTag.
if (line.find(DebianImage.Name) != std::wstring::npos)
{
return;
}
}
test/windows/wslc/e2e/WSLCE2EHelpers.cpp:214
EnsureImageIsDeleted()matchesimage.Nameas a substring inimage listoutput. This is prone to false matches (e.g., another tag for the same repo, or another repo containing the substring), which can cause the helper to attempt deletingimage.NameAndTag()even when that specific tag isn’t present (leading to flaky failures) or to skip deletion when the exact tag still exists. Useimage list --quietand compare exact lines toNameAndTag(), or use--format jsonand match bothRepositoryandTag.
for (const auto& line : outputLines)
{
if (line.find(image.Name) != std::wstring::npos)
{
EnsureImageContainersAreDeleted(image);
auto deleteResult = RunWslc(std::format(L"image delete --force {}", image.NameAndTag()));
deleteResult.Verify({.Stderr = L"", .ExitCode = 0});
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (2)
test/windows/wslc/e2e/WSLCE2EHelpers.cpp:324
EnsureImageIsLoaded()declaresauto resulttwice in the same scope (image list -qand thenlistCommand), which will not compile. Remove the first declaration or rename one of them, and make sure the chosen call is the one actually used for the presence check.
auto result = RunWslc(L"image list -q");
std::wstring listCommand = L"image list";
if (!sessionName.empty())
{
listCommand = std::format(L"image list --session \"{}\"", sessionName);
}
auto result = RunWslc(listCommand);
result.Verify({.Stderr = L"", .ExitCode = 0});
test/windows/wslc/e2e/WSLCE2EHelpers.cpp:333
EnsureImageIsLoaded()searchesimage list(table) output forrepo:tag, but the table output now prints repository and tag in separate columns, so the substringrepo:taglikely won’t appear and this will always treat the image as missing. Useimage list -q(or--format json) for the existence check so the comparison matchesTestImage::NameAndTag()reliably.
std::wstring listCommand = L"image list";
if (!sessionName.empty())
{
listCommand = std::format(L"image list --session \"{}\"", sessionName);
}
auto result = RunWslc(listCommand);
result.Verify({.Stderr = L"", .ExitCode = 0});
auto outputLines = result.GetStdoutLines();
for (const auto& line : outputLines)
{
if (line.find(image.NameAndTag()) != std::wstring::npos)
{
return;
}
}
| std::string Repository; | ||
| std::string Tag; | ||
| std::string Id; | ||
| LONGLONG Created{}; | ||
| ULONGLONG Size{}; | ||
|
|
||
| NLOHMANN_DEFINE_TYPE_INTRUSIVE(ImageInformation, Name, Size); | ||
| NLOHMANN_DEFINE_TYPE_INTRUSIVE(ImageInformation, Repository, Tag, Id, Created, Size); |
There was a problem hiding this comment.
Replacing Name with {Repository, Tag, Id, Created} changes the JSON shape produced/consumed via NLOHMANN_DEFINE_TYPE_INTRUSIVE, which is a breaking change for any existing image list JSON consumers expecting a Name field. If backward compatibility matters, consider keeping Name (populated as Repository + ":" + Tag) and including it in serialization, or implement a custom to_json/from_json that continues to emit Name while adding the new fields.
… into user/beenachauhan/improve-image-list
OneBlue
left a comment
There was a problem hiding this comment.
Change looks good, two minor comments
| MultiByteToWide(image.Repository.value_or("<untagged>")), | ||
| MultiByteToWide(image.Tag.value_or("<untagged>")), | ||
| MultiByteToWide(TruncateId(image.Id, trunc)), | ||
| ContainerService::FormatRelativeTime(image.Created > 0 ? static_cast<ULONGLONG>(image.Created) : 0), |
There was a problem hiding this comment.
ContainerService::FormatRelativeTime(0) will format relative time from the Unix epoch, producing a huge "N days ago" value. If image.Created can be 0/unknown, consider outputting an empty/"-" value (or a dedicated "unknown" string) instead of calling FormatRelativeTime with 0.
| ContainerService::FormatRelativeTime(image.Created > 0 ? static_cast<ULONGLONG>(image.Created) : 0), | |
| image.Created > 0 | |
| ? ContainerService::FormatRelativeTime(static_cast<ULONGLONG>(image.Created)) | |
| : std::wstring(L"-"), |
There was a problem hiding this comment.
I guess this isn't supposed to happen ? Probably not a huge deal
| // Parse the image reference — dangling images have no repo/tag | ||
| std::string imageRef = image.Image; | ||
| if (imageRef != "<none>:<none>") | ||
| { | ||
| auto parsed = wsl::windows::common::wslutil::ParseImage(imageRef); | ||
| info.Repository = parsed.first; | ||
| info.Tag = parsed.second; | ||
| } |
There was a problem hiding this comment.
For dangling images, ImageService::List() leaves Repository/Tag unset (when Image == "<none>:<none>"), which then causes the CLI to synthesize placeholders like <untagged> in both table and --quiet output. That placeholder string is not the actual image reference returned by the service and is unlikely to be usable as an identifier in follow-up commands. Consider preserving the service’s sentinel by setting Repository="<none>" and Tag="<none>" (or storing the raw reference separately) so image list output stays consistent and scriptable even with dangling images present.
Summary of the Pull Request
Enhance


wslc image lsoutput to display REPOSITORY, TAG, IMAGE ID, CREATED, SIZE.PR Checklist
Detailed Description of the Pull Request / Additional comments
Validation Steps Performed