Last active
December 5, 2024 10:02
-
-
Save Eomm/8713b946c1991e5bd0733b9e562f6950 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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