From 9883341c1fbb35abcb7a1d09f93f6a9e805ea551 Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 6 Mar 2014 13:36:23 -0500 Subject: [PATCH] Revise push/mirror tickets branch triggering --- .../com/gitblit/git/GitblitReceivePack.java | 6 +- .../com/gitblit/git/PatchsetReceivePack.java | 23 +++++- .../com/gitblit/git/ReceiveCommandEvent.java | 38 ++++++++++ .../com/gitblit/service/MirrorService.java | 35 +++++++-- .../gitblit/tickets/BranchTicketService.java | 72 ++++++++++++++----- .../com/gitblit/tickets/ITicketService.java | 4 ++ 6 files changed, 147 insertions(+), 31 deletions(-) create mode 100644 src/main/java/com/gitblit/git/ReceiveCommandEvent.java diff --git a/src/main/java/com/gitblit/git/GitblitReceivePack.java b/src/main/java/com/gitblit/git/GitblitReceivePack.java index 605632cf..e3e2faeb 100644 --- a/src/main/java/com/gitblit/git/GitblitReceivePack.java +++ b/src/main/java/com/gitblit/git/GitblitReceivePack.java @@ -51,7 +51,6 @@ import com.gitblit.manager.IGitblit; import com.gitblit.models.RepositoryModel; import com.gitblit.models.UserModel; import com.gitblit.tickets.BranchTicketService; -import com.gitblit.tickets.BranchTicketService.TicketsBranchUpdated; import com.gitblit.utils.ArrayUtils; import com.gitblit.utils.ClientLogger; import com.gitblit.utils.CommitCache; @@ -344,12 +343,13 @@ public class GitblitReceivePack extends ReceivePack implements PreReceiveHook, P } catch (Exception e) { LOGGER.error(MessageFormat.format("Failed to update {0} pushlog", repository.name), e); } - + // check for updates pushed to the BranchTicketService branch + // if the BranchTicketService is active it will reindex, as appropriate for (ReceiveCommand cmd : commands) { if (Result.OK.equals(cmd.getResult()) && BranchTicketService.BRANCH.equals(cmd.getRefName())) { - rp.getRepository().fireEvent(new TicketsBranchUpdated(repository)); + rp.getRepository().fireEvent(new ReceiveCommandEvent(repository, cmd)); } } diff --git a/src/main/java/com/gitblit/git/PatchsetReceivePack.java b/src/main/java/com/gitblit/git/PatchsetReceivePack.java index 2044f604..c0ab8aeb 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.Patchset; 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 @@ public class PatchsetReceivePack extends GitblitReceivePack { 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); @@ -257,12 +258,26 @@ public class PatchsetReceivePack extends GitblitReceivePack { /** 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 @@ public class PatchsetReceivePack extends GitblitReceivePack { 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; @@ -393,6 +408,8 @@ public class PatchsetReceivePack extends GitblitReceivePack { 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); } } } @@ -539,7 +556,7 @@ public class PatchsetReceivePack extends GitblitReceivePack { 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."); diff --git a/src/main/java/com/gitblit/git/ReceiveCommandEvent.java b/src/main/java/com/gitblit/git/ReceiveCommandEvent.java new file mode 100644 index 00000000..84dabb35 --- /dev/null +++ b/src/main/java/com/gitblit/git/ReceiveCommandEvent.java @@ -0,0 +1,38 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.git; + +import org.eclipse.jgit.events.RefsChangedEvent; +import org.eclipse.jgit.transport.ReceiveCommand; + +import com.gitblit.models.RepositoryModel; + +/** + * The event fired by other classes to allow this service to index tickets. + * + * @author James Moger + */ +public class ReceiveCommandEvent extends RefsChangedEvent { + + public final RepositoryModel model; + + public final ReceiveCommand cmd; + + public ReceiveCommandEvent(RepositoryModel model, ReceiveCommand cmd) { + this.model = model; + this.cmd = cmd; + } +} \ No newline at end of file diff --git a/src/main/java/com/gitblit/service/MirrorService.java b/src/main/java/com/gitblit/service/MirrorService.java index 1eb54202..cf9ccb55 100644 --- a/src/main/java/com/gitblit/service/MirrorService.java +++ b/src/main/java/com/gitblit/service/MirrorService.java @@ -28,6 +28,8 @@ import org.eclipse.jgit.lib.RefUpdate.Result; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.transport.FetchResult; +import org.eclipse.jgit.transport.ReceiveCommand; +import org.eclipse.jgit.transport.ReceiveCommand.Type; import org.eclipse.jgit.transport.RemoteConfig; import org.eclipse.jgit.transport.TrackingRefUpdate; import org.slf4j.Logger; @@ -35,11 +37,11 @@ import org.slf4j.LoggerFactory; import com.gitblit.IStoredSettings; import com.gitblit.Keys; +import com.gitblit.git.ReceiveCommandEvent; import com.gitblit.manager.IRepositoryManager; import com.gitblit.models.RepositoryModel; import com.gitblit.models.UserModel; import com.gitblit.tickets.BranchTicketService; -import com.gitblit.tickets.BranchTicketService.TicketsBranchUpdated; import com.gitblit.utils.JGitUtils; /** @@ -147,7 +149,7 @@ public class MirrorService implements Runnable { FetchResult result = git.fetch().setRemote(mirror.getName()).setDryRun(testing).call(); Collection refUpdates = result.getTrackingRefUpdates(); if (refUpdates.size() > 0) { - boolean ticketBranchUpdated = false; + ReceiveCommand ticketBranchCmd = null; for (TrackingRefUpdate ru : refUpdates) { StringBuilder sb = new StringBuilder(); sb.append("updated mirror "); @@ -164,14 +166,33 @@ public class MirrorService implements Runnable { sb.append(".."); sb.append(ru.getNewObjectId() == null ? "" : ru.getNewObjectId().abbreviate(7).name()); logger.info(sb.toString()); - + if (BranchTicketService.BRANCH.equals(ru.getLocalName())) { - ticketBranchUpdated = true; + ReceiveCommand.Type type = null; + switch (ru.getResult()) { + case NEW: + type = Type.CREATE; + break; + case FAST_FORWARD: + type = Type.UPDATE; + break; + case FORCED: + type = Type.UPDATE_NONFASTFORWARD; + break; + default: + type = null; + break; + } + + if (type != null) { + ticketBranchCmd = new ReceiveCommand(ru.getOldObjectId(), + ru.getNewObjectId(), ru.getLocalName(), type); + } } } - - if (ticketBranchUpdated) { - repository.fireEvent(new TicketsBranchUpdated(model)); + + if (ticketBranchCmd != null) { + repository.fireEvent(new ReceiveCommandEvent(model, ticketBranchCmd)); } } } catch (Exception e) { diff --git a/src/main/java/com/gitblit/tickets/BranchTicketService.java b/src/main/java/com/gitblit/tickets/BranchTicketService.java index 60dca276..fc0bd8f0 100644 --- a/src/main/java/com/gitblit/tickets/BranchTicketService.java +++ b/src/main/java/com/gitblit/tickets/BranchTicketService.java @@ -27,6 +27,7 @@ import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import javax.inject.Inject; @@ -50,15 +51,18 @@ import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.transport.ReceiveCommand; import org.eclipse.jgit.treewalk.CanonicalTreeParser; import org.eclipse.jgit.treewalk.TreeWalk; import com.gitblit.Constants; +import com.gitblit.git.ReceiveCommandEvent; import com.gitblit.manager.INotificationManager; import com.gitblit.manager.IRepositoryManager; import com.gitblit.manager.IRuntimeManager; import com.gitblit.manager.IUserManager; import com.gitblit.models.PathModel; +import com.gitblit.models.PathModel.PathChangeModel; import com.gitblit.models.RefModel; import com.gitblit.models.RepositoryModel; import com.gitblit.models.TicketModel; @@ -78,18 +82,6 @@ import com.gitblit.utils.StringUtils; */ public class BranchTicketService extends ITicketService implements RefsChangedListener { - /** - * The event fired by other classes to allow this service to index tickets. - */ - public static class TicketsBranchUpdated extends RefsChangedEvent { - - public final RepositoryModel model; - - public TicketsBranchUpdated(RepositoryModel model) { - this.model = model; - } - } - public static final String BRANCH = "refs/gitblit/tickets"; private static final String JOURNAL = "journal.json"; @@ -111,7 +103,7 @@ public class BranchTicketService extends ITicketService implements RefsChangedLi repositoryManager); lastAssignedId = new ConcurrentHashMap(); - + // register the branch ticket service for repository ref changes Repository.getGlobalListenerList().addRefsChangedListener(this); } @@ -138,16 +130,60 @@ public class BranchTicketService extends ITicketService implements RefsChangedLi } /** - * Listen for refs changed events and reindex that repository. + * Listen for tickets branch changes and (re)index tickets, as appropriate */ @Override - public void onRefsChanged(RefsChangedEvent event) { - if (!(event instanceof TicketsBranchUpdated)) { + public synchronized void onRefsChanged(RefsChangedEvent event) { + if (!(event instanceof ReceiveCommandEvent)) { return; } - RepositoryModel repository = ((TicketsBranchUpdated) event).model; + + ReceiveCommandEvent branchUpdate = (ReceiveCommandEvent) event; + RepositoryModel repository = branchUpdate.model; + ReceiveCommand cmd = branchUpdate.cmd; try { - reindex(repository); + switch (cmd.getType()) { + case CREATE: + case UPDATE_NONFASTFORWARD: + // reindex everything + reindex(repository); + break; + case UPDATE: + // incrementally index ticket updates + resetCaches(repository); + long start = System.nanoTime(); + log.info("incrementally indexing {} ticket branch due to received ref update", repository.name); + Repository db = repositoryManager.getRepository(repository.name); + try { + Set ids = new HashSet(); + List paths = JGitUtils.getFilesInRange(db, + cmd.getOldId().getName(), cmd.getNewId().getName()); + for (PathChangeModel path : paths) { + String name = path.name.substring(path.name.lastIndexOf('/') + 1); + if (!JOURNAL.equals(name)) { + continue; + } + String tid = path.path.split("/")[2]; + long ticketId = Long.parseLong(tid); + if (!ids.contains(ticketId)) { + ids.add(ticketId); + TicketModel ticket = getTicket(repository, ticketId); + log.info(MessageFormat.format("indexing ticket #{0,number,0}: {1}", + ticketId, ticket.title)); + indexer.index(ticket); + } + } + long end = System.nanoTime(); + log.info("incremental indexing of {0} ticket(s) completed in {1} msecs", + ids.size(), TimeUnit.NANOSECONDS.toMillis(end - start)); + } finally { + db.close(); + } + break; + default: + log.warn("Unexpected receive type {} in BranchTicketService.onRefsChanged" + cmd.getType()); + break; + } } catch (Exception e) { log.error("failed to reindex " + repository.name, e); } diff --git a/src/main/java/com/gitblit/tickets/ITicketService.java b/src/main/java/com/gitblit/tickets/ITicketService.java index d04cd5e1..90f9c6dd 100644 --- a/src/main/java/com/gitblit/tickets/ITicketService.java +++ b/src/main/java/com/gitblit/tickets/ITicketService.java @@ -897,6 +897,7 @@ public abstract class ITicketService { public boolean deleteAll(RepositoryModel repository) { boolean success = deleteAllImpl(repository); if (success) { + log.info("Deleted all tickets for {}", repository.name); resetCaches(repository); indexer.deleteAll(repository); } @@ -936,6 +937,8 @@ public abstract class ITicketService { TicketModel ticket = getTicket(repository, ticketId); boolean success = deleteTicketImpl(repository, ticket, deletedBy); if (success) { + log.info(MessageFormat.format("Deleted {0} ticket #{1,number,0}: {2}", + repository.name, ticketId, ticket.title)); ticketsCache.invalidate(new TicketKey(repository, ticketId)); indexer.delete(ticket); return true; @@ -1074,6 +1077,7 @@ public abstract class ITicketService { long end = System.nanoTime(); long secs = TimeUnit.NANOSECONDS.toMillis(end - start); log.info("reindexing completed in {} msecs.", secs); + resetCaches(repository); } /** -- 2.39.5