From 23c416f30f4a1e69e76b70d71f6a9a7da4a020f1 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Thu, 10 Apr 2014 18:58:09 -0400
Subject: [PATCH] Hook-up comprensive command cleanup (destroy)

---
 src/main/java/com/gitblit/git/PatchsetReceivePack.java |   87 ++++++++++++++++++++++++++++++++++---------
 1 files changed, 68 insertions(+), 19 deletions(-)

diff --git a/src/main/java/com/gitblit/git/PatchsetReceivePack.java b/src/main/java/com/gitblit/git/PatchsetReceivePack.java
index 2044f60..2c3b957 100644
--- a/src/main/java/com/gitblit/git/PatchsetReceivePack.java
+++ b/src/main/java/com/gitblit/git/PatchsetReceivePack.java
@@ -60,6 +60,7 @@
 import com.gitblit.models.TicketModel.PatchsetType;
 import com.gitblit.models.TicketModel.Status;
 import com.gitblit.models.UserModel;
+import com.gitblit.tickets.BranchTicketService;
 import com.gitblit.tickets.ITicketService;
 import com.gitblit.tickets.TicketMilestone;
 import com.gitblit.tickets.TicketNotifier;
@@ -105,7 +106,7 @@
 
 	protected final TicketNotifier ticketNotifier;
 
-	private boolean requireCleanMerge;
+	private boolean requireMergeablePatchset;
 
 	public PatchsetReceivePack(IGitblit gitblit, Repository db, RepositoryModel repository, UserModel user) {
 		super(gitblit, db, repository, user);
@@ -162,11 +163,11 @@
 
 	/** Extracts the ticket id from the ref name */
 	private long getTicketId(String refName) {
+		if (refName.indexOf('%') > -1) {
+			refName = refName.substring(0, refName.indexOf('%'));
+		}
 		if (refName.startsWith(Constants.R_FOR)) {
 			String ref = refName.substring(Constants.R_FOR.length());
-			if (ref.indexOf('%') > -1) {
-				ref = ref.substring(0, ref.indexOf('%'));
-			}
 			try {
 				return Long.parseLong(ref);
 			} catch (Exception e) {
@@ -257,12 +258,26 @@
 	/** Execute commands to update references. */
 	@Override
 	protected void executeCommands() {
+		// we process patchsets unless the user is pushing something special
+		boolean processPatchsets = true;
+		for (ReceiveCommand cmd : filterCommands(Result.NOT_ATTEMPTED)) {
+			if (ticketService instanceof BranchTicketService
+					&& BranchTicketService.BRANCH.equals(cmd.getRefName())) {
+				// the user is pushing an update to the BranchTicketService data
+				processPatchsets = false;
+			}
+		}
+
 		// workaround for JGit's awful scoping choices
 		//
 		// reset the patchset refs to NOT_ATTEMPTED (see validateCommands)
 		for (ReceiveCommand cmd : filterCommands(Result.OK)) {
 			if (isPatchsetRef(cmd.getRefName())) {
 				cmd.setResult(Result.NOT_ATTEMPTED);
+			} else if (ticketService instanceof BranchTicketService
+					&& BranchTicketService.BRANCH.equals(cmd.getRefName())) {
+				// the user is pushing an update to the BranchTicketService data
+				processPatchsets = false;
 			}
 		}
 
@@ -292,7 +307,7 @@
 				continue;
 			}
 
-			if (isPatchsetRef(cmd.getRefName())) {
+			if (isPatchsetRef(cmd.getRefName()) && processPatchsets) {
 				if (ticketService == null) {
 					sendRejection(cmd, "Sorry, the ticket service is unavailable and can not accept patchsets at this time.");
 					continue;
@@ -335,6 +350,9 @@
 					continue;
 				}
 
+				LOGGER.info(MessageFormat.format("Verifying {0} push ref \"{1}\" received from {2}",
+						repository.name, cmd.getRefName(), user.username));
+
 				// responsible verification
 				String responsible = PatchsetCommand.getSingleOption(cmd, PatchsetCommand.RESPONSIBLE);
 				if (!StringUtils.isEmpty(responsible)) {
@@ -365,13 +383,18 @@
 				// watcher verification
 				List<String> watchers = PatchsetCommand.getOptions(cmd, PatchsetCommand.WATCH);
 				if (!ArrayUtils.isEmpty(watchers)) {
+					boolean verified = true;
 					for (String watcher : watchers) {
 						UserModel user = gitblit.getUserModel(watcher);
 						if (user == null) {
 							// watcher does not exist
 							sendRejection(cmd, "Sorry, \"{0}\" is not a valid username for the watch list!", watcher);
-							continue;
+							verified = false;
+							break;
 						}
+					}
+					if (!verified) {
+						continue;
 					}
 				}
 
@@ -393,6 +416,8 @@
 				for (ReceiveCommand cmd : toApply) {
 					if (cmd.getResult() == Result.NOT_ATTEMPTED) {
 						sendRejection(cmd, "lock error: {0}", err.getMessage());
+						LOGGER.error(MessageFormat.format("failed to lock {0}:{1}",
+								repository.name, cmd.getRefName()), err);
 					}
 				}
 			}
@@ -412,7 +437,10 @@
 				patchsetRefCmd.setResult(Result.OK);
 
 				// update the ticket branch ref
-				RefUpdate ru = updateRef(patchsetCmd.getTicketBranch(), patchsetCmd.getNewId());
+				RefUpdate ru = updateRef(
+						patchsetCmd.getTicketBranch(),
+						patchsetCmd.getNewId(),
+						patchsetCmd.getPatchsetType());
 				updateReflog(ru);
 
 				TicketModel ticket = processPatchset(patchsetCmd);
@@ -539,7 +567,7 @@
 		case MERGEABLE:
 			break;
 		default:
-			if (ticket == null || requireCleanMerge) {
+			if (ticket == null || requireMergeablePatchset) {
 				sendError("");
 				sendError("Your patchset can not be cleanly merged into {0}.", forBranch);
 				sendError("Please rebase your patchset and push again.");
@@ -647,8 +675,7 @@
 				sendError("  1. you created the ticket");
 				sendError("  2. you created the first patchset");
 				sendError("  3. you are specified as responsible for the ticket");
-				sendError("  4. you are listed as a reviewer for the ticket");
-				sendError("  5. you have push (RW) permission to {0}", repository.name);
+				sendError("  4. you have push (RW) permissions to {0}", repository.name);
 				sendError("");
 				sendRejection(cmd, "not permitted to push to ticket {0,number,0}", ticket.number);
 				return null;
@@ -751,6 +778,9 @@
 				}
 
 				TicketModel ticket = ticketService.getTicket(repository, ticketNumber);
+				if (ticket == null) {
+					continue;
+				}
 				String integrationBranch;
 				if (StringUtils.isEmpty(ticket.mergeTo)) {
 					// unspecified integration branch
@@ -808,8 +838,8 @@
 					psCmd.updateTicket(c, mergeTo, ticket, null);
 
 					// create a ticket patchset ref
-					updateRef(psCmd.getPatchsetBranch(), c.getId());
-					RefUpdate ru = updateRef(psCmd.getTicketBranch(), c.getId());
+					updateRef(psCmd.getPatchsetBranch(), c.getId(), patchset.type);
+					RefUpdate ru = updateRef(psCmd.getTicketBranch(), c.getId(), patchset.type);
 					updateReflog(ru);
 
 					// create a change from the patchset command
@@ -870,11 +900,20 @@
 
 		if (parseMessage) {
 			// parse commit message looking for fixes/closes #n
-			Pattern p = Pattern.compile("(?:fixes|closes)[\\s-]+#?(\\d+)", Pattern.CASE_INSENSITIVE);
-			Matcher m = p.matcher(commit.getFullMessage());
-			while (m.find()) {
-				String val = m.group();
-				return Long.parseLong(val);
+			String dx = "(?:fixes|closes)[\\s-]+#?(\\d+)";
+			String x = settings.getString(Keys.tickets.closeOnPushCommitMessageRegex, dx);
+			if (StringUtils.isEmpty(x)) {
+				x = dx;
+			}
+			try {
+				Pattern p = Pattern.compile(x, Pattern.CASE_INSENSITIVE);
+				Matcher m = p.matcher(commit.getFullMessage());
+				while (m.find()) {
+					String val = m.group(1);
+					return Long.parseLong(val);
+				}
+			} catch (Exception e) {
+				LOGGER.error(String.format("Failed to parse \"%s\" in commit %s", x, commit.getName()), e);
 			}
 		}
 		return 0L;
@@ -1016,7 +1055,7 @@
 		return newPatchset;
 	}
 
-	private RefUpdate updateRef(String ref, ObjectId newId) {
+	private RefUpdate updateRef(String ref, ObjectId newId, PatchsetType type) {
 		ObjectId ticketRefId = ObjectId.zeroId();
 		try {
 			ticketRefId = getRepository().resolve(ref);
@@ -1027,7 +1066,17 @@
 		try {
 			RefUpdate ru = getRepository().updateRef(ref,  false);
 			ru.setRefLogIdent(getRefLogIdent());
-			ru.setForceUpdate(true);
+			switch (type) {
+			case Amend:
+			case Rebase:
+			case Rebase_Squash:
+			case Squash:
+				ru.setForceUpdate(true);
+				break;
+			default:
+				break;
+			}
+
 			ru.setExpectedOldObjectId(ticketRefId);
 			ru.setNewObjectId(newId);
 			RefUpdate.Result result = ru.update(getRevWalk());

--
Gitblit v1.9.1