[READ-ONLY] Mirror of https://github.com/flo-bit/edge-function-github-contribution. edge-function-github-contribution.vercel.app
0

Configure Feed

Select the types of activity you want to include in your feed.

TypeScript 100.0%
16 1 0

Clone this repository

https://git.vm.fail/flo-bit.dev/edge-function-github-contribution https://git.vm.fail/did:plc:vdgzggnt6nctopr2kiqzatgp
ssh://git@knot1.tangled.sh:2222/flo-bit.dev/edge-function-github-contribution ssh://git@knot1.tangled.sh:2222/did:plc:vdgzggnt6nctopr2kiqzatgp

For self-hosted knots, clone URLs may differ based on your setup.


Readme.md

edge-function-github-contributions#

vercel edge function that returns some infos of a github account as a json (contributions, repositories, followers, following, issues, prs, status).

detailed infos:

  • contributions of the last year total, and split by day (return the contribution count of each day and a color for each day, that is used to color the heatmap on github)

  • contributions of the last year split by type (commits, pull requests, issues)

  • up to 100 user owned repositories sorted by most stars (return the name, description, stars, forks, watchers, top 10 languages each with a name and size in bytes)

  • count of: starred repositories, followers, following, repositories, pr requests, issues

  • current status of user

see response type for the full type definition, or click here to see the response for my account

Usage#

  1. create a personal access token on github, go to settings -> developer settings -> personal access tokens (classic) -> generate new token (classic), set expiration date to "No expiration" and add the public_repo scope.

  2. if using in browser, set cors options in github-data.ts:8-10

// set your domain here
const corsOptions = {
  origin: ['https://blento.app', 'https://www.blento.app'],
};
  1. deploy to vercel

Deploy with Vercel

  1. set environment variable GITHUB_TOKEN to the personal access token you created in step 1

  2. get the url of the deployed function and use it in your application, by sending a GET request to the url (if no user is given, returns the data of the user that owns the token, user selection by default is disabled, see below how to enable it):

// get data of user that owns the token
https://<your-deployment-url>/api/github-data

// get data of a specific user (to disable see below)
https://<your-deployment-url>/api/github-data?user=<username>
  1. simple example using fetch:
const res = await fetch('https://edge-function-github-contribution.vercel.app/api/github-data');
const json = await res.json(); // as GitHubResponse, see below

console.log(json);
  1. it's recommended to remove data points you don't need, to reduce the size of the response and speed up the request

  2. if you dont want to allow querying users other than yourself, change line 9 in api/github-data.ts to:

  const allowUserSelection = false;

development#

to run the function locally, you need to have the vercel cli installed:

npm i -g vercel@latest

then clone the repository:

git clone https://github.com/flo-bit/edge-function-github-contribution
cd edge-function-github-contribution

add a .env file with the GITHUB_TOKEN environment variable and run:

vercel dev

response type#

if you're using it in a typescript project, here the type definition of the (successful) response:

const githubGraphColors = ['#ebedf0', '#9be9a8', '#40c463', '#30a14e', '#216e39'] as const;

// Define a type based on the color values
export type GithubGraphColor = (typeof githubGraphColors)[number];

export type GitHubResponse = {
	user: {
		login: string;
		avatarUrl: string;
		contributionsCollection: {
			totalCommitContributions: number;
			totalIssueContributions: number;
			totalPullRequestContributions: number;
			totalPullRequestReviewContributions: number;
			contributionCalendar: {
				totalContributions: number;
				weeks: {
					contributionDays: {
						date: string;
						contributionCount: number;
						color: GithubGraphColor;
					}[];
				}[];
			};
		};
		repositories: {
			totalCount: number;
			nodes: {
				name: string;
				stargazerCount: number;
				forkCount: number;
				watchers: {
					totalCount: number;
				};
				languages: {
					totalSize: number;
					edges: {
						node: {
							name: string;
						};
						size: number;
					}[];
				};
			}[];
		};
		starredRepositories: {
			totalCount: number;
		};
		followers: {
			totalCount: number;
		};
		following: {
			totalCount: number;
		};
		issues_sum: {
			totalCount: number;
		};
		issues_open: {
			totalCount: number;
		};
		issues_closed: {
			totalCount: number;
		};
		pr_sum: {
			totalCount: number;
		};
		pr_open: {
			totalCount: number;
		};
		pr_closed: {
			totalCount: number;
		};
		pr_merged: {
			totalCount: number;
		};
		status: {
			emoji?: string;
			message?: string;
			expiresAt?: string;
			updatedAt?: string;
		} | null;
	};
};

calculate more infos#

here is a typescript example to combine some of the infos to get:

  • total stars of user owned repositories
  • total forks of user owned repositories
  • total watchers of user owned repositories
  • total size of user owned repositories
  • total size of each language in user owned repositories
let totalStars = 0;
let totalSize = 0;
let totalForks = 0;
let totalWatchers = 0;

const languages = new Map<string, number>();

for (const repo of json.data.viewer.repositories.nodes) {
    totalStars += repo.stargazerCount;
    totalSize += repo.languages.totalSize;
    totalForks += repo.forkCount;
    totalWatchers += repo.watchers.totalCount;

    for (const edge of repo.languages.edges) {
        const language = edge.node.name;
        const size = edge.size;
        languages.set(language, (languages.get(language) ?? 0) + size);
    }
}

json.data.viewer.totalStars = totalStars;
json.data.viewer.totalSize = totalSize;
json.data.viewer.totalForks = totalForks;
json.data.viewer.totalWatchers = totalWatchers;
json.data.viewer.languages = Array.from(languages, ([name, size]) => ({ name, size })).sort(
    (a, b) => b.size - a.size
);

add private repositories#

if you want to include private repositories, add the repo:status scope to your personal access token and remove line 33 in api/github-data.ts: privacy: PUBLIC (obviously at your own risk).

rate limits#

the function uses the github graphql api, which has a rate limit of 5000 points per hour, the request made costs 1 point, so you can make 5000 requests per hour (or a bit more than 1 per second). that being said, some simple client side caching is always a good idea (e.g. using localStorage) and a graceful error handling in case the rate limit is exceeded. more complex caching you'll have to figure out yourself.

license#

MIT