Skip to content

Commit

Permalink
fix: Bump inquirer to v3 and promisify everything (#34)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Drop support for Node < v4. This uses native Promises available from Node v4.

* fix: Bump inquirer to v3.0.1. Fixes #33 to improve Windows support.

* refactor: Promisify everything as inquirer uses Promises from 1.0.0 onwards
  • Loading branch information
jfmengels committed Feb 15, 2017
1 parent 1e73194 commit 1305a7c
Show file tree
Hide file tree
Showing 14 changed files with 164 additions and 193 deletions.
73 changes: 36 additions & 37 deletions cli.js
Expand Up @@ -39,39 +39,31 @@ var argv = yargs
})
.argv;

function startGeneration(argv, cb) {
argv.files
.map(function (file) {
return path.join(cwd, file);
})
.forEach(function (file) {
util.markdown.read(file, function (error, fileContent) {
if (error) {
return cb(error);
}
function startGeneration(argv) {
return Promise.all(
argv.files.map(file => {
const filePath = path.join(cwd, file);
return util.markdown.read(filePath)
.then(fileContent => {
var newFileContent = generate(argv, argv.contributors, fileContent);
util.markdown.write(file, newFileContent, cb);
return util.markdown.write(filePath, newFileContent);
});
});
})
);
}

function addContribution(argv, cb) {
function addContribution(argv) {
var username = argv._[1];
var contributions = argv._[2];
// Add or update contributor in the config file
updateContributors(argv, username, contributions, function (error, data) {
if (error) {
return onError(error);
}
return updateContributors(argv, username, contributions)
.then(data => {
argv.contributors = data.contributors;
startGeneration(argv, function (error) {
if (error) {
return cb(error);
}
if (!argv.commit) {
return cb();
return startGeneration(argv)
.then(() => {
if (argv.commit) {
return util.git.commit(argv, data);
}
return util.git.commit(argv, data, cb);
});
});
}
Expand All @@ -81,10 +73,10 @@ function onError(error) {
console.error(error.message);
process.exit(1);
}
process.exit();
process.exit(0);
}

function promptForCommand(argv, cb) {
function promptForCommand(argv) {
var questions = [{
type: 'list',
name: 'command',
Expand All @@ -99,17 +91,24 @@ function promptForCommand(argv, cb) {
when: !argv._[0],
default: 0
}];
inquirer.prompt(questions, function treatAnswers(answers) {
return cb(answers.command || argv._[0]);

return inquirer.prompt(questions)
.then(answers => {
return answers.command || argv._[0];
});
}

promptForCommand(argv, function (command) {
if (command === 'init') {
init(onError);
} else if (command === 'generate') {
startGeneration(argv, onError);
} else if (command === 'add') {
addContribution(argv, onError);
}
});
promptForCommand(argv)
.then(command => {
switch (command) {
case 'init':
return init();
case 'generate':
return startGeneration(argv);
case 'add':
return addContribution(argv);
default:
throw new Error(`Unknown command ${command}`);
}
})
.catch(onError);
16 changes: 7 additions & 9 deletions lib/contributors/add.js
Expand Up @@ -30,21 +30,19 @@ function updateExistingContributor(options, username, contributions) {
});
}

function addNewContributor(options, username, contributions, infoFetcher, cb) {
infoFetcher(username, function (error, userData) {
if (error) {
return cb(error);
}
function addNewContributor(options, username, contributions, infoFetcher) {
return infoFetcher(username)
.then(userData => {
var contributor = _.assign(userData, {
contributions: formatContributions(options, [], contributions)
});
return cb(null, options.contributors.concat(contributor));
return options.contributors.concat(contributor);
});
}

module.exports = function addContributor(options, username, contributions, infoFetcher, cb) {
module.exports = function addContributor(options, username, contributions, infoFetcher) {
if (_.find({login: username}, options.contributors)) {
return cb(null, updateExistingContributor(options, username, contributions));
return Promise.resolve(updateExistingContributor(options, username, contributions));
}
return addNewContributor(options, username, contributions, infoFetcher, cb);
return addNewContributor(options, username, contributions, infoFetcher);
};
53 changes: 24 additions & 29 deletions lib/contributors/add.test.js
@@ -1,8 +1,8 @@
import test from 'ava';
import addContributor from './add';

function mockInfoFetcher(username, cb) {
return cb(null, {
function mockInfoFetcher(username) {
return Promise.resolve({
login: username,
name: 'Some name',
avatar_url: 'www.avatar.url',
Expand Down Expand Up @@ -34,27 +34,27 @@ function fixtures() {
return {options};
}

test.cb('should callback with error if infoFetcher fails', t => {
test('should callback with error if infoFetcher fails', t => {
const {options} = fixtures();
const username = 'login3';
const contributions = ['doc'];
function infoFetcher(username, cb) {
return cb(new Error('infoFetcher error'));
function infoFetcher() {
return Promise.reject(new Error('infoFetcher error'));
}

return addContributor(options, username, contributions, infoFetcher, function (error) {
t.is(error.message, 'infoFetcher error');
t.end();
});
return t.throws(
addContributor(options, username, contributions, infoFetcher),
'infoFetcher error'
);
});

test.cb('should add new contributor at the end of the list of contributors', t => {
test('should add new contributor at the end of the list of contributors', t => {
const {options} = fixtures();
const username = 'login3';
const contributions = ['doc'];

return addContributor(options, username, contributions, mockInfoFetcher, function (error, contributors) {
t.falsy(error);
return addContributor(options, username, contributions, mockInfoFetcher)
.then(contributors => {
t.is(contributors.length, 3);
t.deepEqual(contributors[2], {
login: 'login3',
Expand All @@ -65,18 +65,17 @@ test.cb('should add new contributor at the end of the list of contributors', t =
'doc'
]
});
t.end();
});
});

test.cb('should add new contributor at the end of the list of contributors with a url link', t => {
test('should add new contributor at the end of the list of contributors with a url link', t => {
const {options} = fixtures();
const username = 'login3';
const contributions = ['doc'];
options.url = 'www.foo.bar';

return addContributor(options, username, contributions, mockInfoFetcher, function (error, contributors) {
t.falsy(error);
return addContributor(options, username, contributions, mockInfoFetcher)
.then(contributors => {
t.is(contributors.length, 3);
t.deepEqual(contributors[2], {
login: 'login3',
Expand All @@ -87,28 +86,26 @@ test.cb('should add new contributor at the end of the list of contributors with
{type: 'doc', url: 'www.foo.bar'}
]
});
t.end();
});
});

test.cb(`should not update an existing contributor's contributions where nothing has changed`, t => {
test(`should not update an existing contributor's contributions where nothing has changed`, t => {
const {options} = fixtures();
const username = 'login2';
const contributions = ['blog', 'code'];

return addContributor(options, username, contributions, mockInfoFetcher, function (error, contributors) {
t.falsy(error);
return addContributor(options, username, contributions, mockInfoFetcher)
.then(contributors => {
t.deepEqual(contributors, options.contributors);
t.end();
});
});

test.cb(`should update an existing contributor's contributions if a new type is added`, t => {
test(`should update an existing contributor's contributions if a new type is added`, t => {
const {options} = fixtures();
const username = 'login1';
const contributions = ['bug'];
return addContributor(options, username, contributions, mockInfoFetcher, function (error, contributors) {
t.falsy(error);
return addContributor(options, username, contributions, mockInfoFetcher)
.then(contributors => {
t.is(contributors.length, 2);
t.deepEqual(contributors[0], {
login: 'login1',
Expand All @@ -120,18 +117,17 @@ test.cb(`should update an existing contributor's contributions if a new type is
'bug'
]
});
t.end();
});
});

test.cb(`should update an existing contributor's contributions if a new type is added with a link`, t => {
test(`should update an existing contributor's contributions if a new type is added with a link`, t => {
const {options} = fixtures();
const username = 'login1';
const contributions = ['bug'];
options.url = 'www.foo.bar';

return addContributor(options, username, contributions, mockInfoFetcher, function (error, contributors) {
t.falsy(error);
return addContributor(options, username, contributions, mockInfoFetcher)
.then(contributors => {
t.is(contributors.length, 2);
t.deepEqual(contributors[0], {
login: 'login1',
Expand All @@ -143,6 +139,5 @@ test.cb(`should update an existing contributor's contributions if a new type is
{type: 'bug', url: 'www.foo.bar'}
]
});
t.end();
});
});
16 changes: 7 additions & 9 deletions lib/contributors/github.js
@@ -1,24 +1,22 @@
'use strict';

var request = require('request');
var pify = require('pify');
var request = pify(require('request'));

module.exports = function getUserInfo(username, cb) {
request.get({
module.exports = function getUserInfo(username) {
return request.get({
url: 'https://api.github.com/users/' + username,
headers: {
'User-Agent': 'request'
}
}, function (error, res) {
if (error) {
return cb(error);
}
})
.then(res => {
var body = JSON.parse(res.body);
var user = {
return {
login: body.login,
name: body.name || username,
avatar_url: body.avatar_url,
profile: body.blog || body.html_url
};
return cb(null, user);
});
};
21 changes: 8 additions & 13 deletions lib/contributors/github.test.js
Expand Up @@ -2,18 +2,15 @@ import test from 'ava';
import nock from 'nock';
import getUserInfo from './github';

test.cb('should handle errors', t => {
test('should handle errors', t => {
nock('https://api.github.com')
.get('/users/nodisplayname')
.replyWithError(404);

getUserInfo('nodisplayname', err => {
t.truthy(err);
t.end();
});
return t.throws(getUserInfo('nodisplayname'));
});

test.cb('should fill in the name when null is returned', t => {
test('should fill in the name when null is returned', t => {
nock('https://api.github.com')
.get('/users/nodisplayname')
.reply(200, {
Expand All @@ -23,14 +20,13 @@ test.cb('should fill in the name when null is returned', t => {
html_url: 'https://github.com/nodisplayname'
});

getUserInfo('nodisplayname', (err, info) => {
t.falsy(err);
return getUserInfo('nodisplayname')
.then(info => {
t.is(info.name, 'nodisplayname');
t.end();
});
});

test.cb('should fill in the name when an empty string is returned', t => {
test('should fill in the name when an empty string is returned', t => {
nock('https://api.github.com')
.get('/users/nodisplayname')
.reply(200, {
Expand All @@ -40,9 +36,8 @@ test.cb('should fill in the name when an empty string is returned', t => {
html_url: 'https://github.com/nodisplayname'
});

getUserInfo('nodisplayname', (err, info) => {
t.falsy(err);
return getUserInfo('nodisplayname')
.then(info => {
t.is(info.name, 'nodisplayname');
t.end();
});
});
34 changes: 19 additions & 15 deletions lib/contributors/index.js
Expand Up @@ -10,20 +10,24 @@ function isNewContributor(contributorList, username) {
return !_.find({login: username}, contributorList);
}

module.exports = function addContributor(options, username, contributions, cb) {
prompt(options, username, contributions, function (answers) {
add(options, answers.username, answers.contributions, github, function (error, contributors) {
if (error) {
return cb(error);
}
util.configFile.writeContributors(options.config, contributors, function (error) {
return cb(error, {
username: answers.username,
contributions: answers.contributions,
contributors: contributors,
newContributor: isNewContributor(options.contributors, answers.username)
});
});
});
module.exports = function addContributor(options, username, contributions) {
const answersP = prompt(options, username, contributions);
const contributorsP = answersP
.then(answers => add(options, answers.username, answers.contributions, github));

const writeContributorsP = contributorsP.then(
contributors => util.configFile.writeContributors(options.config, contributors)
);

return Promise.all([answersP, contributorsP, writeContributorsP])
.then(res => {
const answers = res[0];
const contributors = res[1];
return {
username: answers.username,
contributions: answers.contributions,
contributors: contributors,
newContributor: isNewContributor(options.contributors, answers.username)
};
});
};

0 comments on commit 1305a7c

Please sign in to comment.