Skip to content

Commit 1b967ea

Browse files
CC-5462: Simplify containers images list output (#9620)
Use a simple table (one row for each entry) instead of a fancy table with badly drawn box characters. Print one row for each name:tag combination. Co-authored-by: Carmen Popoviciu <[email protected]>
1 parent 0062811 commit 1b967ea

File tree

3 files changed

+49
-40
lines changed

3 files changed

+49
-40
lines changed

.changeset/hungry-garlics-flow.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"wrangler": patch
3+
---
4+
5+
Simplify containers images list output format

packages/wrangler/src/__tests__/cloudchamber/images.test.ts

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -230,15 +230,13 @@ describe("cloudchamber image list", () => {
230230
await runWrangler("cloudchamber images list");
231231
expect(std.err).toMatchInlineSnapshot(`""`);
232232
expect(std.out).toMatchInlineSnapshot(`
233-
"┌─┬─┐
234-
│ REPOSITORY │ TAG │
235-
├─┼─┤
236-
│ one │ hundred ten │
237-
├─┼─┤
238-
│ two │ thousand twenty │
239-
├─┼─┤
240-
│ three │ million thirty │
241-
└─┴─┘"
233+
"REPOSITORY TAG
234+
one hundred
235+
one ten
236+
two thousand
237+
two twenty
238+
three million
239+
three thirty"
242240
`);
243241
});
244242
it("should list images with a filter", async () => {
@@ -276,11 +274,9 @@ describe("cloudchamber image list", () => {
276274
await runWrangler("cloudchamber images list --filter '^two$'");
277275
expect(std.err).toMatchInlineSnapshot(`""`);
278276
expect(std.out).toMatchInlineSnapshot(`
279-
"┌─┬─┐
280-
│ REPOSITORY │ TAG │
281-
├─┼─┤
282-
│ two │ thousand twenty │
283-
└─┴─┘"
277+
"REPOSITORY TAG
278+
two thousand
279+
two twenty"
284280
`);
285281
});
286282
it("should filter out repos with no non-sha tags", async () => {
@@ -320,15 +316,13 @@ describe("cloudchamber image list", () => {
320316
await runWrangler("cloudchamber images list");
321317
expect(std.err).toMatchInlineSnapshot(`""`);
322318
expect(std.out).toMatchInlineSnapshot(`
323-
"┌─┬─┐
324-
│ REPOSITORY │ TAG │
325-
├─┼─┤
326-
│ one │ hundred ten │
327-
├─┼─┤
328-
│ two │ thousand twenty │
329-
├─┼─┤
330-
│ three │ million thirty │
331-
└─┴─┘"
319+
"REPOSITORY TAG
320+
one hundred
321+
one ten
322+
two thousand
323+
two twenty
324+
three million
325+
three thirty"
332326
`);
333327
});
334328
it("should list repos with json flag set", async () => {

packages/wrangler/src/cloudchamber/images/list.ts

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
ImageRegistriesService,
44
} from "@cloudflare/containers-shared";
55
import { logger } from "../../logger";
6+
import { getAccountId } from "../../user";
67
import { handleFailure, promiseSpinner } from "../common";
78
import type { Config } from "../../config";
89
import type { containersScope } from "../../containers";
@@ -100,7 +101,7 @@ async function handleDeleteImageCommand(
100101
`Failed to delete image ${args.image}: ${gcResponse.status} ${gcResponse.statusText}`
101102
);
102103
}
103-
await logger.log(`Deleted tag: ${args.image}`);
104+
logger.log(`Deleted tag: ${args.image}`);
104105
}),
105106
{ message: "Deleting", json: args.json }
106107
);
@@ -111,24 +112,27 @@ async function handleDeleteImageCommand(
111112

112113
async function handleListImagesCommand(
113114
args: StrictYargsOptionsToInterfaceJSON<typeof listImagesYargs>,
114-
_config: Config
115+
config: Config
115116
) {
116117
try {
117118
return await promiseSpinner(
118119
getCreds().then(async (creds) => {
119120
const repos = await listRepos(creds);
120-
const tags: TagsResponse[] = [];
121+
const responses: TagsResponse[] = [];
122+
const accountId = config.account_id || (await getAccountId(config));
123+
const accountIdPrefix = new RegExp(`^${accountId}/`);
124+
const filter = new RegExp(args.filter ?? "");
121125
for (const repo of repos) {
122126
const stripped = repo.replace(/^\/+/, "");
123-
const regex = new RegExp(args.filter ?? "");
124-
if (regex.test(stripped)) {
127+
if (filter.test(stripped)) {
125128
// get all tags for repo
126-
const repoTags = await listTags(stripped, creds);
127-
tags.push({ name: stripped, tags: repoTags });
129+
const tags = await listTags(stripped, creds);
130+
const name = stripped.replace(accountIdPrefix, "");
131+
responses.push({ name, tags });
128132
}
129133
}
130134

131-
await ListTags(tags, false, args.json);
135+
await ListTags(responses, false, args.json);
132136
}),
133137
{ message: "Listing", json: args.json }
134138
);
@@ -157,15 +161,21 @@ async function ListTags(
157161
if (json) {
158162
logger.log(JSON.stringify(responses, null, 2));
159163
} else {
160-
const rows = responses
161-
.map((resp) => {
162-
return {
163-
REPOSITORY: resp.name,
164-
TAG: resp.tags.join(" "),
165-
};
166-
})
167-
.flat();
168-
logger.table(rows);
164+
const rows = responses.flatMap((r) => r.tags.map((t) => [r.name, t]));
165+
const headers = ["REPOSITORY", "TAG"];
166+
const widths = new Array(headers.length).fill(0);
167+
168+
// Find the maximum length of each column (except for the last)
169+
for (let i = 0; i < widths.length - 1; i++) {
170+
widths[i] = rows
171+
.map((r) => r[i].length)
172+
.reduce((a, b) => Math.max(a, b), headers[i].length);
173+
}
174+
175+
logger.log(headers.map((h, i) => h.padEnd(widths[i], " ")).join(" "));
176+
for (const row of rows) {
177+
logger.log(row.map((v, i) => v.padEnd(widths[i], " ")).join(" "));
178+
}
169179
}
170180
}
171181

0 commit comments

Comments
 (0)