UNPKG

jamsocket

Version:

A CLI for the Jamsocket platform

153 lines (152 loc) 7.48 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const core_1 = require("@oclif/core"); const child_process_1 = require("child_process"); const path_1 = require("path"); const chalk_1 = tslib_1.__importDefault(require("chalk")); const inquirer = tslib_1.__importStar(require("inquirer")); const jamsocket_1 = require("../jamsocket"); const docker_1 = require("../lib/docker"); const formatting_1 = require("../lib/formatting"); class Push extends core_1.Command { async run() { const jamsocket = jamsocket_1.Jamsocket.fromEnvironment(); const { args, flags } = await this.parse(Push); // make sure either Dockerfile or an image is provided (not both or neither) if (Boolean(args.image) === Boolean(flags.dockerfile)) { this.error('Either an image or a Dockerfile must be provided. Rerun with --help for more information.'); } let image = null; if (args.image) { if (flags.context !== undefined) { throw new Error('--context flag should only be used with the --dockerfile flag'); } if (flags['build-context']) { throw new Error('--build-context flag should only be used with the --dockerfile flag'); } if (flags['include-git-commit']) { throw new Error('The --include-git-commit flag can only be used when building a fresh image. Please provide a Dockerfile with the --dockerfile flag.'); } const { os, arch } = (0, docker_1.getImagePlatform)(args.image); if (os !== 'linux' || arch !== 'amd64') { this.log(); this.warn(chalk_1.default.bold .red `The image ${args.image} may not be compatible with Jamsocket because its image os/arch is ${os}/${arch}.`); this.log('If you encounter errors while spawning with this image, you may need to rebuild the image with the platform flag (--platform=linux/amd64) and push again.'); this.log(); const response = await inquirer.prompt([ { name: 'goAhead', message: (0, formatting_1.lightMagenta)('Go ahead and push image?'), type: 'list', choices: [{ name: 'no' }, { name: 'yes' }], }, ]); if (response.goAhead !== 'yes') { this.log('Image push canceled.'); return; } } image = args.image; } if (flags.dockerfile) { let labels = {}; if (flags['include-git-commit']) { // check for unstaged changes const cwd = flags.context ? (0, path_1.resolve)(process.cwd(), flags.context) : process.cwd(); const encoding = 'utf-8'; const result = (0, child_process_1.spawnSync)('git', ['diff-index', '--quiet', 'HEAD', '--'], { encoding, cwd }); if (result.status !== 0) { this.error('There unstaged changes in the git repository. The --include-git-commit flag can only be used if there are no unstaged changes. Please commit or stash these changes before continuing.'); } try { const hash = (0, child_process_1.spawnSync)('git', ['rev-parse', 'HEAD'], { cwd, encoding }) .output.join('\n') .trim(); const message = (0, child_process_1.spawnSync)('git', ['log', '-1', '--pretty=%B'], { cwd, encoding }) .output.join('\n') .trim(); const branch = (0, child_process_1.spawnSync)('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd, encoding }) .output.join('\n') .trim(); const originUrl = (0, child_process_1.spawnSync)('git', ['remote', 'get-url', 'origin'], { cwd, encoding, }) .output.join('\n') .trim(); let repository = originUrl.split('github.com')[1] ?? null; repository = originUrl.split('github.com')[1] ?? null; repository = repository?.slice(1) ?? null; if (repository.split('/').length !== 2) repository = null; if (repository?.endsWith('.git')) { repository = repository.slice(0, -4); } labels = { hash, message, branch }; if (repository) { labels.repository = repository; } } catch (error) { this.error('Error retrieving git information:', error); } } const options = { labels }; if (flags.context) { options.path = (0, path_1.resolve)(process.cwd(), flags.context); } if (flags['build-context']) { options.buildContexts = flags['build-context']; } this.log((0, formatting_1.blue)(`Building image from Dockerfile: ${flags.dockerfile}`)); image = await (0, docker_1.buildImage)(flags.dockerfile, options); } if (!image) { // we should never encounter this error because of the check at the beginning of the function this.error('Error building/finding image.'); } this.log(); this.log((0, formatting_1.blue)('Pushing image to Jamsocket...')); await jamsocket.push(args.service, image, flags.tag); } } Push.description = "Builds and pushes an image to Jamsocket's container registry using the provided Dockerfile."; Push.examples = [ '<%= config.bin %> <%= command.id %> my-service -f path/to/Dockerfile', '<%= config.bin %> <%= command.id %> my-service -f path/to/Dockerfile -c .', '<%= config.bin %> <%= command.id %> my-service my-image -t my-tag', ]; Push.flags = { dockerfile: core_1.Flags.string({ char: 'f', description: 'path to the Dockerfile to build the image from', }), context: core_1.Flags.string({ char: 'c', description: 'path to the build context for the Dockerfile (defaults to current working directory)', }), ['build-context']: core_1.Flags.string({ char: 'b', multiple: true, description: 'Additional named build contexts to be used when building the image (e.g. --build-context alpine=docker-image://alpine@sha256:0123456789)', }), tag: core_1.Flags.string({ char: 't', description: 'optional tag to apply to the image in the jamsocket registry', }), ['include-git-commit']: core_1.Flags.boolean({ char: 'g', description: 'optionally include git commit metadata as labels in the image (uses the git repo of the docker context)', }), }; Push.args = [ { name: 'service', description: 'Jamsocket service to push the image to', required: true }, { name: 'image', description: 'Optionally, provide an image to push instead of a Dockerfile', required: false, }, ]; exports.default = Push;