diff --git a/garden-service/src/plugins/container/helpers.ts b/garden-service/src/plugins/container/helpers.ts index ff6ad44616..2c79407ef1 100644 --- a/garden-service/src/plugins/container/helpers.ts +++ b/garden-service/src/plugins/container/helpers.ts @@ -11,7 +11,7 @@ import { join } from "path" import { ConfigurationError } from "../../exceptions" import { splitFirst, spawn } from "../../util/util" import { ModuleConfig } from "../../config/module" -import { ContainerModule, ContainerRegistryConfig, defaultTag } from "./config" +import { ContainerModule, ContainerRegistryConfig, defaultTag, defaultNamespace } from "./config" interface ParsedImageId { host?: string @@ -101,15 +101,16 @@ export const containerHelpers = { }, parseImageId(imageId: string): ParsedImageId { - const parts = imageId.split("/") - let [repository, tag] = parts[0].split(":") + let [name, tag] = imageId.split(":") + const parts = name.length > 0 ? name.split("/") : [] + if (!tag) { tag = defaultTag } if (parts.length === 1) { return { - repository, + repository: parts[0], tag, } } else if (parts.length === 2) { @@ -141,7 +142,7 @@ export const containerHelpers = { const name = `${parsed.repository}:${parsed.tag}` if (parsed.host) { - return `${parsed.host}/${parsed.namespace}/${name}` + return `${parsed.host}/${parsed.namespace || defaultNamespace}/${name}` } else if (parsed.namespace) { return `${parsed.namespace}/${name}` } else { diff --git a/garden-service/test/src/plugins/container.ts b/garden-service/test/src/plugins/container.ts index ecd7ec8d2a..6bed534d1b 100644 --- a/garden-service/test/src/plugins/container.ts +++ b/garden-service/test/src/plugins/container.ts @@ -210,6 +210,92 @@ describe("plugins.container", () => { }) }) + describe("parseImageId", () => { + it("should correctly parse a simple id", () => { + expect(containerHelpers.parseImageId("image:tag")).to.eql({ + repository: "image", + tag: "tag", + }) + }) + + it("should correctly parse an id with a namespace", () => { + expect(containerHelpers.parseImageId("namespace/image:tag")).to.eql({ + namespace: "namespace", + repository: "image", + tag: "tag", + }) + }) + + it("should correctly parse an id with a host and namespace", () => { + expect(containerHelpers.parseImageId("my-host.com/namespace/image:tag")).to.eql({ + host: "my-host.com", + namespace: "namespace", + repository: "image", + tag: "tag", + }) + }) + + it("should correctly parse an id with a host and multi-level namespace", () => { + expect(containerHelpers.parseImageId("my-host.com/a/b/c/d/image:tag")).to.eql({ + host: "my-host.com", + namespace: "a/b/c/d", + repository: "image", + tag: "tag", + }) + }) + + it("should throw on an empty name", async () => { + await expectError(() => containerHelpers.parseImageId(""), "configuration") + }) + }) + + describe("unparseImageId", () => { + it("should correctly compose a simple id", () => { + expect(containerHelpers.unparseImageId({ + repository: "image", + tag: "tag", + })).to.equal("image:tag") + }) + + it("should correctly compose an id with a namespace", () => { + expect(containerHelpers.unparseImageId({ + namespace: "namespace", + repository: "image", + tag: "tag", + })).to.equal("namespace/image:tag") + }) + + it("should correctly compose an id with a host and namespace", () => { + expect(containerHelpers.unparseImageId({ + host: "my-host.com", + namespace: "namespace", + repository: "image", + tag: "tag", + })).to.equal("my-host.com/namespace/image:tag") + }) + + it("should set a default namespace when host but no namespace is specified", () => { + expect(containerHelpers.unparseImageId({ + host: "my-host.com", + repository: "image", + tag: "tag", + })).to.equal("my-host.com/_/image:tag") + }) + + it("should correctly compose an id with a host and multi-level namespace", () => { + expect(containerHelpers.unparseImageId({ + host: "my-host.com", + namespace: "a/b/c/d", + repository: "image", + tag: "tag", + })).to.equal("my-host.com/a/b/c/d/image:tag") + }) + + it("should throw on an empty name", async () => { + await expectError(() => containerHelpers.parseImageId(""), "configuration") + }) + }) + describe("DockerModuleHandler", () => { describe("validate", () => { it("should validate and parse a container module", async () => {