Linking JIRA issues back from GitHub

If you’re using JIRA and GitHub, you probably also use GitHub plugin for JIRA, which allows you to link GitHub PRs from JIRA tickets. However, there is nothing that establishes linking in the other direction. Until now, that is…

In order to get linking from GitHub PRs to JIRA tickets, you need two things, which are actually three things:

  1. Your PR titles (and preferably, commit message subjects) should contain JIRA ticket IDs. For example, a well named PR is “PROJ-123 backend: Add support for Postgres”.
  2. Greasemonkey/Tampermonkey extension installed in Firefox or Chrome (Safari is not supported at the moment).

With the above requirements in place, you just need the following user script installed (this script is also available as a gist). Please change jiraUrl and issueRegExp to match your settings. In most of the cases, you don’t have to touch issueRegExp.

// ==UserScript==
// @name         GitHub/JIRA Links
// @namespace    http://github.com/knl
// @author       knl
// @version      1.0
// @description  Link to JIRA tickets from Github
// @match        https://github.com/**
// @run-at       document-end
// @noframes
// @grant        none
// ==/UserScript==

const jiraUrl     = 'https://my.jira.server';
const issueRegExp = '([A-Z]+\-[0-9]+)(?!")';

function doIt(node) {
    // we actually iterate over the whole document now
    document.querySelectorAll("p, pre, h1, a").forEach(function(elem) {
        const regex = new RegExp(issueRegExp, 'g');
        elem.innerHTML = elem.innerHTML.replace(regex, '<a href="' + jiraUrl + '/browse/$1">$1</a>');
    });
}

/* Wait for selected elements to appear on the page and process them */
function waitForKeyElements (
    selectorTxt,    /* Required: The selector string that specifies the desired element(s). */
    actionFunction, /* Required: The code to run when elements are found. Gets a node to the matched element. */
) {
    document.querySelectorAll(selectorTxt).forEach(function(node) {
        var alreadyFound = node.alreadyFound || false;

        if (!alreadyFound) {
            //--- Call the payload function.
            actionFunction(node);
            node.alreadyFound = true;
        }
    });

    var timeControl = waitForKeyElements.timeControl;

    //--- Set a timer, if needed.
    if (!timeControl) {
        timeControl = setInterval(function () {
            waitForKeyElements(selectorTxt, actionFunction);
        },
                                  1000
                                 );
        waitForKeyElements.timeControl = timeControl;
    }
}

waitForKeyElements ("#commits_bucket, #discussion_bucket, #files_bucket, .subnav", doIt);

When this user script runs, it will modify all occurrences of text that looks like JIRA ticket IDs, and turn them into clickable links.

The code works by waiting for GitHub page to load the right containers and then searches for the ticket-id-looking text. The first step is needed because GitHub is an application that relies heavily on AJAX to load the elements, and simply waiting onLoad() would not work.