jabbar
Version:
Find out who is interested in your code
186 lines (167 loc) • 6.34 kB
JavaScript
const meow = require('meow')
const main = require('./index')
const colors = require('colors')
const fs = require('fs')
const moment = require('moment')
const _ = require('lodash')
const cli = meow(`
Usage
$ jabbar <input> [--watchers|--stargazers]
Options
-r, --repo - Repository to search. Format: RichardLitt/jabbar
This flag is used as the default input.
--all - The default: get all watchers, stargazers, and forkers
-w, --watchers - Get watchers for a repository
-s, --stargazers - Get stargazers for a repository
-f, --forkers - Get forkers for a repository
--ignored - Ignore a user. Defaults to include owner of repository.
Use csv for multiple users.
-h, --help - Show this printout
--output <file> - Print the results to a file as JSON
Authentication
This script looks for an auth token in the env var GITHUB_TOKEN. It needs
to have the read:org scope in order to function properly. Make sure this
var is set to a valid GitHub OAuth token.
Examples
$ jabbar RichardLitt/jabbar
$ jabbar --repo RichardLitt/jabbar --watchers
$ jabbar RichardLitt/jabbar -w --output=results.json
# To pass an authentication token
$ GITHUB_TOKEN=sd2991s jabbar -r RichardLitt/jabbar -w
`, {
flags: {
repo: {
type: 'string',
alias: 'r'
},
watchers: {
type: 'boolean',
alias: 'w'
},
stargazers: {
type: 'boolean',
alias: 's'
},
forkers: {
type: 'boolean',
alias: 'f'
},
ignore: {
type: 'string'
},
help: {
type: 'boolean',
alias: 'h'
},
output: {
type: 'string'
}
}
})
const token = process.env.GITHUB_TOKEN
if (!token) {
console.error(`A token is needed to access the GitHub API.
Please provide one with the GITHUB_TOKEN environment variable.`)
process.exit(1)
}
// Validate repository name inputs
// Specify that the default flag is the repo flag
if (cli.input[0] && !cli.flags.r) {
cli.flags.r = cli.input[0]
} else if (cli.input.length === 0 && !cli.flags.r) {
console.error(`You must specify a repository to query.`)
process.exit(1)
}
// Note: this doesn't validate for more arcane errors, like Ric.ardLitt/10*sk.
cli.flags.r = cli.flags.r.split('/')
if (cli.flags.r.length !== 2) {
console.error(`The repository must be specified in the format: 'owner/repo'.`)
process.exit(1)
}
async function printNames (arr, opts) {
// Print to a file
if (cli.flags.output) {
if (!cli.flags.output.endsWith('.json')) {
cli.flags.output = cli.flags.output + '.json'
}
arr = arr.filter(x => opts.ignore.indexOf(x.login.toLowerCase()) === -1)
await fs.writeFileSync(cli.flags.output, JSON.stringify(arr, null, 2), 'utf8', (err) => {
if (err) throw err; console.log('There was an error saving the file.')
process.exit(1)
})
console.log(`The file has been saved to ${cli.flags.output}.`)
process.exit(0)
}
// Print to the CLI
let readableDate = 'YYYY MMMM Do, h:mma'
let emptyOrgs = arr
.filter(x => (x.organizationsTotalCount === 0 && !x.organization))
.filter(x => opts.ignore.indexOf(x.login.toLowerCase()) === -1)
console.log('These users have interacted with your repository:')
arr
.filter(x => x.organizationsTotalCount !== 0 && !x.organization)
.filter(x => opts.ignore.indexOf(x.login.toLowerCase()) === -1)
.forEach(x => {
console.log(`${colors.green('@' + x.login)}${(x.name) ? ` (${x.name})` : ''}${(x.company) ? `. Works at ${colors.blue(x.company.trimEnd())}.` : ''}
${x.url}`)
if (x.starredAt) { console.log(`Starred on: ${moment(x.starredAt).format(readableDate)}`) }
if (x.forkedAt) { console.log(`Forked on: ${moment(x.starredAt).format(readableDate)}`) }
console.log(`Public organizations:
${colors.blue('-')} ${x.organizations.map(y => `${colors.magenta(y.name)} (@${y.login}) ${y.url}`).join('\n - ')}
`)
})
if (emptyOrgs.length !== 0) {
let companyOnly = emptyOrgs.filter(x => x.company)
if (companyOnly.length !== 0) {
console.log(`And these users with only stated companies, but no public orgs:`)
companyOnly.forEach(x => {
console.log(`${colors.green('@' + x.login)}${(x.name) ? ` (${x.name})` : ''} - Works at ${colors.blue(x.company.trimEnd())}. ${x.url}`)
})
console.log(``) // Newline
}
let emptyAll = emptyOrgs.filter(x => !x.company)
if (emptyAll.length !== 0) {
console.log(`And ${colors.green(emptyAll.length)} ${colors.green('other users')} with no public org memberships or stated companies.`)
}
}
// Filter out the companies
let orgType = arr.filter(x => x.organization).filter(x => opts.ignore.indexOf(x.login.toLowerCase()) === -1)
if (orgType.length !== 0) {
console.log(`
These organizations forked your repository:`)
orgType.forEach(x => {
console.log(`${colors.green('@' + x.login)}${(x.name) ? ` (${x.name})` : ''}. ${x.url}`)
if (x.starredAt) { console.log(`Starred on: ${moment(x.starredAt).format(readableDate)}`) }
if (x.forkedAt) { console.log(`Forked on: ${moment(x.starredAt).format(readableDate)}`) }
})
}
let mostPopularOrgs = await main.mostPopularOrgs(arr, opts)
if (mostPopularOrgs.length !== 0) {
console.log(`
These organizations had ${colors.green('more than one')} person in them:`)
mostPopularOrgs.forEach(x => {
console.log(`${colors.blue('- **@' + x.login)}** (${x.url}): ${colors.magenta(x.users.sort().join(', '))}.`)
})
}
if (opts.ignore.length !== 0) {
console.log(`
These users were ignored: ${opts.ignore.join(', ')}.`)
}
}
(async () => {
let [owner, repo] = cli.flags.r
let ignoreList = _.uniq([owner]
.concat((cli.flags.ignore) ? cli.flags.ignore.split(',') : [])
.map(x => x.toLowerCase()))
if (cli.flags.w) {
printNames(await main.getWatchers(owner, repo), { ignore: ignoreList })
} else if (cli.flags.f) {
printNames(await main.getForkers(owner, repo), { ignore: ignoreList })
} else if (cli.flags.s) {
printNames(await main.getStargazers(owner, repo), { ignore: ignoreList })
} else {
printNames(await main.getAllUsers(owner, repo), { ignore: ignoreList })
}
})()