ask-cli-x
Version:
Alexa Skills Kit (ASK) Command Line Interfaces
222 lines (221 loc) • 11.5 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createCommand = void 0;
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const abstract_command_1 = require("../abstract-command");
const option_model_json_1 = __importDefault(require("../option-model.json"));
const cli_error_1 = __importDefault(require("../../exceptions/cli-error"));
const cli_file_not_found_error_1 = __importDefault(require("../../exceptions/cli-file-not-found-error"));
const cli_warn_1 = __importDefault(require("../../exceptions/cli-warn"));
const resources_config_1 = __importDefault(require("../../model/resources-config"));
const manifest_1 = __importDefault(require("../../model/manifest"));
const constants_1 = __importDefault(require("../../utils/constants"));
const profile_helper_1 = __importDefault(require("../../utils/profile-helper"));
const string_utils_1 = __importDefault(require("../../utils/string-utils"));
const messenger_1 = __importDefault(require("../../view/messenger"));
const spinner_view_1 = __importDefault(require("../../view/spinner-view"));
const ui_1 = __importDefault(require("./ui"));
const helper_1 = __importDefault(require("./helper"));
const ac_util_1 = require("../../utils/ac-util");
class DeployCommand extends abstract_command_1.AbstractCommand {
name() {
return "deploy";
}
description() {
return "deploy the skill project";
}
requiredOptions() {
return [];
}
optionalOptions() {
return ["ignore-hash", "target", "profile", "debug"];
}
async handle(cmd) {
let profile;
try {
profile = profile_helper_1.default.runtimeProfile(cmd.profile);
new resources_config_1.default(path_1.default.join(process.cwd(), constants_1.default.FILE_PATH.ASK_RESOURCES_JSON_CONFIG));
messenger_1.default.getInstance().info(`Deploy configuration loaded from ${constants_1.default.FILE_PATH.ASK_RESOURCES_JSON_CONFIG}`);
helper_1.default.confirmProfile(profile);
this._filterAlexaHostedSkill(profile);
this._initiateManifestModel(profile);
}
catch (err) {
if (err instanceof cli_warn_1.default) {
messenger_1.default.getInstance().warn(err.message);
}
else if (err instanceof cli_file_not_found_error_1.default) {
messenger_1.default.getInstance().warn(err.message);
}
else if (err instanceof cli_error_1.default) {
messenger_1.default.getInstance().error(err.message);
}
else {
messenger_1.default.getInstance().error(err);
}
throw err;
}
const allowedTargets = Object.values(constants_1.default.DEPLOY_TARGET);
if (cmd.target && !allowedTargets.includes(cmd.target)) {
const errMessage = `Target ${cmd.target} is not supported. Supported targets: ${allowedTargets}.`;
messenger_1.default.getInstance().error(errMessage);
throw new cli_error_1.default(errMessage);
}
const options = { profile, doDebug: cmd.debug, ignoreHash: cmd.ignoreHash, target: cmd.target };
return new Promise((resolve, reject) => {
ui_1.default.confirmDeploymentIfNeeded(profile, (err, confirmResult) => {
if (err) {
messenger_1.default.getInstance().error(err);
return reject(err);
}
if (!confirmResult) {
messenger_1.default.getInstance().info("Deployment cancelled.");
return resolve();
}
deployResources(options)
.then(() => {
const deploymentType = helper_1.default.getDeploymentType(profile);
// Save the deployment type to ask states
resources_config_1.default.getInstance().setSkillMetaLastDeployType(profile, deploymentType);
// Write updates back to resources file
resources_config_1.default.getInstance().write();
manifest_1.default.getInstance().write();
// Skipping enable logic if deploying with target flag
// since we may don't have the endpoint
if (cmd.target) {
return resolve();
}
// Post deploy logic
// call smapiClient to enable skill
helper_1.default.enableSkill(profile, cmd.debug, (enableError) => {
if (enableError instanceof cli_warn_1.default) {
messenger_1.default.getInstance().warn(enableError);
return resolve();
}
if (enableError) {
messenger_1.default.getInstance().error(enableError);
return reject(enableError);
}
return resolve();
});
})
.catch((err) => {
messenger_1.default.getInstance().error(err);
return reject(err);
});
});
});
}
_filterAlexaHostedSkill(profile) {
const deployerType = resources_config_1.default.getInstance().getSkillInfraType(profile);
if (deployerType === constants_1.default.DEPLOYER_TYPE.HOSTED.NAME) {
throw new cli_warn_1.default("Alexa hosted skills can be deployed by performing a git push.\n" +
"The master branch gets deployed to skill's development stage\n" +
"The prod branch gets deployed to skill's live stage\n" +
'Please run "git push" at the proper branch to deploy hosted skill to your targeted stage.');
}
}
_initiateManifestModel(profile) {
const skillPackageSrc = resources_config_1.default.getInstance().getSkillMetaSrc(profile);
if (!string_utils_1.default.isNonBlankString(skillPackageSrc)) {
throw new cli_error_1.default("Skill package src is not found in ask-resources.json.");
}
if (!fs_extra_1.default.existsSync(skillPackageSrc)) {
throw new cli_error_1.default(`The skillMetadata src file ${skillPackageSrc} does not exist.`);
}
const manifestPath = path_1.default.join(skillPackageSrc, constants_1.default.FILE_PATH.SKILL_PACKAGE.MANIFEST);
new manifest_1.default(manifestPath);
}
}
exports.default = DeployCommand;
/**
* The deploy function used to deploy all skill related resources
* This steps includes the deploy of skillMeta, skillCode and skillInfra using the deployDelegate plugin
* @param {String} profile The profile name
* @param {Boolean} doDebug The flag of debug or not
* @param {Boolean} ignoreHash The flag to ignore difference between local and remote version
* @param {Function} callback
*/
async function deployResources(options) {
const { profile, doDebug, target, ignoreHash } = options;
await _deploySkillMetadata(options);
if (target && target !== constants_1.default.DEPLOY_TARGET.SKILL_INFRASTRUCTURE) {
return;
}
if (!resources_config_1.default.getInstance().getSkillId(profile)) {
const errorMessage = `Unable to deploy target ${target} when the skillId has not been created yet. ` +
"Please deploy your skillMetadata first by running “ask deploy” command.";
throw new cli_error_1.default(errorMessage);
}
// Skill Code
const regionsList = resources_config_1.default.getInstance().getCodeRegions(profile);
if (!regionsList || regionsList.length === 0) {
return;
}
messenger_1.default.getInstance().info("\n==================== Build Skill Code ====================");
return new Promise((resolve, reject) => {
helper_1.default.buildSkillCode(profile, doDebug, (buildErr, uniqueCodeList) => {
if (buildErr) {
return reject(buildErr);
}
messenger_1.default.getInstance().info("Skill code built successfully.");
uniqueCodeList.forEach((codeProperty) => {
const buildFilePath = codeProperty.build.file;
messenger_1.default.getInstance().info(`Code for region ${codeProperty.regionsList.join("+")} built to ${buildFilePath} successfully \
with build flow ${codeProperty.buildFlow}.`);
});
// Skill Infrastructure
const infraType = resources_config_1.default.getInstance().getSkillInfraType(profile);
if (!string_utils_1.default.isNonBlankString(infraType)) {
return resolve();
}
messenger_1.default.getInstance().info("\n==================== Deploy Skill Infrastructure ====================");
helper_1.default.deploySkillInfrastructure(profile, doDebug, ignoreHash, (infraErr) => {
if (infraErr) {
return reject(infraErr);
}
messenger_1.default.getInstance().info(`\nSkill infrastructures deployed successfully through ${infraType}.`);
resolve();
});
});
});
}
async function _deploySkillMetadata(options) {
const { profile, target } = options;
if (target && target !== constants_1.default.DEPLOY_TARGET.SKILL_METADATA) {
return;
}
// Skill Metadata
messenger_1.default.getInstance().info("==================== Deploy Skill Metadata ====================");
const skillMetaSpinner = new spinner_view_1.default();
const acMsg = "Uploading the entire skill package and building the models. For Alexa Conversations it can take 20-60 minutes...";
const imMsg = "Uploading the entire skill package and building the models. Normally it takes a few minutes...";
const startMsg = (0, ac_util_1.isAcSkill)(profile) ? acMsg : imMsg;
skillMetaSpinner.start(startMsg);
return new Promise((resolve, reject) => {
helper_1.default.deploySkillMetadata(options, skillMetaSpinner, (metaErr) => {
skillMetaSpinner.terminate();
if (metaErr &&
metaErr !==
"The hash of current skill package folder does not change compared to the last deploy hash result, " +
"CLI will skip the deploy of skill package.") {
return reject(metaErr);
}
if (metaErr) {
// this case is the warning message of the same hash skip, deploy will continue
messenger_1.default.getInstance().warn(metaErr);
}
else {
resources_config_1.default.getInstance().write();
messenger_1.default.getInstance().info("Skill package deployed and all models built successfully.");
}
messenger_1.default.getInstance().info(`Skill ID: ${resources_config_1.default.getInstance().getSkillId(profile)}`);
return resolve();
});
});
}
exports.createCommand = new DeployCommand(option_model_json_1.default).createCommand();