Update Hacktoberfest Leaderboard #2
This file contains 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
name: Update Hacktoberfest Leaderboard | |
on: | |
schedule: | |
- cron: '0 * * * *' # Runs every hour at the start of the hour | |
workflow_dispatch: # Allows manual triggering | |
jobs: | |
update-leaderboard: | |
runs-on: ubuntu-latest | |
steps: | |
- name: Checkout repository | |
uses: actions/checkout@v2 | |
- name: Update Leaderboard | |
uses: actions/github-script@v6 | |
with: | |
github-token: ${{ secrets.HACKTOBERFEST_LEADERBOARD_TOKEN }} | |
script: | | |
// GitHub repository details | |
const owner = context.repo.owner; | |
const repo = context.repo.repo; | |
const issueNumber = 1; // Replace with your actual issue number | |
// Repositories to track | |
const REPOS = [ | |
'galaxy-bytes/main-test-repo', | |
'GCodeHouse/Cohort4', | |
'TBD54566975/developer.tbd.website' | |
//'blackgirlbytes/LunaFocus' | |
]; | |
const POINT_VALUES = { | |
small: 5, | |
medium: 10, | |
large: 15 | |
}; | |
const calculatePoints = (labels) => { | |
const size = labels.find(label => POINT_VALUES[label.name.toLowerCase()]); | |
return size ? POINT_VALUES[size.name.toLowerCase()] : POINT_VALUES.small; | |
}; | |
const fetchRecentPRs = async (repo) => { | |
try { | |
console.log(`Fetching recent PRs for ${repo}`); | |
const [repoOwner, repoName] = repo.split('/'); | |
const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000).toISOString(); | |
const { data: prs } = await github.rest.pulls.list({ | |
owner: repoOwner, | |
repo: repoName, | |
state: 'closed', | |
sort: 'updated', | |
direction: 'desc', | |
per_page: 100 | |
}); | |
console.log(`Fetched ${prs.length} PRs for ${repo}`); | |
const recentMergedPRs = prs.filter(pr => | |
pr.merged_at && | |
new Date(pr.merged_at) > new Date(oneHourAgo) && | |
pr.labels.some(label => label.name.toLowerCase() === 'hacktoberfest') | |
); | |
const hacktoberfestPRs = recentMergedPRs.map(pr => ({ | |
user: pr.user.login, | |
points: calculatePoints(pr.labels), | |
repo: repo, | |
prNumber: pr.number, | |
prTitle: pr.title, | |
})); | |
return hacktoberfestPRs; | |
} catch (error) { | |
console.error(`Error fetching PRs for ${repo}: ${error.message}`); | |
return []; | |
} | |
}; | |
const generateLeaderboard = async () => { | |
try { | |
const allPRs = await Promise.all(REPOS.map(fetchRecentPRs)); | |
const flatPRs = allPRs.flat(); | |
const leaderboard = flatPRs.reduce((acc, pr) => { | |
if (!acc[pr.user]) acc[pr.user] = { points: 0, prs: 0 }; | |
acc[pr.user].points += pr.points; | |
acc[pr.user].prs += 1; | |
return acc; | |
}, {}); | |
const sortedLeaderboard = Object.entries(leaderboard) | |
.sort(([, a], [, b]) => b.points - a.points) | |
.map(([username, data], index) => ({ | |
rank: index + 1, | |
username, | |
points: data.points, | |
prs: data.prs | |
})); | |
return sortedLeaderboard; | |
} catch (error) { | |
console.error(`Error generating leaderboard: ${error.message}`); | |
return []; | |
} | |
}; | |
const updateIssue = async (leaderboardData) => { | |
const issueBody = ` | |
# Hacktoberfest Leaderboard | |
| Rank | Username | Points | PRs | | |
|------|----------|--------|-----| | |
${leaderboardData.map(entry => `| ${entry.rank} | ${entry.username} | ${entry.points} | ${entry.prs} |`).join('\n')} | |
Last updated: ${new Date().toUTCString()} | |
`; | |
try { | |
await github.rest.issues.update({ | |
owner, | |
repo, | |
issue_number: issueNumber, | |
body: issueBody | |
}); | |
console.log("Issue updated successfully!"); | |
} catch (error) { | |
throw new Error(`Failed to update issue: ${error.message}`); | |
} | |
}; | |
// Main execution | |
const leaderboardData = await generateLeaderboard(); | |
await updateIssue(leaderboardData); |