import {TemplateContext} from "../../templates/template-context.js"; import {MappingToken, SequenceToken, StringToken, TemplateToken} from "../../templates/tokens/index.js"; import {isString} from "../../templates/tokens/type-guards.js"; import {Container, Credential} from "../workflow-template.js"; export function convertToJobContainer(context: TemplateContext, container: TemplateToken): Container | undefined { let image: StringToken | undefined; let env: MappingToken | undefined; let ports: SequenceToken | undefined; let volumes: SequenceToken | undefined; let options: StringToken | undefined; // Skip validation for expressions for now to match // behavior of the other parsers for (const [, token] of TemplateToken.traverse(container)) { if (token.isExpression) { return; } } if (isString(container)) { // Workflow uses shorthand syntax `container: image-name` image = container.assertString("container item"); return {image: image}; } const mapping = container.assertMapping("container item"); if (mapping) for (const item of mapping) { const key = item.key.assertString("container item key"); const value = item.value; switch (key.value) { case "image": image = value.assertString("container image"); break; case "credentials": convertToJobCredentials(context, value); break; case "env": env = value.assertMapping("container env"); for (const envItem of env) { envItem.key.assertString("container env value"); } break; case "ports": ports = value.assertSequence("container ports"); for (const port of ports) { port.assertString("container port"); } break; case "volumes": volumes = value.assertSequence("container volumes"); for (const volume of volumes) { volume.assertString("container volume"); } break; case "options": options = value.assertString("container options"); break; default: context.error(key, `Unexpected container item key: ${key.value}`); } } if (!image) { context.error(container, "Container image cannot be empty"); } else { return {image, env, ports, volumes, options}; } } export function convertToServiceContainer(context: TemplateContext, container: TemplateToken): Container | undefined { let image: StringToken | undefined; let env: MappingToken | undefined; let ports: SequenceToken | undefined; let volumes: SequenceToken | undefined; let options: StringToken | undefined; let entrypoint: StringToken | undefined; let command: StringToken | undefined; // Skip validation for expressions for now to match // behavior of the other parsers for (const [, token] of TemplateToken.traverse(container)) { if (token.isExpression) { return; } } if (isString(container)) { image = container.assertString("container item"); return {image: image}; } const mapping = container.assertMapping("container item"); if (mapping) for (const item of mapping) { const key = item.key.assertString("container item key"); const value = item.value; switch (key.value) { case "image": image = value.assertString("container image"); break; case "credentials": convertToJobCredentials(context, value); break; case "env": env = value.assertMapping("container env"); for (const envItem of env) { envItem.key.assertString("container env value"); } break; case "ports": ports = value.assertSequence("container ports"); for (const port of ports) { port.assertString("container port"); } break; case "volumes": volumes = value.assertSequence("container volumes"); for (const volume of volumes) { volume.assertString("container volume"); } break; case "options": options = value.assertString("container options"); break; case "entrypoint": entrypoint = value.assertString("container entrypoint"); break; case "command": command = value.assertString("container command"); break; default: context.error(key, `Unexpected container item key: ${key.value}`); } } if (!image) { context.error(container, "Container image cannot be empty"); } else { return {image, env, ports, volumes, options, entrypoint, command}; } } export function convertToJobServices(context: TemplateContext, services: TemplateToken): Container[] | undefined { const serviceList: Container[] = []; const mapping = services.assertMapping("services"); for (const service of mapping) { service.key.assertString("service key"); const container = convertToServiceContainer(context, service.value); if (container) { serviceList.push(container); } } return serviceList; } function convertToJobCredentials(context: TemplateContext, value: TemplateToken): Credential | undefined { const mapping = value.assertMapping("credentials"); let username: StringToken | undefined; let password: StringToken | undefined; for (const item of mapping) { const key = item.key.assertString("credentials item"); const value = item.value; switch (key.value) { case "username": username = value.assertString("credentials username"); break; case "password": password = value.assertString("credentials password"); break; default: context.error(key, `credentials key ${key.value}`); } } return {username, password}; }