TicketModel ticket;
List<Change> effectiveChanges = new ArrayList<Change>();
Map<String, Change> comments = new HashMap<String, Change>();
+ Map<Integer, Integer> latestRevisions = new HashMap<Integer, Integer>();
+
+ int latestPatchsetNumber = -1;
+
+ List<Integer> deletedPatchsets = new ArrayList<Integer>();
+
+ for (Change change : changes) {
+ if (change.patchset != null) {
+ if (change.patchset.isDeleted()) {
+ deletedPatchsets.add(change.patchset.number);
+ } else {
+ Integer latestRev = latestRevisions.get(change.patchset.number);
+
+ if (latestRev == null || change.patchset.rev > latestRev) {
+ latestRevisions.put(change.patchset.number, change.patchset.rev);
+ }
+
+ if (change.patchset.number > latestPatchsetNumber) {
+ latestPatchsetNumber = change.patchset.number;
+ }
+ }
+ }
+ }
+
for (Change change : changes) {
if (change.comment != null) {
if (comments.containsKey(change.comment.id)) {
effectiveChanges.add(change);
comments.put(change.comment.id, change);
}
+ } else if (change.patchset != null) {
+ //All revisions of a deleted patchset are not displayed
+ if (!deletedPatchsets.contains(change.patchset.number)) {
+
+ Integer latestRev = latestRevisions.get(change.patchset.number);
+
+ if ( (change.patchset.number < latestPatchsetNumber)
+ && (change.patchset.rev == latestRev)) {
+ change.patchset.canDelete = true;
+ }
+
+ effectiveChanges.add(change);
+ }
} else {
effectiveChanges.add(change);
}
public int added;
public PatchsetType type;
+ public transient boolean canDelete = false;
+
public boolean isFF() {
return PatchsetType.FastForward == type;
}
+ public boolean isDeleted() {
+ return PatchsetType.Delete == type;
+ }
+
@Override
public int hashCode() {
return toString().hashCode();
}
public static enum PatchsetType {
- Proposal, FastForward, Rebase, Squash, Rebase_Squash, Amend;
+ Proposal, FastForward, Rebase, Squash, Rebase_Squash, Amend, Delete;
public boolean isRewrite() {
return (this != FastForward) && (this != Proposal);
*/\r
package com.gitblit.wicket.pages;\r
\r
+import java.io.IOException;\r
import java.text.DateFormat;\r
import java.text.MessageFormat;\r
import java.text.SimpleDateFormat;\r
import org.apache.wicket.Component;\r
import org.apache.wicket.MarkupContainer;\r
import org.apache.wicket.PageParameters;\r
+import org.apache.wicket.RequestCycle;\r
import org.apache.wicket.RestartResponseException;\r
import org.apache.wicket.ajax.AjaxRequestTarget;\r
import org.apache.wicket.behavior.SimpleAttributeModifier;\r
import org.apache.wicket.markup.html.image.ContextImage;\r
import org.apache.wicket.markup.html.link.BookmarkablePageLink;\r
import org.apache.wicket.markup.html.link.ExternalLink;\r
+import org.apache.wicket.markup.html.link.Link;\r
+import org.apache.wicket.markup.html.link.StatelessLink;\r
+import org.apache.wicket.markup.html.pages.RedirectPage;\r
import org.apache.wicket.markup.html.panel.Fragment;\r
import org.apache.wicket.markup.repeater.Item;\r
import org.apache.wicket.markup.repeater.data.DataView;\r
import org.apache.wicket.markup.repeater.data.ListDataProvider;\r
import org.apache.wicket.model.Model;\r
+import org.apache.wicket.protocol.http.RequestUtils;\r
import org.apache.wicket.protocol.http.WebRequest;\r
+import org.apache.wicket.request.target.basic.RedirectRequestTarget;\r
import org.eclipse.jgit.diff.DiffEntry.ChangeType;\r
import org.eclipse.jgit.lib.PersonIdent;\r
import org.eclipse.jgit.lib.Ref;\r
import com.gitblit.utils.ArrayUtils;\r
import com.gitblit.utils.JGitUtils;\r
import com.gitblit.utils.JGitUtils.MergeStatus;\r
+import com.gitblit.utils.CommitCache;\r
import com.gitblit.utils.MarkdownUtils;\r
+import com.gitblit.utils.RefLogUtils;\r
import com.gitblit.utils.StringUtils;\r
import com.gitblit.utils.TimeUtils;\r
import com.gitblit.wicket.GitBlitWebSession;\r
import com.gitblit.wicket.TicketsUI;\r
import com.gitblit.wicket.WicketUtils;\r
import com.gitblit.wicket.panels.AvatarImage;\r
+import com.gitblit.wicket.panels.BasePanel.JavascriptEventConfirmation;\r
import com.gitblit.wicket.panels.BasePanel.JavascriptTextPrompt;\r
import com.gitblit.wicket.panels.CommentPanel;\r
import com.gitblit.wicket.panels.DiffStatPanel;\r
if (event.hasPatchset()) {\r
// patchset\r
Patchset patchset = event.patchset;\r
+ //In the case of using a cached change list\r
+ item.setVisible(!patchset.isDeleted());\r
+ \r
String what;\r
if (event.isStatusChange() && (Status.New == event.getStatus())) {\r
what = getString("gb.proposedThisChange");\r
}\r
item.add(typeLabel);\r
\r
+ Link<Void> deleteLink = createDeletePatchsetLink(repository, patchset);\r
+ \r
+ if (user.canDeleteRef(repository)) {\r
+ item.add(deleteLink.setVisible(patchset.canDelete));\r
+ } else {\r
+ item.add(deleteLink.setVisible(false));\r
+ }\r
+\r
// show commit diffstat\r
item.add(new DiffStatPanel("patchsetDiffStat", patchset.insertions, patchset.deletions, patchset.rev > 1));\r
} else if (event.hasComment()) {\r
item.add(new Label("what", getString("gb.commented")));\r
item.add(new Label("patchsetRevision").setVisible(false));\r
item.add(new Label("patchsetType").setVisible(false));\r
+ item.add(new Label("deleteRevision").setVisible(false));\r
item.add(new Label("patchsetDiffStat").setVisible(false));\r
} else if (event.hasReview()) {\r
// review\r
.setEscapeModelStrings(false));\r
item.add(new Label("patchsetRevision").setVisible(false));\r
item.add(new Label("patchsetType").setVisible(false));\r
+ item.add(new Label("deleteRevision").setVisible(false));\r
item.add(new Label("patchsetDiffStat").setVisible(false));\r
} else {\r
// field change\r
item.add(new Label("patchsetRevision").setVisible(false));\r
item.add(new Label("patchsetType").setVisible(false));\r
+ item.add(new Label("deleteRevision").setVisible(false));\r
item.add(new Label("patchsetDiffStat").setVisible(false));\r
\r
String what = "";\r
return copyFragment;\r
}\r
}\r
+ \r
+ private Link<Void> createDeletePatchsetLink(final RepositoryModel repositoryModel, final Patchset patchset)\r
+ {\r
+ Link<Void> deleteLink = new Link<Void>("deleteRevision") {\r
+ private static final long serialVersionUID = 1L;\r
+\r
+ @Override\r
+ public void onClick() {\r
+ Repository r = app().repositories().getRepository(repositoryModel.name);\r
+ UserModel user = GitBlitWebSession.get().getUser();\r
+ \r
+ if (r == null) {\r
+ if (app().repositories().isCollectingGarbage(repositoryModel.name)) {\r
+ error(MessageFormat.format(getString("gb.busyCollectingGarbage"), repositoryModel.name));\r
+ } else {\r
+ error(MessageFormat.format("Failed to find repository {0}", repositoryModel.name));\r
+ }\r
+ return;\r
+ }\r
+ \r
+ //Construct the ref name based on the patchset\r
+ String ticketShard = String.format("%02d", ticket.number);\r
+ ticketShard = ticketShard.substring(ticketShard.length() - 2);\r
+ final String refName = String.format("%s%s/%d/%d", Constants.R_TICKETS_PATCHSETS, ticketShard, ticket.number, patchset.number);\r
+\r
+ Ref ref = null;\r
+ boolean success = true;\r
+ \r
+ try {\r
+ ref = r.getRef(refName);\r
+ \r
+ if (ref != null) {\r
+ success = JGitUtils.deleteBranchRef(r, ref.getName());\r
+ } else {\r
+ success = false;\r
+ }\r
+ \r
+ if (success) {\r
+ // clear commit cache\r
+ CommitCache.instance().clear(repositoryModel.name, refName);\r
+\r
+ // optionally update reflog\r
+ if (RefLogUtils.hasRefLogBranch(r)) {\r
+ RefLogUtils.deleteRef(user, r, ref);\r
+ }\r
+\r
+ TicketModel updatedTicket = app().tickets().deletePatchset(ticket, patchset, user.username);\r
+ \r
+ if (updatedTicket == null) {\r
+ success = false;\r
+ }\r
+ }\r
+ } catch (IOException e) {\r
+ logger().error("failed to determine ticket from ref", e);\r
+ success = false;\r
+ } finally {\r
+ r.close();\r
+ }\r
+\r
+ if (success) {\r
+ getSession().info(MessageFormat.format(getString("gb.deletePatchsetSuccess"), patchset.number));\r
+ logger().info(MessageFormat.format("{0} deleted patchset {1} from ticket {2}", \r
+ user.username, patchset.number, ticket.number));\r
+ } else {\r
+ getSession().error(MessageFormat.format(getString("gb.deletePatchsetFailure"),patchset.number));\r
+ }\r
+ \r
+ //Force reload of the page to rebuild ticket change cache\r
+ String relativeUrl = urlFor(TicketsPage.class, getPageParameters()).toString();\r
+ String absoluteUrl = RequestUtils.toAbsolutePath(relativeUrl);\r
+ setResponsePage(new RedirectPage(absoluteUrl));\r
+ }\r
+ };\r
+\r
+ WicketUtils.setHtmlTooltip(deleteLink, MessageFormat.format(getString("gb.deletePatchset"), patchset.number));\r
+ \r
+ deleteLink.add(new JavascriptEventConfirmation("onclick", MessageFormat.format(getString("gb.deletePatchset"), patchset.number)));\r
+ \r
+ return deleteLink;\r
+ }\r
+ \r
}\r