An Emacs package to automatically add JIRA tickets in git-commit
buffers.
Some licensing bullshit:
;;; git-commit-jira.el --- Automatically insert JIRA tickets in git commits -*- lexical-binding: t -*-
;; Copyright (C) 2023 Vitor Leal
;; Author: Vitor Leal <[email protected]>
;; URL: https://github.com/nvimtor/git-commit-jira.el
;; Version: 0.1.0
;; Package-Requires: ((emacs "25.1"))
;; This file is not part of GNU Emacs.
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;
;; The git-commit-jira package automatically inserts JIRA ticket identifiers
;; into git commit messages based on the current branch name.
;;
;;; Code:
Require dependencies. eval-when-compile
is used to load a library only during the compilation of this code, rather than at runtime.
(eval-when-compile
(require 'vc-git))
Originally, this was done using the s
library’s s-split-words
, but as it is a simple function, we will just define our own:
(defun git-commit-jira-split-words (string)
"Split STRING into a list of words, using non-word characters as delimiters."
(split-string string "[^[:word:]]+"))
Let’s start by creating a customization group.
(defgroup git-commit-jira nil
"Customization group for the git-commit-jira package."
:group 'tools
:prefix "git-commit-jira-")
Define a Regular expression that matches JIRA tickets. We need one to match it in brackets (for commit messages), and one without (for branch names).
(defcustom git-commit-jira-ticket-regex-brackets "\\[[A-Za-z]+-[0-9]+\\]"
"Regex pattern used to match JIRA ticket identifiers that are wrapped in brackets, e.g., [ABC-123]."
:type 'regexp
:group 'git-commit-jira)
(defcustom git-commit-jira-ticket-regex-nobrackets "\\([A-Za-z]+-[0-9]+\\)"
"Regex pattern used to match JIRA ticket identifiers that are not wrapped in brackets, e.g., ABC-123."
:type 'regexp
:group 'git-commit-jira)
This block defines a function to retrieve the current branch name, using vc
.
(defun git-commit-jira-vc-current-branch ()
"Get the current git branch using VC."
(car (vc-git-branches)))
And this going to be the default function.
(defcustom git-commit-jira-get-current-branch-function #'git-commit-jira-vc-current-branch
"Function to retrieve the current branch name."
:type 'function
:group 'git-commit-jira)
This is the main function. It inserts the JIRA ticket identifier. It is pretty much the same as the one from gopar’s video, but it checks if the current commit message already contains a JIRA ticket. This is especially useful for commit amends.
(defun git-commit-jira-insert-ticket ()
"Insert a JIRA ticket identifier from the branch name into the commit message if not already present."
(let ((branch-name (funcall git-commit-jira-get-current-branch-function))
(commit-message (buffer-string)))
(unless (string-match git-commit-jira-ticket-regex-brackets commit-message)
(when (string-match git-commit-jira-ticket-regex-nobrackets branch-name)
(let ((words (git-commit-jira-split-words branch-name)))
(insert (format "[%s-%s] " (car words) (car (cdr words)))))))))
The minor mode.
(define-minor-mode git-commit-jira-mode
"Minor mode to automatically insert JIRA ticket in git commit messages."
:global t
:group 'git-commit-jira
(if git-commit-jira-mode
(add-hook 'git-commit-setup-hook #'git-commit-jira-insert-ticket)
(remove-hook 'git-commit-setup-hook #'git-commit-jira-insert-ticket)))
Let’s extend what we currently have by allowing users to optionally control the case of the ticket.
(defcustom git-commit-jira-uppercase-ticket t
"If non-nil, the JIRA ticket identifier will be converted to uppercase."
:type 'boolean
:group 'git-commit-jira)
(defun git-commit-jira-uppercase-advice (func &rest args)
"Advice to conditionally uppercase the inserted JIRA ticket."
(let ((start (point)))
(apply func args)
(when git-commit-jira-uppercase-ticket
(save-excursion
(goto-char start)
(while (re-search-forward git-commit-jira-ticket-regex-brackets nil t)
(replace-match (upcase (match-string 0)) t))))))
(advice-add 'git-commit-jira-insert-ticket :around #'git-commit-jira-uppercase-advice)
Provide the package.
(provide 'git-commit-jira)
;;; git-commit-jira.el ends here
(car (vc-git-branches))
According to this StackOverflow post, vc-git-branches
will always return the current branch as the first element.