I do a lot of work on projects which are on Github and use the Github issues. Because I use Org mode a lot, I thought that it would be nice if I could create Github issues out of my Org mode todo entries. I wanted to learn Emacs Lisp since I started using Emacs, so this was a opportunity to do so.

At first, we need to get the current Org element. There is some documentation about the Org Element API here: http://orgmode.org/worg/dev/org-element-api.html

To get the current heading, we can use

(org-get-heading)

To get the body of the element, there is (org-get-entry). The similarly named (org-entry-get) method returns something different: It gets the property of an Org mode element. This is described in the Org mode manual A.11 Using the property API. We can use that to store the Github project for the current Org mode file. Because properties and be inherited, we have to declare it once in the top level heading properties.

:PROPERTIES:
:GH-PROJECT: mbreit/foobar
:END:

To get the property for the element at the point (that is how the current cursor position is being called in Emacs), we use:

(org-entry-get (point) "GH-PROJECT" t)

The last parameter for org-entry-get tells the function, that we want to get inherited properties from parent headline.

When creating issues from Org mode, I do not want the issue to be created automatically. If we can open URL in the browser with our Org mode entry details filled in, we could review and change the issue before creating it.

Luckily, Github has a URL scheme for prefilling the issue form field. If we open a URL like https://github.com/mbreit/foobar/issues/new?title=mytitle&body=mybody, we get what we want. We have to URL encode our title and body of course, and that is what the url-hexify-string Lisp function is for. Now we can define a function that returns a URL like this:

(defun gh-issue-new-url (project title body)
  (concat "https://github.com/"
          project
          "/issues/new?title="
          (url-hexify-string title)
          "&body="
          (url-hexify-string body)))

To open a new browser tab with a given URL, browse-url can be used.

(defun gh-issue-new-browse (project title body)
  (browse-url (gh-issue-new-url project title body)))

Now we define a function for our current Github project with the org-entry-get function described above.

(defun gh-issue-get-project ()
  (org-entry-get (point) "GH-PROJECT" t))

Let’s put this all together in an interactive function that we can bind to a key:

(defun gh-issue-create ()
  (interactive)
  (gh-issue-new-browse (gh-issue-get-project) (org-get-heading) (org-get-entry)))

This works great, but the body is filled with our Org mode entry, which might have some Org mode markup, which is not the same as Markdown, which Github uses for its issues.

The Org export framework can convert Org mode syntax to Latex and HTML, but also to Markdown. There is even an export for Github flavored markdown or GFM: http://orgmode.org/cgit.cgi/org-mode.git/plain/contrib/lisp/ox-gfm.el

The Org Export API has a function org-export-as, which can return the converted Org buffer in any format that the export framework supports. There is an optional parameter subtreep for exporting only the current subtree, which is what we want.

If ox-gfm is installed, we can use (org-export-as 'gfm t) to get the current entry as markdown. Let’s use that instead of (org-get-entry):

(defun gh-issue-create ()
  (interactive)
  (gh-issue-new-browse (gh-issue-get-project)
                       (org-get-heading)
                       (org-export-as 'gfm t)))

The complete code

With ox-gfm installed, you can add the following code to your Emacs configuration and bind a key to gh-issue-create:

(defun gh-issue-new-url (project title body)
  (concat "https://github.com/"
          project
          "/issues/new?title="
          (url-hexify-string title)
          "&body="
          (url-hexify-string body)))

(defun gh-issue-new-browse (project title body)
  (browse-url (gh-issue-new-url project title body)))

(defun gh-issue-get-project ()
  (org-entry-get (point) "GH-PROJECT" t))

(defun gh-issue-create ()
  (interactive)
  (gh-issue-new-browse (gh-issue-get-project)
                       (org-get-heading)
                       (org-export-as 'gfm t)))

I love Emacs and Org mode for making such things possible with so little code.

Future

In this blog post, the interaction with Github is done with the browser, not the Github API. The advantage of this is that our Emacs Lisp code does not have to handle authentication. But using the API would be much more powerful. So I am working on an Emacs package that uses the gh.el implementation to talk with the Github API for importing and syncing your Org mode elements directly from within Emacs.

So if you are interested, stay tuned on this blog or follow me on Twitter (@m_breit) to get notified when I release this package.