mirror of
https://github.com/all-contributors/cli.git
synced 2025-01-09 13:36:29 +00:00
Modify contributor generation system
This commit is contained in:
parent
24a897019b
commit
f2c8733e03
14 changed files with 543 additions and 255 deletions
16
.all-contributorsrc
Normal file
16
.all-contributorsrc
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"projectOwner": "jfmengels",
|
||||
"projectName": "all-contributors-cli",
|
||||
"imageSize": 100,
|
||||
"contributors": [{
|
||||
"login": "jfmengels",
|
||||
"name": "Jeroen Engels",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/3869412?v=3",
|
||||
"html_url": "https://github.com/jfmengels",
|
||||
"contributions": [
|
||||
"code",
|
||||
"doc",
|
||||
"test"
|
||||
]
|
||||
}]
|
||||
}
|
55
README.md
55
README.md
|
@ -37,46 +37,55 @@ Where:
|
|||
|
||||
## Configuration
|
||||
|
||||
You can configure the project by creating a `.all-contributorsrc` JSON file.
|
||||
### Add contributing section
|
||||
|
||||
If you don't already have a Contributing section in a Markdown file, create one. Then add the following comment tags section to it. Don't worry, they're visible only to those that read the raw file. The tags **must** be at the beginning of the line.
|
||||
|
||||
```md
|
||||
## Contributing
|
||||
|
||||
<!-- CONTRIBUTORS:START - Do not remove or modify this section -->
|
||||
<!-- CONTRIBUTORS:END -->
|
||||
```
|
||||
|
||||
### Create a `.all-contributorsrc` file
|
||||
|
||||
You must create a `.all-contributorsrc` JSON file. The data used to generate the contributors list will be stored in here, and you can configure how you want `all-contributors-cli` to generate the list.
|
||||
|
||||
```json
|
||||
{
|
||||
"file": "README.md",
|
||||
"owner": "jfmengels",
|
||||
"emoji": {
|
||||
"cheerful": ":smiley:"
|
||||
}
|
||||
}
|
||||
```
|
||||
or creating a `all-contributors` updating the `package.json` file:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "all-contributors-cli",
|
||||
"...": "...",
|
||||
"all-contributors": {
|
||||
"file": "README.md",
|
||||
"owner": "jfmengels"
|
||||
}
|
||||
"types": {
|
||||
"cheerful": {
|
||||
"symbol": ":smiley:"
|
||||
}
|
||||
},
|
||||
"contributors": [{
|
||||
"login": "jfmengels",
|
||||
"...": "..."
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
These are the keys you can specify:
|
||||
- `emoji`: Specify custom emoji, can override the documented emojis. It doesn't really have to be emojis really.
|
||||
- `file`: File to write the list of contributors in. Default: 'README.md'
|
||||
- `projectOwner`: Name of the user the project is hosted by. Example: `jfmengels/all-contributor-cli` --> `jfmengels`. Mandatory.
|
||||
- `projectName`: Name of the project. Example: `jfmengels/all-contributor-cli` --> `all-contributor-cli`. Mandatory.
|
||||
- `types`: Specify custom symbols or link templates for contribution types. Can override the documented types.
|
||||
- `imageSize`: Size (in px) of the user's avatar. Default: 100.
|
||||
- `owner`: Name of the user the project is hosted by. Example: `jfmengels/all-contributor-cli` --> `jfmengels`. By default will be parsed from the repo's homepage in `package.json` (TODO).
|
||||
- `project`: Name of the project. Example: `jfmengels/all-contributor-cli` --> `all-contributor-cli`. Default: Name of the project written in the `package.json` file (TODO).
|
||||
- `template`: Define your own contributor template. Please read the code to see what you can define (**warning**: not sure it will work well after several tries).
|
||||
- `contributorsPerLine`: Maximum number of columns for the contributors table. Default: 7.
|
||||
- `template`: Define your own template to generate the contributor list.
|
||||
|
||||
|
||||
## Contributors
|
||||
|
||||
Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)):
|
||||
|
||||
Contributor | Contributions
|
||||
:---: | :---:
|
||||
[![Jeroen Engels](https://avatars.githubusercontent.com/u/3869412?v=3&s=100)<br />Jeroen Engels](https://github.com/jfmengels) | [💻📖⚠️](https://github.com/jfmengels/all-contributors-cli/commits?author=jfmengels)
|
||||
<!-- CONTRIBUTORS:START - Do not remove or modify this section -->
|
||||
| [![Jeroen Engels](https://avatars.githubusercontent.com/u/3869412?v=3&s=100)<br /><sub>Jeroen Engels</sub>](https://github.com/jfmengels)<br />[💻](https://github.com/jfmengels/all-contributors-cli/commits?author=jfmengels) [📖](https://github.com/jfmengels/all-contributors-cli/commits?author=jfmengels) [⚠️](https://github.com/jfmengels/all-contributors-cli/commits?author=jfmengels) |
|
||||
| :---: |
|
||||
<!-- CONTRIBUTORS:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification.
|
||||
Contributions of any kind welcome!
|
||||
|
|
46
cli.js
46
cli.js
|
@ -5,20 +5,22 @@ var fs = require('fs');
|
|||
var path = require('path');
|
||||
var assign = require('lodash.assign');
|
||||
|
||||
var generate = require('./lib/generate');
|
||||
var markdown = require('./lib/markdown');
|
||||
var getUserInfo = require('./lib/github');
|
||||
var defaultEmojis = require('./lib/emoji');
|
||||
var addContributor = require('./lib/addContributor');
|
||||
|
||||
var cwd = process.cwd();
|
||||
var defaultRCFile = path.join(cwd, '.all-contributorsrc');
|
||||
|
||||
var argv = require('yargs')
|
||||
.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)
|
||||
.config('config', function(configPath) {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
||||
|
@ -29,28 +31,40 @@ var argv = require('yargs')
|
|||
}
|
||||
}
|
||||
})
|
||||
.default('emoji', {})
|
||||
.pkgConf('all-contributors')
|
||||
.help('help')
|
||||
.argv;
|
||||
|
||||
argv.emoji = assign({}, defaultEmojis, argv.emoji);
|
||||
argv.username = argv._[1];
|
||||
argv.contributions = argv._[2].split(',');
|
||||
argv.file = path.join(cwd, argv.file);
|
||||
|
||||
getUserInfo(argv.username, function(error, user) {
|
||||
function startGeneration(argv, cb) {
|
||||
markdown.read(argv.file, function(error, fileContent) {
|
||||
if (error) {
|
||||
return cb(error);
|
||||
}
|
||||
var newFileContent = generate(argv, argv.contributors, fileContent);
|
||||
markdown.write(argv.file, newFileContent, cb);
|
||||
});
|
||||
}
|
||||
|
||||
function onError(error) {
|
||||
if (error) {
|
||||
return console.error(error);
|
||||
}
|
||||
markdown.read(argv.file, function(error, fileContent) {
|
||||
}
|
||||
|
||||
if (argv[0] === '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) {
|
||||
if (error) {
|
||||
return console.error(error);
|
||||
}
|
||||
var newFileContent = addContributor(argv, user, fileContent);
|
||||
markdown.write(argv.file, newFileContent, function(error, fileContent) {
|
||||
if (error) {
|
||||
return console.error(error);
|
||||
}
|
||||
});
|
||||
// TODO
|
||||
// Add him to the contributors
|
||||
// Save rc file with updated contributors key
|
||||
startGeneration(argv, onError);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var uniq = require('lodash.uniq');
|
||||
var values = require('lodash.values');
|
||||
var template = require('lodash.template');
|
||||
var findIndex = require('lodash.findindex');
|
||||
|
||||
function listAllContributors(start, lines) {
|
||||
var i = 0;
|
||||
while (start + i < lines.length && lines[start + i].indexOf('[![') === 0) {
|
||||
i++;
|
||||
}
|
||||
return lines.slice(start, start + i);
|
||||
}
|
||||
|
||||
var defaultTemplate =
|
||||
'[![<%= user.name %>](<%= user.avatar_url %>&s=<%= options.imageSize %>)' +
|
||||
'<br /><%= user.name %>](<%= user.html_url %>)' +
|
||||
' | [<%= contributions %>](https://github.com/<%= options.projectOwner %>/<%= options.projectName %>/commits?author=<%= user.login %>)';
|
||||
|
||||
function contributorEntry(options, user, existingContributions) {
|
||||
var contributions = uniq((existingContributions || []).concat(
|
||||
options.contributions
|
||||
.map(function(contribution) {
|
||||
return options.emoji[contribution];
|
||||
})
|
||||
)).join('');
|
||||
|
||||
var contributionTemplate = template(options.template || defaultTemplate);
|
||||
|
||||
return contributionTemplate({
|
||||
user: user,
|
||||
contributions: contributions,
|
||||
options: options
|
||||
});
|
||||
}
|
||||
|
||||
function parseContributionTypes(options, line) {
|
||||
return values(options.emoji)
|
||||
.filter(function findExistingContribution(type) {
|
||||
return line.indexOf(type) !== -1;
|
||||
});
|
||||
}
|
||||
|
||||
function upsertContributor(options, user, existingContributors) {
|
||||
var contributor = contributorEntry(options, user);
|
||||
var existingContributorIndex = findIndex(existingContributors, function(cont) {
|
||||
return cont.indexOf(user.login) !== 1 && cont.indexOf(user.name) !== -1;
|
||||
});
|
||||
|
||||
if (existingContributorIndex === -1) {
|
||||
return [].concat(existingContributors, contributor);
|
||||
}
|
||||
|
||||
var contributionTypes = parseContributionTypes(options, existingContributors[existingContributorIndex]);
|
||||
return [].concat(
|
||||
existingContributors.slice(0, existingContributorIndex),
|
||||
contributorEntry(options, user, contributionTypes),
|
||||
existingContributors.slice(existingContributorIndex + 1)
|
||||
).join('\n')
|
||||
}
|
||||
|
||||
module.exports = function addContributor(options, user, fileContent) {
|
||||
var lines = fileContent.split('\n');
|
||||
var contributorListStart = findIndex(lines, function(line) {
|
||||
return line.indexOf(':---: | :---:') !== -1;
|
||||
});
|
||||
|
||||
var existingContributors = listAllContributors(contributorListStart + 1, lines);
|
||||
var contributors = upsertContributor(options, user, existingContributors);
|
||||
|
||||
return [].concat(
|
||||
lines.slice(0, contributorListStart + 1),
|
||||
contributors,
|
||||
lines.slice(contributorListStart + existingContributors.length + 1)
|
||||
).join('\n')
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
import test from 'ava';
|
||||
import addContributor from './addContributor';
|
||||
|
||||
function getUserLine(content, {login}) {
|
||||
return content
|
||||
.split('\n')
|
||||
.filter(line => line.indexOf(login) !== -1)
|
||||
[0];
|
||||
}
|
||||
|
||||
function fixtures() {
|
||||
const options = {
|
||||
projectOwner: 'kentcdodds',
|
||||
projectName: 'all-contributors',
|
||||
imageSize: 100,
|
||||
contributions: ['doc'],
|
||||
emoji: {
|
||||
code: ':code:',
|
||||
doc: ':doc:',
|
||||
test: ':test:'
|
||||
}
|
||||
};
|
||||
|
||||
const jfmengelsUser = {
|
||||
login: 'jfmengels',
|
||||
name: 'Jeroen Engels',
|
||||
html_url: 'https://github.com/jfmengels',
|
||||
avatar_url: 'https://avatars.githubusercontent.com/u/3869412?v=3'
|
||||
};
|
||||
|
||||
const kentcdoddsUser = {
|
||||
login: 'kentcdodds',
|
||||
name: 'Kent C. Dodds',
|
||||
html_url: 'https://github.com/kentcdodds',
|
||||
avatar_url: 'https://avatars.githubusercontent.com/u/1500684?v=3'
|
||||
};
|
||||
|
||||
const content = `
|
||||
# project
|
||||
|
||||
Description
|
||||
|
||||
## Contributors
|
||||
These people contributed to the project:
|
||||
:---: | :---:
|
||||
[![Kent C. Dodds](https://avatars.githubusercontent.com/u/1500684?v=3&s=100)<br />Kent C. Dodds](https://github.com/kentcdodds) | [:doc:](https://github.com/kentcdodds/all-contributors/commits?author=kentcdodds)
|
||||
[![Divjot Singh](https://avatars1.githubusercontent.com/u/6177621?s=130)<br />Divjot Singh](http://bogas04.github.io) | [:doc:](https://github.com/kentcdodds/all-contributors/commits?author=bogas04)
|
||||
|
||||
Thanks a lot guys!
|
||||
`;
|
||||
|
||||
return {options, jfmengelsUser, kentcdoddsUser, content};
|
||||
}
|
||||
|
||||
test('should add a new contributor to the end of the list', t => {
|
||||
t.pass(1);
|
||||
const {options, jfmengelsUser, content} = fixtures();
|
||||
const expected = `
|
||||
# project
|
||||
|
||||
Description
|
||||
|
||||
## Contributors
|
||||
These people contributed to the project:
|
||||
:---: | :---:
|
||||
[![Kent C. Dodds](https://avatars.githubusercontent.com/u/1500684?v=3&s=100)<br />Kent C. Dodds](https://github.com/kentcdodds) | [:doc:](https://github.com/kentcdodds/all-contributors/commits?author=kentcdodds)
|
||||
[![Divjot Singh](https://avatars1.githubusercontent.com/u/6177621?s=130)<br />Divjot Singh](http://bogas04.github.io) | [:doc:](https://github.com/kentcdodds/all-contributors/commits?author=bogas04)
|
||||
[![Jeroen Engels](https://avatars.githubusercontent.com/u/3869412?v=3&s=100)<br />Jeroen Engels](https://github.com/jfmengels) | [:doc:](https://github.com/kentcdodds/all-contributors/commits?author=jfmengels)
|
||||
|
||||
Thanks a lot guys!
|
||||
`;
|
||||
|
||||
t.is(addContributor(options, jfmengelsUser, content), expected);
|
||||
});
|
||||
|
||||
test('should be able to inject several contributions', t => {
|
||||
t.pass(1);
|
||||
const {options, jfmengelsUser, content} = fixtures();
|
||||
options.contributions = ['doc', 'code'];
|
||||
const expected = '[![Jeroen Engels](https://avatars.githubusercontent.com/u/3869412?v=3&s=100)<br />Jeroen Engels](https://github.com/jfmengels) | [:doc::code:](https://github.com/kentcdodds/all-contributors/commits?author=jfmengels)';
|
||||
|
||||
const result = addContributor(options, jfmengelsUser, content);
|
||||
|
||||
t.is(getUserLine(result, jfmengelsUser), expected);
|
||||
});
|
||||
|
||||
test('should be able to specify a new template in options', t => {
|
||||
t.pass(1);
|
||||
const {options, jfmengelsUser, content} = fixtures();
|
||||
options.template = '<%= user.login %> made awesome contributions!';
|
||||
const expected = 'jfmengels made awesome contributions!';
|
||||
|
||||
const result = addContributor(options, jfmengelsUser, content);
|
||||
|
||||
t.is(getUserLine(result, jfmengelsUser), expected);
|
||||
});
|
||||
|
||||
test('should not modify content when adding an existing contributor that has the given contribution types', t => {
|
||||
t.pass(1);
|
||||
const {options, kentcdoddsUser, content} = fixtures();
|
||||
const expected = content;
|
||||
|
||||
const result = addContributor(options, kentcdoddsUser, content);
|
||||
t.is(result, expected);
|
||||
});
|
||||
|
||||
test('should add new contributions types to an existing contributor', t => {
|
||||
t.pass(1);
|
||||
const {options, kentcdoddsUser, content} = fixtures();
|
||||
options.contributions = ['doc', 'code'];
|
||||
const expected = '[![Kent C. Dodds](https://avatars.githubusercontent.com/u/1500684?v=3&s=100)<br />Kent C. Dodds](https://github.com/kentcdodds) | [:doc::code:](https://github.com/kentcdodds/all-contributors/commits?author=kentcdodds)';
|
||||
|
||||
const result = addContributor(options, kentcdoddsUser, content);
|
||||
|
||||
t.is(getUserLine(result, kentcdoddsUser), expected);
|
||||
});
|
18
lib/emoji.js
18
lib/emoji.js
|
@ -1,18 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
code: '💻',
|
||||
plugin: '🔌',
|
||||
tool: '🔧',
|
||||
doc: '📖',
|
||||
question: '❓',
|
||||
test: '⚠️',
|
||||
bug: '🐛',
|
||||
example: '💡',
|
||||
blog: '📝',
|
||||
tutorial: '✅',
|
||||
video: '📹',
|
||||
talk: '📢',
|
||||
design: '🎨',
|
||||
review: '👀'
|
||||
};
|
22
lib/generate/fixtures/contributors.json
Normal file
22
lib/generate/fixtures/contributors.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"kentcdodds": {
|
||||
"login": "kentcdodds",
|
||||
"name": "Kent C. Dodds",
|
||||
"html_url": "http://kentcdodds.com",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/1500684",
|
||||
"contributions": [
|
||||
"doc",
|
||||
"review",
|
||||
"question"
|
||||
]
|
||||
},
|
||||
"bogas04": {
|
||||
"login": "bogas04",
|
||||
"name": "Divjot Singh",
|
||||
"html_url": "http://bogas04.github.io",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/6177621",
|
||||
"contributions": [
|
||||
"review"
|
||||
]
|
||||
}
|
||||
}
|
59
lib/generate/formatContributionType.js
Normal file
59
lib/generate/formatContributionType.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
'use strict';
|
||||
|
||||
var _ = require('lodash/fp');
|
||||
|
||||
var linkToCommits = 'https://github.com/<%= options.projectOwner %>/<%= options.projectName %>/commits?author=<%= contributor.login %>'
|
||||
var linkToIssues = 'https://github.com/<%= options.projectOwner %>/<%= options.projectName %>/issues?q=author%3A<%= contributor.login %>';
|
||||
|
||||
var linkTemplate = _.template('[<%= symbol %>](<%= url %>)');
|
||||
|
||||
var defaultTypes = {
|
||||
blog: { symbol: '📝' },
|
||||
bug: {
|
||||
symbol: '🐛',
|
||||
link: linkToIssues
|
||||
},
|
||||
code: {
|
||||
symbol: '💻',
|
||||
link: linkToCommits
|
||||
},
|
||||
design: { symbol: '🎨' },
|
||||
doc: {
|
||||
symbol: '📖',
|
||||
link: linkToCommits
|
||||
},
|
||||
example: { symbol: '💡' },
|
||||
plugin: { symbol: '🔌' },
|
||||
question: { symbol: '❓' },
|
||||
review: { symbol: '👀' },
|
||||
talk: { symbol: '📢' },
|
||||
test: {
|
||||
symbol: '⚠️',
|
||||
link: linkToCommits
|
||||
},
|
||||
translation: { symbol: '🌍' },
|
||||
tool: { symbol: '🔧' },
|
||||
tutorial: { symbol: '✅' },
|
||||
video: { symbol: '📹' }
|
||||
};
|
||||
|
||||
module.exports = function formatContribution(options, contributor, contribution) {
|
||||
var types = _.assign(defaultTypes, options.types);
|
||||
var type = types[contribution.type || contribution];
|
||||
var templateData = {
|
||||
symbol: type.symbol,
|
||||
contributor: contributor,
|
||||
options: options
|
||||
};
|
||||
|
||||
if (contribution.url) {
|
||||
return linkTemplate(_.assign({url: contribution.url}, templateData));
|
||||
}
|
||||
|
||||
if (type.link) {
|
||||
var url = _.template(type.link)(templateData);
|
||||
return linkTemplate(_.assign({url: url}, templateData));
|
||||
}
|
||||
|
||||
return type.symbol;
|
||||
};
|
136
lib/generate/formatContributionType.test.js
Normal file
136
lib/generate/formatContributionType.test.js
Normal file
|
@ -0,0 +1,136 @@
|
|||
import test from 'ava';
|
||||
import formatContributionType from './formatContributionType';
|
||||
import contributors from './fixtures/contributors.json';
|
||||
|
||||
const fixtures = () => {
|
||||
const options = {
|
||||
projectOwner: 'jfmengels',
|
||||
projectName: 'all-contributors-cli',
|
||||
imageSize: 100
|
||||
};
|
||||
return {options};
|
||||
}
|
||||
|
||||
test('should return corresponding symbol', t => {
|
||||
t.plan(2);
|
||||
|
||||
const contributor = contributors.kentcdodds;
|
||||
const {options} = fixtures();
|
||||
|
||||
t.is(formatContributionType(options, contributor, 'tool'), '🔧');
|
||||
t.is(formatContributionType(options, contributor, 'question'), '❓');
|
||||
});
|
||||
|
||||
test('should return link to commits', t => {
|
||||
t.plan(3);
|
||||
|
||||
const contributor = contributors.kentcdodds;
|
||||
const {options} = fixtures();
|
||||
const expectedLink = '(https://github.com/jfmengels/all-contributors-cli/commits?author=kentcdodds)';
|
||||
|
||||
t.is(formatContributionType(options, contributor, 'code'), '[💻]' + expectedLink);
|
||||
t.is(formatContributionType(options, contributor, 'doc'), '[📖]' + expectedLink);
|
||||
t.is(formatContributionType(options, contributor, 'test'), '[⚠️]' + expectedLink);
|
||||
});
|
||||
|
||||
test('should return link to issues', t => {
|
||||
t.plan(1);
|
||||
|
||||
const contributor = contributors.kentcdodds;
|
||||
const {options} = fixtures();
|
||||
const expected = '[🐛](https://github.com/jfmengels/all-contributors-cli/issues?q=author%3Akentcdodds)';
|
||||
|
||||
t.is(formatContributionType(options, contributor, 'bug'), expected);
|
||||
});
|
||||
|
||||
test('should make any symbol into a link if contribution is an object', t => {
|
||||
t.plan(1);
|
||||
|
||||
const contributor = contributors.kentcdodds;
|
||||
const {options} = fixtures();
|
||||
const contribution = {
|
||||
type: 'tool',
|
||||
url: 'www.foo.bar'
|
||||
};
|
||||
|
||||
t.is(formatContributionType(options, contributor, contribution), '[🔧](www.foo.bar)');
|
||||
});
|
||||
|
||||
test('should override url for given types', t => {
|
||||
t.plan(1);
|
||||
|
||||
const contributor = contributors.kentcdodds;
|
||||
const {options} = fixtures();
|
||||
const contribution = {
|
||||
type: 'code',
|
||||
url: 'www.foo.bar'
|
||||
};
|
||||
|
||||
t.is(formatContributionType(options, contributor, contribution), '[💻](www.foo.bar)');
|
||||
});
|
||||
|
||||
test('should be able to add types to the symbol list', t => {
|
||||
t.plan(2);
|
||||
|
||||
const contributor = contributors.kentcdodds;
|
||||
const {options} = fixtures();
|
||||
options.types = {
|
||||
cheerful: { symbol: ':smiley:' }
|
||||
};
|
||||
|
||||
t.is(formatContributionType(options, contributor, 'cheerful'), ':smiley:');
|
||||
t.is(formatContributionType(options, contributor, {
|
||||
type: 'cheerful',
|
||||
url: 'www.foo.bar'
|
||||
}), '[:smiley:](www.foo.bar)');
|
||||
});
|
||||
|
||||
test('should be able to add types with template to the symbol list', t => {
|
||||
t.plan(1);
|
||||
|
||||
const contributor = contributors.kentcdodds;
|
||||
const {options} = fixtures();
|
||||
options.types = {
|
||||
web: {
|
||||
symbol: ':web:',
|
||||
link: 'www.<%= contributor.login %>.com'
|
||||
}
|
||||
};
|
||||
|
||||
t.is(formatContributionType(options, contributor, 'web'), '[:web:](www.kentcdodds.com)');
|
||||
});
|
||||
|
||||
test('should be able to override existing types', t => {
|
||||
t.plan(2);
|
||||
|
||||
const contributor = contributors.kentcdodds;
|
||||
const {options} = fixtures();
|
||||
options.types = {
|
||||
code: { symbol: ':smiley:' }
|
||||
};
|
||||
|
||||
t.is(formatContributionType(options, contributor, 'code'), ':smiley:');
|
||||
t.is(formatContributionType(options, contributor, {
|
||||
type: 'code',
|
||||
url: 'www.foo.bar'
|
||||
}), '[:smiley:](www.foo.bar)');
|
||||
});
|
||||
|
||||
test('should be able to override existing templates', t => {
|
||||
t.plan(2);
|
||||
|
||||
const contributor = contributors.kentcdodds;
|
||||
const {options} = fixtures();
|
||||
options.types = {
|
||||
code: {
|
||||
symbol: ':web:',
|
||||
link: 'www.<%= contributor.login %>.com'
|
||||
}
|
||||
};
|
||||
|
||||
t.is(formatContributionType(options, contributor, 'code'), '[:web:](www.kentcdodds.com)');
|
||||
t.is(formatContributionType(options, contributor, {
|
||||
type: 'code',
|
||||
url: 'www.foo.bar'
|
||||
}), '[:web:](www.foo.bar)');
|
||||
});
|
39
lib/generate/formatContributor.js
Normal file
39
lib/generate/formatContributor.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
'use strict';
|
||||
|
||||
var _ = require('lodash/fp');
|
||||
|
||||
var formatContributionType = require('./formatContributionType');
|
||||
|
||||
var avatarTemplate = _.template('![<%= contributor.name %>](<%= contributor.avatar_url %>)');
|
||||
var avatarBlockTemplate = _.template('[<%= avatar %><br /><sub><%= contributor.name %></sub>](<%= contributor.html_url %>)');
|
||||
var contributorTemplate = _.template('<%= avatarBlock %><br /><%= contributions %>');
|
||||
|
||||
function defaultTemplate(templateData) {
|
||||
var avatar = avatarTemplate(templateData);
|
||||
var avatarBlock = avatarBlockTemplate(_.assign({ avatar: avatar }, templateData));
|
||||
return contributorTemplate(_.assign({ avatarBlock: avatarBlock }, templateData));
|
||||
}
|
||||
|
||||
function updateAvatarUrl(options, contributor) {
|
||||
var avatarUrl = contributor.avatar_url;
|
||||
var paramJoiner = _.includes('?', avatarUrl) ? '&' : '?';
|
||||
return _.assign(contributor, {
|
||||
avatar_url: avatarUrl + paramJoiner + 's=' + options.imageSize
|
||||
});
|
||||
'<%= contributor.avatar_url %>?s=<%= options.imageSize %>'
|
||||
}
|
||||
|
||||
module.exports = function formatContributor(options, contributor) {
|
||||
var contributions = contributor.contributions.map(
|
||||
_.partial(formatContributionType, [options, contributor])
|
||||
).join(' ');
|
||||
|
||||
var templateData = {
|
||||
contributions: contributions,
|
||||
contributor: updateAvatarUrl(options, contributor),
|
||||
options: options
|
||||
};
|
||||
|
||||
var customTemplate = options.template && _.template(options.template);
|
||||
return (customTemplate || defaultTemplate)(templateData);
|
||||
};
|
69
lib/generate/formatContributor.test.js
Normal file
69
lib/generate/formatContributor.test.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
import test from 'ava';
|
||||
import _ from 'lodash/fp';
|
||||
import formatContributor from './formatContributor';
|
||||
import contributors from './fixtures/contributors.json';
|
||||
|
||||
function fixtures() {
|
||||
const options = {
|
||||
projectOwner: 'jfmengels',
|
||||
projectName: 'all-contributors-cli',
|
||||
imageSize: 100
|
||||
};
|
||||
return {options};
|
||||
}
|
||||
|
||||
test('should format a simple contributor', t => {
|
||||
t.plan(1);
|
||||
|
||||
const contributor = _.assign(contributors.kentcdodds, { contributions: ['review'] });
|
||||
const {options} = fixtures();
|
||||
|
||||
const expected = '[![Kent C. Dodds](https://avatars1.githubusercontent.com/u/1500684?s=100)<br /><sub>Kent C. Dodds</sub>](http://kentcdodds.com)<br />👀';
|
||||
|
||||
t.is(formatContributor(options, contributor), expected);
|
||||
});
|
||||
|
||||
test('should format contributor with complex contribution types', t => {
|
||||
t.plan(1);
|
||||
|
||||
const contributor = contributors.kentcdodds;
|
||||
const {options} = fixtures();
|
||||
|
||||
const expected = '[![Kent C. Dodds](https://avatars1.githubusercontent.com/u/1500684?s=100)<br /><sub>Kent C. Dodds</sub>](http://kentcdodds.com)<br />[📖](https://github.com/jfmengels/all-contributors-cli/commits?author=kentcdodds) 👀 ❓';
|
||||
|
||||
t.is(formatContributor(options, contributor), expected);
|
||||
});
|
||||
|
||||
test('should format contributor using custom template', t => {
|
||||
t.plan(1);
|
||||
|
||||
const contributor = contributors.kentcdodds;
|
||||
const {options} = fixtures();
|
||||
options.template = '<%= contributor.name %> is awesome!'
|
||||
|
||||
const expected = 'Kent C. Dodds is awesome!';
|
||||
|
||||
t.is(formatContributor(options, contributor), expected);
|
||||
});
|
||||
|
||||
test('should add image size to url', t => {
|
||||
t.plan(2);
|
||||
|
||||
const {options} = fixtures();
|
||||
const contributor = contributors.kentcdodds;
|
||||
options.template = '<%= contributor.name %> at <%= contributor.avatar_url %>'
|
||||
|
||||
var contributionWithoutQuestionMarkUrl = _.assign(contributor, {
|
||||
avatar_url: 'www.some-url-without-question-mark.com'
|
||||
});
|
||||
var contributionWithQuestionMarkUrl = _.assign(contributor, {
|
||||
avatar_url: 'www.some-url-with-question-mark.com?v=3'
|
||||
});
|
||||
|
||||
t.is(formatContributor(options, contributionWithoutQuestionMarkUrl),
|
||||
'Kent C. Dodds at www.some-url-without-question-mark.com?s=100'
|
||||
);
|
||||
t.is(formatContributor(options, contributionWithQuestionMarkUrl),
|
||||
'Kent C. Dodds at www.some-url-with-question-mark.com?v=3&s=100'
|
||||
);
|
||||
});
|
41
lib/generate/index.js
Normal file
41
lib/generate/index.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
'use strict';
|
||||
|
||||
var _ = require('lodash/fp');
|
||||
var formatContributor = require('./formatContributor');
|
||||
|
||||
function injectBetweenTags(fileContent, newContent) {
|
||||
var lines = fileContent.split('\n');
|
||||
var openingTagIndex = _.findIndex(_.startsWith('<!-- CONTRIBUTORS:START'), lines);
|
||||
var closingTagIndex = _.findIndex(_.startsWith('<!-- CONTRIBUTORS:END'), lines);
|
||||
return [].concat(
|
||||
lines.slice(0, openingTagIndex + 1),
|
||||
newContent,
|
||||
lines.slice(closingTagIndex)
|
||||
).join('\n');
|
||||
}
|
||||
|
||||
function formatLine(contributors) {
|
||||
return '| ' + contributors.join(' | ') + ' |';
|
||||
}
|
||||
|
||||
function generateContributorsList(options, contributors) {
|
||||
return _.flow(
|
||||
_.map(function(contributor) {
|
||||
return formatContributor(options, contributor);
|
||||
}),
|
||||
_.chunk(options.contributorsPerLine),
|
||||
_.map(formatLine),
|
||||
_.join('\n'),
|
||||
function appendColumns(content) {
|
||||
var nbColumns = Math.min(options.contributorsPerLine, contributors.length);
|
||||
return content + '\n' + _.repeat(nbColumns, '| :---: ') + '|';
|
||||
}
|
||||
)(contributors);
|
||||
}
|
||||
|
||||
module.exports = function generate(options, contributors, fileContent) {
|
||||
return _.flow(
|
||||
generateContributorsList,
|
||||
_.partial(injectBetweenTags, [fileContent])
|
||||
)(options, contributors);
|
||||
};
|
98
lib/generate/index.test.js
Normal file
98
lib/generate/index.test.js
Normal file
|
@ -0,0 +1,98 @@
|
|||
import test from 'ava';
|
||||
import generate from './';
|
||||
import contributors from './fixtures/contributors.json';
|
||||
|
||||
function getUserLine(content, {login}) {
|
||||
return content
|
||||
.split('\n')
|
||||
.filter(line => line.indexOf(login) !== -1)
|
||||
[0];
|
||||
}
|
||||
|
||||
function fixtures() {
|
||||
const options = {
|
||||
projectOwner: 'kentcdodds',
|
||||
projectName: 'all-contributors',
|
||||
imageSize: 100,
|
||||
contributorsPerLine: 5,
|
||||
contributors: contributors,
|
||||
template: '<%= contributor.name %> is awesome!'
|
||||
};
|
||||
|
||||
const jfmengels = {
|
||||
login: 'jfmengels',
|
||||
name: 'Jeroen Engels',
|
||||
html_url: 'https://github.com/jfmengels',
|
||||
avatar_url: 'https://avatars.githubusercontent.com/u/3869412?v=3',
|
||||
contributions: ['doc']
|
||||
};
|
||||
|
||||
const content = [
|
||||
'# project',
|
||||
'',
|
||||
'Description',
|
||||
'',
|
||||
'## Contributors',
|
||||
'These people contributed to the project:',
|
||||
'<!-- CONTRIBUTORS:START -->',
|
||||
'###Some content that will be replace###',
|
||||
'<!-- CONTRIBUTORS:END -->',
|
||||
'',
|
||||
'Thanks a lot guys!'
|
||||
].join('\n');
|
||||
|
||||
return {options, jfmengels, content};
|
||||
}
|
||||
|
||||
test('should replace the content between the CONTRIBUTORS tags by a table of contributors', t => {
|
||||
t.plan(1);
|
||||
|
||||
const {kentcdodds, bogas04} = contributors;
|
||||
const {options, jfmengels, content} = fixtures();
|
||||
const contributorList = [kentcdodds, bogas04, jfmengels];
|
||||
const expected = [
|
||||
'# project',
|
||||
'',
|
||||
'Description',
|
||||
'',
|
||||
'## Contributors',
|
||||
'These people contributed to the project:',
|
||||
'<!-- CONTRIBUTORS:START -->',
|
||||
'| Kent C. Dodds is awesome! | Divjot Singh is awesome! | Jeroen Engels is awesome! |',
|
||||
'| :---: | :---: | :---: |',
|
||||
'<!-- CONTRIBUTORS:END -->',
|
||||
'',
|
||||
'Thanks a lot guys!'
|
||||
].join('\n');
|
||||
|
||||
const result = generate(options, contributorList, content);
|
||||
|
||||
t.is(result, expected);
|
||||
});
|
||||
|
||||
test('should split contributors into multiples lines when there are too many', t => {
|
||||
t.plan(1);
|
||||
|
||||
const {kentcdodds, bogas04} = contributors;
|
||||
const {options, jfmengels, content} = fixtures();
|
||||
const contributorList = [kentcdodds, kentcdodds, kentcdodds, kentcdodds, kentcdodds, kentcdodds, kentcdodds];
|
||||
const expected = [
|
||||
'# project',
|
||||
'',
|
||||
'Description',
|
||||
'',
|
||||
'## Contributors',
|
||||
'These people contributed to the project:',
|
||||
'<!-- CONTRIBUTORS:START -->',
|
||||
'| Kent C. Dodds is awesome! | Kent C. Dodds is awesome! | Kent C. Dodds is awesome! | Kent C. Dodds is awesome! | Kent C. Dodds is awesome! |',
|
||||
'| Kent C. Dodds is awesome! | Kent C. Dodds is awesome! |',
|
||||
'| :---: | :---: | :---: | :---: | :---: |',
|
||||
'<!-- CONTRIBUTORS:END -->',
|
||||
'',
|
||||
'Thanks a lot guys!'
|
||||
].join('\n');
|
||||
|
||||
const result = generate(options, contributorList, content);
|
||||
|
||||
t.is(result, expected);
|
||||
});
|
|
@ -24,6 +24,7 @@
|
|||
},
|
||||
"homepage": "https://github.com/jfmengels/all-contributors-cli#readme",
|
||||
"dependencies": {
|
||||
"lodash": "^4.5.1",
|
||||
"lodash.assign": "^4.0.4",
|
||||
"lodash.findindex": "^4.2.0",
|
||||
"lodash.template": "^4.2.1",
|
||||
|
@ -32,11 +33,6 @@
|
|||
"request": "^2.69.0",
|
||||
"yargs": "^4.2.0"
|
||||
},
|
||||
"all-contributors": {
|
||||
"projectOwner": "jfmengels",
|
||||
"projectName": "all-contributors-cli",
|
||||
"imageSize": 100
|
||||
},
|
||||
"devDependencies": {
|
||||
"ava": "^0.12.0"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue