| | |
| | | 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;
|
| | |
| | |
|
| | | 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);
|
| | |
| | |
|
| | | /** 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) {
|
| | |
| | | /** 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;
|
| | | }
|
| | | }
|
| | |
|
| | |
| | | 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;
|
| | |
| | | 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)) {
|
| | |
| | | // 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;
|
| | | }
|
| | | }
|
| | |
|
| | |
| | | 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);
|
| | | }
|
| | | }
|
| | | }
|
| | |
| | | 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);
|
| | |
| | | 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.");
|
| | |
| | | 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;
|
| | |
| | | }
|
| | |
|
| | | TicketModel ticket = ticketService.getTicket(repository, ticketNumber);
|
| | | if (ticket == null) {
|
| | | continue;
|
| | | }
|
| | | String integrationBranch;
|
| | | if (StringUtils.isEmpty(ticket.mergeTo)) {
|
| | | // unspecified integration branch
|
| | |
| | | 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
|
| | |
| | |
|
| | | 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;
|
| | |
| | | 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);
|
| | |
| | | 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());
|