Skip to content

Instantly share code, notes, and snippets.

@Eomm
Last active December 5, 2024 10:02
Show Gist options
  • Save Eomm/8713b946c1991e5bd0733b9e562f6950 to your computer and use it in GitHub Desktop.
Save Eomm/8713b946c1991e5bd0733b9e562f6950 to your computer and use it in GitHub Desktop.
import { graphql } from "@octokit/graphql";
import { writeFileSync } from "fs";
// GitHub token for authentication
const TOKEN = process.env.GH_TOKEN;
// Main function to fetch organization data
(async function fetchOrgData () {
try {
const orgName = "fastify";
// Step 1: Get the organization ID
const orgId = await getOrgId(orgName);
console.log(`Organization ID: ${orgId}`);
// Step 2: Get the organization members
const membersData = await getOrgMembers(orgId, orgName);
writeFileSync('./membersData.json', JSON.stringify(membersData, null, 2))
console.log(`Total members: ${membersData.length}`);
// Step 3: Filter the organization members and search for older contributions
const membersWithoutContribInLastYear = membersData.filter(item => !item.lastPR && !item.lastIssue && !item.lastCommit);
writeFileSync('./membersWithoutContribInLastYear.json', JSON.stringify(membersWithoutContribInLastYear, null, 2))
const oldContributors = await getOlderContributions(orgId, membersWithoutContribInLastYear);
const emeritus = oldContributors.filter(item => !item.lastPR && !item.lastIssue && !item.lastCommit);
console.log(`Emeritus members: ${emeritus.length}`);
// Write filtered members data to a file
writeFileSync("emeritus.json", JSON.stringify(emeritus, null, 2));
} catch (error) {
console.error("Error fetching organization data:", error);
}
})();
// Function to configure graphql with authentication headers
function graphqlWithAuth (query, variables) {
return graphql.defaults({
headers: {
authorization: `token ${TOKEN}`,
},
})(query, variables);
}
// Function to get the organization ID
async function getOrgId (orgName) {
const orgQuery = `
query ($orgName:String!) {
organization(login: $orgName) {
id
}
}
`;
const orgResponse = await graphqlWithAuth(orgQuery, { orgName });
return orgResponse.organization.id;
}
// Function to get the organization members
async function getOrgMembers (orgId, orgName) {
let cursor = null;
let hasNextPage = true;
const membersData = [];
while (hasNextPage) {
const membersQuery = `
query ($cursor: String, $orgName: String!, $orgId: ID) {
organization(login: $orgName) {
membersWithRole(first: 15, after: $cursor) {
edges {
node {
login
name
contributionsCollection(
organizationID: $orgId
from: "2024-01-01T00:00:00Z"
to: "2024-12-31T23:59:59Z"
) {
pullRequestContributions(last: 1, orderBy: {direction: ASC}) {
nodes {
occurredAt
pullRequest {
url
}
}
}
issueContributions(last: 1, orderBy: {direction: ASC}) {
nodes {
occurredAt
issue {
url
}
}
}
commitContributionsByRepository(maxRepositories: 1) {
contributions(last: 1, orderBy: {direction: ASC, field: OCCURRED_AT}) {
nodes {
repository {
name
}
occurredAt
url
}
}
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
`;
const variables = { cursor, orgId, orgName };
const membersResponse = await graphqlWithAuth(membersQuery, variables);
const members = membersResponse.organization.membersWithRole.edges;
membersData.push(...members.map(normalizeMember));
cursor = membersResponse.organization.membersWithRole.pageInfo.endCursor;
hasNextPage = membersResponse.organization.membersWithRole.pageInfo.hasNextPage;
}
return membersData;
}
// Since pullRequestContributions accpets only 1y range, we need to query by user with another query
async function getOlderContributions (orgId, users) {
const membersData = []
for (const staleUser of users) {
const variables = { userId: staleUser.user, orgId };
const contributionsQuery = queryByUsers();
const contributionsResponse = await graphqlWithAuth(contributionsQuery, variables);;
membersData.push(normalizeMember({ node: contributionsResponse.user }));
}
return membersData
}
function normalizeMember ({ node }) {
return {
user: node.login,
lastPR: node.contributionsCollection.pullRequestContributions?.nodes[0]?.occurredAt,
lastIssue: node.contributionsCollection.issueContributions?.nodes[0]?.occurredAt,
lastCommit: node.contributionsCollection.commitContributionsByRepository?.[0]?.contributions?.nodes?.[0]?.occurredAt,
socialAccounts: node.socialAccounts?.nodes,
}
}
// Function to query users
function queryByUsers () {
return `
query ($userId: String!, $orgId: ID) {
user(login: $userId) {
login
name
socialAccounts(last:4) {
nodes {
displayName
url
provider
}
}
contributionsCollection(
organizationID: $orgId
from: "2023-01-01T00:00:00Z"
to: "2023-12-31T23:59:59Z"
) {
pullRequestContributions(last: 1, orderBy: {direction: ASC}) {
nodes {
occurredAt
pullRequest {
url
}
}
}
issueContributions(last: 1, orderBy: {direction: ASC}) {
nodes {
occurredAt
issue {
url
}
}
}
commitContributionsByRepository(maxRepositories: 1) {
contributions(last: 1, orderBy: {direction: ASC, field: OCCURRED_AT}) {
nodes {
repository {
name
}
occurredAt
url
}
}
}
}
}
}
`;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment