Use a template to set the subject line.
Add an admin editable ChangeSubject.vm template used to format the subject header in change emails. Change-Id: Iea58807b9a947bf0a4eba31c04977582430137ed
This commit is contained in:
parent
bfa5a181b3
commit
b7f3b2d5be
|
@ -0,0 +1,120 @@
|
|||
Gerrit Code Review - Mail Templates
|
||||
===================================
|
||||
|
||||
Gerrit uses velocity templates for the bulk of the standard mails it sends out.
|
||||
There are builtin default templates which are used if they are not overridden.
|
||||
These defaults are also provided as examples so that administrators may copy
|
||||
them and easily modify them to tweak their contents.
|
||||
|
||||
|
||||
Template Locations and Extensions:
|
||||
----------------------------------
|
||||
|
||||
The default example templates reside under: `'$site_path'/etc/mail` and are
|
||||
terminated with the double extension `.vm.example`. Modifying these example
|
||||
files will have no effect on the behavior of Gerrit. However, copying an
|
||||
example template to an equivalently named file without the `.example` extension
|
||||
and modifying it will allow an administrator to customize the template.
|
||||
|
||||
|
||||
Supported Mail Templates:
|
||||
-------------------------
|
||||
|
||||
Each mail that Gerrit sends out is controlled by at least one template, these
|
||||
are listed below. Change emails are influenced by two additional templates,
|
||||
one to set the subject line, and one to set the footer which gets appended to
|
||||
all the change emails (see `ChangeSubject.vm` and `ChangeFooter.vm` below.)
|
||||
|
||||
ChangeSubject.vm
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
The `ChangeSubject.vm` template will determine the contents of the email
|
||||
subject line for ALL emails related to changes.
|
||||
|
||||
|
||||
Mail Variables and Methods
|
||||
--------------------------
|
||||
|
||||
Mail templates can access and display objects currently made available to them
|
||||
via the velocity context. While the base objects are documented here, it is
|
||||
possible to call public methods on these objects from templates. Those methods
|
||||
are not documented here since they could change with every release. As these
|
||||
templates are meant to be modified only by a qualified sysadmin, it is accepted
|
||||
that writing templates for Gerrit emails is likely to require some basic
|
||||
knowledge of the class structure to be useful. Browsing the source code might
|
||||
be necessary for anything more than a minor formatting change.
|
||||
|
||||
Warning
|
||||
~~~~~~~
|
||||
|
||||
Be aware that modifying templates can cause them to fail to parse and therefor
|
||||
not send out the actual email, or worse, calling methods on the available
|
||||
objects could have internal side effects which would adversely affect the
|
||||
health of your Gerrit server and/or data.
|
||||
|
||||
All OutgoingEmails
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
All outgoing emails have the following variables available to them:
|
||||
|
||||
$email::
|
||||
+
|
||||
A reference to the class constructing the current `OutgoingEmail`. With this
|
||||
reference it is possible to call any public method on the OutgoingEmail class
|
||||
or the current child class inherited from it.
|
||||
|
||||
$messageClass::
|
||||
+
|
||||
A String containing the messageClass
|
||||
|
||||
$StringUtils::
|
||||
+
|
||||
A reference to the Apache `StringUtils` class. This can be very useful for
|
||||
formatting strings.
|
||||
|
||||
Change Emails
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
All change related emails have the following additional variables available to them:
|
||||
|
||||
$change::
|
||||
+
|
||||
A reference to the current `Change` object
|
||||
|
||||
$changeId::
|
||||
+
|
||||
Id of the current change (a `Change.Key`)
|
||||
|
||||
$coverLetter::
|
||||
+
|
||||
The text of the `ChangeMessage`
|
||||
|
||||
$branch::
|
||||
+
|
||||
A reference to the branch of this change (a `Branch.NameKey`)
|
||||
|
||||
$fromName::
|
||||
+
|
||||
The name of the from user
|
||||
|
||||
$projectName::
|
||||
+
|
||||
The name of this change's project
|
||||
|
||||
$patchSet::
|
||||
+
|
||||
A reference to the current `PatchSet`
|
||||
|
||||
$patchSetInfo::
|
||||
+
|
||||
A reference to the current `PatchSetInfo`
|
||||
|
||||
|
||||
See Also
|
||||
--------
|
||||
|
||||
* link:http://velocity.apache.org/[velocity]
|
||||
|
||||
GERRIT
|
||||
------
|
||||
Part of link:index.html[Gerrit Code Review]
|
|
@ -31,6 +31,7 @@ Configuration
|
|||
* link:config-sso.html[Single Sign-On Systems]
|
||||
* link:config-apache2.html[Apache 2 Reverse Proxy]
|
||||
* link:config-hooks.html[Hooks]
|
||||
* link:config-mail.html[Mail Templates]
|
||||
|
||||
Developer Documentation
|
||||
-----------------------
|
||||
|
|
|
@ -25,11 +25,13 @@ import static com.google.gerrit.pgm.init.InitUtil.version;
|
|||
import com.google.gerrit.pgm.Init;
|
||||
import com.google.gerrit.pgm.util.ConsoleUI;
|
||||
import com.google.gerrit.server.config.SitePaths;
|
||||
import com.google.gerrit.server.mail.OutgoingEmail;
|
||||
import com.google.inject.Binding;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -66,6 +68,7 @@ public class SitePathInitializer {
|
|||
mkdir(site.etc_dir);
|
||||
mkdir(site.lib_dir);
|
||||
mkdir(site.logs_dir);
|
||||
mkdir(site.mail_dir);
|
||||
mkdir(site.static_dir);
|
||||
|
||||
for (InitStep step : steps) {
|
||||
|
@ -82,11 +85,19 @@ public class SitePathInitializer {
|
|||
extract(site.gerrit_sh, Init.class, "gerrit.sh");
|
||||
chmod(0755, site.gerrit_sh);
|
||||
|
||||
extractMailExample("ChangeSubject.vm");
|
||||
|
||||
if (!ui.isBatch()) {
|
||||
System.err.println();
|
||||
}
|
||||
}
|
||||
|
||||
private void extractMailExample(String orig) throws Exception {
|
||||
File ex = new File(site.mail_dir, orig + ".example");
|
||||
extract(ex, OutgoingEmail.class, orig);
|
||||
chmod(0444, ex);
|
||||
}
|
||||
|
||||
private static List<InitStep> stepsOf(final Injector injector) {
|
||||
final ArrayList<InitStep> r = new ArrayList<InitStep>();
|
||||
for (Binding<InitStep> b : all(injector)) {
|
||||
|
|
|
@ -30,7 +30,7 @@ public class AbandonedSender extends ReplyToChangeSender {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
protected void init() throws EmailException {
|
||||
super.init();
|
||||
|
||||
ccAllApprovals();
|
||||
|
@ -39,7 +39,7 @@ public class AbandonedSender extends ReplyToChangeSender {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void formatChange() {
|
||||
protected void formatChange() throws EmailException {
|
||||
appendText(getNameFor(fromId));
|
||||
appendText(" has abandoned change " + change.getKey().abbreviate() + ":\n");
|
||||
appendText("\n");
|
||||
|
|
|
@ -32,7 +32,7 @@ public class AddReviewerSender extends NewChangeSender {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
protected void init() throws EmailException {
|
||||
super.init();
|
||||
|
||||
ccExistingReviewers();
|
||||
|
|
|
@ -122,7 +122,7 @@ public abstract class ChangeEmail extends OutgoingEmail {
|
|||
protected abstract void formatChange() throws EmailException;
|
||||
|
||||
/** Setup the message headers and envelope (TO, CC, BCC). */
|
||||
protected void init() {
|
||||
protected void init() throws EmailException {
|
||||
if (args.projectCache != null) {
|
||||
projectState = args.projectCache.get(change.getProject());
|
||||
projectName =
|
||||
|
@ -194,23 +194,8 @@ public abstract class ChangeEmail extends OutgoingEmail {
|
|||
}
|
||||
}
|
||||
|
||||
private void setChangeSubjectHeader() {
|
||||
final StringBuilder subj = new StringBuilder();
|
||||
subj.append("[");
|
||||
subj.append(change.getDest().getShortName());
|
||||
subj.append("] ");
|
||||
subj.append("Change ");
|
||||
subj.append(change.getKey().abbreviate());
|
||||
subj.append(": (");
|
||||
subj.append(projectName);
|
||||
subj.append(") ");
|
||||
if (change.getSubject().length() > 60) {
|
||||
subj.append(change.getSubject().substring(0, 60));
|
||||
subj.append("...");
|
||||
} else {
|
||||
subj.append(change.getSubject());
|
||||
}
|
||||
setHeader("Subject", subj.toString());
|
||||
private void setChangeSubjectHeader() throws EmailException {
|
||||
setHeader("Subject", velocifyFile("ChangeSubject.vm"));
|
||||
}
|
||||
|
||||
/** Get a link to the change; null if the server doesn't know its own address. */
|
||||
|
@ -434,7 +419,10 @@ public abstract class ChangeEmail extends OutgoingEmail {
|
|||
protected void setupVelocityContext() {
|
||||
super.setupVelocityContext();
|
||||
velocityContext.put("change", change);
|
||||
velocityContext.put("changeId", change.getKey());
|
||||
velocityContext.put("coverLetter", getCoverLetter());
|
||||
velocityContext.put("branch", change.getDest());
|
||||
velocityContext.put("fromName", getNameFor(fromId));
|
||||
velocityContext.put("projectName", projectName);
|
||||
velocityContext.put("patchSet", patchSet);
|
||||
velocityContext.put("patchSetInfo", patchSetInfo);
|
||||
|
|
|
@ -56,7 +56,7 @@ public class CommentSender extends ReplyToChangeSender {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
protected void init() throws EmailException {
|
||||
super.init();
|
||||
|
||||
ccAllApprovals();
|
||||
|
@ -65,7 +65,7 @@ public class CommentSender extends ReplyToChangeSender {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void formatChange() {
|
||||
protected void formatChange() throws EmailException {
|
||||
if (!"".equals(getCoverLetter()) || !inlineComments.isEmpty()) {
|
||||
appendText("Comments on Patch Set " + patchSet.getPatchSetId() + ":\n");
|
||||
appendText("\n");
|
||||
|
|
|
@ -40,7 +40,7 @@ public class CreateChangeSender extends NewChangeSender {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
protected void init() throws EmailException {
|
||||
super.init();
|
||||
|
||||
bccWatchers();
|
||||
|
|
|
@ -30,14 +30,14 @@ public class MergeFailSender extends ReplyToChangeSender {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
protected void init() throws EmailException {
|
||||
super.init();
|
||||
|
||||
ccExistingReviewers();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void formatChange() {
|
||||
protected void formatChange() throws EmailException {
|
||||
appendText("Change " + change.getKey().abbreviate());
|
||||
if (patchSetInfo != null && patchSetInfo.getAuthor() != null
|
||||
&& patchSetInfo.getAuthor().getName() != null) {
|
||||
|
|
|
@ -51,7 +51,7 @@ public class MergedSender extends ReplyToChangeSender {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
protected void init() throws EmailException {
|
||||
super.init();
|
||||
|
||||
ccAllApprovals();
|
||||
|
@ -61,7 +61,7 @@ public class MergedSender extends ReplyToChangeSender {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void formatChange() {
|
||||
protected void formatChange() throws EmailException {
|
||||
appendText("Change " + change.getKey().abbreviate());
|
||||
if (patchSetInfo != null && patchSetInfo.getAuthor() != null
|
||||
&& patchSetInfo.getAuthor().getName() != null) {
|
||||
|
|
|
@ -46,7 +46,7 @@ public abstract class NewChangeSender extends ChangeEmail {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
protected void init() throws EmailException {
|
||||
super.init();
|
||||
|
||||
setHeader("Message-ID", getChangeMessageThreadId());
|
||||
|
@ -57,7 +57,7 @@ public abstract class NewChangeSender extends ChangeEmail {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void formatChange() {
|
||||
protected void formatChange() throws EmailException {
|
||||
formatSalutation();
|
||||
formatChangeDetail();
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ public abstract class OutgoingEmail {
|
|||
protected abstract void format() throws EmailException;
|
||||
|
||||
/** Setup the message headers and envelope (TO, CC, BCC). */
|
||||
protected void init() {
|
||||
protected void init() throws EmailException {
|
||||
setupVelocityContext();
|
||||
|
||||
smtpFromAddress = args.fromAddressGenerator.from(fromId);
|
||||
|
|
|
@ -40,7 +40,7 @@ public class RegisterNewEmailSender extends OutgoingEmail {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
protected void init() throws EmailException {
|
||||
super.init();
|
||||
setHeader("Subject", "[Gerrit Code Review] Email Verification");
|
||||
add(RecipientType.TO, new Address(addr));
|
||||
|
@ -52,7 +52,7 @@ public class RegisterNewEmailSender extends OutgoingEmail {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void format() {
|
||||
protected void format() throws EmailException {
|
||||
final StringBuilder url = new StringBuilder();
|
||||
url.append(getGerritUrl());
|
||||
url.append("#VE,");
|
||||
|
|
|
@ -53,7 +53,7 @@ public class ReplacePatchSetSender extends ReplyToChangeSender {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
protected void init() throws EmailException {
|
||||
super.init();
|
||||
|
||||
if (fromId != null) {
|
||||
|
@ -67,7 +67,7 @@ public class ReplacePatchSetSender extends ReplyToChangeSender {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void formatChange() {
|
||||
protected void formatChange() throws EmailException {
|
||||
formatSalutation();
|
||||
formatChangeDetail();
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ public abstract class ReplyToChangeSender extends ChangeEmail {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
protected void init() throws EmailException {
|
||||
super.init();
|
||||
|
||||
final String threadId = getChangeMessageThreadId();
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
## Copyright (C) 2010 The Android Open Source Project
|
||||
##
|
||||
## Licensed under the Apache License, Version 2.0 (the "License");
|
||||
## you may not use this file except in compliance with the License.
|
||||
## You may obtain a copy of the License at
|
||||
##
|
||||
## http://www.apache.org/licenses/LICENSE-2.0
|
||||
##
|
||||
## Unless required by applicable law or agreed to in writing, software
|
||||
## distributed under the License is distributed on an "AS IS" BASIS,
|
||||
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
## See the License for the specific language governing permissions and
|
||||
## limitations under the License.
|
||||
##
|
||||
##
|
||||
## Template Type:
|
||||
## -------------
|
||||
## This is a velocity mail template, see: http://velocity.apache.org and the
|
||||
## gerrit-docs:config-mail.txt for more info on modifying gerrit mail templates.
|
||||
##
|
||||
## Template File Names and extensions:
|
||||
## ----------------------------------
|
||||
## Gerrit will use templates ending in ".vm" but will ignore templates ending
|
||||
## in ".vm.example". If a .vm template does not exist, the default internal
|
||||
## gerrit template which is the same as the .vm.example will be used. If you
|
||||
## want to override the default template, copy the .vm.exmaple file to a .vm
|
||||
## file and edit it appropriately.
|
||||
##
|
||||
## This Template:
|
||||
## --------------
|
||||
## The ChangeSubject.vm template will determine the contents of the email
|
||||
## subject line for ALL emails related to changes.
|
||||
##
|
||||
#macro(elipses $length $str)
|
||||
#if($str.length() > $length)${str.substring(0,$length)}...#else$str#end
|
||||
#end
|
||||
[$branch.shortName] Change $changeId.abbreviate(): ($projectName) #elipses(60, $change.subject)
|
Loading…
Reference in New Issue