diff --git a/.babelrc b/.babelrc index 4af6790..7f139e8 100644 --- a/.babelrc +++ b/.babelrc @@ -1,5 +1,17 @@ { - "presets": [ "es2015" ], + "presets": [ + "es2015", + "es2016", + "es2017" + ], + "plugins": [ + ["transform-runtime", { + "helpers": false, + "polyfill": false, + "regenerator": true, + "moduleName": "babel-runtime" + }] + ], "sourceMaps": true, "retainLines": true } diff --git a/main/index.js b/main/index.js index 19d08c3..1b189fa 100644 --- a/main/index.js +++ b/main/index.js @@ -4,14 +4,13 @@ INDEX ================================================== */ -import 'babel-polyfill'; import path from 'path'; import clear from 'clear'; import chalk from 'chalk'; import figlet from 'figlet'; import inquirer from 'inquirer'; -import { isFile, wrapSpinner, async } from './modules/helpers'; +import { isFile, wrapSpinner } from './modules/helpers'; import { TYPES, Commits, getRepositoryTypeFromUrl } from './modules/commits'; import { FORMATS } from './modules/velocity'; import CommitsDashboard from './modules/dashboard'; @@ -33,18 +32,18 @@ console.log( // START -async(function* () { +(async function start() { try { - const { type } = yield getRepositoryType(); + const { type } = await getRepositoryType(); const commits = Commits(type); - const isAuthorized = yield commits.isAuthorized(); + const isAuthorized = await commits.isAuthorized(); if (!isAuthorized) { console.log(); console.log(chalk.white('Creating auth token in root.')); - const { username, password } = yield getRepositoryCreds(type); + const { username, password } = await getRepositoryCreds(type); commits.authorize(username, password); } @@ -52,103 +51,95 @@ async(function* () { console.log(); console.log(chalk.white('Provide information regarding the repository you\'d like to analyze.')); - const { repository, owner } = yield getRepositoryInfo(); - const data = yield wrapSpinner(commits.getCommitsByRepo, 'Pulling commits...')(repository, owner); - const { format } = yield getVelocityFormat(); + const { repository, owner } = await getRepositoryInfo(); + const data = await wrapSpinner(commits.getCommitsByRepo, 'Pulling commits...')(repository, owner); + const { format } = await getVelocityFormat(); const dashboard = CommitsDashboard(); - yield dashboard.render(format, data); + await dashboard.render(format, data); } catch (error) { console.error(chalk.red('=== ERROR ===')); console.log(error); } -}); +})(); // PROMPTS -function getRepositoryType() { - return new Promise(resolve => { - const questions = [ - { - type: 'list', - name: 'type', - message: 'Select repository type:', - choices: [ - TYPES.GITHUB, - TYPES.BITBUCKET - ], - default: repository_package ? - getRepositoryTypeFromUrl(typeof repository_package.repository === 'string' ? - repository_package.repository : - repository_package.repository.type || repository_package.repository.url) : - TYPES.GITHUB - } - ]; - - inquirer.prompt(questions).then(resolve); - }); +async function getRepositoryType() { + const questions = [ + { + type: 'list', + name: 'type', + message: 'Select repository type:', + choices: [ + TYPES.GITHUB, + TYPES.BITBUCKET + ], + default: repository_package ? + getRepositoryTypeFromUrl(typeof repository_package.repository === 'string' ? + repository_package.repository : + repository_package.repository.type || repository_package.repository.url) : + TYPES.GITHUB + } + ]; + + return await inquirer.prompt(questions); } -function getRepositoryCreds(type) { - return new Promise(resolve => { - const questions = [ - { - name: 'username', - type: 'input', - message: `Enter ${ type } username:`, - validate: value => value.length ? true : 'Please enter a value.' - }, - { - name: 'password', - type: 'password', - message: `Enter ${ type } password:`, - validate: value => value.length ? true : 'Please enter a value.' - } - ]; - - inquirer.prompt(questions).then(resolve); - }); +async function getRepositoryCreds(type) { + const questions = [ + { + name: 'username', + type: 'input', + message: `Enter ${ type } username:`, + validate: value => value.length ? true : 'Please enter a value.' + }, + { + name: 'password', + type: 'password', + message: `Enter ${ type } password:`, + validate: value => value.length ? true : 'Please enter a value.' + } + ]; + + return await inquirer.prompt(questions); } -function getRepositoryInfo() { - return new Promise(resolve => { - const questions = [ - { - name: 'repository', - type: 'input', - message: 'Enter the slugged name of the repository:', - default: path.basename(process.cwd()), - validate: value => value.length ? true : 'Please enter a value.' - }, - { - name: 'owner', - type: 'input', - message: 'Enter the owner of the repository:', - default: repository_package && repository_package.author ? repository_package.author : '', - validate: value => value.length ? true : 'Please enter a value.' - } - ]; - - inquirer.prompt(questions).then(resolve); - }); +async function getRepositoryInfo() { + const questions = [ + { + name: 'repository', + type: 'input', + message: 'Enter the slugged name of the repository:', + default: path.basename(process.cwd()), + validate: value => value.length ? true : 'Please enter a value.' + }, + { + name: 'owner', + type: 'input', + message: 'Enter the owner of the repository:', + default: repository_package && repository_package.author ? repository_package.author : '', + validate: value => value.length ? true : 'Please enter a value.' + } + ]; + + return await inquirer.prompt(questions); } -function getVelocityFormat() { - return new Promise(resolve => { - const questions = [ - { - type: 'list', - name: 'format', - message: 'Velocity calculation format:', - choices: [ - FORMATS.WEEK, - FORMATS.MONTH - ], - default: FORMATS.WEEK - } - ]; - - inquirer.prompt(questions).then(resolve); - }); +async function getVelocityFormat() { + const questions = [ + { + type: 'list', + name: 'format', + message: 'Velocity calculation format:', + choices: [ + FORMATS.WEEK, + FORMATS.MONTH + ], + default: FORMATS.WEEK + } + ]; + + return await inquirer.prompt(questions); } diff --git a/main/modules/auth.js b/main/modules/auth.js index be11808..63ca803 100644 --- a/main/modules/auth.js +++ b/main/modules/auth.js @@ -4,45 +4,28 @@ import fs from 'fs'; -import { isFile, partial } from './helpers'; - -// PUBLIC +import { isFile } from './helpers'; export function Auth(token) { return { - isCredsTokenInitialized: partial(_isCredsTokenInitialized, token), - getCreds: partial(_getCreds, token), - storeCreds: partial(_storeCreds, token) + isCredsTokenInitialized: async function() { + return isFile(`${ process.env.HOME }/${ token }`); + }, + getCreds: async function() { + return JSON.parse(fs.readFileSync(`${ process.env.HOME }/${ token }`, 'utf8')); + }, + storeCreds(username, password) { + return new Promise((resolve, reject) => { + fs.writeFile( + `${ process.env.HOME }/${ token }`, + JSON.stringify({ username, password }), + error => error ? reject(error) : resolve() + ); + }); + } }; } export default { Auth }; - -// PRIVATE - -function _isCredsTokenInitialized(token) { - return new Promise(resolve => resolve(isFile(`${ process.env.HOME }/${ token }`))); -} - -function _getCreds(token) { - return new Promise((resolve, reject) => { - try { - resolve(JSON.parse(fs.readFileSync(`${ process.env.HOME }/${ token }`, 'utf8'))); - } - catch (error) { - reject(error); - } - }); -} - -function _storeCreds(token, username, password) { - return new Promise((resolve, reject) => { - fs.writeFile( - `${ process.env.HOME }/${ token }`, - JSON.stringify({ username, password }), - error => error ? reject(error) : resolve() - ); - }); -} diff --git a/main/modules/commits.js b/main/modules/commits.js index d55ff6c..50ca8b6 100644 --- a/main/modules/commits.js +++ b/main/modules/commits.js @@ -2,7 +2,7 @@ COMMITS ================================================== */ -import { uniq, async, requestPromise } from './helpers'; +import { uniq, requestPromise } from './helpers'; import { Auth } from './auth'; // PUBLIC @@ -52,31 +52,22 @@ function BitBucketCommits(auth) { return { isAuthorized: auth.isCredsTokenInitialized, authorize: auth.storeCreds, - getCommitsByRepo(repository, owner) { - return new Promise((resolve, reject) => { - async(function* () { - try { - const { username, password } = yield auth.getCreds(); - - const options = { - url: config.commits_url.replace('{owner}', owner).replace('{repo}', repository), - config: { - headers: { - 'User-Agent': owner, - Authorization: 'Basic ' + new Buffer(`${ username }:${ password }`).toString('base64') - } - } - }; - - const commits = yield _requestPagedResponse(options, response => response.data.next); - - resolve(commits.reduce((acc, value) => acc.concat(value.values), []).map(BitBucketCommit)); + getCommitsByRepo: async function(repository, owner) { + const { username, password } = await auth.getCreds(); + + const options = { + url: config.commits_url.replace('{owner}', owner).replace('{repo}', repository), + config: { + headers: { + 'User-Agent': owner, + Authorization: 'Basic ' + new Buffer(`${ username }:${ password }`).toString('base64') } - catch (error) { - reject(error); - } - }); - }); + } + }; + + const commits = await _requestPagedResponse(options, response => response.data.next); + + return commits.reduce((acc, value) => acc.concat(value.values), []).map(BitBucketCommit); } }; } @@ -112,39 +103,30 @@ function GitHubCommits(auth) { return { isAuthorized: auth.isCredsTokenInitialized, authorize: auth.storeCreds, - getCommitsByRepo(repository, owner) { - return new Promise((resolve, reject) => { - async(function* () { - try { - const { username, password } = yield auth.getCreds(); - - const options = { - url: config.commits_url.replace('{owner}', owner).replace('{repo}', repository), - config: { - headers: { - 'User-Agent': owner, - Authorization: 'Basic ' + new Buffer(`${ username }:${ password }`).toString('base64') - } - } - }; - - const branches = yield requestPromise(config.branches_url.replace('{owner}', owner).replace('{repo}', repository), options.config); - const branch_commit_results = yield Promise.all(branches.data.map(branch => { - return _requestPagedResponse(Object.assign({}, options, { - url: `${ options.url }?sha=${ branch.name }` - }), nextPageFunc); - })); - - const github_commits = branch_commit_results.reduce((acc, list) => acc.concat(list), []); - const unique_commits = uniq(github_commits, item => item.sha); - - resolve(unique_commits.map(GitHubCommit)); - } - catch (error) { - reject(error); + getCommitsByRepo: async function(repository, owner) { + const { username, password } = await auth.getCreds(); + + const options = { + url: config.commits_url.replace('{owner}', owner).replace('{repo}', repository), + config: { + headers: { + 'User-Agent': owner, + Authorization: 'Basic ' + new Buffer(`${ username }:${ password }`).toString('base64') } - }); - }); + } + }; + + const branches = await requestPromise(config.branches_url.replace('{owner}', owner).replace('{repo}', repository), options.config); + const branch_commit_results = await Promise.all(branches.data.map(branch => { + return _requestPagedResponse(Object.assign({}, options, { + url: `${ options.url }?sha=${ branch.name }` + }), nextPageFunc); + })); + + const github_commits = branch_commit_results.reduce((acc, list) => acc.concat(list), []); + const unique_commits = uniq(github_commits, item => item.sha); + + return unique_commits.map(GitHubCommit); } }; } @@ -160,25 +142,16 @@ function GitHubCommit(value) { // PRIVATE -function _requestPagedResponse(options, next_page_func, values = []) { - return new Promise((resolve, reject) => { - async(function* () { - try { - const { url, config } = options; - const response = yield requestPromise(url, config); - const chunked_values = values.concat(response.data); +async function _requestPagedResponse(options, next_page_func, values = []) { + const { url, config } = options; + const response = await requestPromise(url, config); + const chunked_values = values.concat(response.data); - const next_page_url = next_page_func(response); + const next_page_url = next_page_func(response); - if (next_page_url) { - resolve(_requestPagedResponse({ url: next_page_url, config }, next_page_func, chunked_values)); - } + if (next_page_url) { + return _requestPagedResponse({ url: next_page_url, config }, next_page_func, chunked_values); + } - resolve(chunked_values); - } - catch (error) { - reject(error); - } - }); - }); + return chunked_values; } diff --git a/main/modules/dashboard.js b/main/modules/dashboard.js index d8ad692..33865a9 100644 --- a/main/modules/dashboard.js +++ b/main/modules/dashboard.js @@ -2,7 +2,6 @@ import { screen } from 'blessed'; import { grid, markdown, log, line } from 'blessed-contrib'; import moment from 'moment'; -import { async } from './helpers'; import { Velocity } from './velocity'; // SETTINGS @@ -43,72 +42,61 @@ export default function CommitsDashboard() { let layout; return { - render(format, commits) { - return new Promise((resolve, reject) => { - async(function* () { - try { - // INIT - if (!dashboard) { - dashboard = _initScreen(); - layout = _initLayout(dashboard); - } - - const velocity = Velocity(format); - const grouped_commits = yield velocity.groupCommitsByFormat(commits); - - // INFO - - const info_content_formatted = info_content - .replace('{{format}}', format) - .replace('{{current_commits}}', grouped_commits.current.length) - .replace('{{previous_commits}}', grouped_commits.previous.length); - - // LISTING - - const commit_messages = commits - .slice(0, commits.length < 30 ? commits.length : 30) - .map(commit => `(${ moment(commit.date).format('MMM Do') }) ${ commit.author }: ${ commit.message }`) - .reverse(); - - // VELOCITY - - const previous_daily_commits = yield velocity.groupCommitsByDay(grouped_commits.previous); - const previous_days = Object.keys(previous_daily_commits); - - const previous_commits = { - title: 'Previous', - x: previous_days, - y: previous_days.map(day => previous_daily_commits[day].length), - style: { - line: 'red' - } - }; - - const current_daily_commits = yield velocity.groupCommitsByDay(grouped_commits.current); - const current_days = Object.keys(current_daily_commits); - - const current_commits = { - title: 'Current', - x: current_days, - y: current_days.map(day => current_daily_commits[day].length), - style: { - line: 'green' - } - }; - - // LAYOUT - - layout.info.setMarkdown(info_content_formatted); - layout.velocity.setData([ previous_commits, current_commits ]); - commit_messages.forEach(message => layout.listing.log(message)); - - resolve(); - } - catch (error) { - reject(error); - } - }); - }); + render: async function(format, commits) { + // INIT + + if (!dashboard) { + dashboard = _initScreen(); + layout = _initLayout(dashboard); + } + + const velocity = Velocity(format); + const grouped_commits = await velocity.groupCommitsByFormat(commits); + + // INFO + + const info_content_formatted = info_content + .replace('{{format}}', format) + .replace('{{current_commits}}', grouped_commits.current.length) + .replace('{{previous_commits}}', grouped_commits.previous.length); + + // LISTING + + const commit_messages = [ ...grouped_commits.current, ...grouped_commits.previous ] + .map(commit => `(${ moment(commit.date).format('MMM Do') }) ${ commit.author }: ${ commit.message }`) + .reverse(); + + // VELOCITY + + const previous_daily_commits = await velocity.groupCommitsByDay(grouped_commits.previous); + const previous_days = Object.keys(previous_daily_commits); + + const previous_commits = { + title: 'Previous', + x: previous_days, + y: previous_days.map(day => previous_daily_commits[day].length), + style: { + line: 'red' + } + }; + + const current_daily_commits = await velocity.groupCommitsByDay(grouped_commits.current); + const current_days = Object.keys(current_daily_commits); + + const current_commits = { + title: 'Current', + x: current_days, + y: current_days.map(day => current_daily_commits[day].length), + style: { + line: 'green' + } + }; + + // LAYOUT + + layout.info.setMarkdown(info_content_formatted); + layout.velocity.setData([ previous_commits, current_commits ]); + commit_messages.forEach(message => layout.listing.log(message)); } }; } diff --git a/main/modules/helpers.js b/main/modules/helpers.js index 37135fa..ab1545a 100644 --- a/main/modules/helpers.js +++ b/main/modules/helpers.js @@ -71,25 +71,12 @@ export function requestPromise(url, config) { // SOURCE: https://gist.github.com/ibarsi/856a0c46e37fb4c951b033995aec55d5 export function partial(func, ...args) { - return (...inner_args) => func(...args, ...inner_args); -} - -// SOURCE: https://gist.github.com/ChrisChares/1ed079b9a6c9877ba4b43424139b166d -export function async(gen, context = undefined) { - const generator = typeof gen === 'function' ? gen() : gen; - const { value: promise } = generator.next(context); - - if ( typeof promise !== 'undefined' ) { - promise - .then(resolved => async(generator, resolved)) - .catch(error => generator.throw(error)); - } + return func.bind(undefined, ...args); } export default { isFile, uniq, wrapSpinner, - partial, - async + partial }; diff --git a/main/modules/velocity.js b/main/modules/velocity.js index 0888403..9356667 100644 --- a/main/modules/velocity.js +++ b/main/modules/velocity.js @@ -4,8 +4,6 @@ import moment from 'moment'; -import { partial } from './helpers'; - // PUBLIC export const FORMATS = { @@ -14,33 +12,10 @@ export const FORMATS = { }; export function Velocity(format) { - return { - groupCommitsByFormat: partial(_groupCommitsByFormat, format), - groupCommitsByDay: partial(_groupCommitsByDay, format) - }; -} - -export default { - FORMATS, - Velocity -}; - -// PRIVATE + const time = _getFormatTimeValue(format); -function _groupCommitsByFormat(format, commits) { - switch (format) { - case FORMATS.WEEK: - return _groupCommitsByTime('week', commits); - case FORMATS.MONTH: - return _groupCommitsByTime('month', commits); - default: - return undefined; - } -} - -function _groupCommitsByTime(time, commits) { - return new Promise((resolve, reject) => { - try { + return { + groupCommitsByFormat: async function (commits) { const now = moment(); const start_of_time = moment(now).startOf(time).hours(0); const start_of_last_time = moment(start_of_time).subtract(1, `${ time }s`); @@ -48,46 +23,49 @@ function _groupCommitsByTime(time, commits) { const commits_this_time = commits.filter(commit => start_of_time.isBefore(commit.date) && now.isAfter(commit.date)); const commits_last_time = commits.filter(commit => start_of_last_time.isBefore(commit.date) && start_of_time.isAfter(commit.date)); - resolve({ + return { current: commits_this_time, previous: commits_last_time - }); - } - catch (error) { - reject(error); - } - }); -} - -function _groupCommitsByDay(format, commits) { - return new Promise((resolve, reject) => { - try { + }; + }, + groupCommitsByDay: async function (commits) { const days_of_week = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ]; const days_of_month = [ ...Array(31).keys() ].map(i => ++i); switch (format) { case FORMATS.WEEK: - resolve(days_of_week.reduce((group, day) => { + return days_of_week.reduce((group, day) => { group[day] = commits.filter(commit => moment(commit.date).format('ddd') === day); return group; - }, {})); - - break; + }, {}); case FORMATS.MONTH: - resolve(days_of_month.reduce((group, day) => { + return days_of_month.reduce((group, day) => { group[day] = commits.filter(commit => moment(commit.date).date() === day); return group; - }, {})); - - break; + }, {}); default: - resolve({}); + return {}; } } - catch (error) { - reject(error); - } - }); + }; +} + +export default { + FORMATS, + Velocity +}; + +// PRIVATE + +function _getFormatTimeValue(format) { + switch (format) { + case FORMATS.WEEK: + return 'week'; + case FORMATS.MONTH: + return 'month'; + default: + return undefined; + } } diff --git a/package.json b/package.json index 3bc07ac..0ba7b99 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ }, "dependencies": { "async": "2.1.4", - "babel-polyfill": "6.22.0", + "babel-runtime": "6.23.0", "blessed": "0.1.81", "blessed-contrib": "4.7.5", "chalk": "1.1.3", @@ -45,7 +45,11 @@ "devDependencies": { "babel-cli": "6.9.0", "babel-core": "6.9.0", + "babel-plugin-transform-runtime": "6.23.0", "babel-preset-es2015": "6.9.0", + "babel-preset-es2016": "6.22.0", + "babel-preset-es2017": "6.22.0", + "babel-regenerator-runtime": "6.5.0", "chai": "3.5.0", "commitizen": "2.9.5", "cz-conventional-changelog": "1.2.0",