James Moger
2014-09-25 388f49ada1b32bd2e99c964a0278094e4f21c3fb
src/main/java/com/gitblit/git/PatchsetReceivePack.java
@@ -51,6 +51,7 @@
import com.gitblit.Constants;
import com.gitblit.Keys;
import com.gitblit.extensions.PatchsetHook;
import com.gitblit.manager.IGitblit;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.TicketModel;
@@ -163,11 +164,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) {
@@ -308,6 +309,7 @@
         }
         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;
@@ -345,10 +347,27 @@
               continue;
            }
            if (cmd.getNewId().equals(ObjectId.zeroId())) {
               // ref deletion request
               if (cmd.getRefName().startsWith(Constants.R_TICKET)) {
                  if (user.canDeleteRef(repository)) {
                     batch.addCommand(cmd);
                  } else {
                     sendRejection(cmd, "Sorry, you do not have permission to delete {}", cmd.getRefName());
                  }
               } else {
                  sendRejection(cmd, "Sorry, you can not delete {}", cmd.getRefName());
               }
               continue;
            }
            if (patchsetRefCmd != null) {
               sendRejection(cmd, "You may only push one patchset at a time.");
               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);
@@ -380,13 +399,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;
               }
            }
@@ -429,7 +453,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);
@@ -484,8 +511,6 @@
    * @return the patchset command
    */
   private PatchsetCommand preparePatchset(ReceiveCommand cmd) {
      LOGGER.info(MessageFormat.format("Preparing {0} patchset command for \"{1}\" received from {2}",
            repository.name, cmd.getRefName(), user.username));
      String branch = getIntegrationBranch(cmd.getRefName());
      long number = getTicketId(cmd.getRefName());
@@ -511,8 +536,10 @@
                  break;
               }
            }
            sendError("Sorry, {0} already merged {1} from ticket {2,number,0} to {3}!",
            if (mergeChange != null) {
               sendError("Sorry, {0} already merged {1} from ticket {2,number,0} to {3}!",
                  mergeChange.author, mergeChange.patchset, number, ticket.mergeTo);
            }
            sendRejection(cmd, "Ticket {0,number,0} already resolved", number);
            return null;
         } else if (!StringUtils.isEmpty(ticket.mergeTo)) {
@@ -707,6 +734,15 @@
            RefLogUtils.updateRefLog(user, getRepository(),
                  Arrays.asList(new ReceiveCommand(cmd.getOldId(), cmd.getNewId(), cmd.getRefName())));
            // call any patchset hooks
            for (PatchsetHook hook : gitblit.getExtensions(PatchsetHook.class)) {
               try {
                  hook.onNewPatchset(ticket);
               } catch (Exception e) {
                  LOGGER.error("Failed to execute extension", e);
               }
            }
            return ticket;
         } else {
            sendError("FAILED to create ticket");
@@ -733,6 +769,20 @@
            // log the new patchset ref
            RefLogUtils.updateRefLog(user, getRepository(),
               Arrays.asList(new ReceiveCommand(cmd.getOldId(), cmd.getNewId(), cmd.getRefName())));
            // call any patchset hooks
            final boolean isNewPatchset = change.patchset.rev == 1;
            for (PatchsetHook hook : gitblit.getExtensions(PatchsetHook.class)) {
               try {
                  if (isNewPatchset) {
                     hook.onNewPatchset(ticket);
                  } else {
                     hook.onUpdatePatchset(ticket);
                  }
               } catch (Exception e) {
                  LOGGER.error("Failed to execute extension", e);
               }
            }
            // return the updated ticket
            return ticket;
@@ -769,6 +819,9 @@
            }
            TicketModel ticket = ticketService.getTicket(repository, ticketNumber);
            if (ticket == null) {
               continue;
            }
            String integrationBranch;
            if (StringUtils.isEmpty(ticket.mergeTo)) {
               // unspecified integration branch
@@ -826,8 +879,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
@@ -888,11 +941,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;
@@ -1034,7 +1096,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);
@@ -1045,7 +1107,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());
@@ -1130,11 +1202,24 @@
      if (ticket != null) {
         ticketNotifier.queueMailing(ticket);
         // update the reflog with the merge
         if (oldRef != null) {
            ReceiveCommand cmd = new ReceiveCommand(oldRef.getObjectId(),
                  ObjectId.fromString(mergeResult.sha), oldRef.getName());
            RefLogUtils.updateRefLog(user, getRepository(), Arrays.asList(cmd));
            cmd.setResult(Result.OK);
            List<ReceiveCommand> commands = Arrays.asList(cmd);
            logRefChange(commands);
            updateIncrementalPushTags(commands);
            updateGitblitRefLog(commands);
         }
         // call patchset hooks
         for (PatchsetHook hook : gitblit.getExtensions(PatchsetHook.class)) {
            try {
               hook.onMergePatchset(ticket);
            } catch (Exception e) {
               LOGGER.error("Failed to execute extension", e);
            }
         }
         return mergeResult.status;
      } else {