From f76fee63ed9cb3a30d3c0c092d860b1cb93a481b Mon Sep 17 00:00:00 2001
From: Gerard Smyth <gerard.smyth@gmail.com>
Date: Thu, 08 May 2014 13:09:30 -0400
Subject: [PATCH] Updated the SyndicationServlet to provide an additional option to return details of the tags in the repository instead of the commits. This uses a new 'ot' request parameter to indicate the object type of the content to return, which can be ither TAG or COMMIT. If this is not provided, then COMMIT is assumed to maintain backwards compatability. If tags are returned, then the paging parameters, 'l' and 'pg' are still supported, but searching options are currently ignored.
---
src/main/java/com/gitblit/git/PatchsetReceivePack.java | 139 +++++++++++++++++++++++++++++++++++++++------
1 files changed, 119 insertions(+), 20 deletions(-)
diff --git a/src/main/java/com/gitblit/git/PatchsetReceivePack.java b/src/main/java/com/gitblit/git/PatchsetReceivePack.java
index 2044f60..f7412a3 100644
--- a/src/main/java/com/gitblit/git/PatchsetReceivePack.java
+++ b/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;
@@ -60,6 +61,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 +107,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 +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) {
@@ -257,12 +259,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 +308,8 @@
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;
@@ -330,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);
@@ -365,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;
}
}
@@ -393,6 +432,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 +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);
@@ -492,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)) {
@@ -539,7 +585,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 +693,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;
@@ -689,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");
@@ -715,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;
@@ -751,6 +819,9 @@
}
TicketModel ticket = ticketService.getTicket(repository, ticketNumber);
+ if (ticket == null) {
+ continue;
+ }
String integrationBranch;
if (StringUtils.isEmpty(ticket.mergeTo)) {
// unspecified integration branch
@@ -808,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
@@ -870,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;
@@ -1016,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);
@@ -1027,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());
@@ -1118,6 +1208,15 @@
ObjectId.fromString(mergeResult.sha), oldRef.getName());
RefLogUtils.updateRefLog(user, getRepository(), Arrays.asList(cmd));
}
+
+ // 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 {
LOGGER.error("FAILED to resolve ticket {} by merge from web ui", ticketId);
--
Gitblit v1.9.1