@@ -19,6 +19,33 @@ import { useMockStdin } from "../helpers/mock-stdin";
1919import { createFetchResult , msw } from "../helpers/msw" ;
2020import { runWrangler } from "../helpers/run-wrangler" ;
2121
22+ describe ( "containers registries --help" , ( ) => {
23+ const std = mockConsoleMethods ( ) ;
24+
25+ it ( "should help" , async ( ) => {
26+ await runWrangler ( "containers registries --help" ) ;
27+ expect ( std . out ) . toMatchInlineSnapshot ( `
28+ "wrangler containers registries
29+
30+ Configure and manage non-Cloudflare registries [open beta]
31+
32+ COMMANDS
33+ wrangler containers registries configure <DOMAIN> Configure credentials for a non-Cloudflare container registry [open beta]
34+ wrangler containers registries list List all configured container registries [open beta]
35+ wrangler containers registries delete <DOMAIN> Delete a configured container registry [open beta]
36+ wrangler containers registries credentials [DOMAIN] Get a temporary password for a specific domain [open beta]
37+
38+ GLOBAL FLAGS
39+ -c, --config Path to Wrangler configuration file [string]
40+ --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string]
41+ -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string]
42+ --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array]
43+ -h, --help Show help [boolean]
44+ -v, --version Show version number [boolean]"
45+ ` ) ;
46+ } ) ;
47+ } ) ;
48+
2249describe ( "containers registries configure" , ( ) => {
2350 const { setIsTTY } = useMockIsTTY ( ) ;
2451 const cliStd = mockCLIOutput ( ) ;
@@ -31,15 +58,14 @@ describe("containers registries configure", () => {
3158 afterEach ( ( ) => {
3259 clearDialogs ( ) ;
3360 } ) ;
34-
3561 it ( "should reject unsupported registry domains" , async ( ) => {
3662 await expect (
3763 runWrangler (
38- `containers registries configure docker.io --public-credential=test-id`
64+ `containers registries configure unsupported.domain --public-credential=test-id`
3965 )
4066 ) . rejects . toThrowErrorMatchingInlineSnapshot ( `
41- [Error: docker.io is not a supported image registry.
42- Currently we support the following non-Cloudflare registries: AWS ECR.
67+ [Error: unsupported.domain is not a supported image registry.
68+ Currently we support the following non-Cloudflare registries: AWS ECR, DockerHub .
4369 To use an existing image from another repository, see https://developers.cloudflare.com/containers/platform-details/image-management/#using-pre-built-container-images]
4470 ` ) ;
4571 } ) ;
@@ -81,15 +107,37 @@ describe("containers registries configure", () => {
81107 ) ;
82108 } ) ;
83109
110+ it ( "should enforce mutual exclusivity for public credential arguments" , async ( ) => {
111+ await expect (
112+ runWrangler ( `containers registries configure docker.io` )
113+ ) . rejects . toThrowErrorMatchingInlineSnapshot (
114+ `[Error: Missing required argument: dockerhub-username]`
115+ ) ;
116+
117+ await expect (
118+ runWrangler (
119+ `containers registries configure 123456789012.dkr.ecr.region.amazonaws.com`
120+ )
121+ ) . rejects . toThrowErrorMatchingInlineSnapshot (
122+ `[Error: Missing required argument: aws-access-key-id]`
123+ ) ;
124+
125+ await expect (
126+ runWrangler (
127+ `containers registries configure docker.io --public-credential=test-id --dockerhub-username=another-test-id`
128+ )
129+ ) . rejects . toThrowErrorMatchingInlineSnapshot (
130+ `[Error: Arguments public-credential and dockerhub-username are mutually exclusive]`
131+ ) ;
132+ } ) ;
133+
84134 it ( "should no-op on cloudflare registry (default)" , async ( ) => {
85135 await runWrangler (
86- `containers registries configure registry.cloudflare.com --public-credential=test-id `
136+ `containers registries configure registry.cloudflare.com`
87137 ) ;
88138 expect ( cliStd . stdout ) . toMatchInlineSnapshot ( `
89139 "╭ Configure a container registry
90140 │
91- │ Configuring Cloudflare Containers Managed Registry registry: registry.cloudflare.com
92- │
93141 │ You do not need to configure credentials for Cloudflare managed registries.
94142 │
95143 ╰ No configuration required
@@ -406,6 +454,95 @@ describe("containers registries configure", () => {
406454 } ) ;
407455 } ) ;
408456 } ) ;
457+
458+ describe ( "DockerHub registry configuration" , ( ) => {
459+ it ( "should configure DockerHub registry with interactive prompts" , async ( ) => {
460+ setIsTTY ( true ) ;
461+ const dockerHubDomain = "docker.io" ;
462+ const storeId = "test-store-id-123" ;
463+ mockPrompt ( {
464+ text : "Enter DockerHub PAT Token:" ,
465+ options : { isSecret : true } ,
466+ result : "test-pat-token" ,
467+ } ) ;
468+ mockPrompt ( {
469+ text : "Secret name:" ,
470+ options : { isSecret : false , defaultValue : "DockerHub_PAT_Token" } ,
471+ result : "DockerHub_PAT_Token" ,
472+ } ) ;
473+
474+ mockListSecretStores ( [
475+ {
476+ id : storeId ,
477+ account_id : "some-account-id" ,
478+ name : "Default" ,
479+ created : "2024-01-01T00:00:00Z" ,
480+ modified : "2024-01-01T00:00:00Z" ,
481+ } ,
482+ ] ) ;
483+ mockListSecrets ( storeId , [ ] ) ;
484+ mockCreateSecret ( storeId ) ;
485+ mockPutRegistry ( {
486+ domain : "docker.io" ,
487+ is_public : false ,
488+ auth : {
489+ public_credential : "cloudchambertest" ,
490+ private_credential : {
491+ store_id : storeId ,
492+ secret_name : "DockerHub_PAT_Token" ,
493+ } ,
494+ } ,
495+ kind : "DockerHub" ,
496+ } ) ;
497+
498+ await runWrangler (
499+ `containers registries configure ${ dockerHubDomain } --dockerhub-username=cloudchambertest`
500+ ) ;
501+
502+ expect ( cliStd . stdout ) . toContain ( "Using existing Secret Store Default" ) ;
503+ } ) ;
504+
505+ describe ( "non-interactive" , ( ) => {
506+ beforeEach ( ( ) => {
507+ setIsTTY ( false ) ;
508+ } ) ;
509+ const dockerHubDomain = "docker.io" ;
510+ const mockStdIn = useMockStdin ( { isTTY : false } ) ;
511+
512+ it ( "should accept the secret from piped input" , async ( ) => {
513+ const secret = "example-pat-token" ;
514+ const storeId = "test-store-id-999" ;
515+
516+ mockStdIn . send ( secret ) ;
517+ mockListSecretStores ( [
518+ {
519+ id : storeId ,
520+ account_id : "some-account-id" ,
521+ name : "Default" ,
522+ created : "2024-01-01T00:00:00Z" ,
523+ modified : "2024-01-01T00:00:00Z" ,
524+ } ,
525+ ] ) ;
526+ mockListSecrets ( storeId , [ ] ) ;
527+ mockCreateSecret ( storeId ) ;
528+ mockPutRegistry ( {
529+ domain : dockerHubDomain ,
530+ is_public : false ,
531+ auth : {
532+ public_credential : "cloudchambertest" ,
533+ private_credential : {
534+ store_id : storeId ,
535+ secret_name : "DockerHub_PAT_Token" ,
536+ } ,
537+ } ,
538+ kind : "DockerHub" ,
539+ } ) ;
540+ await runWrangler (
541+ `containers registries configure ${ dockerHubDomain } --public-credential=cloudchambertest --secret-name=DockerHub_PAT_Token`
542+ ) ;
543+ } ) ;
544+ } ) ;
545+ } ) ;
409546} ) ;
410547
411548describe ( "containers registries list" , ( ) => {
0 commit comments