Skip to content

Commit e82aa19

Browse files
[wrangler] Add --json flag to r2 bucket info command (#9530)
* Clean commit: Add --json flag to r2 bucket info * Update packages/wrangler/src/r2/bucket.ts Co-authored-by: Pete Bacon Darwin <[email protected]> * test: simplify R2 bucket --json test per review suggestion * Update .changeset/happy-streets-leave.md * fix formatting * skip remote unenv-preset tests on forks --------- Co-authored-by: Pete Bacon Darwin <[email protected]> Co-authored-by: Peter Bacon Darwin <[email protected]>
1 parent 1655bec commit e82aa19

File tree

4 files changed

+71
-3
lines changed

4 files changed

+71
-3
lines changed

.changeset/happy-streets-leave.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"wrangler": minor
3+
---
4+
5+
Add --json flag to r2 bucket info command for machine-readable output.

packages/wrangler/e2e/unenv-preset/preset.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { join } from "node:path";
22
import { fetch } from "undici";
33
import { afterAll, beforeAll, describe, expect, test, vi } from "vitest";
4+
import { CLOUDFLARE_ACCOUNT_ID } from "../helpers/account-id";
45
import { WranglerE2ETestHelper } from "../helpers/e2e-wrangler-test";
56
import { generateResourceName } from "../helpers/generate-resource-name";
67
import { retry } from "../helpers/retry";
@@ -85,6 +86,12 @@ describe.each(testConfigs)(
8586
// The "local" and "remote" runtimes do not necessarily use the exact same version
8687
// of workerd and we want to make sure the preset works for both.
8788
describe.for(["local", "remote"])("%s tests", (localOrRemote) => {
89+
// Skip the remote tests if the user is not logged in (e.g. a PR from a forked repo)
90+
if (localOrRemote === "remote" && !CLOUDFLARE_ACCOUNT_ID) {
91+
test.skip("Remote tests are not supported");
92+
return;
93+
}
94+
8895
let url: string;
8996
let wrangler: WranglerLongLivedCommand;
9097
beforeAll(async () => {
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { beforeEach, describe, expect, it, vi } from "vitest";
2+
import { getR2Bucket, getR2BucketMetrics } from "../../r2/helpers";
3+
import { requireAuth } from "../../user";
4+
import { mockConsoleMethods } from "../helpers/mock-console";
5+
import { runWrangler } from "../helpers/run-wrangler";
6+
7+
vi.unmock("../../wrangler-banner");
8+
9+
vi.mock("../../r2/helpers");
10+
vi.mock("../../user");
11+
12+
const logs = mockConsoleMethods();
13+
14+
const mockRequireAuth = vi.mocked(requireAuth);
15+
const mockGetR2Bucket = vi.mocked(getR2Bucket);
16+
const mockGetR2BucketMetrics = vi.mocked(getR2BucketMetrics);
17+
18+
describe("r2 bucket info", () => {
19+
beforeEach(() => {
20+
vi.resetAllMocks();
21+
22+
mockRequireAuth.mockResolvedValue("test-account-id");
23+
mockGetR2Bucket.mockResolvedValue({
24+
name: "my-bucket-name",
25+
creation_date: "2025-06-07T15:55:22.222Z",
26+
location: "APAC",
27+
storage_class: "Standard",
28+
});
29+
mockGetR2BucketMetrics.mockResolvedValue({
30+
objectCount: 0,
31+
totalSize: "0 B",
32+
});
33+
});
34+
35+
it("should output valid JSON format when --json flag is used", async () => {
36+
await runWrangler("r2 bucket info my-bucket-name --json");
37+
const json = JSON.parse(logs.out);
38+
expect(json.name).toBe("my-bucket-name");
39+
});
40+
});

packages/wrangler/src/r2/bucket.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ export const r2BucketInfoCommand = createCommand({
198198
positionalArgs: ["bucket"],
199199
args: {
200200
bucket: {
201-
describe: "The name of the bucket to delete",
201+
describe: "The name of the bucket to retrieve info for",
202202
type: "string",
203203
demandOption: true,
204204
},
@@ -208,18 +208,30 @@ export const r2BucketInfoCommand = createCommand({
208208
requiresArg: true,
209209
type: "string",
210210
},
211+
json: {
212+
describe: "Return the bucket information as JSON",
213+
type: "boolean",
214+
default: false,
215+
},
211216
},
217+
behaviour: {
218+
printBanner: (args) => !args.json,
219+
},
220+
212221
async handler(args, { config }) {
213222
const accountId = await requireAuth(config);
214223

215-
logger.log(`Getting info for '${args.bucket}'...`);
224+
if (!args.json) {
225+
logger.log(`Getting info for '${args.bucket}'...`);
226+
}
216227

217228
const bucketInfo = await getR2Bucket(
218229
config,
219230
accountId,
220231
args.bucket,
221232
args.jurisdiction
222233
);
234+
223235
const bucketMetrics = await getR2BucketMetrics(
224236
config,
225237
accountId,
@@ -236,7 +248,11 @@ export const r2BucketInfoCommand = createCommand({
236248
bucket_size: bucketMetrics.totalSize,
237249
};
238250

239-
logger.log(formatLabelledValues(output));
251+
if (args.json) {
252+
logger.json(output);
253+
} else {
254+
logger.log(formatLabelledValues(output));
255+
}
240256
},
241257
});
242258

0 commit comments

Comments
 (0)