@ghuser/github-contribs
Advanced tools
Comparing version 0.0.2 to 1.0.0
22
cli.js
@@ -9,3 +9,3 @@ #!/usr/bin/env node | ||
const githubContribs = require('./'); | ||
const githubContribs = require('.'); | ||
@@ -29,11 +29,11 @@ const cli = meow(` | ||
`, { | ||
boolean: [ | ||
'quiet', | ||
'verbose', | ||
], | ||
string: [ | ||
'since', | ||
'until', | ||
], | ||
}); | ||
boolean: [ | ||
'quiet', | ||
'verbose', | ||
], | ||
string: [ | ||
'since', | ||
'until', | ||
], | ||
}); | ||
@@ -61,3 +61,3 @@ if (cli.flags.quiet && cli.flags.verbose) { | ||
} | ||
for (let repo of repos) { | ||
for (const repo of repos) { | ||
console.log(repo); | ||
@@ -64,0 +64,0 @@ } |
86
index.js
@@ -5,3 +5,3 @@ 'use strict'; | ||
const promisePool = require('es6-promise-pool'); | ||
const PromisePool = require('es6-promise-pool'); | ||
const fetch = require('fetch-retry'); | ||
@@ -14,6 +14,6 @@ const htmlparser = require('htmlparser'); | ||
return { | ||
start: function () { return this; }, | ||
stop: () => {}, | ||
succeed: () => {}, | ||
warn: () => {}, | ||
start() { return this; }, | ||
stop() {}, | ||
succeed() {}, | ||
warn() {}, | ||
}; | ||
@@ -30,7 +30,33 @@ }); | ||
const fetchRetry = url => { | ||
const tooManyRequests = 429; | ||
return fetch(url, { | ||
retryOn: [tooManyRequests], | ||
retries: 300, | ||
}); | ||
}; | ||
const getFirstDayAtGithub = async (user, ora) => { | ||
let urlSuffix = ''; | ||
if (process.env.GITHUB_CLIENT_ID && process.env.GITHUB_CLIENT_SECRET) { | ||
console.log('GitHub API key found.'); | ||
urlSuffix = `?client_id=${process.env.GITHUB_CLIENT_ID}&client_secret=${process.env.GITHUB_CLIENT_SECRET}`; | ||
} | ||
const firstDaySpinner = ora('Fetching first day at GitHub...').start(); | ||
const userInfo = await fetch(`https://api.github.com/users/${user}`); | ||
const userInfoJson = await userInfo.json(); | ||
let error = false; | ||
let userInfoJson; | ||
try { | ||
const userInfo = await fetchRetry(`https://api.github.com/users/${user}${urlSuffix}`); | ||
userInfoJson = await userInfo.json(); | ||
} catch (_) { | ||
// This error handling should be the least verbose possible in order not to leak the API key | ||
// by just having the URL printed. | ||
error = true; | ||
} | ||
if (error || !userInfoJson.created_at) { | ||
firstDaySpinner.stop(); | ||
throw new Error('Failed to fetch first day at GitHub.'); | ||
} | ||
@@ -50,12 +76,12 @@ const result = stringToDate(userInfoJson.created_at); | ||
for (let i = 0; i < handler.dom.length; ++i) { | ||
if (handler.dom[i].type == 'tag' && handler.dom[i].name == 'ul') { | ||
if (handler.dom[i].type === 'tag' && handler.dom[i].name === 'ul') { | ||
const ul = handler.dom[i].children; | ||
for (let j = 0; j < ul.length; ++j) { | ||
if (ul[j].type == 'tag' && ul[j].name == 'li') { | ||
if (ul[j].type === 'tag' && ul[j].name === 'li') { | ||
const li = ul[j].children; | ||
for (let k = 0; k < li.length; ++k) { | ||
if (li[k].type == 'tag' && li[k].name == 'div') { | ||
if (li[k].type === 'tag' && li[k].name === 'div') { | ||
const div = li[k].children; | ||
for (let l = 0; l < div.length; ++l) { | ||
if (div[l].type == 'tag' && div[l].name == 'a') { | ||
if (div[l].type === 'tag' && div[l].name === 'a') { | ||
const a = div[l].children[0].data; | ||
@@ -84,12 +110,12 @@ if (!a.includes(' ')) { | ||
for (let i = 0; i < handler.dom.length; ++i) { | ||
if (handler.dom[i].type == 'tag' && handler.dom[i].name == 'div') { | ||
if (handler.dom[i].type === 'tag' && handler.dom[i].name === 'div') { | ||
const div1 = handler.dom[i].children; | ||
for (let j = 0; j < div1.length; ++j) { | ||
if (div1[j].type == 'tag' && div1[j].name == 'div') { | ||
if (div1[j].type === 'tag' && div1[j].name === 'div') { | ||
const div2 = div1[j].children; | ||
for (let k = 0; k < div2.length; ++k) { | ||
if (div2[k].type == 'tag' && div2[k].name == 'button') { | ||
if (div2[k].type === 'tag' && div2[k].name === 'button') { | ||
const button = div2[k].children; | ||
for (let l = 0; l < button.length; ++l) { | ||
if (button[l].type == 'tag' && button[l].name == 'span') { | ||
if (button[l].type === 'tag' && button[l].name === 'span') { | ||
const span = button[l].children[0].data.trim(); | ||
@@ -133,15 +159,8 @@ if (span) { | ||
return (async () => { | ||
const tooManyRequests = 429; | ||
const fetchOptions = { | ||
retryOn: [tooManyRequests], | ||
retries: 300, | ||
}; | ||
const userCommits = await fetch( | ||
`https://github.com/users/${user}/created_commits?from=${currDateStr}&to=${currDateStr}`, | ||
fetchOptions | ||
const userCommits = await fetchRetry( | ||
`https://github.com/users/${user}/created_commits?from=${currDateStr}&to=${currDateStr}` | ||
); | ||
const userCommitsHtml = await userCommits.text(); | ||
const userPRs = await fetch( | ||
const userPRs = await fetchRetry( | ||
`https://github.com/users/${user}/created_pull_requests?from=${currDateStr}&to=${currDateStr}`, | ||
fetchOptions | ||
); | ||
@@ -152,7 +171,7 @@ const userPRsHtml = await userPRs.text(); | ||
progressSpinner.stop(); // temporary stop for logging | ||
for (let repo of commitsRepos) { | ||
for (const repo of commitsRepos) { | ||
console.log(`${currDateStr}: (commits) ${repo}`); | ||
result.add(repo); | ||
} | ||
for (let repo of prsRepos) { | ||
for (const repo of prsRepos) { | ||
console.log(`${currDateStr}: (PRs) ${repo}`); | ||
@@ -166,3 +185,3 @@ result.add(repo); | ||
const numOfDaysToQuery = (newestDate - oldestDate) / (24 * 60 * 60 * 1000) + 1; | ||
const numOfDaysToQuery = ((newestDate - oldestDate) / (24 * 60 * 60 * 1000)) + 1; | ||
@@ -178,3 +197,3 @@ const durationMsToQueryADay = 3500; | ||
const progressSpinner = ora('Fetching all commits and PRs...').start(); | ||
await new promisePool(getContribsOnOneDay, 5).start(); | ||
await new PromisePool(getContribsOnOneDay, 5).start(); | ||
progressSpinner.succeed('Fetched all commits and PRs.'); | ||
@@ -184,8 +203,7 @@ return result; | ||
// See https://stackoverflow.com/a/28431880/1855917 | ||
const stringToDate = (string) => { | ||
const stringToDate = string => { | ||
return new Date(`${string.substring(0, 10)}T00:00:00Z`); | ||
}; | ||
const dateToString = (date) => { | ||
const dateToString = date => { | ||
return date.toISOString().substring(0, 10); | ||
@@ -195,6 +213,6 @@ }; | ||
// See https://stackoverflow.com/a/25114400/1855917 | ||
const prevDay = (date) => { | ||
return new Date(date.getTime() - 24 * 60 * 60 * 1000); | ||
const prevDay = date => { | ||
return new Date(date.getTime() - (24 * 60 * 60 * 1000)); | ||
}; | ||
})(); |
{ | ||
"name": "@ghuser/github-contribs", | ||
"version": "0.0.2", | ||
"version": "1.0.0", | ||
"description": "List all GitHub repos a user has contributed to since the beginning of time.", | ||
@@ -20,3 +20,3 @@ "license": "Unlicense", | ||
"scripts": { | ||
"test": "xo && ava" | ||
"test": "xo && nyc ava" | ||
}, | ||
@@ -43,7 +43,37 @@ "keywords": [ | ||
"ava": "*", | ||
"codecov": "^3.0.2", | ||
"nyc": "^12.0.2", | ||
"xo": "*" | ||
}, | ||
"xo": { | ||
"esnext": true | ||
"esnext": true, | ||
"rules": { | ||
"brace-style": "off", | ||
"capitalized-comments": "off", | ||
"comma-dangle": "off", | ||
"indent": "off", | ||
"max-depth": "off", | ||
"max-params": "off", | ||
"no-unused-vars": "off", | ||
"no-use-before-define": "off", | ||
"no-warning-comments": "off", | ||
"padded-blocks": "off", | ||
"spaced-comment": "off", | ||
"unicorn/explicit-length-check": "off" | ||
}, | ||
"space": true | ||
}, | ||
"nyc": { | ||
"reporter": [ | ||
"html", | ||
"lcov", | ||
"text" | ||
], | ||
"all": true, | ||
"extension": [ | ||
".js" | ||
], | ||
"check-coverage": true, | ||
"lines": 80 | ||
} | ||
} |
@@ -1,3 +0,7 @@ | ||
[![npm version](https://img.shields.io/npm/v/@ghuser/github-contribs.svg)](https://www.npmjs.com/package/@ghuser/github-contribs) | ||
[![Build Status](https://travis-ci.org/AurelienLourot/github-contribs.svg?branch=master)](https://travis-ci.org/AurelienLourot/github-contribs) | ||
[![Coverage Status](https://codecov.io/gh/AurelienLourot/github-contribs/branch/master/graph/badge.svg)](https://codecov.io/gh/AurelienLourot/github-contribs) | ||
[![npm version](https://rawgit.com/AurelienLourot/github-contribs/master/thirdparty/badges/npm.svg)](https://www.npmjs.com/package/@ghuser/github-contribs) | ||
[<img src="https://rawgit.com/AurelienLourot/github-contribs/master/thirdparty/octicons/repo.svg" align="left" width="64" height="64">](https://github.com/AurelienLourot/github-contribs) | ||
# github-contribs | ||
@@ -8,3 +12,4 @@ | ||
* not just the last few months, | ||
* not just the repos owned by the user or their organisations. | ||
* not just the repos owned by the user or their organisations, | ||
* simply all repos a user has ever pushed to. | ||
@@ -23,2 +28,4 @@ ```bash | ||
⇒ [Advanced usage](https://github.com/AurelienLourot/github-contribs/tree/master/docs/advanced.md) | ||
## Installation | ||
@@ -78,2 +85,5 @@ | ||
**1.0.0** (2018-06-11): | ||
* Support for passing a GitHub API key. | ||
**0.0.2** (2018-05-29): | ||
@@ -80,0 +90,0 @@ * Cosmetic improvements to the [npm page](https://www.npmjs.com/package/@ghuser/github-contribs). |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
14883
234
1
91
1
4
4