Use a template to set the contents of the MergedEmails.

Add an admin editable Merged.vm template used to format the
contents of the merged change emails.

Change-Id: I79823c2135383a7dbf7f245abea3d693db025150
diff --git a/Documentation/config-mail.txt b/Documentation/config-mail.txt
index 656f740..3f891c9 100644
--- a/Documentation/config-mail.txt
+++ b/Documentation/config-mail.txt
@@ -31,6 +31,13 @@
 The `ChangeSubject.vm` template will determine the contents of the email
 subject line for ALL emails related to changes.
 
+Merged.vm
+~~~~~~~~~
+
+The `Merged.vm` template will determine the contents of the email related to
+a change successfully merged to the head.  It is a `ChangeEmail`: see
+`ChangeSubject.vm` and `ChangeFooter.vm`.
+
 
 Mail Variables and Methods
 --------------------------
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 2af694f..a36a2a7 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
@@ -86,6 +86,7 @@
     chmod(0755, site.gerrit_sh);
 
     extractMailExample("ChangeSubject.vm");
+    extractMailExample("Merged.vm");
 
     if (!ui.isBatch()) {
       System.err.println();
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 20f1a7a..b8a0ae5 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
@@ -252,21 +252,27 @@
 
   /** Format the change message and the affected file list. */
   protected void formatChangeDetail() {
+    appendText(getChangeDetail());
+  }
+
+  /** Create the change message and the affected file list. */
+  public String getChangeDetail() {
+    StringBuilder detail = new StringBuilder();
+
     if (patchSetInfo != null) {
-      appendText(patchSetInfo.getMessage().trim());
-      appendText("\n");
+      detail.append(patchSetInfo.getMessage().trim() + "\n");
     } else {
-      appendText(change.getSubject().trim());
-      appendText("\n");
+      detail.append(change.getSubject().trim() + "\n");
     }
 
     if (patchSet != null) {
-      appendText("---\n");
+      detail.append("---\n");
       for (PatchListEntry p : getPatchList().getPatches()) {
-        appendText(p.getChangeType().getCode() + " " + p.getNewName() + "\n");
+        detail.append(p.getChangeType().getCode() + " " + p.getNewName() + "\n");
       }
-      appendText("\n");
+      detail.append("\n");
     }
+    return detail.toString();
   }
 
   /** Get the patch list corresponding to this patch set. */
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 5680423..40f4790 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
@@ -62,57 +62,46 @@
 
   @Override
   protected void formatChange() throws EmailException {
-    appendText("Change " + change.getKey().abbreviate());
-    if (patchSetInfo != null && patchSetInfo.getAuthor() != null
-        && patchSetInfo.getAuthor().getName() != null) {
-      appendText(" by ");
-      appendText(patchSetInfo.getAuthor().getName());
-    }
-    appendText(" submitted to ");
-    appendText(dest.getShortName());
-    appendText(":\n\n");
-    formatChangeDetail();
-    formatApprovals();
+    appendText(velocifyFile("Merged.vm"));
   }
 
-  private void formatApprovals() {
-    if (patchSet != null) {
-      try {
-        final Map<Account.Id, Map<ApprovalCategory.Id, PatchSetApproval>> pos =
-            new HashMap<Account.Id, Map<ApprovalCategory.Id, PatchSetApproval>>();
+  public String getApprovals() {
+    try {
+      final Map<Account.Id, Map<ApprovalCategory.Id, PatchSetApproval>> pos =
+          new HashMap<Account.Id, Map<ApprovalCategory.Id, PatchSetApproval>>();
 
-        final Map<Account.Id, Map<ApprovalCategory.Id, PatchSetApproval>> neg =
-            new HashMap<Account.Id, Map<ApprovalCategory.Id, PatchSetApproval>>();
+      final Map<Account.Id, Map<ApprovalCategory.Id, PatchSetApproval>> neg =
+          new HashMap<Account.Id, Map<ApprovalCategory.Id, PatchSetApproval>>();
 
-        for (PatchSetApproval ca : args.db.get().patchSetApprovals()
-            .byPatchSet(patchSet.getId())) {
-          if (ca.getValue() > 0) {
-            insert(pos, ca);
-          } else if (ca.getValue() < 0) {
-            insert(neg, ca);
-          }
+      for (PatchSetApproval ca : args.db.get().patchSetApprovals()
+          .byPatchSet(patchSet.getId())) {
+        if (ca.getValue() > 0) {
+          insert(pos, ca);
+        } else if (ca.getValue() < 0) {
+          insert(neg, ca);
         }
-
-        format("Approvals", pos);
-        format("Objections", neg);
-      } catch (OrmException err) {
-        // Don't list the approvals
       }
+
+      return format("Approvals", pos) + format("Objections", neg);
+    } catch (OrmException err) {
+      // Don't list the approvals
     }
+    return "";
   }
 
-  private void format(final String type,
+  private String format(final String type,
       final Map<Account.Id, Map<ApprovalCategory.Id, PatchSetApproval>> list) {
+    StringBuilder txt = new StringBuilder();
     if (list.isEmpty()) {
-      return;
+      return "";
     }
-    appendText(type + ":\n");
+    txt.append(type + ":\n");
     for (final Map.Entry<Account.Id, Map<ApprovalCategory.Id, PatchSetApproval>> ent : list
         .entrySet()) {
       final Map<ApprovalCategory.Id, PatchSetApproval> l = ent.getValue();
-      appendText("  ");
-      appendText(getNameFor(ent.getKey()));
-      appendText(": ");
+      txt.append("  ");
+      txt.append(getNameFor(ent.getKey()));
+      txt.append(": ");
       boolean first = true;
       for (ApprovalType at : approvalTypes.getApprovalTypes()) {
         final PatchSetApproval ca = l.get(at.getCategory().getId());
@@ -123,24 +112,25 @@
         if (first) {
           first = false;
         } else {
-          appendText("; ");
+          txt.append("; ");
         }
 
         final ApprovalCategoryValue v = at.getValue(ca);
         if (v != null) {
-          appendText(v.getName());
+          txt.append(v.getName());
         } else {
-          appendText(at.getCategory().getName());
-          appendText("=");
+          txt.append(at.getCategory().getName());
+          txt.append("=");
           if (ca.getValue() > 0) {
-            appendText("+");
+            txt.append("+");
           }
-          appendText("" + ca.getValue());
+          txt.append("" + ca.getValue());
         }
       }
-      appendText("\n");
+      txt.append("\n");
     }
-    appendText("\n");
+    txt.append("\n");
+    return txt.toString();
   }
 
   private void insert(
diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/Merged.vm b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/Merged.vm
new file mode 100644
index 0000000..c459c16
--- /dev/null
+++ b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/Merged.vm
@@ -0,0 +1,38 @@
+## 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 Merged.vm template will determine the contents of the email related to
+## a change successfully merged to the head.  It is a ChangeEmail: see
+## ChangeSubject.vm and ChangeFooter.vm.
+##
+Change $changeId.abbreviate()#if ($patchSetInfo.author.name)
+ by $patchSetInfo.author.name#end submitted to $change.dest.shortName:
+
+$email.changeDetail$email.approvals