thunderbird-patch-review
Easy-to-use patch review interface for Thunderbird
Contribute: ~marcc/thunderbird-review-plugin@lists.sr.ht
git clone git://mccd.space/thunderbird-patch-review
| Log | Files | Refs | README | LICENSE |
patch-review.1 (6952B)
1 .TH PATCH\-REVIEW 1 "July 2026" "patch-review 0.1.0" "Thunderbird Patch Review"
2 .SH NAME
3 patch\-review \- review git patches from email inside Thunderbird
4 .SH SYNOPSIS
5 A Thunderbird MailExtension.
6 Open a patch email, press
7 .BR Review ,
8 comment on hunks, send the review as a mailing-list reply, and apply the
9 series to a local repository with
10 .BR git\-am (1).
11 .SH DESCRIPTION
12 .B patch\-review
13 brings a review interface to git-by-email workflows
14 .RB ( git\-send\-email (1)
15 style).
16 When the selected messages (or thread) look like a patch \(em a
17 .B [PATCH]
18 subject tag or a unified diff in the body \(em the
19 .B Review
20 button in the main toolbar becomes active.
21 It opens a dedicated review tab that shows the whole series:
22 cover letter, per-patch commit messages, and every file and hunk rendered
23 as a colored diff.
24 Within replaced lines, the span that actually changed gets a stronger
25 highlight, computed from the common prefix and suffix of each
26 deleted/added line pair.
27 .PP
28 Clicking a diff line attaches an inline comment to it; comments are saved
29 as drafts (keyed by Message-ID) and survive restarting Thunderbird.
30 .B Send review
31 turns the comments of each commented patch into one plain-text reply-to-all,
32 quoting the relevant hunks kernel-style with the comments interleaved
33 unquoted below the lines they target, and sends the replies immediately;
34 the draft comments are then cleared and the review tab closes.
35 The attached drop-down offers
36 .I "Preview in compose"
37 instead, which leaves the reply drafts open in compose windows.
38 A reply that fails to send also stays open, so nothing is lost.
39 .B Apply series
40 runs
41 .B git am \-\-3way
42 on the raw patch messages in the configured repository.
43 On conflict
44 .B git am \-\-abort
45 is run and its output reported, leaving the repository untouched.
46 Its drop-down offers
47 .I "Modify and apply"
48 \(em apply, then open the touched files in your editor \(em and
49 .I "Download patchset"
50 \(em save the raw series as one mbox file, ready for
51 .BR "git am" .
52 .SH INSTALLATION
53 Package the extension as an
54 .B .xpi
55 and install it via the Add-ons Manager gear menu
56 .RB ( "Install Add-on From File..." ).
57 From the project root:
58 .RS
59 .PP
60 (cd extension && zip -qrX ../patch\-review.xpi .)
61 .RE
62 .PP
63 The subshell runs the
64 .BR zip (1)
65 from inside
66 .I extension/
67 so the archive holds
68 .B manifest.json
69 at its root, not under
70 .IR extension/ .
71 .BR git (1)
72 is a dependency (for
73 .BR Apply ).
74 For development, instead pick
75 .IR "Tools \(-> Developer Tools \(-> Debug Add\-ons \(-> Load Temporary Add\-on..." ,
76 and select
77 .BR extension/manifest.json ;
78 it is dropped on restart.
79 .SH CONFIGURATION
80 Open the extension's preferences:
81 .TP
82 .B Editor command
83 Run from the repository after a successful apply, with the changed files as
84 arguments.
85 Use a non-blocking GUI-capable command such as
86 .B code \-n
87 or
88 .BR "emacsclient \-n" ;
89 a bare terminal editor has no terminal to open in.
90 Empty means
91 .BR $EDITOR .
92 .TP
93 .B Apply strategy
94 .B git am \-\-3way
95 (default) or plain
96 .BR "git am" .
97 .TP
98 .B Repository mappings
99 Substring matches against a patch's List-Id header or sender, mapped to an
100 absolute repository path.
101 When no mapping matches, the last path a series was applied to is used;
102 it is remembered until changed.
103 .PP
104 Repository paths can be chosen with the
105 .B Browse
106 button, which opens Thunderbird's native directory chooser; the path field
107 stays editable either way.
108 .SH PERMISSIONS
109 The extension requests the fewest permissions it needs;
110 none are granted to remote content.
111 .TP
112 .B messagesRead
113 Reads the selected message and its sibling patches in the same folder
114 (subject, author, body) to build the review.
115 .TP
116 .B accountsRead
117 Resolves the default identity of the account that owns the reviewed
118 message, for the From-address label and send-as.
119 .TP
120 .B storage
121 Persists draft comments (keyed by Message-ID) across restarts,
122 plus the editor command, apply strategy, repo mappings, and the last
123 applied repository path.
124 .TP
125 .BR compose , " (compose.send)"
126 Opens reply-to-all compose windows from
127 .B "Send review"
128 and sends them in
129 .I "Send now"
130 mode.
131 Without
132 .B compose.send
133 the review can only be previewed in compose, never sent.
134 .TP
135 .B downloads
136 Writes the
137 .I "Download patchset"
138 .B .mbox
139 to disk.
140 .TP
141 .B tabs
142 Opens the review tab and removes it after a successful send.
143 .PP
144 The privileged
145 .BR Apply ,
146 .IR "Browse... " ,
147 and
148 .I "Open editor"
149 code does not use a Mozilla permission:
150 it is a WebExtension Experiment
151 .RB ( experiment_apis.patchHost )
152 shipped inside the XPI and runs only when the extension is loaded.
153 .SH SOURCEHUT INTEGRATION
154 When the series arrives via a sourcehut mailing list (a
155 .B lists.sr.ht
156 address in the List-Id or recipients), the review tab shows a
157 .B "set status"
158 checkbox with the patchset states sourcehut understands:
159 APPROVED, NEEDS_REVISION, REJECTED, PROPOSED, SUPERSEDED, APPLIED.
160 When enabled, the first reply of the review carries an
161 .B X\-Sourcehut\-Patchset\-Update
162 header with the chosen status, which sourcehut applies to the patchset.
163 A status can also be sent without any line comments \(em
164 .B Send review
165 then sends a single, empty reply to the cover letter (or first patch)
166 carrying just the header.
167 .SH REVIEW WORKFLOW
168 .nf
169 1. Select any message of the series \(em or the whole
170 thread \(em and press Review in the main toolbar.
171 2. The tab collects the sibling patches from the same folder
172 (same series tag, version, and patch count).
173 3. Click lines, write comments; Ctrl+Enter saves.
174 "Comment on patch" attaches a general remark instead.
175 4. Send review: one reply per commented patch, sent
176 immediately (or use the drop-down to preview first).
177 5. Apply series: git am into the mapped repository,
178 then Open editor on the touched files.
179 .fi
180 .SH FILES
181 .TP
182 .I extension/
183 The MailExtension (manifest v2, vanilla ES modules, no build step).
184 .TP
185 .I extension/api/patchHost/
186 The privileged part (a WebExtension Experiment): runs
187 .BR git\-am (1)
188 and the editor through Thunderbird's Subprocess API and shows the
189 directory chooser with nsIFilePicker.
190 Everything outside this directory runs as ordinary sandboxed WebExtension
191 code.
192 .TP
193 .I tests/
194 .B node tests/run.mjs
195 exercises the pure modules (subject parsing, diff parsing, reply
196 formatting) against fixtures generated by
197 .BR git\-format\-patch (1),
198 and checks the experiment's manifest wiring.
199 Regenerate fixtures with
200 .BR tests/gen\-fixtures.sh .
201 .SH CAVEATS
202 Patches arriving as attachments, HTML-only mail, and reviewing from a git
203 worktree preview are not supported yet.
204 Series collection searches the folder of the opened message only.
205 .SH SEE ALSO
206 .PP
207 The introductory post can be found at
208 .MT https://mccd.space/posts/26-07-18/3-patch-review-tool-for-thunderbird
209 .ME
210 .SH CONTRIBUTING
211 Disclaimer: this plugin was vibe coded \(em written by an AI agent under
212 human direction.
213 .PP
214 Contributions and bug reports go to the mailing list:
215 .MT ~marcc/thunderbird\-review\-plugin@lists.sr.ht
216 .ME
217 .SH AUTHOR
218 Marc Coquand
219 .MT marc@coquand.email
220 .ME