Skip to content

Commit 9324e5c

Browse files
committed
feat: added config file support.
1 parent 3d5d85b commit 9324e5c

File tree

5 files changed

+147
-6
lines changed

5 files changed

+147
-6
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
node_modules
2+
config.json
23
data

config.json.example

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"token": "123435abcdf",
3+
"repos": [{
4+
"login": "mntnr",
5+
"repo": "name-your-contributors",
6+
"before": "2017-11-30",
7+
"after": "2017-06-01"
8+
}, {
9+
"login": "mntnr",
10+
"repo": "whodidwhat"
11+
}],
12+
"orgs": [{
13+
"login": "adventure-js",
14+
"after": "2017-07-01"
15+
}]
16+
}

readme.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,57 @@ $ export GITHUB_TOKEN={your-token}
7979
$ name-your-contributors -u mntnr -r name-your-contributors
8080

8181
$ name-your-contributors -o ipfs -a 2017-01-01 > ipfs-contrib.json
82+
83+
$ name-your-contributors --config config.json > combined-out.json
84+
```
85+
86+
### Config File
87+
88+
For batching convenience, Name Your Contributors takes a config file which
89+
specifies a token, a list of repos, and a list of orgs to grab. The
90+
`config.json.example` is an outline of this file format:
91+
92+
```json
93+
{
94+
"token": "123435abcdf",
95+
"repos": [{
96+
"login": "mntnr",
97+
"repo": "name-your-contributors",
98+
"before": "2017-11-30",
99+
"after": "2017-06-01"
100+
}, {
101+
"login": "mntnr",
102+
"repo": "whodidwhat"
103+
}],
104+
"orgs": [{
105+
"login": "adventure-js",
106+
"after": "2017-07-01"
107+
}]
108+
}
109+
```
110+
111+
A token passed in the config file will override any token present in the
112+
environment.
113+
114+
The output when passed a config file is a mirror of the config file with the
115+
token removed and a `contributions` key added to each object, like so:
116+
117+
```json
118+
{
119+
"repos": [{
120+
"login": "mntnr",
121+
"repo": "name-your-contributors",
122+
"before": "2017-11-30",
123+
"after": "2017-06-01",
124+
"contributions" : {
125+
"commitAuthors": [...],
126+
"commitCommentators: [...],
127+
,,,
128+
},
129+
...
130+
}],
131+
"orgs": [...]
132+
}
82133
```
83134

84135
The output will be in the format:

src/cli.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ const cli = meow([`
1616
-r, --repo - Repository to search
1717
-t, --token - GitHub auth token to use
1818
-u, --user - User to which repository belongs
19+
--config - Operate from config file. In this mode only token, verbose, and
20+
debug flags apply.
1921
2022
Authentication
2123
This script looks for an auth token in the env var GITHUB_TOKEN. Make sure
@@ -25,6 +27,8 @@ const cli = meow([`
2527
$ name-your-contributors -r ipfs -u ipfs --after=2016-01-15T00:20:24Z --before=2016-01-20T00:20:24Z
2628
2729
$ name-your-contributors -o ipfs -a 2017-01-01 > ipfs-contrib-2017.json
30+
31+
$ name-your-contributors --config config.json > combined-out.json
2832
`], {
2933
alias: {
3034
a: 'after',
@@ -43,7 +47,7 @@ const token = cli.flags.t || process.env.GITHUB_TOKEN
4347
const after = cli.flags.a ? new Date(cli.flags.a) : new Date(0)
4448
const before = cli.flags.b ? new Date(cli.flags.b) : new Date()
4549

46-
if (!token) {
50+
if (!token && !cli.flags.config) {
4751
console.error('A token is needed to access the GitHub API. Please provide one with -t or the GITHUB_TOKEN environment variable.')
4852
process.exit(1)
4953
}
@@ -76,7 +80,17 @@ const callWithDefaults = (f, opts) => {
7680
const fetchRepo = (user, repo) =>
7781
callWithDefaults(main.repoContributors, {user, repo})
7882

79-
if (cli.flags.o) {
83+
if (cli.flags.config) {
84+
main.fromConfig({
85+
file: cli.flags.config,
86+
token,
87+
verbose: cli.flags.v,
88+
debug: cli.flags.debug,
89+
dryRun: cli.flags.dryRun
90+
}).then(x => JSON.stringify(x, null, 2))
91+
.then(handleOut)
92+
.catch(handleError)
93+
} else if (cli.flags.o) {
8094
callWithDefaults(main.orgContributors, {orgName: cli.flags.o})
8195
} else if (cli.flags.u && cli.flags.r) {
8296
fetchRepo(cli.flags.u, cli.flags.r)

src/index.js

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const graphql = require('./graphql')
44
const queries = require('./queries')
55
const csv = require('csv-writer').createArrayCsvStringifier
66
const exec = require('child_process').exec
7+
const fs = require('fs')
78

89
//
910
// Shell Helpers
@@ -65,6 +66,9 @@ const verifyResultHasKey = (key, query) =>
6566
}
6667
}
6768

69+
//
70+
// Config File Parsing
71+
6872
//
6973
// API
7074
//
@@ -76,14 +80,14 @@ const verifyResultHasKey = (key, query) =>
7680
* @param before - only return contributions before this timestamp
7781
* @param after - only return contributions after this timestamp
7882
*/
79-
const repoContributors = (
80-
{token, user, repo, before, after, debug, dryRun, verbose}) =>
83+
const repoContributors =
84+
({token, user, repo, before, after, debug, dryRun, verbose}) =>
8185
graphql.executequery({
8286
token,
8387
debug,
8488
dryRun,
8589
verbose,
86-
name: 'repoContributors',
90+
name: `repoContributors: ${user}/${repo}`,
8791
query: queries.repository(repo, user, before, after)
8892
}).then(verifyResultHasKey('repository', user + '/' + repo))
8993
.then(json => {
@@ -106,7 +110,7 @@ const orgContributors = ({token, orgName, before, after, debug, dryRun, verbose}
106110
debug,
107111
dryRun,
108112
verbose,
109-
name: 'orgContributors',
113+
name: `orgContributors: ${orgName}`,
110114
query: queries.orgRepos(orgName, before, after)
111115
}).then(verifyResultHasKey('organization', orgName))
112116
.then(data => {
@@ -117,6 +121,60 @@ const orgContributors = ({token, orgName, before, after, debug, dryRun, verbose}
117121
}
118122
})
119123

124+
/** Returns all contributions to repos and orgs specified in `file`
125+
* @param token - GitHub auth token
126+
* @param file - Config file path
127+
*/
128+
const fromConfig = async ({token, file, verbose, debug, dryRun}) => {
129+
const config = JSON.parse(fs.readFileSync(file))
130+
const ght = config.token || token
131+
if (!ght) {
132+
throw new Error('No token specified in config or arguments. Aborting.')
133+
}
134+
const repoResults = config.repos.map(({login, repo, before, after}) => {
135+
const afterDate = after ? new Date(after) : new Date(0)
136+
const beforeDate = before ? new Date(before) : new Date()
137+
138+
return repoContributors({
139+
token: ght,
140+
user: login,
141+
repo,
142+
before: beforeDate,
143+
after: afterDate,
144+
debug,
145+
dryRun,
146+
verbose
147+
})
148+
})
149+
150+
const orgResults = config.orgs.map(({login, before, after}) => {
151+
const afterDate = after ? new Date(after) : new Date(0)
152+
const beforeDate = before ? new Date(before) : new Date()
153+
return orgContributors({
154+
orgName: login,
155+
before: beforeDate,
156+
after: afterDate,
157+
token: ght,
158+
verbose,
159+
debug,
160+
dryRun
161+
})
162+
})
163+
164+
return {
165+
repos: (await Promise.all(repoResults)).map((result, index) => {
166+
const repo = config.repos[index]
167+
repo.contributions = result
168+
return repo
169+
}),
170+
orgs: (await Promise.all(orgResults)).map((result, index) => {
171+
const org = config.orgs[index]
172+
org.contributions = result
173+
return org
174+
})
175+
}
176+
}
177+
120178
/** Returns the login of the user to whom the given token is registered.
121179
* @param token - GitHub Auth token
122180
*/
@@ -128,6 +186,7 @@ const currentUser = token =>
128186

129187
module.exports = {
130188
toCSV,
189+
fromConfig,
131190
parseGitURL,
132191
getCurrentRepoInfo,
133192
currentUser,

0 commit comments

Comments
 (0)