Skip to content

Commit

Permalink
fix: change upgrade-project command to track skill-id in ask-states.j…
Browse files Browse the repository at this point in the history
…son (#90)

* fix: better message when upgrade-project for hosted skill fails by the commit that is not checked in

* fix: change upgrade-project command to track skill-id in ask-states.json

* fix: modify .gitignore after upgrade-project succeeds to add the ask-resources.json
  • Loading branch information
RonWang authored Mar 31, 2020
1 parent 5d86874 commit 97e986e
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 112 deletions.
119 changes: 65 additions & 54 deletions lib/commands/init/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,69 +40,80 @@ class InitCommand extends AbstractCommand {
return cb(err);
}

const rootPath = process.cwd();
if (!cmd.hostedSkillId) {
const rootPath = process.cwd();
helper.preInitCheck(rootPath, profile, (preCheckErr) => {
if (preCheckErr) {
Messenger.getInstance().error(preCheckErr);
return cb(preCheckErr);
initNonHostedSkill(rootPath, cmd, profile, (nhsErr) => {
cb(nhsErr);
});
} else {
initAlexaHostedSkill(rootPath, cmd, profile, (ahsErr) => {
cb(ahsErr);
});
}
}
}

function initAlexaHostedSkill(rootPath, cmd, profile, cb) {
const smapiClient = new SmapiClient({ profile, doDebug: cmd.debug });
const hostedSkillController = new HostedSkillController({ profile, doDebug: cmd.debug });
_getSkillName(smapiClient, cmd.hostedSkillId, (nameErr, skillName) => {
if (nameErr) {
Messenger.getInstance().error(nameErr);
return cb(nameErr);
}
_confirmProjectFolderName(skillName, (confirmErr, folderName) => {
if (confirmErr) {
Messenger.getInstance().error(confirmErr);
return cb(confirmErr);
}
const projectPath = path.join(rootPath, folderName);
hostedSkillController.clone(cmd.hostedSkillId, skillName, projectPath, (cloneErr) => {
if (cloneErr) {
Messenger.getInstance().error(cloneErr);
return cb(cloneErr);
}
_collectAskResources((inputErr, userInput) => {
if (inputErr) {
Messenger.getInstance().error(inputErr);
return cb(inputErr);
const templateUrl = CONSTANTS.HOSTED_SKILL.GIT_HOOKS_TEMPLATES.PRE_PUSH.URL;
const filePath = path.join(folderName, '.git', 'hooks', 'pre-push');
hostedSkillController.downloadGitHooksTemplate(templateUrl, filePath, (hooksErr) => {
if (hooksErr) {
Messenger.getInstance().error(hooksErr);
return cb(hooksErr);
}
helper.previewAndWriteAskResources(rootPath, userInput, profile, (previewErr) => {
if (previewErr) {
Messenger.getInstance().error(previewErr);
return cb(previewErr);
}
helper.bootstrapSkillInfra(rootPath, profile, cmd.debug, (postErr) => {
if (postErr) {
Messenger.getInstance().error(postErr);
return cb(postErr);
}
Messenger.getInstance().info('\nSuccess! Run "ask deploy" to deploy your skill.');
cb();
});
});
Messenger.getInstance().info(`\n${skillName} successfully initialized.\n`);
cb();
});
});
} else {
const smapiClient = new SmapiClient({ profile, doDebug: cmd.debug });
const hostedSkillController = new HostedSkillController({ profile, doDebug: cmd.debug });
_getSkillName(smapiClient, cmd.hostedSkillId, (nameErr, skillName) => {
if (nameErr) {
Messenger.getInstance().error(nameErr);
return cb(nameErr);
});
});
}

function initNonHostedSkill(rootPath, cmd, profile, cb) {
helper.preInitCheck(rootPath, profile, (preCheckErr) => {
if (preCheckErr) {
Messenger.getInstance().error(preCheckErr);
return cb(preCheckErr);
}
_collectAskResources((inputErr, userInput) => {
if (inputErr) {
Messenger.getInstance().error(inputErr);
return cb(inputErr);
}
helper.previewAndWriteAskResources(rootPath, userInput, profile, (previewErr) => {
if (previewErr) {
Messenger.getInstance().error(previewErr);
return cb(previewErr);
}
_confirmProjectFolderName(skillName, (confirmErr, folderName) => {
if (confirmErr) {
Messenger.getInstance().error(confirmErr);
return cb(confirmErr);
helper.bootstrapSkillInfra(rootPath, profile, cmd.debug, (postErr) => {
if (postErr) {
Messenger.getInstance().error(postErr);
return cb(postErr);
}
const rootPath = process.cwd();
const projectPath = path.join(rootPath, folderName);
hostedSkillController.clone(cmd.hostedSkillId, skillName, projectPath, (cloneErr) => {
if (cloneErr) {
Messenger.getInstance().error(cloneErr);
return cb(cloneErr);
}
const templateUrl = CONSTANTS.HOSTED_SKILL.GIT_HOOKS_TEMPLATES.PRE_PUSH.URL;
const filePath = path.join(folderName, '.git', 'hooks', 'pre-push');
hostedSkillController.downloadGitHooksTemplate(templateUrl, filePath, (hooksErr) => {
if (hooksErr) {
Messenger.getInstance().error(hooksErr);
return cb(hooksErr);
}
Messenger.getInstance().info(`\n${skillName} successfully initialized.\n`);
cb();
});
});
Messenger.getInstance().info('\nSuccess! Run "ask deploy" to deploy your skill.');
cb();
});
});
}
}
});
});
}

/**
Expand Down
23 changes: 16 additions & 7 deletions lib/commands/util/upgrade-project/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const awsUtil = require('@src/clients/aws-client/aws-util');
const CliError = require('@src/exceptions/cli-error');
const ResourcesConfig = require('@src/model/resources-config');
const AskResources = require('@src/model/resources-config/ask-resources');
const AskStates = require('@src/model/resources-config/ask-states');
const Messenger = require('@src/view/messenger');
const CONSTANTS = require('@src/utils/constants');
const stringUtils = require('@src/utils/string-utils');
Expand All @@ -19,7 +20,7 @@ module.exports = {
extractUpgradeInformation,
previewUpgrade,
moveOldProjectToLegacyFolder,
createV2ProjectSkeleton,
createV2ProjectSkeletonAndLoadModel,
downloadSkillPackage,
handleExistingLambdaCode
};
Expand Down Expand Up @@ -154,22 +155,30 @@ function moveOldProjectToLegacyFolder(v1RootPath) {
* @param {String} skillId the skill id
* @param {String} profile the profile
*/
function createV2ProjectSkeleton(rootPath, skillId, profile) {
function createV2ProjectSkeletonAndLoadModel(rootPath, skillId, profile) {
// prepare skill package folder
const skillPackagePath = path.join(rootPath, CONSTANTS.FILE_PATH.SKILL_PACKAGE.PACKAGE);
fs.ensureDirSync(skillPackagePath);
// prepare skill code folder
const skillCodePath = path.join(rootPath, CONSTANTS.FILE_PATH.SKILL_CODE.LAMBDA);
fs.ensureDirSync(skillCodePath);
// prepare ask-resources config
const askResourcesJson = R.clone(AskResources.BASE);
askResourcesJson.profiles[profile] = {
// prepare resources config
const askResourcesFilePath = path.join(rootPath, CONSTANTS.FILE_PATH.ASK_RESOURCES_JSON_CONFIG);
const askStatesFilePath = path.join(rootPath, CONSTANTS.FILE_PATH.HIDDEN_ASK_FOLDER, CONSTANTS.FILE_PATH.ASK_STATES_JSON_CONFIG);
const askResources = R.clone(AskResources.BASE);
askResources.profiles[profile] = {
skillMetadata: {},
code: {}
};
const askStates = R.clone(AskStates.BASE);
askStates.profiles[profile] = {
skillId,
skillMetadata: {},
code: {}
};
const askResourcesFilePath = path.join(rootPath, CONSTANTS.FILE_PATH.ASK_RESOURCES_JSON_CONFIG);
fs.writeJSONSync(askResourcesFilePath, askResourcesJson, { spaces: CONSTANTS.CONFIGURATION.JSON_DISPLAY_INDENT });
AskResources.withContent(askResourcesFilePath, askResources);
AskStates.withContent(askStatesFilePath, askStates);
new ResourcesConfig(askResourcesFilePath);
}

/**
Expand Down
26 changes: 19 additions & 7 deletions lib/commands/util/upgrade-project/hosted-skill-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ const SkillMetadataController = require('@src/controllers/skill-metadata-control
const CLiError = require('@src/exceptions/cli-error');
const ResourcesConfig = require('@src/model/resources-config');
const AskResources = require('@src/model/resources-config/ask-resources');
const AskStates = require('@src/model/resources-config/ask-states');
const CONSTANTS = require('@src/utils/constants');
const stringUtils = require('@src/utils/string-utils');

module.exports = {
checkIfDevBranchClean,
createV2ProjectSkeleton,
createV2ProjectSkeletonAndLoadModel,
downloadSkillPackage,
handleExistingLambdaCode,
postUpgradeGitSetup
Expand All @@ -31,7 +32,7 @@ function checkIfDevBranchClean(gitClient) {
const countOutput = gitClient.countCommitDifference('origin/dev', 'dev');
const counter = countOutput.toString().replace(/\D/g, '');
if (stringUtils.isNonBlankString(counter) && counter !== '0') {
throw new CLiError('Upgrade project failed. Please follow the project upgrade instruction from '
throw new CLiError('Upgrade project failed, as your dev branch is ahead of the remote.\nPlease follow the project upgrade instruction from '
+ 'https://github.com/alexa-labs/ask-cli/blob/develop/docs/Upgrade-Project-From-V1.md#upgrade-steps to change to ask-cli v2 structure.');
}
}
Expand All @@ -42,20 +43,25 @@ function checkIfDevBranchClean(gitClient) {
* @param {String} skillId the skill id
* @param {String} profile the profile
*/
function createV2ProjectSkeleton(rootPath, skillId, profile) {
function createV2ProjectSkeletonAndLoadModel(rootPath, skillId, profile) {
// prepare skill package folder
const skillPackagePath = path.join(rootPath, CONSTANTS.FILE_PATH.SKILL_PACKAGE.PACKAGE);
fs.ensureDirSync(skillPackagePath);
// prepare skill code folder
const skillCodePath = path.join(rootPath, CONSTANTS.FILE_PATH.SKILL_CODE.LAMBDA);
fs.ensureDirSync(skillCodePath);
// prepare ask-resources config
// prepare resources config
const askResourcesFilePath = path.join(rootPath, CONSTANTS.FILE_PATH.ASK_RESOURCES_JSON_CONFIG);
const askResourcesJson = R.clone(ResourcesConfig.BASE);
askResourcesJson.profiles[profile] = {
const askStatesFilePath = path.join(rootPath, CONSTANTS.FILE_PATH.HIDDEN_ASK_FOLDER, CONSTANTS.FILE_PATH.ASK_STATES_JSON_CONFIG);
const askResources = R.clone(AskResources.BASE);
askResources.profiles[profile] = {};
const askStates = R.clone(AskStates.BASE);
askStates.profiles[profile] = {
skillId
};
AskResources.withContent(askResourcesFilePath, askResourcesJson);
AskResources.withContent(askResourcesFilePath, askResources);
AskStates.withContent(askStatesFilePath, askStates);
new ResourcesConfig(askResourcesFilePath);
}

/**
Expand Down Expand Up @@ -113,6 +119,7 @@ function postUpgradeGitSetup(profile, doDebug, gitClient, callback) {
try {
_setGitCredentialHelper(profile, gitClient);
_setMasterAsDefault(gitClient);
_updateGitIgnoreWithAskResourcesJson(gitClient);
} catch (error) {
return callback(error);
}
Expand All @@ -124,6 +131,11 @@ function _setGitCredentialHelper(profile, gitClient) {
gitClient.configureCredentialHelper(credentialHelperPath);
}

function _updateGitIgnoreWithAskResourcesJson(gitClient) {
const fileToAdd = ['ask-resources.json', '.ask/'];
gitClient.setupGitIgnore(fileToAdd);
}

function _setMasterAsDefault(gitClient) {
gitClient.checkoutBranch('master');
gitClient.merge('dev');
Expand Down
9 changes: 2 additions & 7 deletions lib/commands/util/upgrade-project/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
const path = require('path');

const GitClient = require('@src/clients/git-client');
const { AbstractCommand } = require('@src/commands/abstract-command');
const optionModel = require('@src/commands/option-model');
const ResourcesConfig = require('@src/model/resources-config');
const Messenger = require('@src/view/messenger');
const profileHelper = require('@src/utils/profile-helper');
const CONSTANTS = require('@src/utils/constants');
Expand Down Expand Up @@ -85,8 +82,7 @@ function _createV2HostedSkillProject(upgradeInfo, profile, doDebug, callback) {
// 1.move v1 skill project content into legacy folder
helper.moveOldProjectToLegacyFolder(rootPath);
// 2.instantiate MVC and ask-resource config
hostedSkillHelper.createV2ProjectSkeleton(rootPath, skillId, profile);
new ResourcesConfig(path.join(rootPath, CONSTANTS.FILE_PATH.ASK_RESOURCES_JSON_CONFIG));
hostedSkillHelper.createV2ProjectSkeletonAndLoadModel(rootPath, skillId, profile);
} catch (initProjErr) {
return callback(initProjErr);
}
Expand Down Expand Up @@ -118,8 +114,7 @@ function _createV2NonHostedSkillProject(upgradeInfo, profile, doDebug, callback)
// 1.move v1 skill project content into legacy folder
helper.moveOldProjectToLegacyFolder(rootPath);
// 2.instantiate MVC and ask-resource config
helper.createV2ProjectSkeleton(rootPath, skillId, profile);
new ResourcesConfig(path.join(rootPath, CONSTANTS.FILE_PATH.ASK_RESOURCES_JSON_CONFIG));
helper.createV2ProjectSkeletonAndLoadModel(rootPath, skillId, profile);
} catch (initProjErr) {
return callback(initProjErr);
}
Expand Down
44 changes: 32 additions & 12 deletions test/unit/commands/util/upgrade-project/helper-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const ui = require('@src/commands/util/upgrade-project/ui');
const SkillMetadataController = require('@src/controllers/skill-metadata-controller');
const CLiError = require('@src/exceptions/cli-error');
const ResourcesConfig = require('@src/model/resources-config');
const AskResources = require('@src/model/resources-config/ask-resources');
const AskStates = require('@src/model/resources-config/ask-states');
const Messenger = require('@src/view/messenger');
const CONSTANTS = require('@src/utils/constants');
const hashUtils = require('@src/utils/hash-utils');
Expand All @@ -31,6 +33,7 @@ describe('Commands upgrade-project test - helper test', () => {
const TEST_ROOT_PATH = 'rootPath';
const TEST_ARN = 'arn:aws:lambda:us-west-2:123456789012:function:ask-custom-skill-sample-nodejs-fact-default';
const FIXTURE_RESOURCES_CONFIG_FILE_PATH = path.join(process.cwd(), 'test', 'unit', 'fixture', 'model', 'regular-proj', 'ask-resources.json');
const FIXTURE_STATES_CONFIG_FILE_PATH = path.join(process.cwd(), 'test', 'unit', 'fixture', 'model', 'regular-proj', '.ask', 'ask-states.json');
const TEST_LAMBDAS = [
{
alexaUsage: ['custom/default'],
Expand Down Expand Up @@ -298,28 +301,45 @@ You have multiple Lambda codebases for region ${TEST_REGION}, we will use "${TES
});
});

describe('# test helper method - createV2ProjectSkeleton', () => {
describe('# test helper method - createV2ProjectSkeletonAndLoadModel', () => {
beforeEach(() => {
sinon.stub(path, 'join');
path.join.withArgs(
TEST_ROOT_PATH, CONSTANTS.FILE_PATH.ASK_RESOURCES_JSON_CONFIG
).returns(FIXTURE_RESOURCES_CONFIG_FILE_PATH);
path.join.withArgs(
TEST_ROOT_PATH, CONSTANTS.FILE_PATH.HIDDEN_ASK_FOLDER, CONSTANTS.FILE_PATH.ASK_STATES_JSON_CONFIG
).returns(FIXTURE_STATES_CONFIG_FILE_PATH);
path.join.callThrough();
});

afterEach(() => {
sinon.restore();
});

it('| crate v2 project skeleton, expect write JSON file correctly', () => {
// setup
const ensureDirStub = sinon.stub(fs, 'ensureDirSync');
const writeStub = sinon.stub(fs, 'writeJSONSync');
sinon.stub(R, 'clone').returns({ profiles: {} });
sinon.stub(AskResources, 'withContent');
sinon.stub(AskStates, 'withContent');
// call
helper.createV2ProjectSkeleton(TEST_ROOT_PATH, TEST_SKILL_ID, TEST_PROFILE);
helper.createV2ProjectSkeletonAndLoadModel(TEST_ROOT_PATH, TEST_SKILL_ID, TEST_PROFILE);
expect(ensureDirStub.args[0][0]).eq(path.join(TEST_ROOT_PATH, CONSTANTS.FILE_PATH.SKILL_PACKAGE.PACKAGE));
expect(ensureDirStub.args[1][0]).eq(path.join(TEST_ROOT_PATH, CONSTANTS.FILE_PATH.SKILL_CODE.LAMBDA));
expect(writeStub.args[0][0]).eq(path.join(TEST_ROOT_PATH, CONSTANTS.FILE_PATH.ASK_RESOURCES_JSON_CONFIG));
expect(writeStub.args[0][1]).deep.equal({
profiles: {
[TEST_PROFILE]: {
skillId: TEST_SKILL_ID,
skillMetadata: {},
code: {}
}

expect(AskResources.withContent.args[0][0]).eq(FIXTURE_RESOURCES_CONFIG_FILE_PATH);
expect(AskResources.withContent.args[0][1].profiles).deep.equal({
[TEST_PROFILE]: {
skillMetadata: {},
code: {}
}
});
expect(AskStates.withContent.args[0][0]).eq(FIXTURE_STATES_CONFIG_FILE_PATH);
expect(AskStates.withContent.args[0][1].profiles).deep.equal({
[TEST_PROFILE]: {
skillId: TEST_SKILL_ID,
skillMetadata: {},
code: {}
}
});
});
Expand Down
Loading

0 comments on commit 97e986e

Please sign in to comment.