jabbar
Version:
Find out who is interested in your code
326 lines (305 loc) • 8.18 kB
JavaScript
const { graphql } = require('@octokit/graphql')
const _ = require('lodash')
const token = process.env.GITHUB_TOKEN
const isGitHubUserOrOrg = require('is-github-user-or-org')
const graphqlt = graphql.defaults({
headers: {
authorization: `token ${token}`
}
})
// Small helper function
function timeout (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
// Remove nodes and make the gql object easier to parse
function clean (arr) {
return arr.map(x => {
let newObj = x.node
if (x.starredAt) {
newObj.starredAt = x.starredAt
}
newObj.organizationsTotalCount = newObj.organizations.totalCount
newObj.organizations = newObj.organizations.edges.map(y => {
return y.node
})
return newObj
})
}
// Note: This only works if the object for a 3-deep list of type { obj: field: edge }
async function paginate3DepthEdge (query, obj, path) {
// If there are pages, recursively concatinate res to the resulting object
let result = await graphqlt(query)
obj[path].edges = obj[path].edges.concat(result['repository'][path].edges)
obj[path].pageInfo = result['repository'][path].pageInfo
if (obj[path].pageInfo.hasNextPage) {
query.endCursor = obj[path].pageInfo.endCursor
await timeout(1000) // Let's be nice.
obj = await paginate3DepthEdge(query, obj, path)
}
return obj
}
// Getting watchers and stargazers are basically the same, hence this wrapper.
const getRepoInteractorsWrapper = async function (query, interactors) {
try {
let { repository } = await graphqlt(query)
if (repository[interactors].pageInfo.hasNextPage) {
query.endCursor = repository[interactors].pageInfo.endCursor
repository = await paginate3DepthEdge(query, repository, interactors)
}
return repository[interactors].edges
} catch (error) {
console.log('Request failed:', error.request)
console.log(error.message)
}
}
const getUser = async function (user) {
let query = {
query: `query user($login:String!) {
user(login: $login) {
name
login
company
bio
websiteUrl
url
organizations(first: 100) {
totalCount
edges {
node {
name
login
url
description
websiteUrl
}
}
}
}
}`,
login: user
}
try {
return await graphqlt(query)
} catch (error) {
console.log('Request failed:', error.request)
console.log(error.message)
}
}
const getOrganization = async function (org) {
let query = {
query: `query organization($login:String!) {
organization(login: $login) {
name
login
websiteUrl
url
}
}`,
login: org
}
try {
return await graphqlt(query)
} catch (error) {
console.log('Request failed:', error.request)
console.log(error.message)
}
}
const getForkInformation = async function (owner, repo) {
let endCursor = null
let query = {
query: `query forks($owner: String!, $repo: String!, $endCursor: String) {
repository(name: $repo, owner: $owner) {
forks(first: 100, after: $endCursor) {
totalCount
edges {
node {
createdAt
forkCount
stargazers {
totalCount
}
watchers {
totalCount
}
owner {
login
}
}
}
pageInfo {
hasNextPage
endCursor
startCursor
}
}
}
}`,
repo: repo,
owner: owner,
endCursor: endCursor || null
}
let res = await getRepoInteractorsWrapper(query, 'forks')
res = res.map(async x => {
let newObj = x.node
let typeOfUser = await isGitHubUserOrOrg(newObj.owner.login)
await timeout(1000) // Let's be nice.
if (typeOfUser === 'User') {
newObj.owner = await getUser(newObj.owner.login)
} else {
newObj.owner = await getOrganization(newObj.owner.login)
}
await timeout(1000) // Let's be really nice.
return newObj
})
return Promise.all(res)
}
const getForkers = async function (owner, repo) {
const forks = await getForkInformation(owner, repo)
return forks.map(x => {
let newObj = (x.owner.user) ? x.owner.user : x.owner.organization
newObj.forkedAt = x.createdAt
if (x.owner.organization) {
newObj.organization = true
} else {
newObj.organizationsTotalCount = newObj.organizations.totalCount
newObj.organizations = newObj.organizations.edges.map(y => {
return y.node
})
}
return newObj
})
}
const getWatchers = async function (owner, repo) {
let endCursor = null
let query = {
query: `query watchers($owner: String!, $repo: String!, $endCursor: String) {
repository(name: $repo, owner: $owner) {
watchers(first: 100, after: $endCursor) {
totalCount
edges {
node {
name
login
company
bio
websiteUrl
url
organizations(first: 100) {
totalCount
edges {
node {
name
login
url
description
websiteUrl
}
}
}
}
}
pageInfo {
hasNextPage
endCursor
startCursor
}
}
}
}`,
repo: repo,
owner: owner,
endCursor: endCursor || null
}
return clean(await getRepoInteractorsWrapper(query, 'watchers'))
}
const getStargazers = async function (owner, repo) {
let endCursor = null
let query = {
query: `query stargazers($owner: String!, $repo: String!, $endCursor: String) {
repository(name: $repo, owner: $owner) {
stargazers(first: 100, after: $endCursor) {
totalCount
edges {
starredAt
node {
name
login
company
bio
websiteUrl
url
organizations(first: 100) {
totalCount
edges {
node {
name
login
url
description
websiteUrl
}
}
}
}
}
pageInfo {
hasNextPage
endCursor
startCursor
}
}
}
}`,
repo: repo,
owner: owner,
endCursor: endCursor || null
}
return clean(await getRepoInteractorsWrapper(query, 'stargazers'))
}
const getAllUsers = async function (owner, repo) {
let watchers = await getWatchers(owner, repo)
let stargazers = await getStargazers(owner, repo)
// TODO Add in allContributors or name-your-contributors output
// TODO Figure out how to add getForkers back in. Kept hitting abuse limits.
// Stargazers has more information due to the starredAt field
watchers.forEach(x => {
if (!_.find(stargazers, ['login', x.login])) {
stargazers.push(x)
}
})
return stargazers
}
const mostPopularOrgs = async function (arr, opts) {
let allOrgs = {}
arr
.filter(x => x.organizations)
.filter(x => opts.ignore.indexOf(x.login.toLowerCase()) === -1)
.forEach(x => {
// TODO x.company.stripOut('strings@`) and add them
x.organizations.forEach(o => {
if (!o.organization) {
if (!allOrgs[o.login]) {
allOrgs[o.login] = o
allOrgs[o.login].users = ['@' + x.login]
} else {
allOrgs[o.login].users.push('@' + x.login)
}
}
})
})
// Sort the list and remove orgs that only have one person
let sortedList = _.sortBy(allOrgs, [(o) => o.users.length])
.filter(o => o.users.length !== 1)
if (opts) {
sortedList = sortedList.filter(o => opts.ignore.indexOf(o.login.toLowerCase()) === -1)
}
return _.reverse(sortedList)
}
module.exports = {
getStargazers,
getWatchers,
getAllUsers,
getForkInformation,
getForkers,
mostPopularOrgs
}