disclaimer: I know there are multiple jira-to-org extensions available already. For what I've seen thus far is that none of them support using multiple instances out of the box. If I ever find the time to look into these packages and figure out a nice solution that may make these functions obsolete I will update this post accordingly.
At the company I work at we work on multiple projects and those projects belong to multiple clients. As a result we have a multitude of Jira boards spread across multiple Jira instances. Sometimes I just want to be able to quickly jump to either a specific issue (when a coworker mentions it on a video call) or to the board itself. This package will give me access to both at lightning speed, without having to navigate that great Jira UI.
The code for this project can also be found at GitHub.
To open an issue or the board itself, press
C-c j j (or
jira-jump RET) in any buffer, and it will open the page in your
When you invoke this command the commandline will query you for the
project slug of which the completion has been prefilled with all
configured project slugs. Pressing
Enter on a project slug will
take you to the project board. However, if you suffix the slug with
an issuenumber (e.g.
FOOBAR-123) it will take you directly to the
Sometimes, you don't need the page to be opened, but you need the actual link instead.
- Prefixing this command a single time (
C-u C-c j j) will send the link to the kill-ring instead.
- Prefixing it twice (
C-u C-u C-c j j) will insert an org-mode link into the current buffer.
You can install this package using straight. Configure
jira-jump--projects as shown in the example below.
1(use-package jira-jump 2 :ensure 3 :straight (jira-jump :repo "https://github.com/faijdherbe/jira-jump.el") 4 :bind (("C-c j j" . jira-jump-open-in-browser) 5 ("C-c j w" . jira-jump-send-to-kill-ring) 6 ("C-c j l" . jira-jump-insert-org-mode-link)) 7 :config 8 (setq jira-jump--projects 9 '(("Client A" . ((instance . "https://client_a.atlassian.net") 10 (projects . ("FOO" "BAR")))) 11 ("Client B" . ((instance . "https://client_b.atlassian.net") 12 (projects . ("GARDN" "LIVINGRM" "KITCHN")))) 13 ("Internal" . ((instance . "https://my-company.atlassian.net") 14 (projects . ("DEVIMPR" "ONBOARDNG" "SUPPRT")))))))
We'll start off with a few lines of comments, as this might as well be a simple package.
1;;; jira-jump.el --- Quickly jump to a Jira issue or board. -*- lexical-binding: t; -*- 2 3;; Copyright (C) 2023 Jeroen Faijdherbe. 4 5;; Author: J. Faijdherbe <email@example.com> 6;; Version: 1.3 7;; Created: 3 Feb 2023 8;; Keywords: jira, browser, org-mode 9;; URL: https://github.com/faijdherbe/jira-jump.el 10 11;; This file is not part of GNU Emacs. 12 13;;; Commentary: 14 15;; This package provides a simple interactive function that allows you 16;; to open any known project or issue in your browser. 17 18;;; Code:
First we define our configurable variable
alist is the source for determining the instance we will redirect to
1(defvar jira-jump--projects 2 '() 3 "Alist of Jira projects per host. This doc needs to be expanded.")
The following methods extract specific data from the configuration based on given input.
1(defun jira-jump--tag-for-issue (issue) 2 "Returns the TAG part of a Jira ISSUE. Currently it splits the 3given ISSUE on the - character, and returns the car of the 4result. We might want to change this to a regex match, grabbing 5all alpha characters from the start of the string. " 6 (upcase (car (split-string issue "-")))) 7 8(defun jira-jump--get-project (tag) 9 "Looks up the jira project in jira-jump--projects based on TAG. 10Returns nil if nothing is found." 11 (let ((data nil)) 12 (dolist (project jira-jump--projects) 13 (if (member tag (alist-get 'projects (cdr project))) 14 (setq data project))) 15 data)) 16 17(defun jira-jump--make-link (issue) 18 "Creates url to correct Jira instance base on TAG in ISSUE (the 19part before the -). Returns nil if no project can be found for 20given issue." 21 (let* ((tag (jira-jump--tag-for-issue issue)) 22 (project (jira-jump--get-project tag)) 23 (instance (alist-get 'instance (cdr project)))) 24 (cond (instance (concat instance "/browse/" issue)) 25 (t nil))))
When querying the user for a Jira issue, we want to provide all available projects. This method will grab all configured projects and return it as a flattened list.
1(defun jira-jump--all-project-tags () 2 "Collects all project tags from all configured instances in 3=jira-jump--projects=." 4 (apply #'append (mapcar (lambda (project) 5 (alist-get 'projects project)) 6 jira-jump--projects)))
All parsing methods and providers are now in place. Next we need to retrieve information from the user about what board or issue he would like to visit. For the time being, we simply query the user for the issue, providing all available project tags as the completion list. In the future, this might need to become a multi-step input method with smarter completion incorporated.
1(defun jira-jump--read-issue () 2 (completing-read "Issue: " (jira-jump--all-project-tags)))
With all prerequisites in place we can now define our interactive method. This methods will accept one or two prefix arguments. When no prefix argument is supplied, the default behaviour is triggered an the link will be sent to the default browser. A single prefix argument will add the link to the kill-ring, available for yanking anywhere you want (e.g. in your Slack conversation). A double prefix argument will insert an org-mode formatted link into the current buffer.
1(defun jira-jump-send-to-kill-ring () 2 "" 3 (interactive) 4 (let* ((issue (jira-jump--read-issue)) 5 (link (jira-jump--make-link issue))) 6 (kill-new link) 7 (message (format "Stored Jira link to issue %s (%s) in kill-ring." 8 issue 9 link)))) 10 11(defun jira-jump-insert-org-mode-link () 12 "" 13 (interactive) 14 (let* ((issue (jira-jump--read-issue)) 15 (link (jira-jump--make-link issue))) 16 (insert (format "[[%s][%s]]" 17 link 18 issue)))) 19 20(defun jira-jump-open-in-browser () 21 "" 22 (interactive) 23 (let* ((issue (jira-jump--read-issue)) 24 (link (jira-jump--make-link issue))) 25 (message (format "Opening issue %s in browser..." issue)) 26 (browse-url-default-browser link))) 27 28(defun jira-jump (arg) 29 "Open jira issue in browser. A single prefix command will send 30the link to the kill ring and a double prefix argument will 31insert an org-mode link at point." 32 (interactive "P") 33 (cond ((= 4 (prefix-numeric-value arg)) 34 (jira-jump-send-to-kill-ring)) 35 ((= 16 (prefix-numeric-value arg)) 36 (jira-jump-insert-org-mode-link)) 37 (t (jira-jump-open-in-browser))))
Assign the link builder to the
jira: prefix in org-mode links. This
will make links like
[[jira:FOOBAR-21]] link directly to the Jira
1(add-to-list 'org-link-abbrev-alist 2 '("jira" . "%(jira-jump--make-link)"))
And then some closing comments.
1(provide 'jira-jump) 2;;; jira-jump.el ends here