ryuu
Version:
Domo App Dev Studio CLI, The main tool used to create, edit, and publish app designs to Domo
219 lines • 8.85 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const _ = require("lodash");
const open = require('open');
const path = require("path");
const manifest_1 = require("../util/manifest");
const login_1 = require("../util/login");
const glob = require("glob");
const fs = require("fs-extra");
const log_1 = require("../util/log");
const appStructure = require("../util/appStructure");
const models_1 = require("../models");
const prompts_1 = require("../util/prompts");
module.exports = (program) => {
program
.command('publish')
.description('publish a new or existing Custom App design')
.option('-g, --go', 'navigate to design in Asset Library after publishing')
.option('-d, --build-dir <path>', 'path to build directory containing the app files')
.action(options => {
const manifest = manifest_1.ManifestUtils.getManifest(program.opts().manifest, true);
// Change to build directory if specified
if (options.buildDir) {
const buildPath = path.resolve(options.buildDir);
if (!fs.existsSync(buildPath)) {
log_1.log.fail(`Build directory not found: ${buildPath}`, 'Please provide a valid path to your build directory.');
process.exit(1);
}
if (!fs.statSync(buildPath).isDirectory()) {
log_1.log.fail(`Path is not a directory: ${buildPath}`, 'Please provide a valid directory path.');
process.exit(1);
}
log_1.log.info(`Using build directory: ${buildPath}`);
process.chdir(buildPath);
}
new login_1.Login()
.getClient()
.then(client => {
if (client.getRefreshToken() === undefined) {
log_1.log.notAuthenticated();
}
checkFileNames(manifest);
if (!manifest.id) {
createDesign(client, manifest, options);
}
else {
client
.getDesign(manifest.id, { parts: 'versions' })
.then(result => {
checkMapping(result, manifest);
return publishAssets(client, manifest).then(() => linkToDomoWeb(options, client, manifest));
})
.catch(e => publishErrors(e, client, manifest));
}
})
.catch(log_1.log.notAuthenticated);
});
};
const createDesign = (domo, manifest, options) => {
return domo
.createDesign(manifest)
.then(designResult => {
const newManifestId = manifest_1.ManifestUtils.persistDesignId(designResult.id, manifest);
manifest = { ...manifest, id: newManifestId };
log_1.log.ok('New design created on ' + domo.getInstance());
})
.catch(e => {
log_1.log.fail('Error when creating new design:', e.message);
})
.then(() => domo.uploadAllAssets(manifest))
.then(files => logUploadSuccess(files))
.catch((e) => {
log_1.log.fail(e || 'Error uploading assets in uploading assets for a new design');
})
.then(() => {
linkToDomoWeb(options, domo, manifest);
});
};
const logUploadSuccess = (files) => {
files.forEach(file => {
log_1.log.ok('Uploaded: ' + file.path);
});
};
const linkToDomoWeb = (options, domo, manifest) => {
console.log('Design can be found at https://' +
domo.getInstance() +
'/assetlibrary?designId=' +
manifest.id);
if (options && options.go) {
open.default('https://' + domo.getInstance() + '/assetlibrary?designId=' + manifest.id);
}
};
const checkMapping = (result, manifest) => {
const latestVersionNumber = result.latestVersion;
const latestVersion = result.versions.filter((obj) => {
return obj.version === latestVersionNumber;
});
const oldMapping = latestVersion[0].datasetsMapping[0];
const newMapping = manifest.datasetsMapping[0];
if (oldMapping) {
delete oldMapping.dql;
}
if (!_.isEqual(oldMapping, newMapping)) {
log_1.log.warn('Mapping has changed. Check current cards for potential miss-mappings.');
}
};
const checkFileNames = (manifest) => {
let ignore = ['**/*/node_modules/**/*', 'node_modules/**/*'];
const userIgnore = manifest.ignore;
if (userIgnore) {
if (userIgnore instanceof Array) {
ignore = ignore.concat(userIgnore);
}
else {
log_1.log.fail('The manifest.json `ignore` property must be an Array');
}
}
const badFileList = glob.sync('**/*', { ignore: ignore }).filter(file => {
console.log(file);
// Normalize path separators to forward slashes for cross-platform compatibility
// This allows backslashes as path separators on Windows
const normalizedFile = file.replace(/\\/g, '/');
return (
// special characters except "/" in file names are not allowed
/[~`!#$%^&*+=[\]\\';,{}|\\":<>?]/g.test(normalizedFile) ||
(!fs.lstatSync(file).isDirectory() && file.indexOf(' ') !== -1));
});
if (badFileList.length > 0) {
log_1.log.fail('Special characters in file/directory names are not allowed as well as spaces in file names. Please rename the following file/directory(s): ' +
badFileList);
}
if (!appStructure.hasThumbnail()) {
log_1.log.warn(models_1.constant.THUMBNAIL_CREATE_WARNING, models_1.constant.CREATE_THUMBNAIL);
}
};
const recreateDesign = async (domo, manifest) => {
const choice = await (0, prompts_1.createSelect)('This design has been deleted. Would you like to undelete this design and publish to it, or create a new design with these assets?', ['Undelete', 'Create New Design']);
if (choice === 'Create New Design') {
manifest.id = null;
createDesign(domo, manifest);
}
else if (choice === 'Undelete') {
try {
await domo.unDeleteDesign(manifest.id);
publishAssets(domo, manifest);
}
catch (err) {
log_1.log.fail('Error undeleting design');
console.error(err);
}
}
else {
log_1.log.ok('Exited without republishing design');
}
};
const publishErrors = async (e, domo, manifest) => {
if (e.statusCode === 400 && !e.message.startsWith('DA')) {
log_1.log.fail('Design failed to publish with error:', e.message);
}
else if (e.statusCode === 401) {
log_1.log.notAuthenticated(domo.getRefreshToken());
}
else if (e.statusCode === 403) {
log_1.log.fail('You do not have access to the design with id ' +
manifest.id +
' on ' +
domo.getInstance() +
'.\nIf that seems unlikely, other possibilities are that you are publishing this design to a new environment other than the one in which it was first created.' +
'\nAlternatively, you may have inadvertently changed the design id.');
}
else if (e.message?.substr(0, 23) == 'Design has been deleted')
recreateDesign(domo, manifest);
else if (e.message?.substr(0, 15) == 'No design found') {
const shouldCreate = await (0, prompts_1.createConfirm)('This design does not exist on ' +
domo.getInstance() +
'. Would you like to create a new design with these assets?', true);
if (shouldCreate) {
manifest.id = null;
createDesign(domo, manifest);
}
}
else if (e.message && e.message.startsWith('DA')) {
switch (e.message.substr(0, 6)) {
case 'DA0086':
log_1.log.warn(e.message);
const shouldRecreate = await (0, prompts_1.createConfirm)('This design has been deleted. Would you like to publish a new design with these assets?', true);
if (shouldRecreate) {
manifest.id = null;
createDesign(domo, manifest);
}
break;
default:
// Pass on error messages that aren't in the set of documented errors.
log_1.log.fail(e.message);
break;
}
}
else {
//Error uploading assets
log_1.log.fail(log_1.log.handleErrorMessage(e, 'Error uploading assets in the upload all assets'));
}
};
const publishAssets = (domo, manifest) => {
return domo
.uploadAllAssets(manifest)
.then(files => {
log_1.log.ok('Publishing ' +
manifest.name +
' to ' +
domo.getInstance() +
' on ' +
new Date());
logUploadSuccess(files);
})
.catch(e => {
publishErrors(e, domo, manifest);
});
};
//# sourceMappingURL=publish.js.map