From b7f3b2d5be89baec255cfbf5eedf85032fd06430 Mon Sep 17 00:00:00 2001 From: Martin Fick Date: Fri, 23 Jul 2010 10:23:03 -0600 Subject: [PATCH] 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 --- Documentation/config-mail.txt | 120 ++++++++++++++++++ Documentation/index.txt | 1 + .../gerrit/pgm/init/SitePathInitializer.java | 11 ++ .../gerrit/server/mail/AbandonedSender.java | 4 +- .../gerrit/server/mail/AddReviewerSender.java | 2 +- .../gerrit/server/mail/ChangeEmail.java | 24 +--- .../gerrit/server/mail/CommentSender.java | 4 +- .../server/mail/CreateChangeSender.java | 2 +- .../gerrit/server/mail/MergeFailSender.java | 4 +- .../gerrit/server/mail/MergedSender.java | 4 +- .../gerrit/server/mail/NewChangeSender.java | 4 +- .../gerrit/server/mail/OutgoingEmail.java | 2 +- .../server/mail/RegisterNewEmailSender.java | 4 +- .../server/mail/ReplacePatchSetSender.java | 4 +- .../server/mail/ReplyToChangeSender.java | 2 +- .../gerrit/server/mail/ChangeSubject.vm | 37 ++++++ 16 files changed, 193 insertions(+), 36 deletions(-) create mode 100644 Documentation/config-mail.txt create mode 100644 gerrit-server/src/main/resources/com/google/gerrit/server/mail/ChangeSubject.vm diff --git a/Documentation/config-mail.txt b/Documentation/config-mail.txt new file mode 100644 index 0000000000..656f7401a2 --- /dev/null +++ b/Documentation/config-mail.txt @@ -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] diff --git a/Documentation/index.txt b/Documentation/index.txt index 1e13e8d8f5..e419455204 100644 --- a/Documentation/index.txt +++ b/Documentation/index.txt @@ -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 ----------------------- diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java index 74e754830c..2af694f9db 100644 --- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java +++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java @@ -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 stepsOf(final Injector injector) { final ArrayList r = new ArrayList(); for (Binding b : all(injector)) { diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/AbandonedSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/AbandonedSender.java index d2b5c29c3c..d6bd223aa4 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/AbandonedSender.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/AbandonedSender.java @@ -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"); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/AddReviewerSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/AddReviewerSender.java index be62ba070a..e5437cfac0 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/AddReviewerSender.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/AddReviewerSender.java @@ -32,7 +32,7 @@ public class AddReviewerSender extends NewChangeSender { } @Override - protected void init() { + protected void init() throws EmailException { super.init(); ccExistingReviewers(); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java index fa10784061..20f1a7a8f7 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java @@ -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); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java index be6360fe95..8783d7c96d 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java @@ -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"); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CreateChangeSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CreateChangeSender.java index ea57cde1e5..18bfe976c7 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CreateChangeSender.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CreateChangeSender.java @@ -40,7 +40,7 @@ public class CreateChangeSender extends NewChangeSender { } @Override - protected void init() { + protected void init() throws EmailException { super.init(); bccWatchers(); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergeFailSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergeFailSender.java index 00750ef306..de7871b271 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergeFailSender.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergeFailSender.java @@ -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) { diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergedSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergedSender.java index caf19e472e..5680423ec9 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergedSender.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergedSender.java @@ -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) { diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/NewChangeSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/NewChangeSender.java index dc8c2c2b33..54e72a8772 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/NewChangeSender.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/NewChangeSender.java @@ -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(); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/OutgoingEmail.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/OutgoingEmail.java index 67038569ce..288b182b87 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/OutgoingEmail.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/OutgoingEmail.java @@ -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); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/RegisterNewEmailSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/RegisterNewEmailSender.java index 9b201fd4b5..5bba5d9951 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/RegisterNewEmailSender.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/RegisterNewEmailSender.java @@ -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,"); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplacePatchSetSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplacePatchSetSender.java index 841aa355e0..526458a6ff 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplacePatchSetSender.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplacePatchSetSender.java @@ -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(); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplyToChangeSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplyToChangeSender.java index 05d2753dee..4c3ed76465 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplyToChangeSender.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplyToChangeSender.java @@ -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(); diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ChangeSubject.vm b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ChangeSubject.vm new file mode 100644 index 0000000000..2132c6354d --- /dev/null +++ b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ChangeSubject.vm @@ -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)