Why do you only discover bugs _after_ you've committed?
[slh] / patch-keywords.el
1 ;;; patch-keywords.el --- Insert action keywords into patch followups.
2
3 ;; Copyright (C) 2002 Steve Youngs
4
5 ;; RCS: $Id: patch-keywords.el,v 1.4 2003/08/17 09:34:55 adrian Exp $
6 ;; Author:        Steve Youngs <youngs@xemacs.org>
7 ;; Maintainer:    Steve Youngs <youngs@xemacs.org>
8 ;; Created:       2002-01-14
9 ;; Last-Modified: <2002-03-04 07:18:01 (steve)>
10 ;; Keywords:      maint
11
12 ;; This file is part of XEmacs
13
14 ;; XEmacs is free software; you can redistribute it and/or modify
15 ;; it under the terms of the GNU General Public License as published by
16 ;; the Free Software Foundation; either version 2 of the License, or
17 ;; (at your option) any later version.
18
19 ;; XEmacs is distributed in the hope that it will be useful,
20 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 ;; GNU General Public License for more details.
23
24 ;; You should have received a copy of the GNU General Public License
25 ;; along with this program; if not, write to the Free Software
26 ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
27
28
29 ;;; Commentary:
30 ;;
31 ;;  This file is an aid to mailing followups to patches submitted via
32 ;;  email.  It adds "Reviewer Action Keywords" to the message.  These
33 ;;  "keywords" can later be used as an aid to patch tracking.
34
35 ;;  At this stage, this file is probably only useful to anyone who
36 ;;  reviews patches submitted to <xemacs-patches@xemacs.org>.
37
38 ;;  To use: 
39 ;;    - M-x customize-group RET patch-review RET
40 ;;       Change things to your liking.
41 ;;    - (require 'patch-keywords)
42 ;;       In your ~/.xemacs/init.el
43
44 ;;  Then when you are following up to a patch submission, just hit
45 ;;  'M-p'.  You'll be prompted for the keywords to apply to the
46 ;;  message.  You can use the history mechanism to select keywords.
47 ;;  Enter a null keyword (just hit 'RET') to terminate the list of
48 ;;  keywords.
49
50 ;;  The keywords are added to 3 separate places in the message.
51 ;;    - In abbreviated form (1st character of each keyword) enclosed
52 ;;      in square brackets at the start of the subject header (version
53 ;;      numbers are not abbreviated).
54 ;;
55 ;;    - In a "X-Reviewer-Action:" header (full keywords).
56 ;;
57 ;;    - At line 0, column 0 of the message body.
58
59 ;;  To see how to setup a "X-Reviewer-Action:" header, see
60 ;;  `gnus-posting-styles'
61
62 ;;  Many thanks to Adrian Aichner <adrian@xemacs.org> for his ideas,
63 ;;  code examples and testing.
64
65 ;;; Code:
66 (eval-when-compile
67   (require 'message)
68   (autoload 'gnus-continuum-version "gnus"))
69
70 ;;;###autoload
71 (defgroup patch-review nil
72   "Patch submission review."
73   :group 'mail)
74
75 (defcustom patch-keywords
76   '("APPROVE"
77     "COMMIT"
78     "FORWARD"
79     "QUERY"
80     "RECOMMEND"
81     "SUPERSEDES"
82     "VETO"
83     "21.4"
84     "21.5")
85   "List of keywords used for reviewing patches.
86
87 The default values are the keywords currently used by the XEmacs
88 Review Board."
89   :group 'patch-review
90   :type '(repeat (string :tag "Review Action Keyword"))
91   :tag "Action Keywords")
92
93 (defcustom patch-review-mua 'gnus
94   "The MUA (Mail User Agent) you use for reviewing patches.
95
96 Currently, the only MUAs that are supported are Gnus and VM.  Should
97 we even bother with things like MEW or Rmail?"
98   :group 'patch-review
99   :type '(choice
100           (item gnus)
101           (item vm)
102           (item mew\ \(Not\ Supported\))
103           (item rmail\ \(Not\ Supported\)))
104   :tag "MUA")
105
106 (defcustom patch-keywords-followup-to "XEmacs Beta <xemacs-beta@xemacs.org>"
107   "The address to put into the \"Mail-Followup-To:\" header.
108 This is so that any further discussions relating to the submitted
109 patch can take place in a separate forum."
110   :group 'patch-review
111   :type 'string
112   :tag "Followups Address")
113
114 ;; I use the bleeding edge Gnus (Oort 0.05), so consequently we have
115 ;; to define a couple of functions that aren't in the XEmacs package
116 ;; version of Gnus (5.8.8).  Later on they're wrapped in a version
117 ;; test.
118 (defun patch-keywords-in-header-p ()
119   "Return t if point is in the header.
120 Same as `message-point-in-header-p' which exists in Gnus Oort, but not
121 in Gnus 5.8.8"
122   (save-excursion
123     (let ((p (point)))
124       (goto-char (point-min))
125       (not (re-search-forward
126             (concat "^" (regexp-quote mail-header-separator) "\n")
127             p t)))))
128
129 (defun patch-keywords-message-beginning-of-line (&optional n)
130   "Move point to beginning of header value or to beginning of line.
131 Optional argument N non-nil or 1, move forward N - 1 lines first.
132 Same as `message-beginning-of-line' which exists in Gnus Oort, but not
133 in Gnus 5.8.8."
134   (interactive "p")
135   (if (if (< (gnus-continuum-version gnus-version) 5.090004)
136         (patch-keywords-in-header-p)
137       (message-point-in-header-p))
138       (let* ((here (point))
139              (bol (progn (beginning-of-line n) (point)))
140              (eol (gnus-point-at-eol))
141              (eoh (re-search-forward ": *" eol t)))
142         (if (or (not eoh) (equal here eoh))
143             (goto-char bol)
144           (goto-char eoh)))
145     (beginning-of-line n)))
146
147 (defun patch-keywords-insert-gnus (patch-key)
148   "Insert the action keywords into patch followups.
149
150 Argument PATCH-KEY A list of action keywords as defined in
151 `patch-keywords'.  They may be chosen interactively via the
152 history mechanism.
153
154 Insert abbreviated (1st char) keywords at the beginning of the subject
155 header.  Full keywords into the \"X-Reviewer-Action:\" header, if
156 present, and also at the start of the message body.
157
158 The \"X-Reviewer-Action:\" header can be easily inserted using
159 `gnus-posting-styles'.
160
161 This function also sets followups to xemacs-beta@xemacs.org."
162   (interactive
163    (let
164        ((hist patch-keywords)
165         key
166         keys)
167      (while (not
168              (string-equal
169               (setq key
170                     (read-string
171                      "Enter patch keywords (or RET to finish): " "" 'hist))
172               ""))
173        (setq keys (cons key keys)))
174      (list (mapconcat 'identity (reverse keys) " "))))
175   (if (string-equal patch-key "")
176       (error "Choose at least one patch-key from %s"
177              (mapconcat 'identity patch-keywords ", ")))
178   (save-excursion
179     ;; We need to preserve the original subject header so something
180     ;; like "fix for 21.5 not for 21.4" doesn't turn into "fix for
181     ;; 21.5not for 21.4"
182     (message-goto-subject)
183     (if (< (gnus-continuum-version gnus-version) 5.090004)
184         (patch-keywords-message-beginning-of-line)
185       (message-beginning-of-line))
186     (re-search-forward ".*$" (eolp) t)
187     (let ((oldsub (match-string 0))
188           (keywords (concat "\\("
189                             (regexp-opt patch-keywords)
190                             "\\) ")))
191       ;; Clear the original subject (reinstate it later)
192       (if (< (gnus-continuum-version gnus-version) 5.090004)
193           (patch-keywords-message-beginning-of-line)
194         (message-beginning-of-line))
195       (if (re-search-forward ".*$" (eolp) t)
196           (replace-match ""))
197       ;; Insert the long patch keywords
198       (insert-string
199        (concat "[" patch-key " ]"))
200       (insert-string " ")
201       ;; Convert to abbreviated patch keywords
202       (if (< (gnus-continuum-version gnus-version) 5.090004)
203           (patch-keywords-message-beginning-of-line)
204         (message-beginning-of-line))
205       (save-restriction
206         (narrow-to-region (point) (point-at-eol))
207         (while (re-search-forward keywords (eolp) t)
208           (let ((keyword (match-string 1)))
209             (if (save-match-data
210                   (string-match "\\`[.0-9]+\\'" keyword))
211                 (replace-match (match-string 1))
212               (replace-match (substring (match-string 1) 0 1))))))
213       ;; Reinstate the original subject header after the keywords
214       (end-of-line)
215       (insert-string oldsub))
216     ;; Insert keywords into the 'X-Reviewer-Action:' header
217     (goto-line 0)
218     (if (re-search-forward "^X-Reviewer-Action: " nil t)
219         (insert-string patch-key))
220     ;; Set followups to go to xemacs-beta
221     (if (< (gnus-continuum-version gnus-version) 5.090004)
222         (message-position-on-field "Mail-Followup-To" "From")
223       (message-goto-mail-followup-to))
224     (insert-string patch-keywords-followup-to)
225     ;; Insert the keywords into the body of the message
226     (message-goto-body)
227     (insert-string patch-key)
228     (insert-string "\n\n")))
229
230 (defun patch-keywords-insert-vm (patch-key)
231   "Insert the action keywords into patch followups.
232
233 Argument PATCH-KEY A list of action keywords as defined in
234 `patch-keywords'.  They may be chosen interactively via the
235 history mechanism.
236
237 Insert abbreviated (1st char) keywords at the beginning of the subject
238 header.  Full keywords into the \"X-Reviewer-Action:\" header, and
239 also at the start of the message body.
240
241 This function also sets followups to xemacs-beta@xemacs.org."
242   (interactive
243    (let
244        ((hist patch-keywords)
245         key
246         keys)
247      (while (not
248              (string-equal
249               (setq key
250                     (read-string
251                      "Enter patch keywords (or RET to finish): " "" 'hist))
252               ""))
253        (setq keys (cons key keys)))
254      (list (mapconcat 'identity (reverse keys) " "))))
255   (if (string-equal patch-key "")
256       (error "Choose at least one patch-key from %s"
257              (mapconcat 'identity patch-keywords ", ")))
258   (save-excursion
259     ;; We need to preserve the original subject header so something
260     ;; like "fix for 21.5 not for 21.4" doesn't turn into "fix for
261     ;; 21.5not for 21.4"
262     (mail-subject)
263     (patch-keywords-message-beginning-of-line)
264     (re-search-forward ".*$" (eolp) t)
265     (let ((oldsub (match-string 0))
266           (keywords (concat "\\("
267                             (regexp-opt patch-keywords)
268                             "\\) ")))
269       ;; Clear the original subject (reinstate it later)
270       (patch-keywords-message-beginning-of-line)
271       (if (re-search-forward ".*$" (eolp) t)
272           (replace-match ""))
273       ;; Insert the long patch keywords
274       (insert-string
275        (concat "[" patch-key " ]"))
276       (insert-string " ")
277       ;; Convert to abbreviated patch keywords
278       (patch-keywords-message-beginning-of-line)
279       (save-restriction
280         (narrow-to-region (point) (point-at-eol))
281         (while (re-search-forward keywords (eolp) t)
282           (let ((keyword (match-string 1)))
283             (if (save-match-data
284                   (string-match "\\`[.0-9]+\\'" keyword))
285                 (replace-match (match-string 1))
286               (replace-match (substring (match-string 1) 0 1))))))
287       ;; Reinstate the original subject header after the keywords
288       (end-of-line)
289       (insert-string oldsub))
290     ;; Insert keywords into the 'X-Reviewer-Action:' header
291     (goto-line 0)
292     (insert-string (concat "X-Reviewer-Action: " patch-key "\n"))
293     ;; Set followups to go to xemacs-beta
294     (goto-line 0)
295     (insert-string "Mail-Followup-To: ")
296     (insert-string (concat patch-keywords-followup-to "\n"))
297     ;; Insert the keywords into the body of the message
298     (mail-text)
299     (insert-string patch-key)
300     (insert-string "\n\n")))
301
302 ;; Bind 'patch-keywords-insert-MUA' to M-p.
303 (cond ((string= patch-review-mua "gnus")
304        (define-key message-mode-map "\M-p" 'patch-keywords-insert-gnus))
305       ((string= patch-review-mua "vm")
306        (define-key mail-mode-map "\M-p" 'patch-keywords-insert-vm)))
307
308 (provide 'patch-keywords)
309
310 ;;; patch-keywords.el ends here
311
312 ;Local Variables:
313 ;time-stamp-start: "Last-Modified:[     ]+\\\\?[\"<]+"
314 ;time-stamp-end: "\\\\?[\">]"
315 ;time-stamp-line-limit: 10
316 ;time-stamp-format: "%4y-%02m-%02d %02H:%02M:%02S (%u)"
317 ;End: