Skip to content

Update GitHub portfolio stats #41

Update GitHub portfolio stats

Update GitHub portfolio stats #41

Workflow file for this run

name: Update GitHub portfolio stats
on:
schedule:
- cron: "17 5 * * *"
workflow_dispatch:
permissions:
contents: write
jobs:
update-stats:
runs-on: ubuntu-latest
steps:
- name: Checkout portfolio
uses: actions/checkout@v4
- name: Generate GitHub stats
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
mkdir -p data
node <<'NODE'
const fs = require('fs');
const token = process.env.GH_TOKEN;
const username = 'SCodeGit';
async function graphql(query, variables = {}) {
const response = await fetch('https://api.github.com/graphql', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
'User-Agent': 'SCode-Portfolio-GitHub-Stats'
},
body: JSON.stringify({ query, variables })
});
const json = await response.json();
if (!response.ok || json.errors) {
throw new Error(JSON.stringify(json.errors || json));
}
return json.data;
}
function isoDate(date) {
return date.toISOString().replace('.000Z', 'Z');
}
const now = new Date();
const from = new Date(now);
from.setUTCFullYear(from.getUTCFullYear() - 1);
const query = `
query($login: String!, $from: DateTime!, $to: DateTime!) {
user(login: $login) {
login
name
avatarUrl
htmlUrl
followers { totalCount }
following { totalCount }
repositories(
first: 100
ownerAffiliations: OWNER
privacy: PUBLIC
) {
totalCount
nodes {
name
url
stargazerCount
forkCount
isFork
}
}
contributionsCollection(from: $from, to: $to) {
contributionCalendar {
totalContributions
weeks {
contributionDays {
date
contributionCount
}
}
}
totalCommitContributions
totalIssueContributions
totalPullRequestContributions
totalPullRequestReviewContributions
totalRepositoryContributions
totalRepositoriesWithContributedCommits
}
}
}
`;
const data = await graphql(query, {
login: username,
from: isoDate(from),
to: isoDate(now)
});
const user = data.user;
const collection = user.contributionsCollection;
const calendar = collection.contributionCalendar;
const days = calendar.weeks.flatMap(w => w.contributionDays);
function currentStreak(days) {
const map = new Map(days.map(d => [d.date, d.contributionCount]));
let cursor = new Date(Date.UTC(
now.getUTCFullYear(),
now.getUTCMonth(),
now.getUTCDate()
));
const key = d => d.toISOString().slice(0, 10);
if (!map.get(key(cursor))) {
cursor.setUTCDate(cursor.getUTCDate() - 1);
}
let streak = 0;
while (map.get(key(cursor)) > 0) {
streak++;
cursor.setUTCDate(cursor.getUTCDate() - 1);
}
return streak;
}
const repos = user.repositories.nodes || [];
const totalStars = repos.reduce((sum, repo) => sum + repo.stargazerCount, 0);
const output = {
username,
generatedAt: new Date().toISOString(),
profile: {
name: user.name,
avatarUrl: user.avatarUrl,
htmlUrl: user.htmlUrl,
followers: user.followers.totalCount,
following: user.following.totalCount,
publicRepos: user.repositories.totalCount,
totalStars
},
contributions: {
total: calendar.totalContributions,
commits: collection.totalCommitContributions,
issues: collection.totalIssueContributions,
pullRequests: collection.totalPullRequestContributions,
reviews: collection.totalPullRequestReviewContributions,
repositoriesCreated: collection.totalRepositoryContributions,
repositoriesContributedTo: collection.totalRepositoriesWithContributedCommits,
currentStreak: currentStreak(days),
weeks: calendar.weeks
}
};
fs.writeFileSync('data/github-stats.json', JSON.stringify(output, null, 2) + '\n');
console.log(`Generated ${output.contributions.total} contributions for ${username}`);
NODE
- name: Commit updated stats
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add data/github-stats.json
if git diff --cached --quiet; then
echo "No stats changes."
else
git commit -m "chore: update github stats"
git push
fi