changelog エントリを自動挿入する elisp

お仕事で bug fix した rpm パッケージの spec ファイルを修正したついでに、changelog エントリを自動挿入する elisp を書いてみた。change-log-mode も rpm-spec-mode もよくできているが、日付フォーマットなど細かい制御は自分で行ったほうがより便利だ。

これで M-x my-rpm-add-changelog-entry すればエントリの中に日付とかメールアドレスとか自動で挿入される。バッファの中を検索してリリース番号も入れるようにした。こういうことはなるたけプログラムにやらせないとね。

(setq auto-mode-alist
      (cons '("\\.spec$" . rpm-spec-mode) auto-mode-alist))

(setq user-full-name "kyagi")
(setq user-mail-address "kyagi@example.com")

(autoload 'rpm-spec-mode "rpm-spec-mode" "" t)

(defun my-rpm-goto-section-changelog ()
  (interactive)
  (goto-char (point-min))
  (if (search-forward-regexp "^%changelog" nil t)
    (and (goto-char (match-beginning 0)) (next-line))))

(defun my-rpm-get-version-tag-on-buffer ()
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (let ((version))
      (if (search-forward-regexp "^Version:[ \t]*\\([0-9]+\\)\\(.*\\)" nil t)
          (setq version (concat (match-string 1) (match-string 2)))
        (if (search-forward-regexp "^Version:[ \t]*%{?\\([^}]*\\)}?$" nil t)
            (setq version (match-string 1)))
      version))))

(defun my-rpm-get-release-tag-on-buffer ()
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (let ((release))
      (if (search-forward-regexp "^Release:[ \t]*\\([0-9]+\\)\\(.*\\)" nil t)
          (setq release (concat (match-string 1) (match-string 2)))
        (if (search-forward-regexp "^Release:[ \t]*%{?\\([^}]*\\)}?$" nil t)
            (setq release (match-string 1)))
      release))))

(defun my-rpm-add-changelog-entry ()
  (interactive)
  (rpm-increase-release-tag)
  (my-rpm-goto-section-changelog)
  (setq system-time-locale "C")
  (insert (concat
       (format-time-string "* %a %b %d %Y ")
       (format "%s <%s> " user-full-name user-mail-address)
       (my-rpm-get-version-tag-on-buffer) "-"
       (my-rpm-get-release-tag-on-buffer)))
  (insert "\n- \n\n")
  (previous-line 2)
  (forward-char 2))

参考サイト

また、ありがたいことに英語でどう changelog を書くかをまとめたサイトがある。同僚に教えたら絶賛していた。