Skip to content

Instantly share code, notes, and snippets.

@renatorib
Created August 29, 2018 01:38
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 renatorib/06c9da4d96cfbb7eb852ce856fea69fc to your computer and use it in GitHub Desktop.
Save renatorib/06c9da4d96cfbb7eb852ce856fea69fc to your computer and use it in GitHub Desktop.
extract github followers
outputs/*
config.js
// if goes to public git repository
// this file must be ignored by .gitignore
module.exports = {
github_token: "xxx"
};
const Promise = require("bluebird");
const fetch = require("node-fetch");
const mkdirp = require("mkdirp");
const fs = require("fs");
const path = require("path");
const keys = require("./config");
// file utils
const saveTo = (
filePath,
data,
parse = data => JSON.stringify(data, null, 2)
) => {
const to = path.resolve(`${path.dirname(require.main.filename)}/${filePath}`);
mkdirp(path.dirname(to));
return new Promise((resolve, reject) => {
fs.writeFile(to, parse(data), "utf8", () => resolve(to));
});
};
// graphql utils
const repoFollowersQuery = `
query RepoFollowers($first: Int!, $after: String, $repoOwner: String!, $repoName: String!) {
repository(owner: $repoOwner, name: $repoName) {
stargazers(first: $first, after: $after) {
edges {
cursor
node {
login
name
followers {
totalCount
}
}
}
}
}
}
`;
const fetchQuery = (query, variables = {}) =>
fetch("https://api.github.com/graphql", {
body: JSON.stringify({ query, variables }),
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
Authorization: `bearer ${keys.github_token}`
}
}).then(r => r.json());
const fetchAllByCursor = (query, variables, getAfterCursorFromData) => {
const responses = [];
const recursiveFetchQuery = (query, variables) =>
fetchQuery(query, variables).then(res => {
const { data, errors } = res;
responses.push(res);
if (errors) {
return Promise.resolve(responses);
} else {
const after = getAfterCursorFromData(data);
if (!after) {
return Promise.resolve(responses);
}
const nextVariables = { ...variables, after };
return recursiveFetchQuery(query, nextVariables);
}
});
return recursiveFetchQuery(query, variables);
};
/* extract data logic */
const getEdgeData = ({ node: { name, login, followers } }) => ({
name,
login,
followers: followers.totalCount
});
const getFollowersStargazersData = repo => {
const [repoOwner, repoName] = repo.split("/");
const first = 100;
let looptime = 1;
fetchAllByCursor(repoFollowersQuery, { first, repoOwner, repoName }, data => {
console.log(
`Fetching more ${first}. Total fetched range: ${looptime * first}`
);
const edges = data.repository.stargazers.edges;
if (!edges.length) return false;
looptime++;
return edges[edges.length - 1].cursor;
})
// pick data
.then(responses =>
responses.reduce(
(acc, res) => [
...acc,
...res.data.repository.stargazers.edges.map(getEdgeData)
],
[]
)
)
// sort data by followers
.then(data => [...data].sort((a, b) => b.followers - a.followers))
// save data to json
.then(data => {
saveTo(`./outputs/${repoOwner}.${repoName}.json`, data).then(fullPath =>
console.log(`Done! Saved to ${fullPath}`)
);
});
};
getFollowersStargazersData(process.argv[2]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment