Skip to content

Instantly share code, notes, and snippets.

@Lissy93
Created February 27, 2024 00:19
Show Gist options
  • Save Lissy93/06b8453e791c48ba77a2acddc154259b to your computer and use it in GitHub Desktop.
Save Lissy93/06b8453e791c48ba77a2acddc154259b to your computer and use it in GitHub Desktop.
A quick 'n dirty Cloudflare Worker, for fetching pertinent about a given GitHub repository
export default {
async fetch(request, env) {
// Extract username and repo from the URL path
const url = new URL(request.url);
const pathSegments = url.pathname.split('/').filter(Boolean);
if (pathSegments.length !== 2) {
return new Response('URL must be in the format /{username}/{repo}', { status: 400 });
}
const [username, repo] = pathSegments;
// Headers for GitHub API requests
const headers = {
...(env.GITHUB_TOKEN ? { 'Authorization': `token ${env.GITHUB_TOKEN}` } : {}),
'User-Agent': 'as93-repo-info-worker',
'Accept': 'application/vnd.github.v3+json'
};
// API base URL, for given username and repo
const baseUrl = `https://api.github.com/repos/${username}/${repo}`;
try {
// Parallel fetch requests for repository information
const [
infoResponse, languagesResponse, updatesResponse,
versionsResponse, contributorsResponse, commitsResponse,
] = await Promise.all([
fetch(`${baseUrl}`, { headers }),
fetch(`${baseUrl}/languages`, { headers }),
fetch(`${baseUrl}/events`, { headers }),
fetch(`${baseUrl}/tags`, { headers }),
fetch(`${baseUrl}/contributors`, { headers }),
fetch(`${baseUrl}/commits`, { headers })
]);
// Handle potential fetch errors
const responses = [
infoResponse, languagesResponse, updatesResponse,
versionsResponse, contributorsResponse, commitsResponse,
];
for (const response of responses) {
if (!response.ok) {
throw new Error(`Failed to fetch from GitHub API: ${response.statusText}`);
}
}
// Extract and format JSON data from responses
const data = await Promise.all(responses.map(response => response.json()));
const [info, languages, updates, versions, contributors, commits] = data;
// Construct the final response object, containing only what we need
const result = {
info: {
ownerUsername: info.owner.login,
ownerAvatar: info.owner.avatar_url,
description: info.description,
url: info.html_url,
homepage: info.homepage,
language: info.language,
topics: info.topics,
license: info.license?.spdx_id,
isFork: info.fork,
isArchived: info.archived,
createdAt: info.created_at,
updatedAt: info.updated_at,
size: info.size,
scarCount: info.stargazers_count,
forksCount: info.forks_count,
watchersCount: info.watchers_count
},
languages,
updates: updates.map(update => ({
type: update.type,
actor: {
username: update.actor.login,
avatar: update.actor.avatar_url
},
repo: update.repo.name,
action: update.payload.action,
number: update.payload.number,
createdAt: update.created_at
})),
versions: versions.map(version => ({
name: version.name,
commit: version.commit.sha,
zipball: version.zipball_url,
tarball: version.tarball_url
})),
contributors: contributors.map(contributor => ({
username: contributor.login,
avatar: contributor.avatar_url,
contributions: contributor.contributions
})),
commits: commits.map(commit => ({
sha: commit.sha,
authorName: commit.commit.author.name,
authorDate: commit.commit.author.date,
message: commit.commit.message,
authorUsername: commit.author?.login,
authorAvatar: commit.author?.avatar_url
}))
};
// Return the response as JSON
return new Response(JSON.stringify(result), {
headers: { 'Content-Type': 'application/json' }
});
} catch (error) {
// Something fucked up real bad
return new Response(error.message, { status: 500 });
}
}
};
@Lissy93
Copy link
Author

Lissy93 commented Feb 27, 2024

Docs 👇

About
Simple API to return data about a given GitHub repo. Runs as a Cloudflare Worker.

Why?
To fetch full info on a repository, you're required to make several seperate requests to the GitHub REST API. (One for repo meta, languages, update events, versions, contributors, commits, etc). This is a bit of a faf if you're doing this in a frontend app, as you'll be rate-limited if you don't provide a token, yet it's not secure to use your GitHub token client-side.

As you can see, the code is quick and dirty, written in 5 minutes. But it does the job!

Usage

  1. Setup Node.js, if you haven't already done so, then install wrangler, npm i -g wrangler
  2. Create a new worker project, with wrangler init repo-stats
  3. Navigate into your project, and install deps with cd repo-stats and npm install
  4. In your wrangler.toml add your API key to the GITHUB_TOKEN env var
  5. Start the development server, and test everything's working with wrangler dev
  6. Finally, run wrangler deploy to deploy your app to the world! 🚀

You can now make requests to https://[project-name].workers.dev/[user]/[repo]

License
Licensed under MIT, © Alicia Sykes 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment