Skip to content

Name your GitHub contributors; get commits, issues, and comments

License

Notifications You must be signed in to change notification settings

mntnr/name-your-contributors

Repository files navigation

name-your-contributors

npm version Build and Deploy Commitizen friendly

Name your GitHub contributors; get commits, issues, and comments

name-your-contributors gets all of the code reviewers, commenters, issue and PR creators from your organization or repo.

Table of Contents

Background

NYC started as a means of showing who has been active in a repository or an org over a certain period of time. Originally it was used to populate people for the IPFS newsletter - every week, I would run it again to show new contributions. GitHub doesn't count a lot of contributions as contributions, instead looking at commits alone. NYC looks at all of your community, and logs who did what.

It spits out to a JSON object, because that's the most portable system for using it elsewhere with the formatting you need. It also uses GraphQL to cut down on the amount of queries, as it is pretty intensive otherwise.

Contributors

These people have helped make Name Your Contributors:

Using the jq JSON parsing library (you can use your own), this list was autogenerated like this:

node src/cli.js -u mntnr -r name-your-contributors | jq '[ .[][].login | " - [@ \(.)](https://github.com/\(.))"]' | jq unique | jq -r .[]

Which is a whole lot more useful than manually looking for contributors!

Install

$ npm install --save name-your-contributors

API Limits and setting up a GitHub Token

You also need to get a GitHub Personal Access token, you can create one here. It needs to have the read:org and the user:email scopes in order to function properly. Name the token something informative: name-your-contributors is a good name.

Set the token with the variable name $GITHUB_TOKEN before running the script:

$ export GITHUB_TOKEN=ab34e...

You can also set the var automatically in every session by adding the above line to your .bashrc file in your home directory.

The cost of querying a repo is approximately the number of PRs + the number of issues + the number of comments with reactions (if querying reactions) + the number of commits / 100 (if querying commit log).

So in the simplest case it's simply the total number of issues and PRs in the repos being queried.

Caveats

GitHub regulates API traffic by a credit system. The limits are quite high; it's permitted to query hundreds of repos per hour using the repoContributors function, but some organisations have many hundreds of repos, and a single call to orgContributors could potentially exhaust your entire hourly quota. The WikiMedia Foundation is a good example of an org with way too many repos for this app to handle.

Unfortunately filtering by contributions before or after a given date has no effect on quota use, since the data still needs to be queried before it can be filtered.

For more details on rate limits, see https://developer.github.com/v4/guides/resource-limitations/.

Usage

From Code

const nyc = require('name-your-contributors')

nyc.repoContributors({
	token: process.env.GITHUB_TOKEN,
	user: 'mntnr',
	repo: 'name-your-contributors',
	before: new Date(),
	after: new Date(0)
}).then(
	//do something with the results
)

nyc.orgContributors({
	token: process.env.GITHUB_TOKEN,
	orgName: 'ipfs',
	before: '2017-01-01',
	after: '2016-01-01'
}).then(...)

From the Command Line

# Install the program
$ npm install -g name-your-contributors

# Make sure that a token is enabled - you can also save this in your .env
$ export GITHUB_TOKEN={your-token}

# Get all contributors to mntnr/name-your-contributors. Log to stdout.
$ name-your-contributors -u mntnr -r name-your-contributors

# Or, get all contributors to an org after a certain date, in a file
$ name-your-contributors -o ipfs -a 2017-01-01 > ipfs-contrib.json

# Use a config instead of specifying using CLI arguments - easier for repetitive use
$ name-your-contributors --config config.json > combined-out.json

# Print the help docs!
$ name-your-contributors --help

  Name your GitHub contributors; get commits, issues, and comments

  Usage
    $ name-your-contributors <input> [opts]

  Options
    -t, --token   - GitHub auth token to use
    -a, --after   - Get contributions after date
    -b, --before  - Get contributions before data

    -o, --org     - Search all repos within this organisation
    -r, --repo    - Repository to search
    -u, --user    - User to which repository belongs
    -c, --config  - Operate from config file. In this mode only token, verbose, and
                    debug flags apply.

    --full        - Returns the full tree of contributions rather than the default
                    synopsis.
    --csv         - Output data in CSV format

    --commits     - Get commit authors and comments from GitHub
    --local-dir   - If specified, this script will look for repos being queried in
                    the provided dir and read the commit log from them directly.
    --reactions   - Query reactions of comments as well.

    --wipe-cache  - Wipe local cache before starting query.

    -v, --verbose - Enable verbose logging
    --debug       - Enable extremely verbose logging
    --dry-run     - Check the cost of the query without executing it.

  Authentication
		This script looks for an auth token in the env var GITHUB_TOKEN. It needs
		to have the read:org and the user:email scopes in order to function
		properly. Make sure this var is set to a valid GitHub oauth token. To
		create one see:
		https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/
  Examples
    $ name-your-contributors -r ipfs -u ipfs --after=2016-01-15T00:20:24Z --before=2016-01-20T00:20:24Z

    $ name-your-contributors -o ipfs -a 2017-01-01 > ipfs-contrib-2017.json

    $ name-your-contributors --config config.json > combined-out.json

Config File

For batching convenience, Name Your Contributors takes a config file which specifies a token, a list of repos, and a list of orgs to grab. The config.json.example is an outline of this file format:

{
  "token": "123435abcdf",
  "repos": [{
	"login": "mntnr",
	"repo": "name-your-contributors",
	"before": "2017-11-30",
	"after": "2017-06-01"
  }, {
	"login": "mntnr",
	"repo": "whodidwhat"
  }],
  "orgs": [{
	"login": "adventure-js",
	"after": "2017-07-01"
  }]
}

A token passed in the config file will override any token present in the environment.

The output when passed a config file is a mirror of the config file with the token removed and a contributions key added to each object, like so:

{
  "repos": [{
	"login": "mntnr",
	"repo": "name-your-contributors",
	"before": "2017-11-30",
	"after": "2017-06-01",
	"contributions" : {
	  "commitAuthors": [...],
	  "commitCommentators": [...],
	  ,,,
	},
	...
  }],
  "orgs": [...]
}

The output will be in the format:

$ name-your-contributors -u mntnr -r name-your-contributors --after 2017-11-10

{
  "commitAuthors": [],
  "commitCommentators": [],
  "prCreators": [],
  "prCommentators": [
	{
	  "login": "RichardLitt",
	  "name": "Richard Littauer",
	  "url": "https://github.com/RichardLitt",
	  "count": 3
	},
	{
	  "login": "tgetgood",
	  "name": "Thomas Getgood",
	  "url": "https://github.com/tgetgood",
	  "count": 2
	}
  ],
  "issueCreators": [
	{
	  "login": "RichardLitt",
	  "name": "Richard Littauer",
	  "url": "https://github.com/RichardLitt",
	  "count": 1,
		"titles": [
			"Add example output to the README",
			"Get email for users"
		]
	}
  ],
  "issueCommentators": [
	{
	  "login": "tgetgood",
	  "name": "Thomas Getgood",
	  "url": "https://github.com/tgetgood",
	  "count": 1
	},
	{
	  "login": "RichardLitt",
	  "name": "Richard Littauer",
	  "url": "https://github.com/RichardLitt",
	  "count": 1
	}
  ],
  "reactors": [
	{
	  "login": "patcon",
	  "name": "Patrick Connolly",
	  "url": "https://github.com/patcon",
	  "count": 1
	}
  ],
  "reviewers": []
}

Result formats

Name Your Contributors offers 4 distinct result formats intended for different consumers.

Default

The default result format is an aggregate synopsis of all contributions in the given time window. This is the format in the examples above.

CSV

With the --csv flag provided at the command line, nyc will return the default info in CSV format rather than JSON.

Full Contribution Tree

If the --full flag is passed at the command line, then nyc will return the full tree of org->repo->pr->comment->reaction->author for all interactions in the given time window. This format is quite verbose, but invaluable if you want to know not only who contributed, but the details of every contribution made.

For example,

$ name-your-contributors -r name-your-contributors -u mntnr -b 2017-12-10 -a 2017-11-10 --full

will return (abbreviated):

{
  "repository": {
	"homepageUrl": "",
	"name": "name-your-contributors",
	"owner": {
	  "login": "mntnr"
	},
	"pullRequests": [
	  {
		"title": "Cli updates",
		"number": 43,
		"state": "MERGED",
		"author": {
		  "login": "tgetgood",
		  "name": "Thomas Getgood",
		  "url": "https://github.com/tgetgood"
		},
		"createdAt": "2017-10-26T19:48:39Z",
		"comments": [
		  {
			"author": {
			  "login": "RichardLitt",
			  "name": "Richard Littauer",
			  "url": "https://github.com/RichardLitt"
			},
			"createdAt": "2017-11-20T16:35:31Z"
		  },
		  {
			"author": {
			  "login": "tgetgood",
			  "name": "Thomas Getgood",
			  "url": "https://github.com/tgetgood"
			},
			"createdAt": "2017-11-21T21:05:15Z"
		  },
		  ...
		],
		"reviews": []
	  },
	  ...
	]
  }
}

Notice that the pull request above was created before the date passed to before. It is still included because comments made within it were created in the desired timeframe. If there had been no such comments, the PR would not be included.

Condensed

For an even more condensed output format which also allows filtering on given users, see the postprocessing script Who Did What.

API

orgContributors({orgName, token, before, after})

token

Type: string

Github auth token

org

Type: string

The organization to traverse. If no organization is provided, the script will find the username and repo for the local git repository and use that.

opts.after

Type: string Default value: new Date(0)

The ISO timestamp to get contributors after.

Any string that will be accepted by new Date("...") will work here as expected.

opts.before

Type: string Default value: new Date()

Get contributors from before this ISO timestamp.

repoContributors({user, repo, token, before, after})

opts.user

Type: string

Github user name to whom the repo belongs.

opts.repo

Type: string

Only traverse the given repository.

Development

There are several extra flags that are useful for development and diagnosing issues:

-v, --verbose prints out each query that is sent to the api along with its cost and the quota remaining after it is run.

--debug prints out each query sent to the server and the raw response. This is extremely verbose.

--dry-run prints the cost of the first query that would have been run without running it. Note that since the query isn't executed, follow up queries aren't possible. when used with the -c, --config option, dry runs the first query for each entry of the config file.

Contribute

Name Your Contributors is an open source project - we'd love you to contribute! Check out the Contributing document, and abide by the Code of Conduct.

License

MIT © 2018 Richard Littauer