diff --git a/.changeset/fruity-pillows-peel.md b/.changeset/fruity-pillows-peel.md new file mode 100644 index 000000000000..ee7376393d12 --- /dev/null +++ b/.changeset/fruity-pillows-peel.md @@ -0,0 +1,5 @@ +--- +"wrangler": patch +--- + +Support container image names without account ID diff --git a/packages/wrangler/e2e/containers.dev.test.ts b/packages/wrangler/e2e/containers.dev.test.ts index 93f65f184011..b5b1fc4e72ca 100644 --- a/packages/wrangler/e2e/containers.dev.test.ts +++ b/packages/wrangler/e2e/containers.dev.test.ts @@ -19,7 +19,10 @@ const imageSource = ["pull", "build"]; // We can only really run these tests on Linux, because we build our images for linux/amd64, // and github runners don't really support container virtualization in any sane way describe - .skipIf(process.platform !== "linux" && process.env.CI === "true") + .skipIf( + !CLOUDFLARE_ACCOUNT_ID || + (process.platform !== "linux" && process.env.CI === "true") + ) .each(imageSource)( "containers local dev tests: %s", { timeout: 90_000 }, diff --git a/packages/wrangler/src/__tests__/cloudchamber/apply.test.ts b/packages/wrangler/src/__tests__/cloudchamber/apply.test.ts index 61fead5ebd5a..2f84e99e66eb 100644 --- a/packages/wrangler/src/__tests__/cloudchamber/apply.test.ts +++ b/packages/wrangler/src/__tests__/cloudchamber/apply.test.ts @@ -1,4 +1,5 @@ import { + getCloudflareContainerRegistry, SchedulingPolicy, SecretAccessType, } from "@cloudflare/containers-shared"; @@ -30,14 +31,20 @@ function mockGetApplications(applications: Application[]) { ); } -function mockCreateApplication(expected?: Application) { +function mockCreateApplication( + response?: Partial, + expected?: Partial +) { msw.use( http.post( "*/applications", async ({ request }) => { - const body = await request.json(); + const body = (await request.json()) as CreateApplicationRequest; + if (expected !== undefined) { + expect(body).toMatchObject(expected); + } expect(body).toHaveProperty("instances"); - return HttpResponse.json(expected); + return HttpResponse.json(response); }, { once: true } ) @@ -73,6 +80,12 @@ function mockModifyApplication( } describe("cloudchamber apply", () => { + /* eslint no-irregular-whitespace: ["error", { "skipTemplates": true }] + --- + Wrangler emits \u200a instead of "regular" whitespace in some cases. eslint doesn't like + this so we disable the warning when mixed whitespace is used in template strings. + */ + const { setIsTTY } = useMockIsTTY(); const std = mockCLIOutput(); @@ -102,9 +115,8 @@ describe("cloudchamber apply", () => { ], }); mockGetApplications([]); - mockCreateApplication({ id: "abc" } as Application); + mockCreateApplication({ id: "abc" }); await runWrangler("cloudchamber apply"); - /* eslint-disable */ expect(std.stderr).toMatchInlineSnapshot(`""`); expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application @@ -132,7 +144,6 @@ describe("cloudchamber apply", () => { " `); - /* eslint-enable */ }); test("can apply a simple existing application", async () => { @@ -177,7 +188,6 @@ describe("cloudchamber apply", () => { ]); const applicationReqBodyPromise = mockModifyApplication(); await runWrangler("cloudchamber apply"); - /* eslint-disable */ expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application │ @@ -205,7 +215,6 @@ describe("cloudchamber apply", () => { const app = await applicationReqBodyPromise; expect(app.constraints?.tier).toEqual(2); expect(app.instances).toEqual(4); - /* eslint-enable */ }); test("can apply a simple existing application and create other (max_instances)", async () => { @@ -253,11 +262,10 @@ describe("cloudchamber apply", () => { }, ]); const res = mockModifyApplication(); - mockCreateApplication({ id: "abc" } as Application); + mockCreateApplication({ id: "abc" }); await runWrangler("cloudchamber apply"); const body = await res; expect(body).not.toHaveProperty("instances"); - /* eslint-disable */ expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application │ @@ -296,7 +304,6 @@ describe("cloudchamber apply", () => { " `); expect(std.stderr).toMatchInlineSnapshot(`""`); - /* eslint-enable */ }); test("can skip a simple existing application and create other", async () => { @@ -343,10 +350,9 @@ describe("cloudchamber apply", () => { }, }, ]); - mockCreateApplication({ id: "abc" } as Application); + mockCreateApplication({ id: "abc" }); await runWrangler("cloudchamber apply"); - /* eslint-disable */ expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application │ @@ -382,7 +388,6 @@ describe("cloudchamber apply", () => { " `); expect(std.stderr).toMatchInlineSnapshot(`""`); - /* eslint-enable */ }); test("can apply a simple existing application and create other", async () => { @@ -429,10 +434,9 @@ describe("cloudchamber apply", () => { }, ]); const res = mockModifyApplication(); - mockCreateApplication({ id: "abc" } as Application); + mockCreateApplication({ id: "abc" }); await runWrangler("cloudchamber apply"); await res; - /* eslint-disable */ expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application │ @@ -470,7 +474,6 @@ describe("cloudchamber apply", () => { " `); expect(std.stderr).toMatchInlineSnapshot(`""`); - /* eslint-enable */ }); test("can apply a simple existing application (labels)", async () => { @@ -568,7 +571,6 @@ describe("cloudchamber apply", () => { const res = mockModifyApplication(); await runWrangler("cloudchamber apply"); await res; - /* eslint-disable */ expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application │ @@ -604,7 +606,6 @@ describe("cloudchamber apply", () => { " `); expect(std.stderr).toMatchInlineSnapshot(`""`); - /* eslint-enable */ }); test("can apply an application, and there is no changes (retrocompatibility with regional scheduling policy)", async () => { @@ -702,7 +703,6 @@ describe("cloudchamber apply", () => { }, ]); await runWrangler("cloudchamber apply"); - /* eslint-disable */ expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application │ @@ -715,7 +715,6 @@ describe("cloudchamber apply", () => { " `); expect(std.stderr).toMatchInlineSnapshot(`""`); - /* eslint-enable */ }); test("can apply an application, and there is no changes (two applications)", async () => { @@ -816,7 +815,6 @@ describe("cloudchamber apply", () => { { ...completeApp, version: 1, name: "my-container-app-2", id: "abc2" }, ]); await runWrangler("cloudchamber apply"); - /* eslint-disable */ expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application │ @@ -831,7 +829,6 @@ describe("cloudchamber apply", () => { " `); expect(std.stderr).toMatchInlineSnapshot(`""`); - /* eslint-enable */ }); test("can apply an application, and there is no changes", async () => { @@ -929,7 +926,6 @@ describe("cloudchamber apply", () => { }, ]); await runWrangler("cloudchamber apply"); - /* eslint-disable */ expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application │ @@ -942,7 +938,6 @@ describe("cloudchamber apply", () => { " `); expect(std.stderr).toMatchInlineSnapshot(`""`); - /* eslint-enable */ }); test("can apply an application, and there is no changes (two applications)", async () => { @@ -1043,7 +1038,6 @@ describe("cloudchamber apply", () => { { ...completeApp, version: 1, name: "my-container-app-2", id: "abc2" }, ]); await runWrangler("cloudchamber apply"); - /* eslint-disable */ expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application │ @@ -1058,7 +1052,6 @@ describe("cloudchamber apply", () => { " `); expect(std.stderr).toMatchInlineSnapshot(`""`); - /* eslint-enable */ }); test("can enable observability logs (top-level field)", async () => { @@ -1101,7 +1094,6 @@ describe("cloudchamber apply", () => { ]); const applicationReqBodyPromise = mockModifyApplication(); await runWrangler("cloudchamber apply"); - /* eslint-disable */ expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application │ @@ -1130,7 +1122,6 @@ describe("cloudchamber apply", () => { const app = await applicationReqBodyPromise; expect(app.constraints?.tier).toEqual(1); expect(app.instances).toEqual(1); - /* eslint-enable */ }); test("can enable observability logs (logs field)", async () => { @@ -1173,7 +1164,6 @@ describe("cloudchamber apply", () => { ]); const applicationReqBodyPromise = mockModifyApplication(); await runWrangler("cloudchamber apply"); - /* eslint-disable */ expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application │ @@ -1202,7 +1192,6 @@ describe("cloudchamber apply", () => { const app = await applicationReqBodyPromise; expect(app.constraints?.tier).toEqual(1); expect(app.instances).toEqual(1); - /* eslint-enable */ }); test("can disable observability logs (top-level field)", async () => { @@ -1250,7 +1239,6 @@ describe("cloudchamber apply", () => { ]); const applicationReqBodyPromise = mockModifyApplication(); await runWrangler("cloudchamber apply"); - /* eslint-disable */ expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application │ @@ -1276,7 +1264,6 @@ describe("cloudchamber apply", () => { const app = await applicationReqBodyPromise; expect(app.constraints?.tier).toEqual(1); expect(app.instances).toEqual(1); - /* eslint-enable */ }); test("can disable observability logs (logs field)", async () => { @@ -1324,7 +1311,6 @@ describe("cloudchamber apply", () => { ]); const applicationReqBodyPromise = mockModifyApplication(); await runWrangler("cloudchamber apply"); - /* eslint-disable */ expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application │ @@ -1350,7 +1336,6 @@ describe("cloudchamber apply", () => { const app = await applicationReqBodyPromise; expect(app.constraints?.tier).toEqual(1); expect(app.instances).toEqual(1); - /* eslint-enable */ }); test("can disable observability logs (absent field)", async () => { @@ -1397,7 +1382,6 @@ describe("cloudchamber apply", () => { ]); const applicationReqBodyPromise = mockModifyApplication(); await runWrangler("cloudchamber apply"); - /* eslint-disable */ expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application │ @@ -1423,7 +1407,6 @@ describe("cloudchamber apply", () => { const app = await applicationReqBodyPromise; expect(app.constraints?.tier).toEqual(1); expect(app.instances).toEqual(1); - /* eslint-enable */ }); test("ignores deprecated observability.logging", async () => { @@ -1473,7 +1456,6 @@ describe("cloudchamber apply", () => { ]); const applicationReqBodyPromise = mockModifyApplication(); await runWrangler("cloudchamber apply"); - /* eslint-disable */ expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application │ @@ -1499,7 +1481,6 @@ describe("cloudchamber apply", () => { const app = await applicationReqBodyPromise; expect(app.constraints?.tier).toEqual(1); expect(app.instances).toEqual(1); - /* eslint-enable */ }); test("keeps observability logs enabled", async () => { @@ -1549,7 +1530,6 @@ describe("cloudchamber apply", () => { }, ]); await runWrangler("cloudchamber apply"); - /* eslint-disable */ expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application │ @@ -1562,7 +1542,6 @@ describe("cloudchamber apply", () => { " `); expect(std.stderr).toMatchInlineSnapshot(`""`); - /* eslint-enable */ }); test("keeps observability logs disabled (undefined in the app)", async () => { @@ -1603,7 +1582,6 @@ describe("cloudchamber apply", () => { }, ]); await runWrangler("cloudchamber apply"); - /* eslint-disable */ expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application │ @@ -1616,7 +1594,6 @@ describe("cloudchamber apply", () => { " `); expect(std.stderr).toMatchInlineSnapshot(`""`); - /* eslint-enable */ }); test("keeps observability logs disabled (false in the app)", async () => { @@ -1665,7 +1642,6 @@ describe("cloudchamber apply", () => { }, ]); await runWrangler("cloudchamber apply"); - /* eslint-disable */ expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application │ @@ -1678,7 +1654,6 @@ describe("cloudchamber apply", () => { " `); expect(std.stderr).toMatchInlineSnapshot(`""`); - /* eslint-enable */ }); test("can apply a simple application (instance type)", async () => { @@ -1699,9 +1674,8 @@ describe("cloudchamber apply", () => { ], }); mockGetApplications([]); - mockCreateApplication({ id: "abc" } as Application); + mockCreateApplication({ id: "abc" }); await runWrangler("cloudchamber apply"); - /* eslint-disable */ expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application │ @@ -1729,7 +1703,6 @@ describe("cloudchamber apply", () => { " `); expect(std.stderr).toMatchInlineSnapshot(`""`); - /* eslint-enable */ }); test("can apply a simple existing application (instance type)", async () => { @@ -1775,7 +1748,6 @@ describe("cloudchamber apply", () => { ]); const applicationReqBodyPromise = mockModifyApplication(); await runWrangler("cloudchamber apply"); - /* eslint-disable */ expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application │ @@ -1808,7 +1780,6 @@ describe("cloudchamber apply", () => { expect(std.stderr).toMatchInlineSnapshot(`""`); const app = await applicationReqBodyPromise; expect(app.configuration?.instance_type).toEqual("standard"); - /* eslint-enable */ }); test("falls back on dev instance type when instance type is absent", async () => { @@ -1853,7 +1824,6 @@ describe("cloudchamber apply", () => { ]); const applicationReqBodyPromise = mockModifyApplication(); await runWrangler("cloudchamber apply"); - /* eslint-disable */ expect(std.stdout).toMatchInlineSnapshot(` "╭ Deploy a container application deploy changes to your application │ @@ -1886,6 +1856,63 @@ describe("cloudchamber apply", () => { expect(std.stderr).toMatchInlineSnapshot(`""`); const app = await applicationReqBodyPromise; expect(app.configuration?.instance_type).toEqual("dev"); - /* eslint-enable */ + }); + + test("expands image names from managed registry", async () => { + setIsTTY(false); + const registry = getCloudflareContainerRegistry(); + writeWranglerConfig({ + name: "my-container", + containers: [ + { + name: "my-container-app", + instances: 3, + class_name: "DurableObjectClass", + image: `${registry}/hello:1.0`, + constraints: { + tier: 2, + }, + }, + ], + }); + + mockGetApplications([]); + mockCreateApplication( + { id: "abc" }, + { + configuration: { + image: `${registry}/some-account-id/hello:1.0`, + }, + } + ); + + await runWrangler("cloudchamber apply"); + expect(std.stderr).toMatchInlineSnapshot(`""`); + expect(std.stdout).toMatchInlineSnapshot(` + "╭ Deploy a container application deploy changes to your application + │ + │ Container application changes + │ + ├ NEW my-container-app + │ + │ [[containers]] + │ name = \\"my-container-app\\" + │ instances = 3 + │ scheduling_policy = \\"default\\" + │ + │ [containers.constraints] + │ tier = 2 + │ + │ [containers.configuration] + │ image = \\"${registry}/hello:1.0\\" + │ instance_type = \\"dev\\" + │ + │ + │  SUCCESS  Created application my-container-app (Application ID: abc) + │ + ╰ Applied changes + + " + `); }); }); diff --git a/packages/wrangler/src/__tests__/cloudchamber/build.test.ts b/packages/wrangler/src/__tests__/cloudchamber/build.test.ts index 63c00841cf21..76ea7c25e692 100644 --- a/packages/wrangler/src/__tests__/cloudchamber/build.test.ts +++ b/packages/wrangler/src/__tests__/cloudchamber/build.test.ts @@ -62,7 +62,7 @@ describe("buildAndMaybePush", () => { buildCmd: [ "build", "-t", - `${getCloudflareContainerRegistry()}/test_account_id/test-app:tag`, + `${getCloudflareContainerRegistry()}/some-account-id/test-app:tag`, "--platform", "linux/amd64", "--provenance=false", @@ -73,13 +73,13 @@ describe("buildAndMaybePush", () => { dockerfile, }); expect(dockerImageInspect).toHaveBeenCalledWith("/custom/docker/path", { - imageTag: `${getCloudflareContainerRegistry()}/test_account_id/test-app:tag`, + imageTag: `${getCloudflareContainerRegistry()}/some-account-id/test-app:tag`, formatString: "{{ .Size }} {{ len .RootFS.Layers }} {{json .RepoDigests}}", }); expect(runDockerCmd).toHaveBeenCalledWith("/custom/docker/path", [ "push", - `${getCloudflareContainerRegistry()}/test_account_id/test-app:tag`, + `${getCloudflareContainerRegistry()}/some-account-id/test-app:tag`, ]); expect(dockerLoginManagedRegistry).toHaveBeenCalledWith( "/custom/docker/path" @@ -94,7 +94,7 @@ describe("buildAndMaybePush", () => { buildCmd: [ "build", "-t", - `${getCloudflareContainerRegistry()}/test_account_id/test-app:tag`, + `${getCloudflareContainerRegistry()}/some-account-id/test-app:tag`, "--platform", "linux/amd64", "--provenance=false", @@ -107,11 +107,11 @@ describe("buildAndMaybePush", () => { expect(runDockerCmd).toHaveBeenCalledTimes(1); expect(runDockerCmd).toHaveBeenCalledWith("docker", [ "push", - `${getCloudflareContainerRegistry()}/test_account_id/test-app:tag`, + `${getCloudflareContainerRegistry()}/some-account-id/test-app:tag`, ]); expect(dockerImageInspect).toHaveBeenCalledOnce(); expect(dockerImageInspect).toHaveBeenCalledWith("docker", { - imageTag: `${getCloudflareContainerRegistry()}/test_account_id/test-app:tag`, + imageTag: `${getCloudflareContainerRegistry()}/some-account-id/test-app:tag`, formatString: "{{ .Size }} {{ len .RootFS.Layers }} {{json .RepoDigests}}", }); @@ -121,7 +121,7 @@ describe("buildAndMaybePush", () => { it("should be able to build image and not push if it already exists in remote", async () => { vi.mocked(runDockerCmd).mockResolvedValueOnce(); vi.mocked(dockerImageInspect).mockResolvedValue( - '53387881 2 ["registry.cloudflare.com/test_account_id/test-app@sha256:three"]' + '53387881 2 ["registry.cloudflare.com/some-account-id/test-app@sha256:three"]' ); await runWrangler( "containers build ./container-context -t test-app:tag -p" @@ -130,7 +130,7 @@ describe("buildAndMaybePush", () => { buildCmd: [ "build", "-t", - `${getCloudflareContainerRegistry()}/test_account_id/test-app:tag`, + `${getCloudflareContainerRegistry()}/some-account-id/test-app:tag`, "--platform", "linux/amd64", "--provenance=false", @@ -147,18 +147,18 @@ describe("buildAndMaybePush", () => { [ "manifest", "inspect", - `${getCloudflareContainerRegistry()}/test_account_id/test-app@sha256:three`, + `${getCloudflareContainerRegistry()}/some-account-id/test-app@sha256:three`, ], "ignore" ); expect(runDockerCmd).toHaveBeenNthCalledWith(2, "docker", [ "image", "rm", - `${getCloudflareContainerRegistry()}/test_account_id/test-app:tag`, + `${getCloudflareContainerRegistry()}/some-account-id/test-app:tag`, ]); expect(dockerImageInspect).toHaveBeenCalledOnce(); expect(dockerImageInspect).toHaveBeenCalledWith("docker", { - imageTag: `${getCloudflareContainerRegistry()}/test_account_id/test-app:tag`, + imageTag: `${getCloudflareContainerRegistry()}/some-account-id/test-app:tag`, formatString: "{{ .Size }} {{ len .RootFS.Layers }} {{json .RepoDigests}}", }); @@ -172,7 +172,7 @@ describe("buildAndMaybePush", () => { buildCmd: [ "build", "-t", - `${getCloudflareContainerRegistry()}/test_account_id/test-app`, + `${getCloudflareContainerRegistry()}/some-account-id/test-app`, "--platform", "linux/amd64", "--provenance=false", @@ -194,7 +194,7 @@ describe("buildAndMaybePush", () => { buildCmd: [ "build", "-t", - `${getCloudflareContainerRegistry()}/test_account_id/test-app`, + `${getCloudflareContainerRegistry()}/some-account-id/test-app`, "--platform", "linux/amd64", "--provenance=false", diff --git a/packages/wrangler/src/__tests__/cloudchamber/utils.ts b/packages/wrangler/src/__tests__/cloudchamber/utils.ts index 374d26f8bbce..14ed3efec1a2 100644 --- a/packages/wrangler/src/__tests__/cloudchamber/utils.ts +++ b/packages/wrangler/src/__tests__/cloudchamber/utils.ts @@ -21,12 +21,14 @@ export function mockAccount() { const spy = vi.spyOn(user, "getScopes"); spy.mockImplementationOnce(() => ["cloudchamber:write", "containers:write"]); + const accountId = process.env.CLOUDFLARE_ACCOUNT_ID; + msw.use( http.get( "*/me", async () => { return HttpResponse.json({ - external_account_id: "test_account_id", + external_account_id: accountId, limits: { disk_mb_per_deployment: 2000, }, @@ -41,6 +43,8 @@ export function mockAccountV4(scopes: user.Scope[] = ["containers:write"]) { const spy = vi.spyOn(user, "getScopes"); spy.mockImplementationOnce(() => scopes); + const accountId = process.env.CLOUDFLARE_ACCOUNT_ID; + msw.use( http.get( "*/me", @@ -49,7 +53,7 @@ export function mockAccountV4(scopes: user.Scope[] = ["containers:write"]) { { success: true, result: { - external_account_id: "test_account_id", + external_account_id: accountId, limits: { disk_mb_per_deployment: 2000, }, diff --git a/packages/wrangler/src/__tests__/deploy.test.ts b/packages/wrangler/src/__tests__/deploy.test.ts index d2c6fab906e5..fb4d7c70bf69 100644 --- a/packages/wrangler/src/__tests__/deploy.test.ts +++ b/packages/wrangler/src/__tests__/deploy.test.ts @@ -8784,7 +8784,7 @@ addEventListener('fetch', event => {});` "build", "-t", getCloudflareContainerRegistry() + - "/test_account_id/my-container:Galaxy", + "/some-account-id/my-container:Galaxy", "--platform", "linux/amd64", "--provenance=false", @@ -8823,7 +8823,7 @@ addEventListener('fetch', event => {});` expect(args).toEqual([ "image", "inspect", - `${getCloudflareContainerRegistry()}/test_account_id/my-container:Galaxy`, + `${getCloudflareContainerRegistry()}/some-account-id/my-container:Galaxy`, "--format", "{{ .Size }} {{ len .RootFS.Layers }} {{json .RepoDigests}}", ]); @@ -8847,7 +8847,7 @@ addEventListener('fetch', event => {});` setImmediate(() => { stdout.emit( "data", - `123456 4 ["${getCloudflareContainerRegistry()}/test_account_id/my-container@sha256:three"]` + `123456 4 ["${getCloudflareContainerRegistry()}/some-account-id/my-container@sha256:three"]` ); }); @@ -8888,7 +8888,7 @@ addEventListener('fetch', event => {});` expect(args).toEqual([ "manifest", "inspect", - `${getCloudflareContainerRegistry()}/test_account_id/my-container@three`, + `${getCloudflareContainerRegistry()}/some-account-id/my-container@three`, ]); const readable = new Writable({ write() {}, @@ -8917,7 +8917,7 @@ addEventListener('fetch', event => {});` expect(cmd).toBe("/usr/bin/docker"); expect(args).toEqual([ "push", - `${getCloudflareContainerRegistry()}/test_account_id/my-container:Galaxy`, + `${getCloudflareContainerRegistry()}/some-account-id/my-container:Galaxy`, ]); return defaultChildProcess(); }); @@ -8977,7 +8977,7 @@ addEventListener('fetch', event => {});` return HttpResponse.json({ success: true, result: { - account_id: "test_account_id", + account_id: "some-account-id", registry_host: getCloudflareContainerRegistry(), username: "v1", password: "mockpassword", @@ -8998,7 +8998,7 @@ addEventListener('fetch', event => {});` configuration: { image: getCloudflareContainerRegistry() + - "/test_account_id/my-container:Galaxy", + "/some-account-id/my-container:Galaxy", }, }); @@ -9035,7 +9035,7 @@ addEventListener('fetch', event => {});` Uploaded test-name (TIMINGS) Building image my-container:Galaxy - Image does not exist remotely, pushing: registry.cloudflare.com/test_account_id/my-container:Galaxy + Image does not exist remotely, pushing: registry.cloudflare.com/some-account-id/my-container:Galaxy Deployed test-name triggers (TIMINGS) https://test-name.test-sub-domain.workers.dev Current Version ID: Galaxy-Class" diff --git a/packages/wrangler/src/cloudchamber/apply.ts b/packages/wrangler/src/cloudchamber/apply.ts index 81ea00077803..0ff1804eedd0 100644 --- a/packages/wrangler/src/cloudchamber/apply.ts +++ b/packages/wrangler/src/cloudchamber/apply.ts @@ -13,12 +13,14 @@ import { ApplicationsService, CreateApplicationRolloutRequest, DeploymentMutationError, + getCloudflareContainerRegistry, InstanceType, RolloutsService, SchedulingPolicy, } from "@cloudflare/containers-shared"; import { formatConfigSnippet } from "../config"; import { FatalError, UserError } from "../errors"; +import { getAccountId } from "../user"; import { cleanForInstanceType, promiseSpinner } from "./common"; import { diffLines } from "./helpers/diff"; import type { Config } from "../config"; @@ -415,6 +417,33 @@ function sortObjectRecursive>( return sortObjectKeys(objectCopy) as T; } +// Resolve an image name to the full unambiguous name. +// +// For now, this only converts images stored in the managed registry to contain +// the user's account ID in the path. +async function resolveImageName( + config: Config, + image: string +): Promise { + let url: URL; + try { + url = new URL(`http://${image}`); + } catch (_) { + return image; + } + + if (url.hostname !== getCloudflareContainerRegistry()) { + return image; + } + + const accountId = config.account_id || (await getAccountId(config)); + if (url.pathname.startsWith(`/${accountId}`)) { + return image; + } + + return `${url.hostname}/${accountId}${url.pathname}`; +} + export async function apply( args: { skipDefaults: boolean | undefined; @@ -686,7 +715,17 @@ export async function apply( printLine(el, " "); }); - const configToPush = { ...appConfig }; + const configToPush = { + ...appConfig, + + configuration: { + ...appConfig.configuration, + + // De-sugar image name. We do it here so that the user + // sees the simplified image name in diffs. + image: await resolveImageName(config, appConfig.configuration.image), + }, + }; // add to the actions array to create the app later actions.push({ @@ -716,7 +755,11 @@ export async function apply( return message; } - return ` ${err.body.error}`; + if (err.body.error !== undefined) { + return ` ${err.body.error}`; + } + + return JSON.stringify(err.body); } for (const action of actions) { @@ -769,7 +812,8 @@ export async function apply( action.application.max_instances !== undefined ? undefined : action.application.instances, - }) + }), + { message: `Modifying ${action.application.name}` } ); } catch (err) { if (!(err instanceof Error)) {