Skip to content

Instantly share code, notes, and snippets.

@torgeir
Created September 26, 2018 15:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save torgeir/726ea7557dccefbba05eb5890e7694d6 to your computer and use it in GitHub Desktop.
Save torgeir/726ea7557dccefbba05eb5890e7694d6 to your computer and use it in GitHub Desktop.
Lookup various github stats from npm package name; stars, contributors, open issues/prs etc.
const r2 = require("r2");
const npm = require("npm");
const { spawn } = require("child_process");
const [_, __, accessToken, repo] = process.argv;
const shellCmdStdoutToObject = (cmd, args) =>
new Promise(function(resolve, reject) {
const child = spawn(cmd, args);
let result = "";
child.stdout.on("data", data => {
result += data;
});
child.stderr.on("data", data => {
reject(new Error(`Error running cmd "${cmd}" with args "${args}".`));
});
child.on("close", code => {
const fn = new Function(`return ${result.replace(/\r?\n/g, "")}`);
resolve(fn());
});
});
const appendToken = url =>
url + (url.indexOf("?") > 0 ? "&" : "?") + "access_token=" + accessToken;
const urlToProject = url => {
const split = url.split("/");
return (
split[split.length - 2] + "/" + split[split.length - 1].replace(".git", "")
);
};
const projectToRepoUrl = p => `https://api.github.com/repos/${p}`;
const fetchRepo = repo =>
shellCmdStdoutToObject("npm", ["view", repo, "repository"])
.then(result => result.url)
.then(urlToProject)
.then(projectToRepoUrl)
.then(appendToken)
.then(r2)
.then(o => o.json);
const parseParams = params =>
params
.split("&")
.map(keyValue => keyValue.split("="))
.reduce((acc, [key, value]) => {
acc[key] = value;
return acc;
}, {});
const fetchLastPageNoFor = async (url, params = "") => {
const pagedUrl = `${url}?per_page=1${params}`;
const res = await r2(appendToken(pagedUrl)).response;
const link = res.headers.get("link");
if (!link) {
const body = await res.json();
return body.length;
}
const [n] = link
.split(",")
.filter(link => link.indexOf('rel="last"') != -1)
.map(link => link.replace('>; rel="last"', ""))
.map(link => link.split("?")[1])
.map(parseParams)
.map(query => query.page)
.map(Number);
return n;
};
const fetchRepoStats = async repoName => {
const r = await fetchRepo(repoName);
const commits = fetchLastPageNoFor(r.commits_url.replace("{/sha}", "")),
contributors = fetchLastPageNoFor(r.contributors_url),
openPullRequests = fetchLastPageNoFor(r.pulls_url.replace("{/number}", "")),
closedPullRequests = fetchLastPageNoFor(
r.pulls_url.replace("{/number}", ""),
"&state=closed"
);
return {
url: r.html_url,
repo: r.full_name,
createdAt: r.created_at,
stars: r.stargazers_count,
openIssues: r.open_issues,
watchers: r.subscribers_count,
commits: await commits,
contributors: await contributors,
openPullRequests: await openPullRequests,
closedPullRequests: await closedPullRequests
};
};
(async () => console.log(await fetchRepoStats(repo)))();
➜ node-dependencies node dependency-stats <token> cerebral
{ url: 'https://github.com/cerebral/cerebral',
repo: 'cerebral/cerebral',
createdAt: '2015-05-09T11:40:05Z',
stars: 1634,
openIssues: 34,
watchers: 63,
commits: 2120,
contributors: 67,
openPullRequests: 1,
closedPullRequests: 936 }
➜ node-dependencies node dependency-stats <token> react
{ url: 'https://github.com/facebook/react',
repo: 'facebook/react',
createdAt: '2013-05-24T16:15:54Z',
stars: 112010,
openIssues: 382,
watchers: 6369,
commits: 10306,
contributors: 446,
openPullRequests: 96,
closedPullRequests: 7148 }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment