@enplug/scripts
Version:
Enplug scripts
359 lines (318 loc) • 9.33 kB
JavaScript
;
const commandLineArgs = require('command-line-args');
const fs = require('fs');
const path = require('path');
const chalk = require('chalk');
const AWS = require('aws-sdk');
const uploadDir = require('./functions/uploadDir');
const rootPath = process.cwd();
const packagePath = rootPath + '/package.json';
const pkg = require(packagePath);
const inquirer = require('inquirer');
require('util.promisify/shim')();
const {promisify} = require('util');
const _ = require('lodash');
let bucket;
let appName;
let target;
// Parse inline arguments
const optionDefinitions = [
{ name: 'bucket', alias: 'b', type: String },
{ name: 'appName', alias: 'a', type: String },
{ name: 'target', alias: 't', type: String },
];
const options = commandLineArgs(optionDefinitions);
const appsDestinationPrefix = 'i18n/apps'
/**
* Entry point for the script.
*/
promptForData().then(function(answer) {
if (answer.s3Bucket) {
bucket = answer.s3Bucket;
}
if (answer.target) {
target = answer.target;
}
if (target === 'gateway') {
return releaseProject('gateway', 'i18n/gateway');
} else if (target === 'dashboard project') {
return releaseProject('dashboard', 'i18n/dashboard');
} else if (target === 'everything') {
return releaseEverything();
} else if (target === 'player-web') {
return releaseProject('player-web', 'i18n/player');
} else if (target === 'app') {
return releaseApp();
}
})
/**
* Asks user to which bucket the App should be released.
*/
function promptForData() {
const questions = [];
if (!options['bucket']) {
questions.push({
message: 'Which bucket do you want to use?',
name: 's3Bucket',
type: 'list',
choices: pkg.config.aws.buckets
});
} else {
bucket = options.bucket;
}
if (!options['target']) {
questions.push({
message: 'What project\'s localization files you want to release?',
name: 'target',
type: 'list',
choices: [
'app',
'gateway',
'dashboard project',
'everything',
'player-web'
]
});
} else {
target = options.target;
}
return inquirer.prompt(questions);
}
/** Release app files */
function releaseApp() {
return askForAppName().then((response) => {
if (response.confirm) {
return syncAppTranslations(bucket, appName);
}
}).then(result => {
console.log('Release succesful, invalidating cache...');
return invalidateAppCache(appName);
});
}
function askForAppName() {
let appCollection;
return collectAppNames().then((apps) => {
appCollection = apps;
if (!options['appName']) {
return promptForApp(appCollection).then(answer => {
appName = answer.appName;
return confirmDestination(appName);
});
} else {
appName = options.appName;
return confirmDestination(appName);
}
});
}
/** Releases every translation */
function releaseEverything() {
return confirmReleaseEverything().then((answer) => {
if (answer.confirm) {
return syncEverything();
} else {
return Promise.reject('canceled');
}
}).then(() => {
console.log('Release finished, invalidating cache...');
return invalidatePaths(['/i18n/*']);
}).then(() => {
console.log('Everything released!');
}, error => {
console.log('Release not finished: ', error);
});
}
function confirmReleaseEverything() {
return inquirer.prompt({
message: `All localization files will be overwritten with what is currently in this directory. Are you sure?`,
name: 'confirm',
type: 'confirm'
});
}
function syncEverything() {
let s3Client = createS3Client();
return Promise.all([
uploadDir(s3Client, 'apps', bucket, 'i18n/apps'),
uploadDir(s3Client, 'dashboard', bucket, 'i18n/dashboard'),
uploadDir(s3Client, 'gateway', bucket, 'i18n/gateway')
]).catch(err => {
console.log('Error releasing everything: ', err.stack);
});
}
/** Releases every apps translation */
function releaseAllApps() {
return confirmReleaseAllApps().then((answer) => {
if (answer.confirm) {
return syncAllApps();
} else {
return Promise.reject('canceled');
}
}).then(() => {
console.log('Release finished, invalidating cache...');
return invalidatePaths(['/i18n/apps/*']);
}).then(() => {
console.log('Every app localization file has been released!');
}, error => {
console.log('Release not finished: ', error);
});
}
function confirmReleaseAllApps() {
return inquirer.prompt({
message: `Every app localization file will be overwritten with what is currently in this directory. Are you sure?`,
name: 'confirm',
type: 'confirm'
});
}
function syncAllApps() {
let s3Client = createS3Client();
return Promise.all([
uploadDir(s3Client, 'apps', bucket, 'i18n/apps'),
uploadDir(s3Client, 'dashboard', bucket, 'i18n/dashboard'),
uploadDir(s3Client, 'gateway', bucket, 'i18n/gateway')
]).catch(err => {
console.log('Error releasing everything: ', err.stack);
});
}
/* Release gateway */
function releaseProject(name, releaseDir) {
return confirmReleaseProject(name, releaseDir).then((answer) => {
if (answer.confirm) {
return syncProject(name, releaseDir);
} else {
return Promise.reject('canceled');
}
}).then(() => {
console.log('Release finished, invalidating cache...');
return invalidatePaths([`/${releaseDir}/*`]);
}).then(() => {
console.log(`${name} localization files released!`);
}, error => {
console.log('Release not finished: ', error);
})
}
function confirmReleaseProject(name, releaseDir) {
return inquirer.prompt({
message: `Confirm release of project ${name} localization files to ${bucket}/${releaseDir}`,
name: 'confirm',
type: 'confirm'
});
}
function syncProject(localDir, remoteDir) {
let s3Client = createS3Client();
return uploadDir(s3Client, localDir, bucket, remoteDir);
}
/** Common functions */
/**
* Looks into `dashboard` and `player` directories and gathers list of apps' files in each of them.
*/
function collectAppNames() {
const readdirAsync = promisify(fs.readdir);
return readdirAsync('apps/');
}
/**
* Asks user which app's localization strings should be released.
*/
function promptForApp(appList) {
if (!options['appName']) {
return inquirer.prompt({
message: `Which app's files do you want to release?`,
name: 'appName',
type: 'list',
choices: appList
});
} else Promise.resolve(options['appName']);
}
function confirmDestination(appName) {
let uploadPath = path.posix.join(bucket, appsDestinationPrefix, appName);
return inquirer.prompt({
message: `Confirm release of localization files for '${appName}' to ${uploadPath}`,
name: 'confirm',
type: 'confirm'
});
}
/**
* Creates an S3 client.
*/
function createS3Client() {
let creds;
const s3Options = Object.assign({}, pkg.config.aws.s3);
try {
creds = JSON.parse(fs.readFileSync(path.resolve(rootPath, './aws.private.json'), 'utf8'));
} catch (e) {
console.error(`Error finding/parsing ${chalk.default.cyan('aws.private.json')}`);
throw e;
}
if (creds.accessKeyId == null || creds.secretAccessKey == null) {
throw new TypeError(`Error could not find accessKeyId or secretAccessKey in ${chalk.default.cyan('aws.private.json')} file.`);
}
// Setting up the credentials globally
AWS.config.update({
accessKeyId: creds.accessKeyId,
secretAccessKey: creds.secretAccessKey,
maxRetries: 3,
});
return new AWS.S3(s3Options);
}
/**
*
* @param {*} bucket
* @param {*} appName
*/
function syncAppTranslations(bucket, appName) {
if (appName.startsWith('/')) {
appName = appName.substr(1);
}
let s3Client = createS3Client();
return uploadDir(s3Client, `apps/${appName}`, bucket, `i18n/apps/${appName}`).catch(function (error) {
console.error('There was an error during the release process!');
console.error(error.stack);
return null;
});
}
/**
* Invalidates cache for `appName`.
* @param {string} appName
* @returns {Promise}
*/
function invalidateAppCache(appName) {
const paths = [
`/i18n/apps/${appName}/dashboard/*`,
`/i18n/apps/${appName}/player/*`
];
return invalidatePaths(paths);
}
/**
* Invalidates cache on paths that are passed.
* @param {Array<string>} paths - paths to invalidate.
* @returns {Promise}
*/
function invalidatePaths(paths) {
return new Promise((resolve, reject) => {
const distributionIds = {
'dev-apps.enplug.in': 'E3IQ50D070L7PA',
'apps.enplug.in': 'EG84KEU04G44V',
'apps.enplug.com': 'E1YGTSTR7FTNEX'
}
AWS.config.loadFromPath('./aws.private.json');
const cloudfront = new AWS.CloudFront();
var params = {
DistributionId: distributionIds[bucket],
InvalidationBatch: {
CallerReference: String(Date.now()),
Paths: {
Quantity: paths.length,
Items: paths
}
}
};
cloudfront.createInvalidation(params, function(err, data) {
if (err) {
console.error(`Cache invalidation error: ${err}`);
reject(err);
} else {
console.log('Cache invalidation finished.');
resolve(data);
}
});
});
}