Posted by Will Stocks in Javascript, Snippets on Jun 19, 2019

So, I recently found myself needing to publicise how many public GitHub commits I had made on any repo I've worked on.

Making use of GitHub's incredibly useful public API, I managed to cobble together a function to pull in the last 90 days/300 GitHub events (because that's the limit that GitHub have implemented on this specific API route) worth of commits.

I'm gonna start out by saying, this is my first time consuming a public API... as a matter of fact, this is the first time I've ever consumed any API! So be warned, this may be a fairly rudimentary approach, but I've learned a lot along the way of putting this together. I've also tried to make it usable by others without a lot of work, not just bespoke for myself.

If there's a more efficient way of grabbing this data, let me know! I want to learn more!!!

-- Will Stocks

On with the code - I'll warn you now though, this turned out to be bigger than I had anticipated!


function recentGitHubCommits(username, autorecheck, recheckFrequency) {
  var commits = [];
  var commitsOld;
  var commitsNew;
  var today = new Date();
  var priorDate = new Date(today.setDate(today.getDate() - 90));
  const months = [
    "January",
    "February",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December"
  ];
  function nth(d) { //TODO: Check whether new Intl API is useful here?
    if (d > 3 && d < 21) return "th";
      switch (d % 10) {
        case 1:
          return "st";
        case 2:
          return "nd";
        case 3:
          return "rd";
        default:
          return "th";
      }
  }
  var ninetyDaysAgo =
    priorDate.getDate() +
    nth(priorDate.getDate()) +
    " " +
    months[priorDate.getMonth()] +
    " " +
    priorDate.getFullYear();

  //FIXME: There's probably a MUCH more efficient way of doing this...
  return new Promise((resolve, reject) => {
    let headers = new Headers();
    var githubUser = username;
    var urls = [];
    var pushEventArray = [];
    var commitCount = 0;
    var promises;

    for (i = 1; i <= 10; i++) {
      urls.push(
        "https://api.github.com/users/" + githubUser + "/events?page=" + i
      );
    }

    headers.append(
      "Authorization",
      "basic GitHubPersonalAccessTokengoeshereforhigherrequestlimit" //requires tweaking to set your own token!
    );

    promises = urls.map(url =>
      fetch(url, {
        headers: headers
      })
      .then(response => response.json())
    );

    Promise.all(promises)
      .then(function(promArr) {
        promArr = promArr.filter(r => r.length);
        promArr.forEach(function(respArr) {
          respArr.forEach(function(resp) {
            if (resp.type === "PushEvent") {
              pushEventArray.push(resp);
            }
          });
        });
      })
      .then(function() {
        pushEventArray.forEach(function(event) {
          commitCount += event.payload.size;
        });
        commitCount != commitsNew ? commits.push(commitCount) : null;
      })
      .then(function() {
        if (commits.length >= 2) {
          commitsOld = commits[commits.length - 2];
          commitsNew = commits[commits.length - 1];
        } else {
          commitsOld = 0;
          commitsNew = commits[commits.length - 1];
        }
        resolve([commitsOld, commitsNew, ninetyDaysAgo]);
      })
      .catch(error => {
        console.error(error);
      });

      if (autorecheck === true) {
            recheckGHCommits(recheckFrequency);
      }
  });
}

function recheckGHCommits(recheckFrequency) {
  var isIntervalInProgress;
  var intervalFrequency;

  if (isIntervalInProgress) { //bail if an Interval has already been triggered
    return false;
  }

  if (recheckFrequency != undefined && recheckFrequency != null) {
    if (recheckFrequency < 60000) { //bail, due to GitHub API rate limiting
      console.error("GitHub API rate limit is 60s");
      return false;
    } else {
      intervalFrequency = recheckFrequency;
    }
  } else {
    intervalFrequency = 60000; //default to 60s (GitHub API rate limit)
  }

  console.log("Checking GitHub every", intervalFrequency / 1000, "seconds");

  var checkGH = setInterval(function() {
    isIntervalInProgress = true;
    recentGitHubCommits(username)
      .then(function(value) {
        var valueSpan = document.getElementById("value-span"); //requires tweaking to your own elements
        var textSpan = document.getElementById("text-span"); //requires tweaking to your own elements
        var dateSpan = document.getElementById("date-span"); //requires tweaking to your own elements
        valueSpan.innerHTML = value[1];
        dateSpan.innerHTML = value[2];
      });
  }, intervalFrequency);
}

So how do you use this? Well, it's easy enough -

Next up, once you've pasted this wherever you need to, there are a couple of things that need tweaking:

  • First up, on Line 59 you need to add your own GitHub Personal Access Token. This will allow you to increase your rate limit for requests, if you so wish.

  • Lines 131-136 - these are bespoke elements on a really basic HTML page I set up. If you're planning on using this to display a GitHub counter on your site or something, change these to ensure you're selecting the right elements on your page!

Then, you call the function to kick things off! So an example of this would be:


recentGitHubCommits("willstocks-tech", true)
.then(
    function(value) {
        var commitEl = document.getElementById("commit-stats");
        var valueSpan = document.getElementById("value-span");
        var textSpan = document.getElementById("text-span");
        var dateSpan = document.getElementById("date-span");
        valueSpan.innerHTML = value[1];
        dateSpan.innerHTML = value[2];
        commitEl.append(valueSpan, textSpan, dateSpan);
    }
);

So here you can see I'm calling recentGitHubCommits("willstocks-tech", true) - I'm passing my GitHub handle and an autorecheck value of true, because I want the value to automatically update as and when I make commits to GitHub! I haven't passed the third variable of recheckFrequency, which means I'm going to use the default GitHub request frequency of 60s. What I could do here is something like recentGitHubCommits("willstocks-tech", true, 300000), which will make the request out to the GitHub API every 5 minutes!