How to Display a List of GitHub Commit Messages and Contributor Commit Graph in a React App

Explore how to obtain commits and commit counts for each contributor, create a list of commit messages, and display a graph of commits relative to contributors.

Matheshyogeswaran
Bits and Pieces

--

In this article, we’ll explore how to obtain commits and commit counts for each contributor, create a list of commit messages, and display a graph of commits relative to contributors. We’ll begin by setting up a basic React application. In the App.js file, we'll create inputs for the username and repository to search on GitHub.

Below is the code to capture user inputs.

 <form onSubmit={handleSubmit}>
<div className="row mb-3">
<div className="col-md-6">
<label htmlFor="username" className="form-label">
GitHub Username
</label>
<input
type="text"
className="form-control"
id="username"
name="username"
placeholder="Enter your GitHub username"
value={username}
onChange={(event) => setUsername(event.target.value)}
/>
</div>
<div className="col-md-6">
<label htmlFor="repo" className="form-label">
Repository Name
</label>
<input
type="text"
className="form-control"
id="repo"
name="repo"
placeholder="Enter the repository name"
value={repo}
onChange={(event) => setRepo(event.target.value)}
/>
</div>
</div>
<button type="submit" className="btn btn-primary">
Search
</button>
</form>

Here I used Bootstrap. To add Bootstrap designs to your React app, use the npm install command followed by “bootstrap”.

npm install bootstrap

Next, we’ll create a components folder in our project directory, and within that folder, we'll create two files: ContributorCommitMessagesChart.js and ContributorCommitMessages.js.

💡 Note: Once you build these two components, it might be a good idea to isolate and extract them into packages, so you can use an open-source toolchain like Bit to publish, version, and reuse them across all of your projects with a simple npm i @bit/your-username/your-component.

Learn more here:

Let’s focus on the ContributorCommitMessages.js file for now. This component will display the list of commit messages for each contributor. Below is the code for this component.

import React, { useEffect, useState } from 'react';

function ContributorCommitMessages({ username, repo }) {
const [contributorMessages, setContributorMessages] = useState([]);
const [error, setError] = useState(null);
console.log(username);
console.log(repo);


useEffect(() => {
async function fetchData() {
try {
const response = await fetch(`https://api.github.com/repos/${username}/${repo}/commits`);
if (!response.ok) {
throw new Error(`Failed to fetch data: ${response.status} ${response.statusText}`);
}
const data = await response.json();
if (!Array.isArray(data)) {
throw new Error(`Invalid data format: expected an array, got ${typeof data}`);
}
const contributors = Array.from(new Set(data.map(commit => commit.author.login)));
const messagesByContributor = contributors.map(contributor => {
const messages = data.filter(commit => commit.author.login === contributor)
.map(commit => {
const date = new Date(commit.commit.author.date).toLocaleString();
return {message: commit.commit.message, date: date};
});
const name = data.find(commit => commit.author.login === contributor).commit.author.name;
return { contributor, name, messages };
});
setContributorMessages(messagesByContributor);
} catch (error) {
setError(error.message);
}
}

fetchData();
}, [username, repo]);

if (error) {
return <div className="container mt-3">Error: {error}</div>;
}

return (
<div className="container mt-3">
{contributorMessages.map(contributor => (
<div key={contributor.contributor} className="card mb-3">
<div className="card-header">
<h2 className="h6 card-title">Commit messages by {contributor.name} ({contributor.contributor}):</h2>
</div>
<div className="card-body">
<ul className="list-group">
{contributor.messages.map(message => (
<li key={message.message} className="list-group-item d-flex justify-content-between align-items-center">
<div>{message.message}</div>
<div><small>{message.date}</small></div>
</li>
))}
</ul>
</div>
</div>
))}
</div>
);
}

export default ContributorCommitMessages;

In the ContributorCommitMessages.js component, we'll use the useEffect hook to fetch data from the GitHub API endpoint. Once we have the data, we can display the list of commit messages for each contributor.

Moving on to the ContributorCommitMessagesChart.js component, this component will display a graph of commits relative to contributors.

import React, { useEffect, useState } from 'react';
import ReactApexChart from 'react-apexcharts';

function ContributorCommitMessagesChart({ username, repo }) {
const [contributorMessages, setContributorMessages] = useState([]);

useEffect(() => {
async function fetchData() {
const response = await fetch(`https://api.github.com/repos/${username}/${repo}/commits`);
const data = await response.json();
const contributors = Array.from(new Set(data.map(commit => commit.author.login)));
const messagesByContributor = contributors.map(contributor => {
const messages = data.filter(commit => commit.author.login === contributor)
.map(commit => commit.commit.message);
const name = data.find(commit => commit.author.login === contributor).commit.author.name;
return { contributor, name, messages, commitCount: messages.length };
});
setContributorMessages(messagesByContributor);
}

fetchData();
}, [username, repo]);

const chartOptions = {
chart: {
id: 'commit-messages-chart',
toolbar: {
show: false,
},
},
xaxis: {
categories: contributorMessages.map(contributor => contributor.name),
},
yaxis: {
title: {
text: 'Commit Count',
},
},
dataLabels: {
enabled: false,
},
fill: {
colors: ['#4dc9f6'],
},
};

const chartSeries = [
{
name: 'Commit Count',
data: contributorMessages.map(contributor => contributor.commitCount),
},
];

return (
<div className="container mt-3">
<div className="card mb-3">
<div className="card-header">
<h2 className="h6 card-title">Contributors vs Commit Count</h2>
</div>

<div className="card-body">
<ReactApexChart options={chartOptions} series={chartSeries} type="bar" height={350} />
</div>

<div className="card-footer text-muted">
Data fetched from{' '}
<a href={`https://github.com/${username}/${repo}/commits`} target="_blank" rel="noopener noreferrer">
GitHub API
</a>
</div>
</div>
</div>
);
}

export default ContributorCommitMessagesChart;

To use ReactApexChart to display the graph of commits relative to contributors in our React application, we’ll need to install the react-apexcharts and apexcharts packages.

To do this, open your terminal and navigate to your project directory. Then, enter the following command:

npm install react-apexcharts apexcharts

After installing the necessary packages and creating our ContributorCommitMessages.js and ContributorCommitMessagesChart.js components, we need to call them in the App.js file.

To do this, we’ll import the two components at the top of the App.js file.

import "./App.css";
import { useState } from "react";
import ContributorCommitMessages from "./components/ContributorCommitMessages";
import ContributorCommitMessagesChart from "./components/ContributorCommitMessagesChart";

function App() {
const [username, setUsername] = useState("");
const [repo, setRepo] = useState("");
const [showResult, setShowResult] = useState(false);

const handleSubmit = (event) => {
event.preventDefault();
// add code here to handle the form submission
setShowResult(true);
};
console.log(showResult);

return (
<>
<div className="App" style={{ backgroundColor: "#F5F5F5" }}>
<div className="container mt-5">
<form onSubmit={handleSubmit}>
<div className="row mb-3">
<div className="col-md-6">
<label htmlFor="username" className="form-label">
GitHub Username
</label>
<input
type="text"
className="form-control"
id="username"
name="username"
placeholder="Enter your GitHub username"
value={username}
onChange={(event) => setUsername(event.target.value)}
/>
</div>
<div className="col-md-6">
<label htmlFor="repo" className="form-label">
Repository Name
</label>
<input
type="text"
className="form-control"
id="repo"
name="repo"
placeholder="Enter the repository name"
value={repo}
onChange={(event) => setRepo(event.target.value)}
/>
</div>
</div>
<button type="submit" className="btn btn-primary">
Search
</button>
</form>
<div className="row mt-5">
<div className="col-md-6">
{showResult && (
<ContributorCommitMessages username={username} repo={repo} />
)}
</div>
<div className="col-md-6">
{showResult && (
<ContributorCommitMessagesChart
username={username}
repo={repo}
/>
)}
</div>
</div>
</div>
</div>
</>
);
}

export default App;

In this code if showResult is true, meaning that the user has entered a valid username and repository name and clicked the search button, we render the ContributorCommitMessages component in the left column and the ContributorCommitMessagesChart component in the right column.

We pass the username and repo props to both components, which are used to fetch the relevant data from the GitHub API and display the commit messages and commit chart for the specified repository.

Here is a gif showing the React app in action.

Source code:https://github.com/matheshyogeswaran/git_chart_commits.git

Build React Apps with reusable components, just like Lego

Bit’s open-source tool help 250,000+ devs to build apps with components.

Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.

Learn more

Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:

Micro-Frontends

Design System

Code-Sharing and reuse

Monorepo

--

--