diff --git a/.all-contributorsrc b/.all-contributorsrc index 7459677b..5de1c6d4 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -204,6 +204,16 @@ "doc", "ideas" ] + }, + { + "login": "xuchaoying", + "name": "C.Y.Xu", + "avatar_url": "https://avatars2.githubusercontent.com/u/8073251?v=4", + "profile": "https://github.com/xuchaoying", + "contributions": [ + "code" + ] } - ] + ], + "repoType": "github" } diff --git a/README.md b/README.md index a0357fcc..b0a72a29 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![version][version-badge]][package] [![downloads][downloads-badge]][downloads] [![MIT License][license-badge]][license] -[![All Contributors](https://img.shields.io/badge/all_contributors-21-orange.svg?style=flat-square)](#contributors) +[![All Contributors](https://img.shields.io/badge/all_contributors-22-orange.svg?style=flat-square)](#contributors) [![PRs Welcome][prs-badge]][prs] [![Code of Conduct][coc-badge]][coc] [![Watch on GitHub][github-watch-badge]][github-watch] [![Star on GitHub][github-star-badge]][github-star] @@ -158,6 +158,7 @@ These are the keys you can specify: --> `all-contributors-cli`. Mandatory. * `repoType`: Type of repository. Must be either `github` or `gitlab`. Default: `github`. * `repoHost`: Points to the repository hostname. Change it if you use a self hosted repository. Default: `https://github.com` if `repoType` is `github`, and `https://gitlab.com` if `repoType` is `gitlab`. +* `private_token`: The personal access token to to authenticate with the GitLab API. Offer it if you use a self hosted repository. Default: `''`. * `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`. @@ -178,7 +179,7 @@ Thanks goes to these wonderful people | :---: | :---: | :---: | :---: | :---: | :---: | | [
Jerod Santo](https://jerodsanto.net)
[💻](https://github.com/jfmengels/all-contributors-cli/commits?author=jerodsanto "Code") | [
Kevin Jalbert](https://github.com/kevinjalbert)
[💻](https://github.com/jfmengels/all-contributors-cli/commits?author=kevinjalbert "Code") | [
tunnckoCore](https://i.am.charlike.online)
[🔧](#tool-charlike "Tools") | [
Mehdi Achour](https://machour.idk.tn/)
[💻](https://github.com/jfmengels/all-contributors-cli/commits?author=machour "Code") | [
Roy Revelt](https://codsen.com)
[🐛](https://github.com/jfmengels/all-contributors-cli/issues?q=author%3Arevelt "Bug reports") | [
Chris Vickery](https://github.com/chrisinajar)
[💻](https://github.com/jfmengels/all-contributors-cli/commits?author=chrisinajar "Code") | | [
Bryce Reynolds](https://github.com/brycereynolds)
[💻](https://github.com/jfmengels/all-contributors-cli/commits?author=brycereynolds "Code") | [
James, please](http://www.jmeas.com)
[🤔](#ideas-jmeas "Ideas, Planning, & Feedback") [💻](https://github.com/jfmengels/all-contributors-cli/commits?author=jmeas "Code") | [
Spyros Ioakeimidis](http://www.spyros.io)
[💻](https://github.com/jfmengels/all-contributors-cli/commits?author=spirosikmd "Code") | [
Fernando Costa](https://github.com/fadc80)
[💻](https://github.com/jfmengels/all-contributors-cli/commits?author=fadc80 "Code") | [
snipe](https://snipe.net)
[📖](https://github.com/jfmengels/all-contributors-cli/commits?author=snipe "Documentation") | [
Gant Laborde](http://gantlaborde.com/)
[💻](https://github.com/jfmengels/all-contributors-cli/commits?author=GantMan "Code") | -| [
Md Zubair Ahmed](https://in.linkedin.com/in/mzubairahmed)
[📖](https://github.com/jfmengels/all-contributors-cli/commits?author=M-ZubairAhmed "Documentation") [🐛](https://github.com/jfmengels/all-contributors-cli/issues?q=author%3AM-ZubairAhmed "Bug reports") | [
Divjot Singh](http://bogas04.github.io)
[📖](https://github.com/jfmengels/all-contributors-cli/commits?author=bogas04 "Documentation") | [
João Marques](https://github.com/tigermarques)
[💻](https://github.com/jfmengels/all-contributors-cli/commits?author=tigermarques "Code") [📖](https://github.com/jfmengels/all-contributors-cli/commits?author=tigermarques "Documentation") [🤔](#ideas-tigermarques "Ideas, Planning, & Feedback") | +| [
Md Zubair Ahmed](https://in.linkedin.com/in/mzubairahmed)
[📖](https://github.com/jfmengels/all-contributors-cli/commits?author=M-ZubairAhmed "Documentation") [🐛](https://github.com/jfmengels/all-contributors-cli/issues?q=author%3AM-ZubairAhmed "Bug reports") [💻](https://github.com/jfmengels/all-contributors-cli/commits?author=M-ZubairAhmed "Code") [⚠️](https://github.com/jfmengels/all-contributors-cli/commits?author=M-ZubairAhmed "Tests") | [
Divjot Singh](http://bogas04.github.io)
[📖](https://github.com/jfmengels/all-contributors-cli/commits?author=bogas04 "Documentation") | [
João Marques](https://github.com/tigermarques)
[💻](https://github.com/jfmengels/all-contributors-cli/commits?author=tigermarques "Code") [📖](https://github.com/jfmengels/all-contributors-cli/commits?author=tigermarques "Documentation") [🤔](#ideas-tigermarques "Ideas, Planning, & Feedback") | [
C.Y.Xu](https://github.com/xuchaoying)
[💻](https://github.com/jfmengels/all-contributors-cli/commits?author=xuchaoying "Code") | This project follows the diff --git a/src/cli.js b/src/cli.js index 636881dc..367e7c4f 100755 --- a/src/cli.js +++ b/src/cli.js @@ -76,7 +76,13 @@ function checkContributors(argv) { const configData = util.configFile.readConfig(argv.config) return repo - .getContributors(configData.projectOwner, configData.projectName, configData.repoType, configData.repoHost) + .getContributors( + configData.projectOwner, + configData.projectName, + configData.repoType, + configData.repoHost, + configData.private_token, + ) .then(repoContributors => { const checkKey = repo.getCheckKey(configData.repoType) const knownContributions = configData.contributors.reduce((obj, item) => { @@ -138,7 +144,8 @@ function promptForCommand(argv) { value: 'generate', }, { - name: 'Compare contributors from the repository with the credited ones', + name: + 'Compare contributors from the repository with the credited ones', value: 'check', }, ], @@ -155,16 +162,16 @@ function promptForCommand(argv) { promptForCommand(yargv) .then(command => { switch (command) { - case 'init': - return init() - case 'generate': - return startGeneration(yargv) - case 'add': - return addContribution(yargv) - case 'check': - return checkContributors(yargv) - default: - throw new Error(`Unknown command ${command}`) + case 'init': + return init() + case 'generate': + return startGeneration(yargv) + case 'add': + return addContribution(yargv) + case 'check': + return checkContributors(yargv) + default: + throw new Error(`Unknown command ${command}`) } }) .catch(onError) diff --git a/src/contributors/add.js b/src/contributors/add.js index a23a2ddf..df53d343 100644 --- a/src/contributors/add.js +++ b/src/contributors/add.js @@ -38,7 +38,12 @@ function updateExistingContributor(options, username, contributions) { } function addNewContributor(options, username, contributions, infoFetcher) { - return infoFetcher(username, options.repoType, options.repoHost).then(userData => { + return infoFetcher( + username, + options.repoType, + options.repoHost, + options.private_token, + ).then(userData => { const contributor = _.assign(userData, { contributions: formatContributions(options, [], contributions), }) diff --git a/src/init/prompt.js b/src/init/prompt.js index 81dcdd19..bded98f6 100644 --- a/src/init/prompt.js +++ b/src/init/prompt.js @@ -41,6 +41,13 @@ const questions = [ } }, }, + { + type: 'input', + name: 'private_token', + message: + 'What is the personal access token? (If you use a self hosted repository)', + default: '', + }, { type: 'input', name: 'contributorFile', @@ -79,7 +86,10 @@ const questions = [ }, ] -const uniqueFiles = _.flow(_.compact, _.uniq) +const uniqueFiles = _.flow( + _.compact, + _.uniq, +) module.exports = function prompt() { return git @@ -98,6 +108,7 @@ module.exports = function prompt() { projectOwner: answers.projectOwner, repoType: answers.repoType, repoHost: answers.repoHost, + private_token: answers.private_token, files: uniqueFiles([answers.contributorFile, answers.badgeFile]), imageSize: answers.imageSize, commit: answers.commit, diff --git a/src/repo/__tests__/gitlab.js b/src/repo/__tests__/gitlab.js index c13cbff0..c00f708e 100644 --- a/src/repo/__tests__/gitlab.js +++ b/src/repo/__tests__/gitlab.js @@ -19,12 +19,15 @@ test('handle errors', async () => { test('fill in the name when it is returned', async () => { nock('https://gitlab.com') .get('/api/v4/users?username=nodisplayname') - .reply(200, [{ - username: 'nodisplayname', - name: 'No Display Name', - avatar_url: 'http://www.gravatar.com/avatar/3186450a99d1641bf75a44baa23f0826?s=80\u0026d=identicon', - web_url: 'https://gitlab.com/nodisplayname', - }]) + .reply(200, [ + { + username: 'nodisplayname', + name: 'No Display Name', + avatar_url: + 'http://www.gravatar.com/avatar/3186450a99d1641bf75a44baa23f0826?s=80\u0026d=identicon', + web_url: 'https://gitlab.com/nodisplayname', + }, + ]) const info = await getUserInfo('nodisplayname') expect(info.name).toBe('No Display Name') @@ -33,12 +36,15 @@ test('fill in the name when it is returned', async () => { test('fill in the name when null is returned', async () => { nock('https://gitlab.com') .get('/api/v4/users?username=nodisplayname') - .reply(200, [{ - username: 'nodisplayname', - name: null, - avatar_url: 'http://www.gravatar.com/avatar/3186450a99d1641bf75a44baa23f0826?s=80\u0026d=identicon', - web_url: 'https://gitlab.com/nodisplayname', - }]) + .reply(200, [ + { + username: 'nodisplayname', + name: null, + avatar_url: + 'http://www.gravatar.com/avatar/3186450a99d1641bf75a44baa23f0826?s=80\u0026d=identicon', + web_url: 'https://gitlab.com/nodisplayname', + }, + ]) const info = await getUserInfo('nodisplayname') expect(info.name).toBe('nodisplayname') @@ -47,12 +53,15 @@ test('fill in the name when null is returned', async () => { test('fill in the name when an empty string is returned', async () => { nock('https://gitlab.com') .get('/api/v4/users?username=nodisplayname') - .reply(200, [{ - username: 'nodisplayname', - name: '', - avatar_url: 'http://www.gravatar.com/avatar/3186450a99d1641bf75a44baa23f0826?s=80\u0026d=identicon', - web_url: 'https://gitlab.com/nodisplayname', - }]) + .reply(200, [ + { + username: 'nodisplayname', + name: '', + avatar_url: + 'http://www.gravatar.com/avatar/3186450a99d1641bf75a44baa23f0826?s=80\u0026d=identicon', + web_url: 'https://gitlab.com/nodisplayname', + }, + ]) const info = await getUserInfo('nodisplayname') expect(info.name).toBe('nodisplayname') @@ -61,12 +70,15 @@ test('fill in the name when an empty string is returned', async () => { test('append http when no absolute link is provided', async () => { nock('https://gitlab.com') .get('/api/v4/users?username=nodisplayname') - .reply(200, [{ - username: 'nodisplayname', - name: 'No Display Name', - avatar_url: 'http://www.gravatar.com/avatar/3186450a99d1641bf75a44baa23f0826?s=80\u0026d=identicon', - web_url: 'www.gitlab.com/nodisplayname', - }]) + .reply(200, [ + { + username: 'nodisplayname', + name: 'No Display Name', + avatar_url: + 'http://www.gravatar.com/avatar/3186450a99d1641bf75a44baa23f0826?s=80\u0026d=identicon', + web_url: 'www.gitlab.com/nodisplayname', + }, + ]) const info = await getUserInfo('nodisplayname') expect(info.profile).toBe('http://www.gitlab.com/nodisplayname') @@ -75,13 +87,50 @@ test('append http when no absolute link is provided', async () => { test('retrieve user from a different gitlab registry', async () => { nock('http://gitlab.myhost.com:3000') .get('/api/v4/users?username=nodisplayname') - .reply(200, [{ - username: 'nodisplayname', - name: 'No Display Name', - avatar_url: 'http://www.gravatar.com/avatar/3186450a99d1641bf75a44baa23f0826?s=80\u0026d=identicon', - web_url: 'https://gitlab.com/nodisplayname', - }]) - - const info = await getUserInfo('nodisplayname', 'http://gitlab.myhost.com:3000') + .reply(200, [ + { + username: 'nodisplayname', + name: 'No Display Name', + avatar_url: + 'http://www.gravatar.com/avatar/3186450a99d1641bf75a44baa23f0826?s=80\u0026d=identicon', + web_url: 'https://gitlab.com/nodisplayname', + }, + ]) + + const info = await getUserInfo( + 'nodisplayname', + 'http://gitlab.myhost.com:3000', + ) + expect(info.name).toBe('No Display Name') +}) + +test('retrieve user from a gitlab registry that needs a token', async () => { + nock('http://gitlab.needtoken.com:3000') + .get('/api/v4/users?username=nodisplayname&private_token=faketoken') + .reply(200, [ + { + username: 'nodisplayname', + name: 'No Display Name', + avatar_url: + 'http://www.gravatar.com/avatar/3186450a99d1641bf75a44baa23f0826?s=80\u0026d=identicon', + web_url: 'https://gitlab.com/nodisplayname', + }, + ]) + + const info = await getUserInfo( + 'nodisplayname', + 'http://gitlab.needtoken.com:3000', + 'faketoken', + ) expect(info.name).toBe('No Display Name') }) + +test('handle error when no token is offered', async () => { + nock('http://gitlab.needtoken.com:3000') + .get('/api/v4/users?username=nodisplayname') + .reply(200, []) + + await rejects( + getUserInfo('nodisplayname', 'http://gitlab.needtoken.com:3000', ''), + ) +}) diff --git a/src/repo/gitlab.js b/src/repo/gitlab.js index 5d7a69bc..6c139ce3 100644 --- a/src/repo/gitlab.js +++ b/src/repo/gitlab.js @@ -1,15 +1,26 @@ const pify = require('pify') const request = pify(require('request')) -const getUserInfo = function(username, hostname) { +const addPrivateToken = (url, private_token = '') => { + if (private_token === '') return url + + return `${url}&private_token=${private_token}` + .replace(/\?/g, '&') + .replace('&', '?') +} + +const getUserInfo = function(username, hostname, private_token = '') { /* eslint-disable complexity */ if (!hostname) { - hostname = 'https://gitlab.com'; + hostname = 'https://gitlab.com' } return request .get({ - url: `${hostname}/api/v4/users?username=${username}`, + url: addPrivateToken( + `${hostname}/api/v4/users?username=${username}`, + private_token, + ), headers: { 'User-Agent': 'request', }, @@ -28,19 +39,24 @@ const getUserInfo = function(username, hostname) { login: user.username, name: user.name || username, avatar_url: user.avatar_url, - profile: user.web_url.startsWith('http') ? user.web_url : `http://${user.web_url}`, + profile: user.web_url.startsWith('http') + ? user.web_url + : `http://${user.web_url}`, } }) } -const getContributors = function(owner, name, hostname) { +const getContributors = function(owner, name, hostname, private_token = '') { if (!hostname) { - hostname = 'https://gitlab.com'; + hostname = 'https://gitlab.com' } return request .get({ - url: `${hostname}/api/v4/projects?search=${name}`, + url: addPrivateToken( + `${hostname}/api/v4/projects?search=${name}`, + private_token, + ), headers: { 'User-Agent': 'request', }, @@ -57,7 +73,7 @@ const getContributors = function(owner, name, hostname) { for (let i = 0; i < projects.length; i++) { if (projects[i].path_with_namespace === `${owner}/${name}`) { project = projects[i] - break; + break } } @@ -67,7 +83,10 @@ const getContributors = function(owner, name, hostname) { return request .get({ - url: `${hostname}/api/v4/projects/${project.id}/repository/contributors`, + url: addPrivateToken( + `${hostname}/api/v4/projects/${project.id}/repository/contributors`, + private_token, + ), headers: { 'User-Agent': 'request', }, @@ -87,5 +106,5 @@ const getContributors = function(owner, name, hostname) { module.exports = { getUserInfo, - getContributors + getContributors, } diff --git a/src/repo/index.js b/src/repo/index.js index 1810c7fc..26361109 100644 --- a/src/repo/index.js +++ b/src/repo/index.js @@ -7,30 +7,36 @@ const SUPPORTED_REPO_TYPES = { name: 'GitHub', checkKey: 'login', defaultHost: 'https://github.com', - linkToCommits: '<%= options.repoHost || "https://github.com" %>/<%= options.projectOwner %>/<%= options.projectName %>/commits?author=<%= contributor.login %>', - linkToIssues: '<%= options.repoHost || "https://github.com" %>/<%= options.projectOwner %>/<%= options.projectName %>/issues?q=author%3A<%= contributor.login %>', + linkToCommits: + '<%= options.repoHost || "https://github.com" %>/<%= options.projectOwner %>/<%= options.projectName %>/commits?author=<%= contributor.login %>', + linkToIssues: + '<%= options.repoHost || "https://github.com" %>/<%= options.projectOwner %>/<%= options.projectName %>/issues?q=author%3A<%= contributor.login %>', getUserInfo: githubAPI.getUserInfo, - getContributors: githubAPI.getContributors + getContributors: githubAPI.getContributors, }, gitlab: { value: 'gitlab', name: 'GitLab', checkKey: 'name', defaultHost: 'https://gitlab.com', - linkToCommits: '<%= options.repoHost || "https://gitlab.com" %>/<%= options.projectOwner %>/<%= options.projectName %>/commits/master', - linkToIssues: '<%= options.repoHost || "https://gitlab.com" %>/<%= options.projectOwner %>/<%= options.projectName %>/issues?author_username=<%= contributor.login %>', + linkToCommits: + '<%= options.repoHost || "https://gitlab.com" %>/<%= options.projectOwner %>/<%= options.projectName %>/commits/master', + linkToIssues: + '<%= options.repoHost || "https://gitlab.com" %>/<%= options.projectOwner %>/<%= options.projectName %>/issues?author_username=<%= contributor.login %>', getUserInfo: gitlabAPI.getUserInfo, - getContributors: gitlabAPI.getContributors - } + getContributors: gitlabAPI.getContributors, + }, } const getChoices = function() { - return Object.keys(SUPPORTED_REPO_TYPES).map(key => SUPPORTED_REPO_TYPES[key]).map(item => { - return { - value: item.value, - name: item.name - } - }) + return Object.keys(SUPPORTED_REPO_TYPES) + .map(key => SUPPORTED_REPO_TYPES[key]) + .map(item => { + return { + value: item.value, + name: item.name, + } + }) } const getHostname = function(repoType, repoHost) { @@ -70,16 +76,31 @@ const getLinkToIssues = function(repoType) { return null } -const getUserInfo = function(username, repoType, repoHost) { +const getUserInfo = function(username, repoType, repoHost, private_token = '') { if (repoType in SUPPORTED_REPO_TYPES) { - return SUPPORTED_REPO_TYPES[repoType].getUserInfo(username, getHostname(repoType, repoHost)) + return SUPPORTED_REPO_TYPES[repoType].getUserInfo( + username, + getHostname(repoType, repoHost), + private_token, + ) } return null } -const getContributors = function(owner, name, repoType, repoHost) { +const getContributors = function( + owner, + name, + repoType, + repoHost, + private_token = '', +) { if (repoType in SUPPORTED_REPO_TYPES) { - return SUPPORTED_REPO_TYPES[repoType].getContributors(owner, name, getHostname(repoType, repoHost)) + return SUPPORTED_REPO_TYPES[repoType].getContributors( + owner, + name, + getHostname(repoType, repoHost), + private_token, + ) } return null } @@ -92,5 +113,5 @@ module.exports = { getLinkToCommits, getLinkToIssues, getUserInfo, - getContributors + getContributors, }