ask-cli
Version:
Alexa Skills Kit (ASK) Command Line Interfaces
237 lines (236 loc) • 12.4 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 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));
resources_config_1.default.getInstance().setDeploymentStatus(profile, "IN_PROGRESS");
resources_config_1.default.getInstance().write();
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);
resources_config_1.default.getInstance().setDeploymentStatus(profile, "COMPLETE");
// 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) => {
resources_config_1.default.getInstance().setDeploymentStatus(profile, "COMPLETE");
// Write updates back to resources file
resources_config_1.default.getInstance().write();
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.`);
}
// check whether it is a AC skill
if ((0, ac_util_1.isAcSkill)(profile) === true) {
// if it's AC skill, check if the build/skill-package exists
const buildPackageSrc = path_1.default.join("build", skillPackageSrc);
if (!fs_extra_1.default.existsSync(buildPackageSrc)) {
throw new cli_error_1.default(`The directory specified, ${buildPackageSrc}, does not exist. Please compile your AC skill before deploying it.`);
}
}
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;
}
const isAcdlSkill = (0, ac_util_1.isAcSkill)(profile);
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 = isAcdlSkill ? acMsg : imMsg;
if (isAcdlSkill) {
messenger_1.default.getInstance().warn(constants_1.default.ACDL_BETA_MESSAGE + "\n");
}
// Skill Metadata
messenger_1.default.getInstance().info("==================== Deploy Skill Metadata ====================");
messenger_1.default.getInstance().info(startMsg);
return new Promise((resolve, reject) => {
helper_1.default.deploySkillMetadata(options, (metaErr) => {
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();