From b447fcefdf069b80cbcabca6be0d86d56b0cebf4 Mon Sep 17 00:00:00 2001 From: Thomas Getgood Date: Thu, 19 Oct 2017 18:38:09 -0400 Subject: [PATCH] feat: commit authors now included in results. --- src/cli.js | 4 +-- src/graphql.js | 2 +- src/index.js | 4 +-- src/queries.js | 68 +++++++++++++++++++++++++++++++++++----- test/integration-test.js | 14 ++++++--- 5 files changed, 75 insertions(+), 17 deletions(-) diff --git a/src/cli.js b/src/cli.js index 33dae5a..ada73ca 100755 --- a/src/cli.js +++ b/src/cli.js @@ -56,8 +56,8 @@ const cli = meow([` const token = cli.flags.t || process.env.GITHUB_TOKEN -const after = cli.flags.a && new Date(cli.flags.a) -const before = cli.flags.b && new Date(cli.flags.b) +const after = cli.flags.a && new Date(cli.flags.a) || new Date(0) +const before = cli.flags.b && new Date(cli.flags.b) || new Date() const debugMode = cli.flags.debug diff --git a/src/graphql.js b/src/graphql.js index e1081f0..f673e0f 100644 --- a/src/graphql.js +++ b/src/graphql.js @@ -17,7 +17,7 @@ const argsString = args => { return '' } else { const s = keys.map(k => { - return encodeURIComponent(k) + ': ' + escapeArgValue(args[k]) + ',' + return k + ': ' + escapeArgValue(args[k]) + ',' }).reduce((acc, next) => acc + next, '') return '(' + s.substr(0, s.length - 1) + ')' } diff --git a/src/index.js b/src/index.js index a499a20..ec10d96 100644 --- a/src/index.js +++ b/src/index.js @@ -11,7 +11,7 @@ const queries = require('./queries') * @param after - only return contributions after this timestamp */ const repoContributors = ({token, user, repo, before, after, debug}) => - graphql.executequery(token, queries.repository(repo, user), debug) + graphql.executequery(token, queries.repository(repo, user, before, after), debug) .then(json => queries.cleanRepo(token, json.repository, before, after)) /** Returns a list of names of all repos belonging to user. */ @@ -26,7 +26,7 @@ const userRepoNames = ({token, login, debug}) => * @param after - only return contributions after this timestamp */ const orgContributors = ({token, orgName, before, after, debug}) => - graphql.executequery(token, queries.orgRepos(orgName), debug) + graphql.executequery(token, queries.orgRepos(orgName, before, after), debug) .then(data => queries.cleanOrgRepos(token, data, before, after)) module.exports = { diff --git a/src/queries.js b/src/queries.js index 4be73e7..eae5f1a 100644 --- a/src/queries.js +++ b/src/queries.js @@ -11,14 +11,17 @@ const pagination = node('pageInfo') .addChild(node('endCursor')) .addChild(node('hasNextPage')) +const userInfo = node('user') + .addChild(node('login')) + .addChild(node('name')) + .addChild(node('url')) + const reactorQ = node('reactions', {first: 10}) .addChild(pagination) .addChild(node('nodes') + .addChild(node('id')) .addChild(node('createdAt')) - .addChild(node('user') - .addChild(node('login')) - .addChild(node('name')) - .addChild(node('url')))) + .addChild(userInfo)) const authoredQ = node('nodes') .addChild(node('id')) @@ -29,6 +32,30 @@ const authoredQ = node('nodes') .addChild(node('url')))) .addChild(node('createdAt')) +const commitAuthorQ = node('author').addChild(userInfo) + +const commitHistoryQ = node('nodes') + .addChild(node('id')) + .addChild(commitAuthorQ) + +const commitQ = (before, after) => { + const b = before.toISOString() + const a = after.toISOString() + return node('nodes') + .addChild(node('id')) + .addChild(node('target') + .addChild(node('id')) + .addChild(node('... on Commit') + .addChild( + node('history', {first: 100, since: a, until: b}) + .addChild(pagination) + .addChild(commitHistoryQ)))) +} + +const refsQ = (before, after) => node('refs', {first: 100, refPrefix: 'refs/heads/'}) + .addChild(pagination) + .addChild(commitQ(before, after)) + const authoredWithReactionsQ = authoredQ .addChild(reactorQ) @@ -55,10 +82,11 @@ const commitCommentQ = node('commitComments', {first: 100}) .addChild(authoredQ) /** Returns a query to retrieve all contributors to a repo */ -const repository = (repoName, ownerName) => +const repository = (repoName, ownerName, before, after) => node('repository', {name: repoName, owner: ownerName}) .addChild(node('id')) .addChild(commitCommentQ) + .addChild(refsQ(before, after)) .addChild(prsQ) .addChild(issuesQ) @@ -68,15 +96,18 @@ const organization = name => .addChild(node('id')) .addChild(node('repositories', {first: 100}, pagination) .addChild(node('nodes') + .addChild(node('id')) .addChild(node('name')))) -const orgRepos = name => +const orgRepos = (name, before, after) => node('organization', {login: name}) .addChild(node('id')) .addChild(node('repositories', {first: 25}) .addChild(pagination) .addChild(node('nodes') .addChild(node('id')) + .addChild(commitCommentQ) + .addChild(refsQ(before, after)) .addChild(prsQ) .addChild(issuesQ))) @@ -126,7 +157,7 @@ const fetchAll = async ({token, acc, data, type, key, count, query}) => { * returns an array containing only those objects created between before and * after. */ -const timeFilter = (before = new Date(), after = new Date(0)) => +const timeFilter = (before, after) => data => data.filter(x => { const date = new Date(x.createdAt) return after <= date && date <= before @@ -199,6 +230,28 @@ const cleanRepo = async (token, result, before, after) => { const tf = timeFilter(before, after) const process = x => mergeContributions(users(tf(x))) + const branches = await fetchAll({ + token, + acc: result.refs.nodes, + data: result, + type: 'Repository', + key: 'refs', + count: 100, + query: commitQ(before, after) + }) + + const targets = Array.from(branches).map(b => b.target) + + const commits = await depaginateAll(targets, { + token, + acc: ref => ref.history.nodes, + type: 'Commit', + key: 'history', + query: commitHistoryQ + }) + + const commitAuthors = Array.from(commits).map(x => x.author) + const prs = await fetchAll({ token, acc: result.pullRequests.nodes, @@ -286,6 +339,7 @@ const cleanRepo = async (token, result, before, after) => { })) return { + commitAuthors: mergeContributions(users(commitAuthors)), commitCommentators: process(commitComments), prCreators: process(prs), prCommentators: process(prComments), diff --git a/test/integration-test.js b/test/integration-test.js index ef34754..fa3ae57 100644 --- a/test/integration-test.js +++ b/test/integration-test.js @@ -37,12 +37,13 @@ test('No contributions in a single second', t => { token: token, user: 'RichardLitt', repo: 'name-your-contributors', - after: '2016-01-01T15:21:08.104Z', - before: '2016-01-02T15:21:08.104Z' + after: new Date('2016-01-01T15:21:08.104Z'), + before: new Date('2016-01-02T15:21:08.104Z') }).then(result => { for (let key in result) { t.deepEqual(result[key], []) - }}) + } + }) }) const compareKeys = (x, k) => @@ -64,7 +65,8 @@ test('Contributors before a fixed date remain static', t => { token: token, user: 'RichardLitt', repo: 'name-your-contributors', - before: '2017-09-21' + before: new Date('2017-09-21'), + after: new Date(0) }).then(result => { t.true(compareKeys(result, 'prCreators')) t.true(compareKeys(result, 'prCommentators')) @@ -76,7 +78,9 @@ test('Contributors before a fixed date remain static', t => { test('Queries without tokens get rejected', t => { return main.repoContributors({ user: 'RichardLitt', - repo: 'name-your-contributors' + repo: 'name-your-contributors', + before: new Date(), + after: new Date(0) }).catch(error => t.is(error.message, 'Unauthorized')) })