use of com.gitblit.utils.DiffUtils.DiffStat in project gitblit by gitblit.
the class TicketNotifier method formatLastChange.
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());
break;
case vetoed:
score = MessageFormat.format(delPattern, Math.abs(change.review.score.getValue()));
break;
default:
score = "" + change.review.score.getValue();
}
String date = df.format(change.date);
sb.append(String.format("| %1$s | %2$s | %3$s | %4$s |\n", date, name, score, change.review.score.toString()));
}
sb.append(HARD_BRK);
} else if (lastChange.hasComment()) {
// comment update
sb.append(MessageFormat.format("**{0}** commented on this ticket.", user.getDisplayName()));
sb.append(HARD_BRK);
} else if (lastChange.hasReference()) {
// reference update
String type = "?";
switch(lastChange.reference.getSourceType()) {
case Commit:
{
type = "commit";
}
break;
case Ticket:
{
type = "ticket";
}
break;
default:
{
}
break;
}
sb.append(MessageFormat.format("**{0}** referenced this ticket in {1} {2}", type, lastChange.toString()));
sb.append(HARD_BRK);
} else {
// general update
pattern = "**{0}** has updated this ticket.";
sb.append(MessageFormat.format(pattern, user.getDisplayName()));
sb.append(HARD_BRK);
}
// ticket link
sb.append(MessageFormat.format("[view ticket {0,number,0}]({1})", ticket.number, ticketService.getTicketUrl(ticket)));
sb.append(HARD_BRK);
if (newTicket) {
// ticket title
sb.append(MessageFormat.format("### {0}", ticket.title));
sb.append(HARD_BRK);
// ticket description, on state change
if (StringUtils.isEmpty(ticket.body)) {
sb.append("<span style=\"color: #888;\">no description entered</span>");
} else {
sb.append(ticket.body);
}
sb.append(HARD_BRK);
sb.append(HR);
}
// field changes
if (lastChange.hasFieldChanges()) {
Map<Field, String> filtered = new HashMap<Field, String>();
for (Map.Entry<Field, String> fc : lastChange.fields.entrySet()) {
if (!fieldExclusions.contains(fc.getKey())) {
// field is included
filtered.put(fc.getKey(), fc.getValue());
}
}
// sort by field ordinal
List<Field> fields = new ArrayList<Field>(filtered.keySet());
Collections.sort(fields);
if (filtered.size() > 0) {
sb.append(HARD_BRK);
sb.append("| Field Changes ||\n");
sb.append("| ------------: | :----------- |\n");
for (Field field : fields) {
String value;
if (filtered.get(field) == null) {
value = "";
} else {
value = filtered.get(field).replace("\r\n", "<br/>").replace("\n", "<br/>").replace("|", "|");
}
sb.append(String.format("| **%1$s:** | %2$s |\n", field.name(), value));
}
sb.append(HARD_BRK);
}
}
// new comment
if (lastChange.hasComment()) {
sb.append(HR);
sb.append(lastChange.comment.text);
sb.append(HARD_BRK);
}
// insert the patchset details and review instructions
if (lastChange.hasPatchset() && ticket.isOpen()) {
if (commits != null && commits.size() > 0) {
// append the commit list
String title = isFastForward ? "Commits added to previous patchset revision" : "All commits in patchset";
sb.append(MessageFormat.format("| {0} |||\n", title));
sb.append("| SHA | Author | Title |\n");
sb.append("| :-- | :----- | :---- |\n");
for (RevCommit commit : commits) {
sb.append(MessageFormat.format("| {0} | {1} | {2} |\n", commit.getName(), commit.getAuthorIdent().getName(), StringUtils.trimString(commit.getShortMessage(), Constants.LEN_SHORTLOG).replace("|", "|")));
}
sb.append(HARD_BRK);
}
if (diffstat != null) {
// append the changed path list
String title = isFastForward ? "Files changed since previous patchset revision" : "All files changed in patchset";
sb.append(MessageFormat.format("| {0} |||\n", title));
sb.append("| :-- | :----------- | :-: |\n");
for (PathChangeModel path : diffstat.paths) {
String add = MessageFormat.format(addPattern, path.insertions);
String del = MessageFormat.format(delPattern, path.deletions);
String diff = null;
switch(path.changeType) {
case ADD:
diff = add;
break;
case DELETE:
diff = del;
break;
case MODIFY:
if (path.insertions > 0 && path.deletions > 0) {
// insertions & deletions
diff = add + "/" + del;
} else if (path.insertions > 0) {
// just insertions
diff = add;
} else {
// just deletions
diff = del;
}
break;
default:
diff = path.changeType.name();
break;
}
sb.append(MessageFormat.format("| {0} | {1} | {2} |\n", getChangeType(path.changeType), path.name, diff));
}
sb.append(HARD_BRK);
}
sb.append(formatPatchsetInstructions(ticket, lastChange.patchset));
}
return sb.toString();
}
use of com.gitblit.utils.DiffUtils.DiffStat in project gitblit by gitblit.
the class PatchsetReceivePack method newPatchset.
/**
* Creates a new patchset with metadata.
*
* @param ticket
* @param mergeBase
* @param tip
*/
private Patchset newPatchset(TicketModel ticket, String mergeBase, String tip) {
int totalCommits = JGitUtils.countCommits(getRepository(), getRevWalk(), mergeBase, tip);
Patchset newPatchset = new Patchset();
newPatchset.tip = tip;
newPatchset.base = mergeBase;
newPatchset.commits = totalCommits;
Patchset currPatchset = ticket == null ? null : ticket.getCurrentPatchset();
if (currPatchset == null) {
/*
* PROPOSAL PATCHSET
* patchset 1, rev 1
*/
newPatchset.number = 1;
newPatchset.rev = 1;
newPatchset.type = PatchsetType.Proposal;
// diffstat from merge base
DiffStat diffStat = DiffUtils.getDiffStat(getRepository(), mergeBase, tip);
newPatchset.insertions = diffStat.getInsertions();
newPatchset.deletions = diffStat.getDeletions();
} else {
/*
* PATCHSET UPDATE
*/
int added = totalCommits - currPatchset.commits;
boolean ff = JGitUtils.isMergedInto(getRepository(), currPatchset.tip, tip);
boolean squash = added < 0;
boolean rebase = !currPatchset.base.equals(mergeBase);
// determine type, number and rev of the patchset
if (ff) {
/*
* FAST-FORWARD
* patchset number preserved, rev incremented
*/
boolean merged = JGitUtils.isMergedInto(getRepository(), currPatchset.tip, ticket.mergeTo);
if (merged) {
// current patchset was already merged
// new patchset, mark as rebase
newPatchset.type = PatchsetType.Rebase;
newPatchset.number = currPatchset.number + 1;
newPatchset.rev = 1;
// diffstat from parent
DiffStat diffStat = DiffUtils.getDiffStat(getRepository(), mergeBase, tip);
newPatchset.insertions = diffStat.getInsertions();
newPatchset.deletions = diffStat.getDeletions();
} else {
// FF update to patchset
newPatchset.type = PatchsetType.FastForward;
newPatchset.number = currPatchset.number;
newPatchset.rev = currPatchset.rev + 1;
newPatchset.parent = currPatchset.tip;
// diffstat from parent
DiffStat diffStat = DiffUtils.getDiffStat(getRepository(), currPatchset.tip, tip);
newPatchset.insertions = diffStat.getInsertions();
newPatchset.deletions = diffStat.getDeletions();
}
} else {
/*
* NON-FAST-FORWARD
* new patchset, rev 1
*/
if (rebase && squash) {
newPatchset.type = PatchsetType.Rebase_Squash;
newPatchset.number = currPatchset.number + 1;
newPatchset.rev = 1;
} else if (squash) {
newPatchset.type = PatchsetType.Squash;
newPatchset.number = currPatchset.number + 1;
newPatchset.rev = 1;
} else if (rebase) {
newPatchset.type = PatchsetType.Rebase;
newPatchset.number = currPatchset.number + 1;
newPatchset.rev = 1;
} else {
newPatchset.type = PatchsetType.Amend;
newPatchset.number = currPatchset.number + 1;
newPatchset.rev = 1;
}
// diffstat from merge base
DiffStat diffStat = DiffUtils.getDiffStat(getRepository(), mergeBase, tip);
newPatchset.insertions = diffStat.getInsertions();
newPatchset.deletions = diffStat.getDeletions();
}
if (added > 0) {
// ignore squash (negative add)
newPatchset.added = added;
}
}
return newPatchset;
}
use of com.gitblit.utils.DiffUtils.DiffStat in project gitblit by gitblit.
the class ITicketService method getTicket.
/**
* Retrieves the ticket.
*
* @param repository
* @param ticketId
* @return a ticket, if it exists, otherwise null
* @since 1.4.0
*/
public final TicketModel getTicket(RepositoryModel repository, long ticketId) {
TicketKey key = new TicketKey(repository, ticketId);
TicketModel ticket = ticketsCache.getIfPresent(key);
// if ticket not cached
if (ticket == null) {
//load ticket
ticket = getTicketImpl(repository, ticketId);
// if ticket exists
if (ticket != null) {
if (ticket.hasPatchsets() && updateDiffstats) {
Repository r = repositoryManager.getRepository(repository.name);
try {
Patchset patchset = ticket.getCurrentPatchset();
DiffStat diffStat = DiffUtils.getDiffStat(r, patchset.base, patchset.tip);
// mirroring
if (diffStat != null) {
ticket.insertions = diffStat.getInsertions();
ticket.deletions = diffStat.getDeletions();
}
} finally {
r.close();
}
}
//cache ticket
ticketsCache.put(key, ticket);
}
}
return ticket;
}
Aggregations