James Moger
2014-03-27 ab07d0d86d8b64b4f7c88b45bc81f1eec22105db
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());