Adding contributors to config file

This commit is contained in:
Jeroen Engels 2016-03-02 23:45:23 +01:00
parent f2c8733e03
commit ff7457c825
7 changed files with 281 additions and 15 deletions

28
cli.js
View file

@ -7,20 +7,23 @@ var assign = require('lodash.assign');
var generate = require('./lib/generate');
var markdown = require('./lib/markdown');
var getUserInfo = require('./lib/github');
var updateContributors = require('./lib/contributors');
var cwd = process.cwd();
var defaultRCFile = path.join(cwd, '.all-contributorsrc');
var argv = require('yargs')
.help('help')
.alias('h', 'help')
.command('generate', 'Generate the list of contributors')
.usage('Usage: $0 generate')
.command('add', 'add a new contributor')
.usage('Usage: $0 add <username> <contribution>')
.demand(2)
.default('config', defaultRCFile)
.default('file', 'README.md')
.default('contributorsPerLine', 7)
.default('contributors', [])
.default('config', defaultRCFile)
.config('config', function(configPath) {
try {
return JSON.parse(fs.readFileSync(configPath, 'utf-8'));
@ -31,7 +34,6 @@ var argv = require('yargs')
}
}
})
.help('help')
.argv;
argv.file = path.join(cwd, argv.file);
@ -52,19 +54,19 @@ function onError(error) {
}
}
if (argv[0] === 'generate') {
var command = argv._[0];
if (command === 'generate') {
startGeneration(argv, onError);
} else if (argv[0] === 'add') {
// Fetch user
argv.username = argv._[1];
argv.contributions = argv._[2].split(',');
getUserInfo(argv.username, function(error, user) {
} else if (command === 'add') {
var username = argv._[1];
var contributions = argv._[2];
// Add/update contributor and save him to the config file
updateContributors(argv, username, contributions, function(error, contributors) {
if (error) {
return console.error(error);
return onError(error);
}
// TODO
// Add him to the contributors
// Save rc file with updated contributors key
argv.contributors = contributors;
startGeneration(argv, onError);
});
}

28
lib/configFile.js Normal file
View file

@ -0,0 +1,28 @@
'use strict';
var fs = require('fs');
var _ = require('lodash/fp');
function formatCommaFirst(o) {
return JSON.stringify(o, null, 2)
.split(/(,\n\s+)/)
.map(function (e, i) {
return i%2 ? '\n'+e.substring(4)+', ' : e
})
.join('');
}
function readConfig(configPath) {
return JSON.parse(fs.readFileSync(configPath, 'utf-8'));
}
function writeContributors(configPath, contributors, cb) {
var config = readConfig(configPath);
var content = _.assign(config, { contributors: contributors });
return fs.writeFile(configPath, formatCommaFirst(content), cb);
}
module.exports = {
readConfig: readConfig,
writeContributors: writeContributors
}

57
lib/contributors/add.js Normal file
View file

@ -0,0 +1,57 @@
'use strict';
var _ = require('lodash/fp');
function matchContribution(type) {
return function(existing) {
return type === existing || type === existing.type;
};
}
function uniqueTypes(contribution) {
return contribution.type || contribution;
}
function formatContributions(options, existing, newTypes) {
var types = newTypes.split(',');
if (options.url) {
return (existing || []).concat(types.map(function(type) {
return { type: type, url: options.url };
}));
}
return _.uniqBy(uniqueTypes, (existing || []).concat(types));
}
function updateContributor(options, contributor, contributions) {
return _.assign(contributor, {
contributions: formatContributions(options, contributor.contributions, contributions)
});
}
function updateExistingContributor(options, username, contributions) {
return options.contributors.map(function(contributor, index) {
if (username !== contributor.login) {
return contributor;
}
return updateContributor(options, contributor, contributions);
});
}
function addNewContributor(options, username, contributions, infoFetcher, cb) {
infoFetcher(username, function(error, userData) {
if (error) {
return cb(error);
}
var contributor = _.assign(userData, {
contributions: formatContributions(options, [], contributions)
});
return cb(null, options.contributors.concat(contributor));
});
}
module.exports = function addContributor(options, username, contributions, infoFetcher, cb) {
if (_.find({login: username}, options.contributors)) {
return cb(null, updateExistingContributor(options, username, contributions));
}
return addNewContributor(options, username, contributions, infoFetcher, cb);
}

View file

@ -0,0 +1,161 @@
import test from 'ava';
import addContributor from './add';
function mockInfoFetcher(username, cb) {
return cb(null, {
login: username,
name: 'Some name',
avatar_url: 'www.avatar.url',
html_url: 'www.html.url'
});
}
function fixtures() {
const options = {
contributors: [{
login: 'login1',
name: 'Some name',
avatar_url: 'www.avatar.url',
html_url: 'www.html.url',
contributions: [
'code'
]
}, {
login: 'login2',
name: 'Some name',
avatar_url: 'www.avatar.url',
html_url: 'www.html.url',
contributions: [
{ type: 'blog', url: 'www.blog.url/path' },
'code'
]
}]
};
return {options};
}
test.cb('should callback with error if infoFetcher fails', t => {
t.plan(1);
const {options} = fixtures();
const username = 'login3';
const contributions = ['doc'];
function infoFetcher(username, cb) {
return cb(new Error('infoFetcher error'));
}
return addContributor(options, username, contributions, infoFetcher, function(error) {
t.is(error.message, 'infoFetcher error');
t.end();
});
});
test.cb('should add new contributor at the end of the list of contributors', t => {
t.plan(3);
const {options} = fixtures();
const username = 'login3';
const contributions = 'doc';
return addContributor(options, username, contributions, mockInfoFetcher, function(error, contributors) {
t.notOk(error);
t.is(contributors.length, 3);
t.same(contributors[2], {
login: 'login3',
name: 'Some name',
avatar_url: 'www.avatar.url',
html_url: 'www.html.url',
contributions: [
'doc'
]
});
t.end();
});
});
test.cb('should add new contributor at the end of the list of contributors with a url link', t => {
t.plan(3);
const {options} = fixtures();
const username = 'login3';
const contributions = 'doc';
options.url = 'www.foo.bar';
return addContributor(options, username, contributions, mockInfoFetcher, function(error, contributors) {
t.notOk(error);
t.is(contributors.length, 3);
t.same(contributors[2], {
login: 'login3',
name: 'Some name',
avatar_url: 'www.avatar.url',
html_url: 'www.html.url',
contributions: [
{ type: 'doc', url: 'www.foo.bar' }
]
});
t.end();
});
});
test.cb(`should not update an existing contributor's contributions where nothing has changed`, t => {
t.plan(2);
const {options} = fixtures();
const username = 'login2';
const contributions = 'blog,code';
return addContributor(options, username, contributions, mockInfoFetcher, function(error, contributors) {
t.notOk(error);
t.same(contributors, options.contributors);
t.end();
});
});
test.cb(`should update an existing contributor's contributions if a new type is added`, t => {
t.plan(3);
const {options} = fixtures();
const username = 'login1';
const contributions = 'bug';
return addContributor(options, username, contributions, mockInfoFetcher, function(error, contributors) {
t.notOk(error);
t.is(contributors.length, 2);
t.same(contributors[0], {
login: 'login1',
name: 'Some name',
avatar_url: 'www.avatar.url',
html_url: 'www.html.url',
contributions: [
'code',
'bug'
]
});
t.end();
});
});
test.cb(`should update an existing contributor's contributions if a new type is added with a link`, t => {
t.plan(3);
const {options} = fixtures();
const username = 'login1';
const contributions = 'bug';
options.url = 'www.foo.bar';
return addContributor(options, username, contributions, mockInfoFetcher, function(error, contributors) {
t.notOk(error);
t.is(contributors.length, 2);
t.same(contributors[0], {
login: 'login1',
name: 'Some name',
avatar_url: 'www.avatar.url',
html_url: 'www.html.url',
contributions: [
'code',
{ type: 'bug', url: 'www.foo.bar' },
]
});
t.end();
});
});

View file

@ -1,5 +1,6 @@
'use strict';
var _ = require('lodash/fp');
var request = require('request');
module.exports = function getUserInfo(username, cb) {
@ -12,6 +13,7 @@ module.exports = function getUserInfo(username, cb) {
if (error) {
return cb(error);
}
return cb(null, JSON.parse(res.body));
var user = JSON.parse(res.body);
return cb(null, _.pick(['login', 'name', 'avatar_url', 'html_url'], user));
});
}

16
lib/contributors/index.js Normal file
View file

@ -0,0 +1,16 @@
'use strict';
var add = require('./add');
var github = require('./github');
var configFile = require('../configFile');
module.exports = function addContributor(options, username, contributions, cb) {
add(options, username, contributions, github, function(error, contributors) {
if (error) {
return cb(error);
}
configFile.writeContributors(options.config, contributors, function(error) {
return cb(error, contributors);
});
});
};

View file

@ -24,7 +24,7 @@
},
"homepage": "https://github.com/jfmengels/all-contributors-cli#readme",
"dependencies": {
"lodash": "^4.5.1",
"lodash": "^4.6.1",
"lodash.assign": "^4.0.4",
"lodash.findindex": "^4.2.0",
"lodash.template": "^4.2.1",