@metacall/deploy
Version:
Tool for deploying into MetaCall FaaS platform.
152 lines (151 loc) • 8.16 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.deployFromRepository = exports.deployPackage = exports.ErrorCode = void 0;
const package_1 = require("@metacall/protocol/package");
const protocol_1 = require("@metacall/protocol/protocol");
const fs_1 = require("fs");
const path_1 = require("path");
const args_1 = __importDefault(require("./cli/args"));
const inputs_1 = require("./cli/inputs");
const messages_1 = require("./cli/messages");
const progress_1 = __importDefault(require("./cli/progress"));
const selection_1 = require("./cli/selection");
const logs_1 = require("./logs");
const tty_1 = require("./tty");
const utils_1 = require("./utils");
var ErrorCode;
(function (ErrorCode) {
ErrorCode[ErrorCode["Ok"] = 0] = "Ok";
ErrorCode[ErrorCode["NotDirectoryRootPath"] = 1] = "NotDirectoryRootPath";
ErrorCode[ErrorCode["EmptyRootPath"] = 2] = "EmptyRootPath";
ErrorCode[ErrorCode["NotFoundRootPath"] = 3] = "NotFoundRootPath";
ErrorCode[ErrorCode["AccountDisabled"] = 4] = "AccountDisabled";
ErrorCode[ErrorCode["DeployPackageFailed"] = 5] = "DeployPackageFailed";
ErrorCode[ErrorCode["DeployRepositoryFailed"] = 6] = "DeployRepositoryFailed";
})(ErrorCode = exports.ErrorCode || (exports.ErrorCode = {}));
const deployPackage = async (rootPath, api, plan) => {
try {
const name = args_1.default['projectName'].toLowerCase();
let descriptor = await (0, package_1.generatePackage)(rootPath);
const deploy = async (additionalJsons) => {
// TODO: We should cache the plan and ask for it only once
const descriptor = await (0, package_1.generatePackage)(rootPath);
const { progress, pulse, hide } = (0, progress_1.default)();
const archive = await (0, utils_1.zip)(rootPath, descriptor.files, progress, pulse, hide);
// TODO: We should do something with the return value, for example
// check for error or show the output to the user
await api.upload(name, archive, additionalJsons, descriptor.runners);
// TODO: We can ask for environment variables here too and cache them
const env = await (0, utils_1.getEnv)(rootPath);
(0, messages_1.info)(`Deploying ${rootPath}...\n`);
try {
const deploy = await api.deploy(name, env, plan, protocol_1.ResourceType.Package);
if ((0, tty_1.isInteractive)()) {
// TODO: Need a TUI for logs
await (0, logs_1.logs)(descriptor.runners, name, args_1.default['dev']);
}
if (deploy) {
(0, messages_1.info)('Repository deployed, Use command $ metacall-deploy --inspect, to know more about deployment');
}
}
catch (err) {
(0, messages_1.apiError)(err);
}
};
const createJsonAndDeploy = async (saveConsent) => {
let languages = [];
let packages = [];
let wait = true;
do {
const potentialPackages = (0, package_1.generateJsonsFromFiles)(descriptor.files);
const potentialLanguages = Array.from(new Set(potentialPackages.reduce((langs, pkg) => [...langs, pkg.language_id], [])));
languages = await (0, selection_1.languageSelection)(potentialLanguages);
if (languages.length == 0) {
(0, messages_1.warn)('You must choose a language in order to proceed with the deployment procedure, do not continue without doing so.');
wait = false;
continue;
}
packages = potentialPackages.filter(pkg => languages.includes(pkg.language_id));
await (0, utils_1.loadFilesToRun)(packages);
const langId = [];
for (const pkg of packages) {
pkg.scripts.length === 0 && langId.push(pkg.language_id);
}
if (!langId.length)
break;
if (langId.length === packages.length) {
(0, messages_1.warn)('You must choose a file to continue the deployment procedure, do not continue without doing so.');
wait = false;
continue;
}
const deployConsent = (await (0, inputs_1.input)(`You selected language${langId.length > 1 ? 's' : ''} ${langId
.map(el => (0, messages_1.printLanguage)(el))
.join(', ')} but you didn't select any file, do you want to continue? (Y/N):`)).toUpperCase();
wait = deployConsent === 'Y' || deployConsent === 'YES';
} while (!wait);
const cacheJsons = saveConsent === 'Y' || saveConsent === 'YES';
const additionalPackages = cacheJsons
? await (async () => {
for (const pkg of packages) {
if (pkg.scripts.length === 0)
continue;
await fs_1.promises.writeFile((0, path_1.join)(rootPath, `metacall-${pkg.language_id}.json`), JSON.stringify(pkg, null, 2));
}
// If they are cached, genearte the descriptor again
descriptor = await (0, package_1.generatePackage)(rootPath);
// The descriptor already contains the packages so
// there is no need to send additional packages
return [];
})()
: packages; // Otherwise, packages are not cached, send them
await deploy(additionalPackages);
};
switch (descriptor.error) {
case package_1.PackageError.None: {
await deploy([]);
break;
}
case package_1.PackageError.Empty: {
return (0, messages_1.error)(`The directory you specified (${rootPath}) is empty.`, ErrorCode.EmptyRootPath);
}
case package_1.PackageError.JsonNotFound: {
(0, messages_1.warn)(`No metacall.json was found in ${rootPath}, launching the wizard...`);
const askToCachePackagesFile = () => (0, inputs_1.input)('Do you want to save metacall.json file? (Y/N):');
await createJsonAndDeploy((await askToCachePackagesFile()).toUpperCase());
break;
}
}
}
catch (e) {
(0, messages_1.error)(String(e), ErrorCode.DeployPackageFailed);
}
};
exports.deployPackage = deployPackage;
const deployFromRepository = async (api, plan, url) => {
try {
const { branches } = await api.branchList(url);
if (!branches.length)
return (0, messages_1.error)('Invalid Repository URL');
// TODO: API response type should be created in protocol, it is string as of now
const selectedBranch = branches.length === 1
? branches[0]
: await (0, selection_1.listSelection)(branches, 'Select branch:');
if (branches.length === 1)
(0, messages_1.info)(`Only one branch found : ${selectedBranch}, Selecting it automatically.`);
const runners = Array.from((0, package_1.findRunners)(await api.fileList(url, selectedBranch)));
const name = (await api.add(url, selectedBranch, [])).id;
const env = await (0, utils_1.getEnv)();
const deploy = await api.deploy(name, env, plan, protocol_1.ResourceType.Repository);
(0, messages_1.info)('Deploying...');
await (0, logs_1.logs)(runners, deploy.suffix, args_1.default['dev']);
if (deploy)
(0, messages_1.info)('Repository deployed, Use command $ metacall-deploy --inspect, to know more about deployment');
}
catch (e) {
(0, messages_1.error)(String(e), ErrorCode.DeployRepositoryFailed);
}
};
exports.deployFromRepository = deployFromRepository;