@buildo/hophop
Version:
A minimal tool to accelerate the GitHub workflow from the command line.
201 lines (171 loc) • 5.7 kB
JavaScript
import { ArgumentParser } from 'argparse';
import { assign, uniqueId } from 'lodash';
import R from 'ramda';
import github from 'octonode';
import child_process from 'child_process';
import fs from 'fs';
import promisify from 'es6-promisify';
import semver from 'semver';
import inquirer from 'inquirer';
import clc from 'cli-color';
const cmdoutc = clc.blackBright;
const issuec = clc.bold;
const warning = clc.xterm(184);
function log(l) {
console.log(l); // eslint-disable-line no-console
}
function error(e) {
console.error(e); // eslint-disable-line no-console
}
function rlinterface() {
return {
question: (question, defaultInput) => new Promise((resolve) => {
const qName = question.name || uniqueId('question_');
const enhancedQ = assign({}, {
type: 'input',
name: qName,
default: defaultInput || null
}, question);
inquirer.prompt([enhancedQ], a => resolve(a[qName]));
}),
yesOrNoQuestion: (message, defaultInput) => new Promise((resolve) => {
const enhancedQ = {
message: `${message} (y/n)`,
name: uniqueId('yes_or_no_question_'),
type: 'input',
default: defaultInput || 'n'
};
inquirer.prompt([enhancedQ], a => resolve(a[enhancedQ.name]));
})
};
}
const rl = rlinterface();
const exec = (cmd) => new Promise((resolve) => child_process.exec(cmd, (err, o, i) => {
if (!!err) throw err;
resolve({ stdout: o, stderr: i });
}));
const execF = (cmd) => new Promise((resolve) => child_process.exec(cmd, (err, o, i) => {
resolve({ err, stdout: o, stderr: i });
}));
const enterpriseRepos = {
'buildo/labonline': {
apiEndpoint: 'github.omnilab.our.buildo.io/api/v3',
githubURL: 'github.omnilab.our.buildo.io',
accountName: 'omnilab'
}
};
async function origin() {
const _origin = (await exec('git remote -v | grep origin | grep fetch')).stdout.replace('\t', ' ').replace('\n', '').split(' ');
return _origin[1].replace('.git', '').split(':')[1];
}
async function currBranch() {
const o = (await exec('git rev-parse --abbrev-ref HEAD')).stdout;
return o.split('\n')[0];
}
const issuesLabelMapper = (issues) => {
return issues
.map(i => ({ name: `${issuec(i.number)}\t${i.title}`, value: i.number }));
};
function slugify(s) {
const fullSlug = s.toLowerCase().replace(/[^\w ]+/g, '').replace(/ +/g, '_');
const shortSlugify = R.compose(R.join('_'), R.take(4), R.split('_'));
return shortSlugify(fullSlug);
}
function gh_token_file_name(gheAccountName) {
const prefix = '.hophop_gh_token';
return gheAccountName ? `${prefix}_${gheAccountName}` : prefix;
}
function gh_token(gheAccountName) {
const fileName = gh_token_file_name(gheAccountName);
return fs.readFileSync(`${process.env.HOME}/${fileName}`, 'utf8');
}
async function gh_helper() {
const repo_name = await origin();
const config = {};
const {
[repo_name]: { apiEndpoint, accountName } = {}
} = enterpriseRepos;
if (apiEndpoint) {
config.hostname = apiEndpoint;
}
const client = github.client(gh_token(accountName), config);
// FIXME(gabro): this is here because omnilab's github SSL cert is currently self-signed
if (apiEndpoint) {
client.requestDefaults.rejectUnhauthorized = false;
client.requestDefaults.strictSSL = false;
}
const repo = client.repo(repo_name);
return { repo_name, client, repo };
}
async function gh_me(client) {
const clientMe = client.me();
try {
const me = await promisify(clientMe.info.bind(clientMe))();
return me;
} catch (e) {
error(e);
}
}
async function checkForUpdates() {
const latestVersion = (await exec('npm view @buildo/hophop version')).stdout.replace(/\n/g, '');
const installedVersion = (await exec('npm list -g --depth=0 @buildo/hophop | grep hophop | cut -d@ -f3')).stdout.replace(/\n/g, '');
if (semver.gt(latestVersion, installedVersion)) {
log(`
-------------------------------------------------------
| A new version of hophop is available! Update with |
| |
| npm install -g @buildo/hophop |
| |
-------------------------------------------------------
`);
}
}
function parseArgs() {
const parser = new ArgumentParser({
version: '0.0.1',
addHelp: true,
description: 'Argparse example'
});
const subparsers = parser.addSubparsers({
title: 'subcommand',
dest: 'cmd'
});
const gh = subparsers.addParser('gh', { addHelp: true });
const toggl = subparsers.addParser('toggl', { addHelp: true });
const gh_sp = gh.addSubparsers({
title: 'gh',
dest: 'cmd_gh'
});
const toggl_sp = toggl.addSubparsers({
title: 'toggl',
dest: 'cmd_toggl'
});
gh_sp.addParser('pr', { addHelp: true });
const gh_feature_sp = gh_sp.addParser('feature', { addHelp: true });
gh_feature_sp.addArgument(['issueNumber'], { nargs: '?' });
gh_sp.addParser('setup', { addHelp: true });
const gh_setup_sp = gh_sp.addParser('setup', { addHelp: true });
gh_setup_sp.addArgument(['gheAccountName'], { nargs: '?' });
gh_sp.addParser('commit', { addHelp: true });
toggl_sp.addParser('setup', { addHelp: true });
toggl_sp.addParser('start', { addHelp: true });
toggl_sp.addParser('stop', { addHelp: true });
toggl_sp.addParser('install-hooks', { addHelp: true });
return parser.parseArgs();
}
export default {
rl,
exec, execF,
currBranch,
issuesLabelMapper,
slugify,
gh_helper,
gh_me,
checkForUpdates,
parseArgs,
cmdoutc, issuec, warning,
log, error,
origin,
enterpriseRepos,
gh_token_file_name
};