Skip to content

Update Loose Goose Leaderboard #204

Update Loose Goose Leaderboard

Update Loose Goose Leaderboard #204

name: Update Loose Goose Leaderboard
on:
schedule:
- cron: '0 * * * *' # Runs every hour at the start of the hour
workflow_dispatch: # Allows manual triggering
permissions:
issues: write
pull-requests: read
jobs:
update-leaderboard:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Update Leaderboard
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const issueNumber = 46; // Change this to match your issue number
const REPOS = [
'block-open-source/goose-plugins', // Update to your repo(s)
];
const calculatePoints = (labels) => {
const labelNames = labels.map(label => label.name.toLowerCase());
const hasLooseGoose = labelNames.includes('loosegoose');
const hasCode = labelNames.includes('code');
return {
points: hasLooseGoose && hasCode ? 15 : (hasLooseGoose ? 10 : 0),
isCodePR: hasCode,
isContentPR: hasLooseGoose && !hasCode
};
};
const fetchRecentPRs = async (repo) => {
try {
console.log(`Fetching recent PRs for ${repo}`);
const [repoOwner, repoName] = repo.split('/');
const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 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 loosegoosePRs = prs.filter(pr => {
const isMerged = !!pr.merged_at;
const isRecent = new Date(pr.merged_at) > new Date(thirtyDaysAgo);
const isLoosegoose = pr.labels.some(label => label.name.toLowerCase() === 'loosegoose');
return isMerged && isRecent && isLoosegoose;
}).map(pr => {
const pointsData = calculatePoints(pr.labels);
return {
user: pr.user.login,
points: pointsData.points,
isCodePR: pointsData.isCodePR,
isContentPR: pointsData.isContentPR,
repo: repo,
prNumber: pr.number,
prTitle: pr.title,
};
});
return loosegoosePRs;
} 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,
codePRs: 0,
contentPRs: 0
};
}
acc[pr.user].points += pr.points;
acc[pr.user].prs += 1;
if (pr.isCodePR) {
acc[pr.user].codePRs += 1;
}
if (pr.isContentPR) {
acc[pr.user].contentPRs += 1;
}
return acc;
}, {});
return Object.entries(leaderboard)
.sort(([, a], [, b]) => b.points - a.points)
.map(([username, data], index) => ({
rank: index + 1,
username,
points: data.points,
prs: data.prs,
codePRs: data.codePRs,
contentPRs: data.contentPRs
}));
} catch (error) {
console.error(`Error generating leaderboard: ${error.message}`);
return [];
}
};
const updateIssue = async (leaderboardData) => {
try {
const rows = leaderboardData.map(entry =>
`| ${entry.rank} | @${entry.username} | ${entry.points} | ${entry.prs} | ${entry.codePRs} | ${entry.contentPRs} |`
).join('\n');
const issueBody = [
'# πŸ† Loose Goose November 2024 Leaderboard πŸ†',
'You thought Hacktoberfest 2024 was over?! The open source party is just getting started..! Wrap up 2024 with a bang (or honk) while enjoying super-fun contributions with Loose Goose November. From Nov 1st to Nov 20th, check our live leaderboard below to see who our top contributors are in real-time. Not only does this recognize everyone\'s efforts, it also brings an amplified competitive vibe with each contribution. πŸ‘€',
'',
'## This event is open to both employees and external contributors! 🦒',
'### 🌟 **Current Rankings:**',
'| Rank | Contributor | Points | Total PRs | Code PRs | Content PRs |',
'|------|-------------|--------|-----------|-----------|-------------|',
rows,
'',
'### πŸ“œ How It Works:',
'The top 3 contributors with the most points will earn $$$ gift cards (more on rewards below). Points are awarded based on the following criteria:',
'- 15 points for each merged PR with both `loosegoose` and `code` labels',
'- 10 points for each merged PR with just the `loosegoose` label (Content PR)',
'',
'### 🎁 Rewards',
'- Among our **top 3**? Our Top 3 Superstars earn $150 gift cards on Amazon. Stay tuned for the winners!',
'',
'### FAQ',
'- **Frequency of Updates:** The leaderboard will be updated every 1 hour.',
'- **Points System:**',
' - 15 points: Code PRs (PRs with both `loosegoose` and `code` labels)',
' - 10 points: Content PRs (PRs with just the `loosegoose` label)',
'- **Criteria:** Rankings are based on how many points you earn and PRs you close in the goose-plugins repo. To ensure your PRs are successfully merged:',
' - Ensure your contributions are aligned with our [project\'s CoC](https://github.com/block-open-source/goose-plugins/blob/main/CODE_OF_CONDUCT.md).',
' - Refer to our [Contributing Guide](https://github.com/block-open-source/goose-plugins/blob/main/CONTRIBUTING.md).',
'- **Tie-Breaker:** In the event of a tie-breaker, the tie-breaking PR that was submitted soonest will break the tie.',
'',
'### πŸš€ Get Featured:',
'Want to see your name climbing our ranks? Explore our content issues with the labels `loosegoose` in our Loose Goose Project Hub:',
'- [ ] #32',
'',
'Excited to see everyone\'s hard work. Thank you so much for your invaluable contributions, and let the fun competition begin!',
`Last updated: ${new Date().toUTCString()}`
].join('\n');
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();
if (leaderboardData.length > 0) {
await updateIssue(leaderboardData);
} else {
console.log("No leaderboard data to update.");
const emptyIssueBody = [
'# πŸ† Loose Goose November 2024 Leaderboard πŸ†',
'You thought Hacktoberfest 2024 was over?! The open source party is just getting started..! Wrap up 2024 with a bang (or honk) while enjoying super-fun contributions with Loose Goose November. From Nov 1st to Nov 20th, check our live leaderboard below to see who our top contributors are in real-time. Not only does this recognize everyone\'s efforts, it also brings an amplified competitive vibe with each contribution. πŸ‘€',
'',
'## This event is open to both employees and external contributors! 🦒',
'### 🌟 **Current Rankings:**',
'| Rank | Contributor | Points | Total PRs | Code PRs | Content PRs |',
'|------|-------------|--------|-----------|-----------|-------------|',
'No qualifying PRs found at this time. Check back soon!',
'',
'### πŸ“œ How It Works:',
'The top 3 contributors with the most points will earn $$$ gift cards (more on rewards below). Points are awarded based on the following criteria:',
'- 15 points for each merged PR with both `loosegoose` and `code` labels (Code PR)',
'- 10 points for each merged PR with just the `loosegoose` label (Content PR)',
'',
'### 🎁 Rewards',
'- Among our **top 3**? Our Top 3 Superstars earn $150 gift cards on Amazon. Stay tuned for the winners!',
'',
'### FAQ',
'- **Frequency of Updates:** The leaderboard will be updated every 1 hour.',
'- **Points System:**',
' - 15 points: Code PRs (PRs with both `loosegoose` and `code` labels)',
' - 10 points: Content PRs (PRs with just the `loosegoose` label)',
'- **Criteria:** Rankings are based on how many points you earn and PRs you close in the goose-plugins repo. To ensure your PRs are successfully merged:',
' - Ensure your contributions are aligned with our [project\'s CoC](https://github.com/block-open-source/goose-plugins/blob/main/CODE_OF_CONDUCT.md).',
' - Refer to our [Contributing Guide](https://github.com/block-open-source/goose-plugins/blob/main/CONTRIBUTING.md).',
'- **Tie-Breaker:** In the event of a tie-breaker, the tie-breaking PR that was submitted soonest will break the tie.',
'',
'### πŸš€ Get Featured:',
'Want to see your name climbing our ranks? Explore our content issues with the labels `loosegoose` in our Loose Goose Project Hub:',
'- [ ] #32',
'',
'Excited to see everyone\'s hard work. Thank you so much for your invaluable contributions, and let the fun competition begin!',
`Last updated: ${new Date().toUTCString()}`
].join('\n');
await github.rest.issues.update({
owner,
repo,
issue_number: issueNumber,
body: emptyIssueBody
});
console.log("Updated issue with empty leaderboard message.");
}