technology from back to front

Using GitHub for planning

An important part of delivering software is knowing how long it will take to deliver some piece of functionality. Today we will see a small GitHub hack to help control estimation.

It’s all very well knowing the parts we need to implement some system. We need to know how long it will take to build. To that end, several of LShift’s GitHub-hosted projects use numeric tags to indicate the size of a task – maybe it’s in perfect engineering days, or abstract points. Regardless, with a large number of tickets, we can’t easily see how much work we’ve signed up for.

Something that would really help in understanding how much work is left in a milestone is simply totalling up the estimates. Given 5 tasks of 0.5 days each, and 2 tasks of 1 day each, it’d be nice to see at a glance that we have 5 × 0.5 + 2 × 1 = 4.5 days’ worth of work left.

Handily, Chrome makes it really easy to write an extension to augment GitHub’s pages.

A manifest tells Chrome about the extension, including where to find any scripts:

  "name": "GitHub Planning Helper",
  "version": "1.0",
  "manifest_version": 1,
  "description": "Display the total estimate for your GitHub milestones.",
  "content_scripts": [
      "matches": [
      "js": ["src/add-numeric-tags.js"]

And a simple little script does the work:

// Find all the labels
var labels = document.getElementsByClassName('filter-item');
var total = 0.0;
for (var i = 0; i < labels.length; i++) {
  var element = labels[i];
  var scale = element.querySelector('.name');
  var count = element.querySelector('.count');
  if (scale && count) {
    scale = parseFloat(scale.innerHTML);
    count = parseInt(count.innerHTML);
    // Filter out any non-numeric labels.
    // Also, protect against with non-numeric counts (which shouldn't
    // happen, but...).
    if (!isNaN(scale) && !isNaN(count)) {
      total += scale * count;

var hangPoint = document.querySelector('.info-secondary');
var totalDescription = "Total estimate: " + total.toString();

if (!hangPoint) {
  var progBar = document.querySelector('.sidebar-milestone-widget');
  var fakeInfo = document.createElement('div');
  fakeInfo.className = 'info-secondary';
  hangPoint = fakeInfo;
} else {
  totalDescription = "| " + totalDescription;

var display = document.createElement('span');
display.innerHTML = totalDescription;
display.className = 'open';

It’s not perfect – it currently only works on page loads (and GitHub likes their partial page loads) – but it does the job.

You can find the extension hosted, naturally enough, on GitHub.

Frank Shearar

7 × = thirty five

2000-14 LShift Ltd, 1st Floor, Hoxton Point, 6 Rufus Street, London, N1 6PE, UK+44 (0)20 7729 7060   Contact us