feat: support Github Enterprise (#97)

* add isEnterprise config option and add function to change hostname if on enterprise

* add hipstersmoothie as contributor

* infer enterprise API

* handle enterprise authentication

* add tylerkrupicka as a contributor

Co-authored-by: Tyler Krupicka <tylerkrupicka@gmail.com>
Co-authored-by: Maximilian Berkmann <maxieberkmann@gmail.com>
This commit is contained in:
Andrew Lisowski 2020-01-17 12:09:58 -08:00 committed by Maximilian Berkmann
parent 4f407508cc
commit 0965095ecd
4 changed files with 69 additions and 22 deletions

View file

@ -381,6 +381,16 @@
"code"
]
},
{
"login": "tylerkrupicka",
"name": "Tyler Krupicka",
"avatar_url": "https://avatars1.githubusercontent.com/u/5761061?s=460&v=4",
"profile": "https://github.com/tylerkrupicka",
"contributions": [
"code",
"test"
]
},
{
"login": "smoia",
"name": "Stefano Moia",

View file

@ -1,12 +1,11 @@
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [ all-contributors-cli ](#all-contributors-cli)
- [The problem](#the-problem)
- [This solution](#this-solution)
- [Using the all-contributors-cli](#using-the-all-contributors-cli)
- [Contributors ✨](#contributors-)
- [LICENSE](#license)
- [The problem](#the-problem)
- [This solution](#this-solution)
- [Using the all-contributors-cli](#using-the-all-contributors-cli)
- [Contributors ✨](#contributors-%e2%9c%a8)
- [LICENSE](#license)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
@ -130,6 +129,7 @@ Thanks goes to these wonderful people
<td align="center"><a href="https://www.destro.me"><img src="https://avatars1.githubusercontent.com/u/7031675?v=4" width="100px;" alt=""/><br /><sub><b>Fabrizio</b></sub></a><br /><a href="https://github.com/all-contributors/all-contributors-cli/issues?q=author%3Adexpota" title="Bug reports">🐛</a> <a href="https://github.com/all-contributors/all-contributors-cli/commits?author=dexpota" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/marceloalves"><img src="https://avatars1.githubusercontent.com/u/216782?v=4" width="100px;" alt=""/><br /><sub><b>Marcelo Alves</b></sub></a><br /><a href="https://github.com/all-contributors/all-contributors-cli/commits?author=MarceloAlves" title="Code">💻</a></td>
<td align="center"><a href="https://phacks.dev/"><img src="https://avatars1.githubusercontent.com/u/2587348?v=4" width="100px;" alt=""/><br /><sub><b>Nicolas Goutay</b></sub></a><br /><a href="https://github.com/all-contributors/all-contributors-cli/commits?author=phacks" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/tylerkrupicka"><img src="https://avatars1.githubusercontent.com/u/5761061?s=460&v=4" width="100px;" alt=""/><br /><sub><b>Tyler Krupicka</b></sub></a><br /><a href="https://github.com/all-contributors/all-contributors-cli/commits?author=tylerkrupicka" title="Code">💻</a> <a href="https://github.com/all-contributors/all-contributors-cli/commits?author=tylerkrupicka" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/smoia"><img src="https://avatars3.githubusercontent.com/u/35300580?v=4" width="100px;" alt=""/><br /><sub><b>Stefano Moia</b></sub></a><br /><a href="https://github.com/all-contributors/all-contributors-cli/commits?author=smoia" title="Code">💻</a></td>
</tr>
</table>

View file

@ -85,6 +85,21 @@ test('Throw error when non existent username is provided', async () => {
)
})
test('Throw error when missing enterprise authentication', async () => {
const username = 'notauthenticated'
nock('http://github.myhost.com:3000/api/v3')
.get(`/users/${username}`)
.reply(401, {
message: 'Must authenticate to access this API.',
documentation_url: 'https://developer.github.com/enterprise/2.17/v3',
})
await expect(
getUserInfo(username, 'http://github.myhost.com:3000'),
).rejects.toThrow(
`Missing authentication for GitHub API. Did you set PRIVATE_TOKEN?`,
)
})
test('handle github errors', async () => {
nock('https://api.github.com')
.get('/users/nodisplayname')
@ -174,7 +189,7 @@ test('append http when no absolute link is provided', async () => {
})
test('retrieve user from a different github registry', async () => {
nock('http://api.github.myhost.com:3000')
nock('http://github.myhost.com:3000/api/v3')
.get('/users/nodisplayname')
.reply(200, {
login: 'nodisplayname',

View file

@ -1,6 +1,27 @@
const url = require('url')
const pify = require('pify')
const request = pify(require('request'))
/**
* Get the host based on public or enterprise GitHub.
* https://developer.github.com/enterprise/2.17/v3/#current-version
*
* @param {String} hostname - Hostname from config.
* @returns {String} - Host for GitHub API.
*/
function getApiHost(hostname) {
if (!hostname) {
hostname = 'https://github.com'
}
if (hostname !== 'https://github.com') {
// Assume Github Enterprise
return url.resolve(hostname, '/api/v3')
}
return hostname.replace(/:\/\//, '://api.')
}
function getRequestHeaders(optionalPrivateToken = '') {
const requestHeaders = {
'User-Agent': 'request',
@ -27,10 +48,10 @@ function getNextLink(link) {
return nextLink.split(';')[0].slice(1, -1)
}
function getContributorsPage(url, optionalPrivateToken) {
function getContributorsPage(githubUrl, optionalPrivateToken) {
return request
.get({
url,
url: githubUrl,
headers: getRequestHeaders(optionalPrivateToken),
})
.then(res => {
@ -55,18 +76,13 @@ function getContributorsPage(url, optionalPrivateToken) {
}
const getUserInfo = function(username, hostname, optionalPrivateToken) {
/* eslint-disable complexity */
if (!hostname) {
hostname = 'https://github.com'
}
if (!username) {
throw new Error(
`No login when adding a contributor. Please specify a username.`,
)
}
const root = hostname.replace(/:\/\//, '://api.')
const root = getApiHost(hostname)
return request
.get({
url: `${root}/users/${username}`,
@ -77,6 +93,16 @@ const getUserInfo = function(username, hostname, optionalPrivateToken) {
let profile = body.blog || body.html_url
// Check for authentication required
if (
(!profile && body.message.includes('Must authenticate')) ||
res.statusCode === 401
) {
throw new Error(
`Missing authentication for GitHub API. Did you set PRIVATE_TOKEN?`,
)
}
// Github throwing specific errors as 200...
if (!profile && body.message) {
throw new Error(
@ -96,13 +122,9 @@ const getUserInfo = function(username, hostname, optionalPrivateToken) {
}
const getContributors = function(owner, name, hostname, optionalPrivateToken) {
if (!hostname) {
hostname = 'https://github.com'
}
const root = hostname.replace(/:\/\//, '://api.')
const url = `${root}/repos/${owner}/${name}/contributors?per_page=100`
return getContributorsPage(url, optionalPrivateToken)
const root = getApiHost(hostname)
const contributorsUrl = `${root}/repos/${owner}/${name}/contributors?per_page=100`
return getContributorsPage(contributorsUrl, optionalPrivateToken)
}
module.exports = {