Skip to content

Instantly share code, notes, and snippets.

@zgorizzo69
Created August 27, 2025 15:18
Show Gist options
  • Select an option

  • Save zgorizzo69/5e960865819e4a6212e741e566d83a51 to your computer and use it in GitHub Desktop.

Select an option

Save zgorizzo69/5e960865819e4a6212e741e566d83a51 to your computer and use it in GitHub Desktop.
gives the number of PR reviewed and line addition + deletion by user on the usual-dao organisation
#!/usr/bin/env node
/**
* Script to get the number of PRs reviewed by you in the usual-dao organization in 2025
*
* Usage:
* 1. Set your GitHub username in the GITHUB_USERNAME variable below
* 2. Set your GitHub personal access token in the GITHUB_TOKEN environment variable
* 3. Run: node get-pr-reviews.js
*
* To create a GitHub token:
* 1. Go to https://github.com/settings/tokens
* 2. Generate a new token with 'repo' and 'read:org' scopes
* 3. Export it: export GITHUB_TOKEN="your_token_here"
*/
const https = require('https');
// Configuration
const GITHUB_USERNAME = 'YOUR_GITHUB_USERNAME'; // Replace with your GitHub username
const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
const ORG = 'usual-dao';
const YEAR = '2025';
if (!GITHUB_TOKEN) {
console.error('Error: Please set your GITHUB_TOKEN environment variable');
console.error('Example: export GITHUB_TOKEN="your_token_here"');
process.exit(1);
}
if (GITHUB_USERNAME === 'YOUR_GITHUB_USERNAME') {
console.error('Error: Please set your GitHub username in the GITHUB_USERNAME variable');
process.exit(1);
}
function makeGitHubRequest(path) {
return new Promise((resolve, reject) => {
const options = {
hostname: 'api.github.com',
path: path,
method: 'GET',
headers: {
'Authorization': `token ${GITHUB_TOKEN}`,
'User-Agent': 'PR-Review-Counter',
'Accept': 'application/vnd.github.v3+json'
}
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
if (res.statusCode === 200) {
resolve(JSON.parse(data));
} else {
reject(new Error(`GitHub API error: ${res.statusCode} ${res.statusMessage}\n${data}`));
}
});
});
req.on('error', (error) => {
reject(error);
});
req.end();
});
}
async function getAllRepos() {
console.log(`Fetching repositories for organization: ${ORG}...`);
const repos = [];
let page = 1;
while (true) {
try {
const data = await makeGitHubRequest(`/orgs/${ORG}/repos?page=${page}&per_page=100`);
if (data.length === 0) break;
repos.push(...data.map(repo => repo.name));
page++;
} catch (error) {
console.error('Error fetching repositories:', error.message);
break;
}
}
console.log(`Found ${repos.length} repositories in ${ORG}`);
return repos;
}
async function getPRsWithReviews(repo) {
console.log(`Checking repository: ${repo}...`);
const reviewedPRs = [];
let page = 1;
while (true) {
try {
// Get all PRs updated in 2025
const prs = await makeGitHubRequest(
`/repos/${ORG}/${repo}/pulls?state=all&page=${page}&per_page=100&sort=updated&direction=desc`
);
if (prs.length === 0) break;
// Filter PRs updated in 2025
const prs2025 = prs.filter(pr => {
const updatedAt = new Date(pr.updated_at);
return updatedAt.getFullYear() === 2025;
});
if (prs2025.length === 0) {
// If no PRs from 2025 on this page, we can stop (since they're sorted by updated date)
break;
}
// Check reviews for each PR
for (const pr of prs2025) {
try {
const reviews = await makeGitHubRequest(`/repos/${ORG}/${repo}/pulls/${pr.number}/reviews`);
// Check if you reviewed this PR in 2025
const yourReviews = reviews.filter(review => {
const reviewDate = new Date(review.submitted_at);
return review.user.login === GITHUB_USERNAME &&
reviewDate.getFullYear() === 2025;
});
if (yourReviews.length > 0) {
// Get PR details including line counts
const prDetails = await makeGitHubRequest(`/repos/${ORG}/${repo}/pulls/${pr.number}`);
reviewedPRs.push({
id: `${repo}#${pr.number}`,
title: pr.title,
additions: prDetails.additions || 0,
deletions: prDetails.deletions || 0,
changedFiles: prDetails.changed_files || 0,
reviewCount: yourReviews.length
});
}
} catch (error) {
console.error(`Error fetching reviews for ${repo}#${pr.number}:`, error.message);
}
}
page++;
} catch (error) {
console.error(`Error fetching PRs for ${repo}:`, error.message);
break;
}
}
return reviewedPRs;
}
async function main() {
console.log(`Counting PRs reviewed by ${GITHUB_USERNAME} in ${ORG} organization for ${YEAR}...\n`);
try {
const repos = await getAllRepos();
const allReviewedPRs = [];
for (const repo of repos) {
const reviewedPRs = await getPRsWithReviews(repo);
allReviewedPRs.push(...reviewedPRs);
}
// Calculate totals
const totalPRs = allReviewedPRs.length;
const totalAdditions = allReviewedPRs.reduce((sum, pr) => sum + pr.additions, 0);
const totalDeletions = allReviewedPRs.reduce((sum, pr) => sum + pr.deletions, 0);
const totalChangedFiles = allReviewedPRs.reduce((sum, pr) => sum + pr.changedFiles, 0);
const totalLinesReviewed = totalAdditions + totalDeletions;
console.log('\n' + '='.repeat(60));
console.log(`RESULTS FOR ${YEAR}`);
console.log('='.repeat(60));
console.log(`Organization: ${ORG}`);
console.log(`Reviewer: ${GITHUB_USERNAME}`);
console.log(`Total PRs reviewed: ${totalPRs}`);
console.log(`Total lines reviewed: ${totalLinesReviewed.toLocaleString()}`);
console.log(` - Lines added: ${totalAdditions.toLocaleString()}`);
console.log(` - Lines deleted: ${totalDeletions.toLocaleString()}`);
console.log(`Total files changed: ${totalChangedFiles.toLocaleString()}`);
if (totalPRs > 0) {
console.log(`\nAverage per PR:`);
console.log(` - Lines per PR: ${Math.round(totalLinesReviewed / totalPRs).toLocaleString()}`);
console.log(` - Files per PR: ${Math.round(totalChangedFiles / totalPRs)}`);
}
if (allReviewedPRs.length > 0) {
console.log('\n' + '='.repeat(60));
console.log('DETAILED BREAKDOWN:');
console.log('='.repeat(60));
// Sort by total lines (additions + deletions) in descending order
allReviewedPRs.sort((a, b) => (b.additions + b.deletions) - (a.additions + a.deletions));
allReviewedPRs.forEach(pr => {
const totalLines = pr.additions + pr.deletions;
console.log(`${pr.id}: ${totalLines.toLocaleString()} lines (+${pr.additions.toLocaleString()}/-${pr.deletions.toLocaleString()}) in ${pr.changedFiles} files`);
console.log(` Title: ${pr.title}`);
console.log('');
});
}
} catch (error) {
console.error('Error:', error.message);
process.exit(1);
}
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment