jamsocket
Version:
A CLI for the Jamsocket platform
153 lines (152 loc) • 7.48 kB
JavaScript
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;
;