Skip to content

Commit 24c2c8f

Browse files
[R2 Data Catalog] Add wrangler commands for R2 Data Catalog (#8548)
* [R2 Data Catalog] Add wrangler commands for R2 Data Catalog * Copy changes, removed catalog list command, updated tests * Fixed typos, change copy * Minor response changes --------- Co-authored-by: Phillip Jones <[email protected]>
1 parent 665ebd8 commit 24c2c8f

File tree

6 files changed

+458
-0
lines changed

6 files changed

+458
-0
lines changed

.changeset/tangy-camels-write.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+
feat: Add wrangler commands for R2 Data Catalog

packages/wrangler/src/__tests__/r2.test.ts

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ describe("r2", () => {
157157
wrangler r2 bucket info <bucket> Get information about an R2 bucket
158158
wrangler r2 bucket delete <bucket> Delete an R2 bucket
159159
wrangler r2 bucket sippy Manage Sippy incremental migration on an R2 bucket
160+
wrangler r2 bucket catalog Manage the data catalog for your R2 buckets - provides an Iceberg REST interface for query engines like Spark, DuckDB, and Trino [open-beta]
160161
wrangler r2 bucket notification Manage event notification rules for an R2 bucket
161162
wrangler r2 bucket domain Manage custom domains for an R2 bucket
162163
wrangler r2 bucket dev-url Manage public access via the r2.dev URL for an R2 bucket
@@ -197,6 +198,7 @@ describe("r2", () => {
197198
wrangler r2 bucket info <bucket> Get information about an R2 bucket
198199
wrangler r2 bucket delete <bucket> Delete an R2 bucket
199200
wrangler r2 bucket sippy Manage Sippy incremental migration on an R2 bucket
201+
wrangler r2 bucket catalog Manage the data catalog for your R2 buckets - provides an Iceberg REST interface for query engines like Spark, DuckDB, and Trino [open-beta]
200202
wrangler r2 bucket notification Manage event notification rules for an R2 bucket
201203
wrangler r2 bucket domain Manage custom domains for an R2 bucket
202204
wrangler r2 bucket dev-url Manage public access via the r2.dev URL for an R2 bucket
@@ -929,6 +931,248 @@ describe("r2", () => {
929931
});
930932
});
931933

934+
describe("catalog", () => {
935+
it("should show the correct help when an invalid command is passed", async () => {
936+
await expect(() =>
937+
runWrangler("r2 bucket catalog foo")
938+
).rejects.toThrowErrorMatchingInlineSnapshot(
939+
`[Error: Unknown argument: foo]`
940+
);
941+
expect(std.err).toMatchInlineSnapshot(`
942+
"X [ERROR] Unknown argument: foo
943+
944+
"
945+
`);
946+
expect(std.out).toMatchInlineSnapshot(`
947+
"
948+
wrangler r2 bucket catalog
949+
950+
Manage the data catalog for your R2 buckets - provides an Iceberg REST interface for query engines like Spark, DuckDB, and Trino [open-beta]
951+
952+
COMMANDS
953+
wrangler r2 bucket catalog enable <bucket> Enable the data catalog on an R2 bucket [open-beta]
954+
wrangler r2 bucket catalog disable <bucket> Disable the data catalog for an R2 bucket [open-beta]
955+
wrangler r2 bucket catalog get <bucket> Get the status of the data catalog for an R2 bucket [open-beta]
956+
957+
GLOBAL FLAGS
958+
-c, --config Path to Wrangler configuration file [string]
959+
--cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string]
960+
-e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string]
961+
-h, --help Show help [boolean]
962+
-v, --version Show version number [boolean]"
963+
`);
964+
});
965+
966+
describe("enable", () => {
967+
it("should enable R2 catalog for the given bucket", async () => {
968+
msw.use(
969+
http.post(
970+
"*/accounts/some-account-id/r2-catalog/testBucket",
971+
async () => {
972+
return HttpResponse.json(
973+
createFetchResult(
974+
{
975+
id: "test-warehouse-id",
976+
name: "test-warehouse-name",
977+
},
978+
true
979+
)
980+
);
981+
},
982+
{ once: true }
983+
)
984+
);
985+
await runWrangler("r2 bucket catalog enable testBucket");
986+
expect(std.out).toMatchInlineSnapshot(
987+
`"✨ Successfully enabled data catalog on bucket 'testBucket'.
988+
989+
Catalog URI: 'https://catalog.cloudflarestorage.com/test-warehouse-name'
990+
991+
Use this Catalog URI with Iceberg-compatible query engines (Spark, DuckDB, Trino, etc.) to query data as tables.
992+
Note: You'll need a Cloudflare API token with 'R2 Data Catalog' permission to authenticate your client with this catalog.
993+
For more details, refer to: https://developers.cloudflare.com/r2/api/s3/tokens/"`
994+
);
995+
});
996+
997+
it("should error if no bucket name is given", async () => {
998+
await expect(
999+
runWrangler("r2 bucket catalog enable")
1000+
).rejects.toThrowErrorMatchingInlineSnapshot(
1001+
`[Error: Not enough non-option arguments: got 0, need at least 1]`
1002+
);
1003+
expect(std.out).toMatchInlineSnapshot(`
1004+
"
1005+
wrangler r2 bucket catalog enable <bucket>
1006+
1007+
Enable the data catalog on an R2 bucket [open-beta]
1008+
1009+
POSITIONALS
1010+
bucket The name of the bucket to enable [string] [required]
1011+
1012+
GLOBAL FLAGS
1013+
-c, --config Path to Wrangler configuration file [string]
1014+
--cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string]
1015+
-e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string]
1016+
-h, --help Show help [boolean]
1017+
-v, --version Show version number [boolean]"
1018+
`);
1019+
expect(std.err).toMatchInlineSnapshot(`
1020+
"X [ERROR] Not enough non-option arguments: got 0, need at least 1
1021+
1022+
"
1023+
`);
1024+
});
1025+
});
1026+
1027+
describe("disable", () => {
1028+
const { setIsTTY } = useMockIsTTY();
1029+
it("should error if no bucket name is given", async () => {
1030+
await expect(
1031+
runWrangler("r2 bucket catalog disable")
1032+
).rejects.toThrowErrorMatchingInlineSnapshot(
1033+
`[Error: Not enough non-option arguments: got 0, need at least 1]`
1034+
);
1035+
expect(std.out).toMatchInlineSnapshot(`
1036+
"
1037+
wrangler r2 bucket catalog disable <bucket>
1038+
1039+
Disable the data catalog for an R2 bucket [open-beta]
1040+
1041+
POSITIONALS
1042+
bucket The name of the bucket to disable the data catalog for [string] [required]
1043+
1044+
GLOBAL FLAGS
1045+
-c, --config Path to Wrangler configuration file [string]
1046+
--cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string]
1047+
-e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string]
1048+
-h, --help Show help [boolean]
1049+
-v, --version Show version number [boolean]"
1050+
`);
1051+
expect(std.err).toMatchInlineSnapshot(`
1052+
"X [ERROR] Not enough non-option arguments: got 0, need at least 1
1053+
1054+
"
1055+
`);
1056+
});
1057+
1058+
it("should disable R2 catalog for the given bucket", async () => {
1059+
setIsTTY(true);
1060+
mockConfirm({
1061+
text: "Are you sure you want to disable the data catalog for bucket 'testBucket'? This action is irreversible, and you cannot re-enable it on this bucket.",
1062+
result: true,
1063+
});
1064+
msw.use(
1065+
http.delete(
1066+
"*/accounts/some-account-id/r2-catalog/testBucket",
1067+
async () => {
1068+
return HttpResponse.json(createFetchResult({}));
1069+
},
1070+
{ once: true }
1071+
)
1072+
);
1073+
await runWrangler("r2 bucket catalog disable testBucket");
1074+
expect(std.out).toMatchInlineSnapshot(
1075+
`"Successfully disabled the data catalog on bucket 'testBucket'."`
1076+
);
1077+
});
1078+
});
1079+
1080+
describe("get", () => {
1081+
it("should error if no bucket name is given", async () => {
1082+
await expect(
1083+
runWrangler("r2 bucket catalog get")
1084+
).rejects.toThrowErrorMatchingInlineSnapshot(
1085+
`[Error: Not enough non-option arguments: got 0, need at least 1]`
1086+
);
1087+
expect(std.out).toMatchInlineSnapshot(`
1088+
"
1089+
wrangler r2 bucket catalog get <bucket>
1090+
1091+
Get the status of the data catalog for an R2 bucket [open-beta]
1092+
1093+
POSITIONALS
1094+
bucket The name of the R2 bucket whose data catalog status to retrieve [string] [required]
1095+
1096+
GLOBAL FLAGS
1097+
-c, --config Path to Wrangler configuration file [string]
1098+
--cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string]
1099+
-e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string]
1100+
-h, --help Show help [boolean]
1101+
-v, --version Show version number [boolean]"
1102+
`);
1103+
expect(std.err).toMatchInlineSnapshot(`
1104+
"X [ERROR] Not enough non-option arguments: got 0, need at least 1
1105+
1106+
"
1107+
`);
1108+
});
1109+
1110+
it("should get the catalog status for the given bucket", async () => {
1111+
msw.use(
1112+
http.get(
1113+
"*/accounts/:accountId/r2-catalog/:bucketName",
1114+
async ({ request, params }) => {
1115+
const { accountId } = params;
1116+
expect(accountId).toEqual("some-account-id");
1117+
expect(await request.text()).toEqual("");
1118+
return HttpResponse.json(
1119+
createFetchResult(
1120+
{
1121+
id: "test-id",
1122+
name: "test-name",
1123+
bucket: "test-bucket",
1124+
status: "active",
1125+
},
1126+
true
1127+
)
1128+
);
1129+
},
1130+
{ once: true }
1131+
)
1132+
);
1133+
await runWrangler("r2 bucket catalog get test-bucket");
1134+
expect(std.out).toMatchInlineSnapshot(`
1135+
"Getting data catalog status for 'test-bucket'...
1136+
Bucket: test-bucket
1137+
Catalog URI: https://catalog.cloudflarestorage.com/test-name
1138+
Status: active"
1139+
`);
1140+
});
1141+
1142+
it("should inform user if no active warehouse is present for the bucket", async () => {
1143+
msw.use(
1144+
http.get(
1145+
"*/accounts/:accountId/r2-catalog/:bucketName",
1146+
async ({ request, params }) => {
1147+
const { accountId } = params;
1148+
expect(accountId).toEqual("some-account-id");
1149+
expect(await request.text()).toEqual("");
1150+
return HttpResponse.json(
1151+
{
1152+
success: false,
1153+
errors: [
1154+
{
1155+
code: 40401,
1156+
message: "Warehouse not found",
1157+
},
1158+
],
1159+
result: null,
1160+
},
1161+
{ status: 404 }
1162+
);
1163+
},
1164+
{ once: true }
1165+
)
1166+
);
1167+
await runWrangler("r2 bucket catalog get test-bucket");
1168+
expect(std.out).toMatchInlineSnapshot(`
1169+
"Getting data catalog status for 'test-bucket'...
1170+
Data catalog isn't enabled for bucket 'test-bucket'."
1171+
`);
1172+
});
1173+
});
1174+
});
1175+
9321176
describe("notification", () => {
9331177
describe("list", () => {
9341178
it("follows happy path as expected", async () => {

packages/wrangler/src/core/teams.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export type Teams =
99
| "Workers: Workers Observability"
1010
| "Product: KV"
1111
| "Product: R2"
12+
| "Product: R2 Data Catalog"
1213
| "Product: D1"
1314
| "Product: Queues"
1415
| "Product: AI"

packages/wrangler/src/index.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ import {
8181
r2BucketUpdateNamespace,
8282
r2BucketUpdateStorageClassCommand,
8383
} from "./r2/bucket";
84+
import {
85+
r2BucketCatalogDisableCommand,
86+
r2BucketCatalogEnableCommand,
87+
r2BucketCatalogGetCommand,
88+
r2BucketCatalogNamespace,
89+
} from "./r2/catalog";
8490
import {
8591
r2BucketCORSDeleteCommand,
8692
r2BucketCORSListCommand,
@@ -620,6 +626,22 @@ export function createCLIParser(argv: string[]) {
620626
command: "wrangler r2 bucket sippy get",
621627
definition: r2BucketSippyGetCommand,
622628
},
629+
{
630+
command: "wrangler r2 bucket catalog",
631+
definition: r2BucketCatalogNamespace,
632+
},
633+
{
634+
command: "wrangler r2 bucket catalog enable",
635+
definition: r2BucketCatalogEnableCommand,
636+
},
637+
{
638+
command: "wrangler r2 bucket catalog disable",
639+
definition: r2BucketCatalogDisableCommand,
640+
},
641+
{
642+
command: "wrangler r2 bucket catalog get",
643+
definition: r2BucketCatalogGetCommand,
644+
},
623645
{
624646
command: "wrangler r2 bucket notification",
625647
definition: r2BucketNotificationNamespace,

0 commit comments

Comments
 (0)