Search in sources :

Example 1 with DiffStat

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("|", "&#124;");
                }
                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("|", "&#124;")));
            }
            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();
}
Also used : HashMap(java.util.HashMap) DiffStat(com.gitblit.utils.DiffUtils.DiffStat) ArrayList(java.util.ArrayList) Patchset(com.gitblit.models.TicketModel.Patchset) Review(com.gitblit.models.TicketModel.Review) UserModel(com.gitblit.models.UserModel) Field(com.gitblit.models.TicketModel.Field) HashSet(java.util.HashSet) RevCommit(org.eclipse.jgit.revwalk.RevCommit) PathChangeModel(com.gitblit.models.PathModel.PathChangeModel) TicketModel(com.gitblit.models.TicketModel) Change(com.gitblit.models.TicketModel.Change) IOException(java.io.IOException) Repository(org.eclipse.jgit.lib.Repository) SimpleDateFormat(java.text.SimpleDateFormat) DateFormat(java.text.DateFormat) SimpleDateFormat(java.text.SimpleDateFormat) HashMap(java.util.HashMap) Map(java.util.Map) TreeMap(java.util.TreeMap)

Example 2 with DiffStat

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;
}
Also used : DiffStat(com.gitblit.utils.DiffUtils.DiffStat) Patchset(com.gitblit.models.TicketModel.Patchset)

Example 3 with DiffStat

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;
}
Also used : Repository(org.eclipse.jgit.lib.Repository) DiffStat(com.gitblit.utils.DiffUtils.DiffStat) TicketModel(com.gitblit.models.TicketModel) Patchset(com.gitblit.models.TicketModel.Patchset)

Aggregations

Patchset (com.gitblit.models.TicketModel.Patchset)3 DiffStat (com.gitblit.utils.DiffUtils.DiffStat)3 TicketModel (com.gitblit.models.TicketModel)2 Repository (org.eclipse.jgit.lib.Repository)2 PathChangeModel (com.gitblit.models.PathModel.PathChangeModel)1 Change (com.gitblit.models.TicketModel.Change)1 Field (com.gitblit.models.TicketModel.Field)1 Review (com.gitblit.models.TicketModel.Review)1 UserModel (com.gitblit.models.UserModel)1 IOException (java.io.IOException)1 DateFormat (java.text.DateFormat)1 SimpleDateFormat (java.text.SimpleDateFormat)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 Map (java.util.Map)1 TreeMap (java.util.TreeMap)1 RevCommit (org.eclipse.jgit.revwalk.RevCommit)1