return subject;
}
protected String formatLastChange(TicketModel ticket) {
Change lastChange = ticket.changes.get(ticket.changes.size() - 1);
UserModel user = getUserModel(lastChange.author);
// define the fields we do NOT want to see in an email notification
Set<TicketModel.Field> fieldExclusions = new HashSet<TicketModel.Field>();
fieldExclusions.addAll(Arrays.asList(Field.watchers, Field.voters));
StringBuilder sb = new StringBuilder();
boolean newTicket = lastChange.isStatusChange() && Status.New == lastChange.getStatus();
boolean isFastForward = true;
List<RevCommit> commits = null;
DiffStat diffstat = null;
String pattern;
if (lastChange.hasPatchset()) {
// patchset uploaded
Patchset patchset = lastChange.patchset;
String base = "";
// determine the changed paths
Repository repo = null;
try {
repo = repositoryManager.getRepository(ticket.repository);
if (patchset.isFF() && (patchset.rev > 1)) {
// fast-forward update, just show the new data
isFastForward = true;
Patchset prev = ticket.getPatchset(patchset.number, patchset.rev - 1);
base = prev.tip;
} else {
// proposal OR non-fast-forward update
isFastForward = false;
base = patchset.base;
}
diffstat = DiffUtils.getDiffStat(repo, base, patchset.tip);
commits = JGitUtils.getRevLog(repo, base, patchset.tip);
} catch (Exception e) {
Logger.getLogger(getClass()).error("failed to get changed paths", e);
} finally {
if (repo != null) {
repo.close();
}
}
String compareUrl = ticketService.getCompareUrl(ticket, base, patchset.tip);
if (newTicket) {
// new proposal
pattern = "**{0}** is proposing a change.";
sb.append(MessageFormat.format(pattern, user.getDisplayName()));
fieldExclusions.add(Field.status);
fieldExclusions.add(Field.title);
fieldExclusions.add(Field.body);
} else {
// describe the patchset
if (patchset.isFF()) {
pattern = "**{0}** added {1} {2} to patchset {3}.";
sb.append(MessageFormat.format(pattern, user.getDisplayName(), patchset.added, patchset.added == 1 ? "commit" : "commits", patchset.number));
} else {
pattern = "**{0}** uploaded patchset {1}. *({2})*";
sb.append(MessageFormat.format(pattern, user.getDisplayName(), patchset.number, patchset.type.toString().toUpperCase()));
}
}
sb.append(HARD_BRK);
sb.append(MessageFormat.format("{0} {1}, {2} {3}, <span style=\"color:darkgreen;\">+{4} insertions</span>, <span style=\"color:darkred;\">-{5} deletions</span> from {6}. [compare]({7})",
commits.size(), commits.size() == 1 ? "commit" : "commits",
diffstat.paths.size(),
diffstat.paths.size() == 1 ? "file" : "files",
diffstat.getInsertions(),
diffstat.getDeletions(),
isFastForward ? "previous revision" : "merge base",
compareUrl));
// note commit additions on a rebase,if any
switch (lastChange.patchset.type) {
case Rebase:
if (lastChange.patchset.added > 0) {
sb.append(SOFT_BRK);
sb.append(MessageFormat.format("{0} {1} added.", lastChange.patchset.added, lastChange.patchset.added == 1 ? "commit" : "commits"));
}
break;
default:
break;
}
sb.append(HARD_BRK);
} else if (lastChange.isStatusChange()) {
if (newTicket) {
fieldExclusions.add(Field.status);
fieldExclusions.add(Field.title);
fieldExclusions.add(Field.body);
pattern = "**{0}** created this ticket.";
sb.append(MessageFormat.format(pattern, user.getDisplayName()));
} else if (lastChange.hasField(Field.mergeSha)) {
// closed by merged
pattern = "**{0}** closed this ticket by merging {1} to {2}.";
// identify patchset that closed the ticket
String merged = ticket.mergeSha;
for (Patchset patchset : ticket.getPatchsets()) {
if (patchset.tip.equals(ticket.mergeSha)) {
merged = patchset.toString();
break;
}
}
sb.append(MessageFormat.format(pattern, user.getDisplayName(), merged, ticket.mergeTo));
} else {
// workflow status change by user
pattern = "**{0}** changed the status of this ticket to **{1}**.";
sb.append(MessageFormat.format(pattern, user.getDisplayName(), lastChange.getStatus().toString().toUpperCase()));
}
sb.append(HARD_BRK);
} else if (lastChange.hasReview()) {
// review
Review review = lastChange.review;
pattern = "**{0}** has reviewed patchset {1,number,0} revision {2,number,0}.";
sb.append(MessageFormat.format(pattern, user.getDisplayName(), review.patchset, review.rev));
sb.append(HARD_BRK);
String d = settings.getString(Keys.web.datestampShortFormat, "yyyy-MM-dd");
String t = settings.getString(Keys.web.timeFormat, "HH:mm");
DateFormat df = new SimpleDateFormat(d + " " + t);
List<Change> reviews = ticket.getReviews(ticket.getPatchset(review.patchset, review.rev));
sb.append("| Date | Reviewer | Score | Description |\n");
sb.append("| :--- | :------------ | :---: | :----------- |\n");
for (Change change : reviews) {
String name = change.author;
UserModel u = userManager.getUserModel(change.author);
if (u != null) {
name = u.getDisplayName();
}
String score;
switch (change.review.score) {
case approved:
score = MessageFormat.format(addPattern, change.review.score.getValue());