bitbucket-env-manager
Version:
Deploys Bitbucket Environment
193 lines (169 loc) • 5.66 kB
JavaScript
const dotenv = require('dotenv');
const fs = require('fs-extra');
const path = require('path');
const inquirer = require('inquirer');
const { capitalizeFirstLetter } = require('./helpers');
const { names } = require('./config');
const getEnvFileNameParams = (filename) => {
const splits = filename.split('.');
const splitsLength = splits.length;
const verify_start = splits[0] === '' && splits[1] === 'env';
const env_name = splits[splitsLength - 1];
const rankRaw = splits[splitsLength - 2];
const rank = Number(rankRaw);
if (splitsLength !== 4 || !verify_start || !env_name || ![0, 1, 2].includes(rank)) {
throw new Error('Specify env filename in the format .env.{rank}.{env_name}. 0|1|2 for rank');
}
return {
env_name: capitalizeFirstLetter(env_name),
rank,
};
};
const getInfoJsonParams = (envfilePath) => {
const parent = path.dirname(envfilePath);
const infoJsonPath = path.join(parent, names.infoJsonFile);
if (!fs.existsSync(infoJsonPath)) {
throw new Error(
`Please specify {workspace:, repo:, secured:[]} under "${names.infoJsonFile}" file`
);
}
const infoRaw = fs.readFileSync(infoJsonPath, { encoding: 'utf-8' });
const infoJson = JSON.parse(infoRaw);
if (
!infoJson.workspace ||
!infoJson.repo ||
!infoJson.secured ||
!Array.isArray(infoJson.secured)
) {
throw new Error(
`Please specify {workspace:, repo:, secured:[]} under "${names.infoJsonFile}" file`
);
}
return {
workspace: infoJson.workspace,
repo: infoJson.repo,
secured: infoJson.secured,
envs_config: infoJson.envs_config || {},
};
};
const runConvert = async ({ multiple = false } = {}) => {
try {
inquirer.registerPrompt('file-tree-selection', require('inquirer-file-tree-selection-prompt'));
const basePath = path.join(process.cwd());
const answers = await inquirer.prompt([
/* Pass your questions in here */
{
type: 'file-tree-selection',
name: 'filePaths',
message: `\n\n\x1b[45m\x1b[33mSelect .env file(s) to deploy to bitbucket\n\x1b[0m(format ".env.{0|1|2}.{env_name}")\n\n\x1b[36m"Arrow keys" -> Navigate\n"Space" -> toggle file selection\n"Enter" -> Submit selected envs\n\x1b[0m`,
root: basePath,
loop: false,
pageSize: 20,
validate: (item) => {
const name = item.split(path.sep).pop();
if (name[0] != '.') {
return 'please select another file in the format ".env.{0|1|2}.{env_name}"';
}
try {
getEnvFileNameParams(name);
} catch (e) {
return 'please select another file in the format ".env.{0|1|2}.{env_name}"';
}
// try {
// getInfoJsonParams(item);
// } catch (e) {
// return e.message || 'Error info.json';
// }
return true;
},
onlyShowValid: false,
multiple: multiple,
},
]);
const filePaths = multiple ? answers.filePaths : [answers.filePaths];
if (!filePaths.length) {
throw new Error('No Files Selected!');
}
const jsonCfgs = [];
for (const fPath of filePaths) {
const jsonCfg = await getCfgForEnvFile(fPath);
jsonCfgs.push(jsonCfg);
}
return jsonCfgs;
} catch (e) {
console.error(e.message);
} finally {
}
};
const getCfgForEnvFile = async (filePath) => {
const filename = path.basename(filePath);
const { env_name, rank } = getEnvFileNameParams(filename);
const { workspace, repo, secured, envs_config = {} } = getInfoJsonParams(filePath);
const cfg = dotenv.config({ path: filePath });
const vars = Object.keys(cfg.parsed)
.map((key) => {
return {
secured: secured.includes(key),
key,
rawValue: cfg.parsed[key],
/* NOTE
To escape \n, as other escape sequence charactes seem to be already escaped.
*/
value: cfg.parsed[key].replace(/\n/g, '\\n'),
};
})
.filter((v) => v.value);
const found = Object.keys(envs_config).find((a) => a.toLowerCase() === env_name.toLowerCase());
const env_config = {
admin_only: found && envs_config[found] ? !!envs_config[found].admin_only : false,
}; //TODO: add allowed branches
const jsonCfg = {
workspace,
repo,
env_name,
rank,
vars,
env_config,
};
console.log('\n');
console.log('%s\x1b[34m%s\x1b[0m', 'workspace = ', `${workspace}`);
console.log('%s\x1b[34m%s\x1b[0m', 'repo = ', `${repo}`);
console.log('%s\x1b[34m%s\x1b[0m', 'env_name = ', `${env_name}`);
console.log('%s\x1b[34m%s\x1b[0m', 'rank = ', `${rank}`);
console.log('%s\x1b[34m%s\x1b[0m', 'env_config = ', `${JSON.stringify(env_config)}`);
const { destConfirm } = await inquirer.prompt([
{
type: 'confirm',
name: 'destConfirm',
message: 'Do the destination details above look correct?',
},
]);
if (!destConfirm) {
throw new Error('Operation Cancelled!');
}
console.log('\n');
vars.forEach((v) => {
v.secured
? console.log('\x1b[36m%s\x1b[0m', `${v.key}="🔒🔒🔒"`)
: console.log(`${v.key}="${v.value}"`);
});
console.log('\n');
const { varsConfirm } = await inquirer.prompt([
{
type: 'confirm',
name: 'varsConfirm',
message: 'Do the variables above look correct?',
},
]);
if (!varsConfirm) {
throw new Error('Operation Cancelled!');
}
console.log(
'\n----------------------------------------------------------------------------------------'
);
return jsonCfg;
};
module.exports = {
runConvert,
};