While browsing the Ant Design documentation, I noticed that they show the GitHub contributors of a file at the bottom of the page. I thought it was a nice feature and wanted to blog about it.
Contents
The GitHub API
The GitHub API is a great resource to get information about a repository. It is very well-documented and has a lot of endpoints. The endpoint we are interested in is the commits endpoint. It returns a list of commits for a repository. We can use the path
parameter to filter the commits by a file path and filter the commits by a specific author with the author
parameter. For example, the following request returns the commits for the README.md
file in the gatsby
repository:
https://api.github.com/repos/gatsbyjs/gatsby/commits?path=README.md
it will give us an array of commits like this:
[
{
sha: '',
node_id: '',
commit: {
author: {
name: '',
email: '',
date: '2022-11-08T07:08:16Z'
},
committer: {
name: '',
email: 'noreply@github.com',
date: '2022-11-08T07:08:16Z'
},
message: 'chore: Update main README (#36954)',
tree: {
sha: '041fd9524aae99d573dbf6bd03a09953faa87ad8',
url: 'https://api.github.com/repos/gatsbyjs/gatsby/git/trees/041fd9524aae99d573dbf6bd03a09953faa87ad8'
},
url: 'https://api.github.com/repos/gatsbyjs/gatsby/git/commits/5e8e621bef0d4244f718d3b42d668d63504260e7',
comment_count: 0,
verification: {
verified: true,
reason: 'valid',
signature: '',
payload: ''
}
}
}
];
Creating a frontend to show the contributors
We will create a mini frontend to show getting the commits for a file and showing the contributors. We will use Alpine.js and PicoCSS to create the frontend because they are small and easy to use. First, create an index.html
file with the following content:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.min.css" />
<style>
.avatar {
border-radius: 50%;
}
</style>
</head>
<body>
<div class="container" x-data>
<h1>Some stuff</h1>
<p>
Lorem ipsum dolor, sit amet consectetur adipisicing elit. A quasi nobis in. Neque harum
assumenda, mollitia voluptatibus voluptatum laudantium, magnam quasi ipsum error voluptas at
rerum libero placeat. Molestiae, obcaecati.
</p>
<h2>Contributors</h2>
<!-- Contributors will be shown here -->
</div>
<script>
/** Alpine.js stuff */
</script>
</body>
</html>
Here we have a simple HTML page that looks like this:
Now I will save a sample response as test.json
because I can’t send a request every time I refresh the page. That will be a bad thing to do and we can get a rate limited.
Getting the commits
In the scripting part, we will first define a constant to the API URL we want.
const API_PATH = './test.json'; // https://api.github.com/repos/ant-design/ant-design/commits?path=components/button/index.en-US.md
Then we define an alpine.js store to hold the commits.
const cStore = {
contribs: [],
setContribs(contribs) {
this.contribs = contribs;
}
};
We then initialize the store with the Alpine.store()
function.
document.addEventListener('alpine:init', () => {
Alpine.store('cStore', cStore);
});
After that, we will fetch the commits and parse them to JSON.
const commitsData = fetch(API_PATH).then((res) => res.json());
We will create a function to format the commits to the format we want. We will use the reduce()
function to get the unique contributors and the map()
function to get the commits for each contributor.
const format = (data) =>
data
.map((item) => ({
name: item.commit.author.name || item.author.login,
id: item.author.id,
username: item.author.login,
link: item.author.html_url,
avatar: item.author.avatar_url
}))
.filter((item, index, self) => self.findIndex((t) => t.id === item.id) === index);
You can learn more about array methods here.
Finally, we will call the format()
function with the commitsData
and set the contribs
store to the result.
commitsData.then((data) => {
Alpine.store('cStore').setContribs(format(data));
});
Our final script will look like this:
const API_PATH = './test.json'; // https://api.github.com/repos/ant-design/ant-design/commits?path=components/button/index.en-US.md
const cStore = {
contribs: [],
setContribs(contribs) {
this.contribs = contribs;
}
};
document.addEventListener('alpine:init', () => {
Alpine.store('cStore', cStore);
});
const commitsData = fetch(API_PATH).then((res) => res.json());
const format = (data) =>
data
.map((item) => ({
name: item.commit.author.name || item.author.login,
id: item.author.id,
username: item.author.login,
link: item.author.html_url,
avatar: item.author.avatar_url
}))
.filter((item, index, self) => self.findIndex((t) => t.id === item.id) === index);
commitsData.then((data) => {
Alpine.store('cStore').setContribs(format(data));
});
Now we will create a component to show the contributors. We will use the x-for
directive to loop through the contributors and show them.
<div x-show="!$store.cStore.contribs.length">
<p>There are no contributors</p>
</div>
<div x-show="$store.cStore.contribs.length">
<template x-for="contrib in $store.cStore.contribs" :key="contrib.id">
<a :href="contrib.link" target="_blank" :title="contrib.name">
<img :src="contrib.avatar" :alt="contrib.name" width="50" height="50" class="avatar" />
</a>
</template>
<br /><br />
<p x-text="$store.cStore.contribs.length+` Contributors`"></p>
</div>
And save the file. Now when we refresh the page,
and Voila! We have our contributors.
Conclusion
In this tutorial, we learned how to get the contributors of a file in a GitHub repository using the GitHub API. We also learned how to use Alpine.js to show the contributors on a simple HTML page. I hope this tutorial was helpful to you and get a taste of Alpine.js’ simplicity and power.