mirror of
https://github.com/all-contributors/cli.git
synced 2025-01-09 13:36:29 +00:00
Adding contributors to config file
This commit is contained in:
parent
f2c8733e03
commit
ff7457c825
7 changed files with 281 additions and 15 deletions
28
cli.js
28
cli.js
|
@ -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
28
lib/configFile.js
Normal 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
57
lib/contributors/add.js
Normal 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);
|
||||
}
|
161
lib/contributors/add.test.js
Normal file
161
lib/contributors/add.test.js
Normal 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();
|
||||
});
|
||||
});
|
|
@ -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
16
lib/contributors/index.js
Normal 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);
|
||||
});
|
||||
});
|
||||
};
|
|
@ -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",
|
||||
|
|
Loading…
Reference in a new issue