Merge branch 'stable-2.11' into stable-2.12 * stable-2.11: Fetch parent groups of the authGroups Change-Id: I9fdfccadcd14fb707676abeaedaa8a2a7455a55b
diff --git a/BUCK b/BUCK index 2e8a623..3da69ef 100644 --- a/BUCK +++ b/BUCK
@@ -1,3 +1,5 @@ +include_defs('//lib/maven.defs') + gerrit_plugin( name = 'replication', srcs = glob(['src/main/java/**/*.java']), @@ -9,15 +11,27 @@ 'Gerrit-Module: com.googlesource.gerrit.plugins.replication.ReplicationModule', 'Gerrit-SshModule: com.googlesource.gerrit.plugins.replication.SshModule' ], + deps = [ + ':commons-io', + ], provided_deps = [ - '//lib/commons:io', + '//lib:gson', '//lib/log:log4j' ], ) +maven_jar( + name = 'commons-io', + id = 'commons-io:commons-io:1.4', + sha1 = 'a8762d07e76cfde2395257a5da47ba7c1dbd3dce', + license = 'Apache2.0', +) + java_test( name = 'replication_tests', srcs = glob(['src/test/java/**/*.java']), + labels = ['replication'], + source_under_test = [':replication__plugin'], deps = [ ':replication__plugin', '//gerrit-common:server',
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadConfigDecorator.java b/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadConfigDecorator.java index 14db7a3..2743549 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadConfigDecorator.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadConfigDecorator.java
@@ -13,6 +13,7 @@ // limitations under the License. package com.googlesource.gerrit.plugins.replication; +import com.google.gerrit.common.FileUtil; import com.google.gerrit.server.PluginUser; import com.google.gerrit.server.account.GroupBackend; import com.google.gerrit.server.account.GroupIncludeCache; @@ -44,6 +45,7 @@ private final GitRepositoryManager gitRepositoryManager; private final GroupBackend groupBackend; private final WorkQueue workQueue; + private final ReplicationStateListener stateLog; private final GroupIncludeCache groupIncludeCache; @Inject @@ -51,6 +53,7 @@ RemoteSiteUser.Factory ruf, PluginUser pu, GitRepositoryManager grm, GroupBackend gb, WorkQueue workQueue, + ReplicationStateListener stateLog, GroupIncludeCache groupIncludeCache) throws ConfigInvalidException, IOException { this.injector = injector; @@ -61,14 +64,20 @@ this.groupBackend = gb; this.groupIncludeCache = groupIncludeCache; this.currentConfig = loadConfig(); - this.currentConfigTs = currentConfig.getCfgPath().lastModified(); + this.currentConfigTs = getLastModified(currentConfig); this.workQueue = workQueue; + this.stateLog = stateLog; + } + + private static long getLastModified(ReplicationFileBasedConfig cfg) { + return FileUtil.lastModified(cfg.getCfgPath()); } private ReplicationFileBasedConfig loadConfig() throws ConfigInvalidException, IOException { return new ReplicationFileBasedConfig(injector, site, remoteSiteUserFactory, - pluginUser, gitRepositoryManager, groupBackend, groupIncludeCache); + pluginUser, gitRepositoryManager, groupBackend, stateLog, + groupIncludeCache); } private synchronized boolean isAutoReload() { @@ -82,25 +91,27 @@ } private void reloadIfNeeded() { - if (isAutoReload() - && currentConfig.getCfgPath().lastModified() > currentConfigTs) { - try { - ReplicationFileBasedConfig newConfig = loadConfig(); - newConfig.startup(workQueue); - int discarded = currentConfig.shutdown(); + try { + if (isAutoReload()) { + long lastModified = getLastModified(currentConfig); + if (lastModified > currentConfigTs) { + ReplicationFileBasedConfig newConfig = loadConfig(); + newConfig.startup(workQueue); + int discarded = currentConfig.shutdown(); - this.currentConfig = newConfig; - this.currentConfigTs = currentConfig.getCfgPath().lastModified(); - log.info("Configuration reloaded: " + this.currentConfig = newConfig; + this.currentConfigTs = lastModified; + log.info("Configuration reloaded: " + currentConfig.getDestinations(FilterType.ALL).size() + " destinations, " + discarded + " replication events discarded"); - } catch (Exception e) { - log.error( - "Cannot reload replication configuration: keeping existing settings", - e); - return; + } } + } catch (Exception e) { + log.error( + "Cannot reload replication configuration: keeping existing settings", + e); + return; } }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadSecureCredentialsFactoryDecorator.java b/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadSecureCredentialsFactoryDecorator.java index 4017822..3a0cc3f 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadSecureCredentialsFactoryDecorator.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadSecureCredentialsFactoryDecorator.java
@@ -11,18 +11,20 @@ // 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.googlesource.gerrit.plugins.replication; +import static com.google.gerrit.common.FileUtil.lastModified; + import com.google.gerrit.server.config.SitePaths; import com.google.inject.Inject; import org.eclipse.jgit.errors.ConfigInvalidException; -import org.eclipse.jgit.storage.file.FileBasedConfig; -import org.eclipse.jgit.util.FS; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.nio.file.Files; import java.util.concurrent.atomic.AtomicReference; public class AutoReloadSecureCredentialsFactoryDecorator implements @@ -47,32 +49,29 @@ } private long getSecureConfigLastEditTs() { - FileBasedConfig cfg = new FileBasedConfig(site.secure_config, FS.DETECTED); - if (cfg.getFile().exists()) { - return cfg.getFile().lastModified(); - } else { + if (!Files.exists(site.secure_config)) { return 0L; } + return lastModified(site.secure_config); } @Override public SecureCredentialsProvider create(String remoteName) { - if (needsReload()) { - try { + try { + if (needsReload()) { secureCredentialsFactory.compareAndSet(secureCredentialsFactory.get(), new SecureCredentialsFactory(site)); secureCredentialsFactoryLoadTs = getSecureConfigLastEditTs(); log.info("secure.config reloaded as it was updated on the file system"); - } catch (Exception e) { - log.error("Unexpected error while trying to reload " - + "secure.config: keeping existing credentials", e); } + } catch (Exception e) { + log.error("Unexpected error while trying to reload " + + "secure.config: keeping existing credentials", e); } return secureCredentialsFactory.get().create(remoteName); } - private boolean needsReload() { return config.getConfig().getBoolean("gerrit", "autoReload", false) && getSecureConfigLastEditTs() != secureCredentialsFactoryLoadTs;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java b/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java index 544a285..e267da3 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java
@@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableSet.Builder; import com.google.common.collect.Lists; import com.google.gerrit.common.data.GroupReference; +import com.google.gerrit.extensions.config.FactoryModule; import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.RefNames; @@ -31,7 +32,6 @@ import com.google.gerrit.server.account.GroupIncludeCache; import com.google.gerrit.server.account.ListGroupMembership; import com.google.gerrit.server.config.ConfigUtil; -import com.google.gerrit.server.config.FactoryModule; import com.google.gerrit.server.config.RequestScopedReviewDbProvider; import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.PerThreadRequestScope; @@ -68,15 +68,16 @@ class Destination { private static final Logger repLog = ReplicationQueue.repLog; - private static final ReplicationStateLogger stateLog = - new ReplicationStateLogger(repLog); + private final ReplicationStateListener stateLog; private final int poolThreads; private final String poolName; private final RemoteConfig remote; private final String[] adminUrls; + private final String[] urls; private final String[] projects; + private final String[] authGroupNames; private final int delay; private final int retryDelay; private final Object stateLock = new Object(); @@ -104,15 +105,19 @@ final PluginUser pluginUser, final GitRepositoryManager gitRepositoryManager, final GroupBackend groupBackend, + final ReplicationStateListener stateLog, final GroupIncludeCache groupIncludeCache) { remote = rc; gitManager = gitRepositoryManager; + this.stateLog = stateLog; + delay = Math.max(0, getTimeUnit(rc, cfg, "replicationdelay", 15, TimeUnit.SECONDS)); retryDelay = Math.max(0, getTimeUnit(rc, cfg, "replicationretry", 1, TimeUnit.MINUTES)); lockErrorMaxRetries = cfg.getInt("replication", "lockErrorMaxRetries", 0); adminUrls = cfg.getStringList("remote", rc.getName(), "adminUrl"); + urls = cfg.getStringList("remote", rc.getName(), "url"); poolThreads = Math.max(0, getInt(rc, cfg, "threads", 1)); poolName = "ReplicateTo-" + rc.getName(); @@ -127,7 +132,7 @@ projects = cfg.getStringList("remote", rc.getName(), "projects"); final CurrentUser remoteUser; - String[] authGroupNames = cfg.getStringList("remote", rc.getName(), "authGroup"); + authGroupNames = cfg.getStringList("remote", rc.getName(), "authGroup"); if (authGroupNames.length > 0) { ImmutableSet.Builder<AccountGroup.UUID> builder = ImmutableSet.builder(); for (String name : authGroupNames) { @@ -164,7 +169,7 @@ final Provider<RequestScopedReviewDbProvider> dbProvider) { final RequestContext requestContext = new RequestContext() { @Override - public CurrentUser getCurrentUser() { + public CurrentUser getUser() { return remoteUser; } @@ -257,27 +262,23 @@ e = pending.get(uri); } if (e == null) { - Repository git; - try { - git = gitManager.openRepository(project); - } catch (IOException err) { - stateLog.error(String.format( - "source project %s not available", project), err, state); - return; - } - try { - Ref head = git.getRef(Constants.HEAD); - if (head != null - && head.isSymbolic() - && RefNames.REFS_CONFIG.equals(head.getLeaf().getName())) { + try (Repository git = gitManager.openRepository(project)) { + try { + Ref head = git.getRef(Constants.HEAD); + if (head != null + && head.isSymbolic() + && RefNames.REFS_CONFIG.equals(head.getLeaf().getName())) { + return; + } + } catch (IOException err) { + stateLog.error(String.format( + "cannot check type of project %s", project), err, state); return; } } catch (IOException err) { stateLog.error(String.format( - "cannot check type of project %s", project), err, state); + "source project %s not available", project), err, state); return; - } finally { - git.close(); } } } @@ -522,6 +523,22 @@ return adminUrls; } + String[] getUrls() { + return urls; + } + + RemoteConfig getRemoteConfig() { + return remote; + } + + String[] getAuthGroupNames() { + return authGroupNames; + } + + String[] getProjects() { + return projects; + } + int getLockErrorMaxRetries() { return lockErrorMaxRetries; }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ListCommand.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ListCommand.java new file mode 100644 index 0000000..91fa65a --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ListCommand.java
@@ -0,0 +1,118 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// 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.googlesource.gerrit.plugins.replication; + +import com.google.common.base.Strings; +import com.google.gerrit.common.data.GlobalCapability; +import com.google.gerrit.extensions.annotations.RequiresCapability; +import com.google.gerrit.sshd.CommandMetaData; +import com.google.gerrit.sshd.SshCommand; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import com.google.inject.Inject; + +import com.googlesource.gerrit.plugins.replication.ReplicationConfig.FilterType; + +import org.kohsuke.args4j.Option; + +import java.util.List; + +@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER) +@CommandMetaData(name = "list", description = "List specific remote destinations information") +final class ListCommand extends SshCommand { + @Option(name = "--remote", metaVar = "PATTERN", usage = "pattern to match remote name on") + private String remote; + + @Option(name = "--detail", usage = "print remote destination detail information") + private boolean detail; + + @Option(name = "--json", usage = "output in json format") + private boolean json; + + @Inject + private ReplicationConfig config; + + @Override + protected void run() { + List<Destination> dest = config.getDestinations(FilterType.ALL); + for (Destination d : dest) { + if (matches(d.getRemoteConfig().getName())) { + printRemote(d, detail); + } + } + } + + private boolean matches(String name) { + return (Strings.isNullOrEmpty(remote) + || name.contains(remote) + || name.matches(remote)); + } + + private void addProperty(JsonObject obj, String key, String[] values) { + if (values.length > 0) { + JsonArray list = new JsonArray(); + for (String v : values) { + list.add(new JsonPrimitive(v)); + } + obj.add(key, list); + } + } + + private void printRemote(Destination d, boolean detail) { + if (json) { + JsonObject obj = new JsonObject(); + obj.addProperty("remote", d.getRemoteConfig().getName()); + addProperty(obj, "Url", d.getUrls()); + if (detail) { + addProperty(obj, "AdminUrl", d.getAdminUrls()); + addProperty(obj, "AuthGroup", d.getAuthGroupNames()); + addProperty(obj, "Project", d.getProjects()); + } + stdout.print(obj.toString() + "\n"); + } else { + StringBuilder out = new StringBuilder(); + out.append("Remote: ") + .append(d.getRemoteConfig().getName()) + .append("\n"); + for (String url : d.getUrls()) { + out.append("Url: ") + .append(url) + .append("\n"); + } + + if (detail) { + for (String adminUrl : d.getAdminUrls()) { + out.append("AdminUrl: ") + .append(adminUrl) + .append("\n"); + } + + for (String authGroup : d.getAuthGroupNames()) { + out.append("AuthGroup: ") + .append(authGroup) + .append("\n"); + } + + for (String project : d.getProjects()) { + out.append("Project: ") + .append(project) + .append("\n"); + } + } + stdout.print(out.toString() + "\n"); + } + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/PushAll.java b/src/main/java/com/googlesource/gerrit/plugins/replication/PushAll.java index c6ad873..5ff4035 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/PushAll.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/PushAll.java
@@ -25,8 +25,7 @@ import java.util.concurrent.TimeUnit; class PushAll implements Runnable { - private static final ReplicationStateLogger stateLog = - new ReplicationStateLogger(ReplicationQueue.repLog); + private final ReplicationStateListener stateLog; interface Factory { PushAll create(String urlMatch, @@ -45,12 +44,14 @@ PushAll(WorkQueue wq, ProjectCache projectCache, ReplicationQueue rq, + ReplicationStateListener stateLog, @Assisted @Nullable String urlMatch, @Assisted ReplicationFilter filter, @Assisted ReplicationState state) { this.workQueue = wq; this.projectCache = projectCache; this.replication = rq; + this.stateLog = stateLog; this.urlMatch = urlMatch; this.filter = filter; this.state = state;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java b/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java index 255c51b..4a2d01b 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java
@@ -14,6 +14,8 @@ package com.googlesource.gerrit.plugins.replication; +import static com.googlesource.gerrit.plugins.replication.ReplicationQueue.repLog; + import com.google.common.base.Throwables; import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.Lists; @@ -59,7 +61,6 @@ import org.eclipse.jgit.transport.RemoteRefUpdate; import org.eclipse.jgit.transport.Transport; import org.eclipse.jgit.transport.URIish; -import org.slf4j.Logger; import org.slf4j.MDC; import java.io.IOException; @@ -78,9 +79,7 @@ * take that lock to ensure they are working with a current view of the object. */ class PushOne implements ProjectRunnable { - private static final Logger repLog = ReplicationQueue.repLog; - private static final ReplicationStateLogger stateLog = - new ReplicationStateLogger(repLog); + private final ReplicationStateListener stateLog; static final String ALL_REFS = "..all.."; static final String ID_MDC_KEY = "pushOneId"; @@ -124,6 +123,7 @@ final ChangeCache cc, final ReplicationQueue rq, final IdGenerator ig, + final ReplicationStateListener sl, @Assisted final Project.NameKey d, @Assisted final URIish u) { gitManager = grm; @@ -140,6 +140,7 @@ lockRetryCount = 0; maxLockRetries = pool.getLockErrorMaxRetries(); id = ig.next(); + stateLog = sl; createdAt = TimeUtil.nowMs(); } @@ -243,7 +244,7 @@ if (!stateMap.isEmpty() && !isRetrying()) { for (Map.Entry<String,ReplicationState> entry : stateMap.entries()) { entry.getValue().notifyRefReplicated(projectName.get(), entry.getKey(), uri, - RefPushResult.FAILED); + RefPushResult.FAILED, null); } } } @@ -427,19 +428,13 @@ local = n; } - ReviewDb db; - try { - db = schema.open(); + try (ReviewDb db = schema.open()) { + local = new VisibleRefFilter(tagCache, changeCache, git, pc, db, true) + .filter(local, true); } catch (OrmException e) { stateLog.error("Cannot read database to replicate to " + projectName, e, getStatesAsArray()); return Collections.emptyList(); } - try { - local = new VisibleRefFilter(tagCache, changeCache, git, pc, db, true) - .filter(local, true); - } finally { - db.close(); - } } return pushAllRefs ? doPushAll(tn, local) : doPushDelta(local); @@ -549,6 +544,7 @@ throws LockFailureException { Set<String> doneRefs = new HashSet<>(); boolean anyRefFailed = false; + RemoteRefUpdate.Status lastRefStatusError = RemoteRefUpdate.Status.OK; for (RemoteRefUpdate u : refUpdates) { RefPushResult pushStatus = RefPushResult.SUCCEEDED; @@ -574,6 +570,7 @@ u.getRemoteName(), uri, u.getStatus()), logStatesArray); pushStatus = RefPushResult.FAILED; anyRefFailed = true; + lastRefStatusError = u.getStatus(); break; case REJECTED_OTHER_REASON: @@ -591,30 +588,31 @@ } pushStatus = RefPushResult.FAILED; anyRefFailed = true; + lastRefStatusError = u.getStatus(); break; } for (ReplicationState rs : getStatesByRef(u.getSrcRef())) { rs.notifyRefReplicated(projectName.get(), u.getSrcRef(), - uri, pushStatus); + uri, pushStatus, u.getStatus()); } } doneRefs.add(ALL_REFS); for (ReplicationState rs : getStatesByRef(ALL_REFS)) { - rs.notifyRefReplicated(projectName.get(), ALL_REFS, - uri, anyRefFailed ? RefPushResult.FAILED : RefPushResult.SUCCEEDED); + rs.notifyRefReplicated(projectName.get(), ALL_REFS, uri, anyRefFailed + ? RefPushResult.FAILED : RefPushResult.SUCCEEDED, lastRefStatusError); } - for (Map.Entry<String,ReplicationState> entry : stateMap.entries()) { + for (Map.Entry<String, ReplicationState> entry : stateMap.entries()) { if (!doneRefs.contains(entry.getKey())) { - entry.getValue().notifyRefReplicated(projectName.get(), entry.getKey(), uri, - RefPushResult.NOT_ATTEMPTED); + entry.getValue().notifyRefReplicated(projectName.get(), entry.getKey(), + uri, RefPushResult.NOT_ATTEMPTED, null); } } stateMap.clear(); } - public class LockFailureException extends TransportException { + public static class LockFailureException extends TransportException { private static final long serialVersionUID = 1L; public LockFailureException(URIish uri, String message) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/PushResultProcessing.java b/src/main/java/com/googlesource/gerrit/plugins/replication/PushResultProcessing.java index 0f8cc9e..c63d346 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/PushResultProcessing.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/PushResultProcessing.java
@@ -26,6 +26,7 @@ import com.googlesource.gerrit.plugins.replication.ReplicationState.RefPushResult; +import org.eclipse.jgit.transport.RemoteRefUpdate; import org.eclipse.jgit.transport.URIish; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,7 +36,8 @@ public abstract class PushResultProcessing { - abstract void onRefReplicatedToOneNode(String project, String ref, URIish uri, RefPushResult status); + abstract void onRefReplicatedToOneNode(String project, String ref, + URIish uri, RefPushResult status, RemoteRefUpdate.Status refStatus); abstract void onRefReplicatedToAllNodes(String project, String ref, int nodesCount); @@ -83,7 +85,7 @@ @Override void onRefReplicatedToOneNode(String project, String ref, URIish uri, - RefPushResult status) { + RefPushResult status, RemoteRefUpdate.Status refStatus) { StringBuilder sb = new StringBuilder(); sb.append("Replicate "); sb.append(project); @@ -107,6 +109,9 @@ sb.append("UNKNOWN RESULT!"); break; } + sb.append(" ("); + sb.append(refStatus.toString()); + sb.append(")"); writeStdOut(sb.toString()); } @@ -167,9 +172,9 @@ @Override void onRefReplicatedToOneNode(String project, String ref, URIish uri, - RefPushResult status) { + RefPushResult status, RemoteRefUpdate.Status refStatus) { RefReplicatedEvent event = - new RefReplicatedEvent(project, ref, resolveNodeName(uri), status); + new RefReplicatedEvent(project, ref, resolveNodeName(uri), status, refStatus); postEvent(project, ref, event); } @@ -185,16 +190,11 @@ } private void postEvent(String project, String ref, RefEvent event) { - if (PatchSet.isRef(ref)) { - try { - ReviewDb db = schema.open(); - try { - Change change = retrieveChange(ref, db); - if (change != null) { - dispatcher.postEvent(change, event, db); - } - } finally { - db.close(); + if (PatchSet.isChangeRef(ref)) { + try (ReviewDb db = schema.open()) { + Change change = retrieveChange(ref, db); + if (change != null) { + dispatcher.postEvent(change, event, db); } } catch (Exception e) { log.error("Cannot post event", e);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/RefReplicatedEvent.java b/src/main/java/com/googlesource/gerrit/plugins/replication/RefReplicatedEvent.java index 664e819..f200194 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/RefReplicatedEvent.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/RefReplicatedEvent.java
@@ -19,19 +19,24 @@ import com.googlesource.gerrit.plugins.replication.ReplicationState.RefPushResult; +import org.eclipse.jgit.transport.RemoteRefUpdate; +import org.eclipse.jgit.transport.RemoteRefUpdate.Status; + public class RefReplicatedEvent extends RefEvent { public final String project; public final String ref; public final String targetNode; public final String status; + public final Status refStatus; public RefReplicatedEvent(String project, String ref, String targetNode, - RefPushResult status) { + RefPushResult status, RemoteRefUpdate.Status refStatus) { super("ref-replicated"); this.project = project; this.ref = ref; this.targetNode = targetNode; this.status = toStatusString(status); + this.refStatus = refStatus; } private String toStatusString(RefPushResult status) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationFileBasedConfig.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationFileBasedConfig.java index e796c9f..f7dc733 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationFileBasedConfig.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationFileBasedConfig.java
@@ -36,9 +36,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; import java.io.IOException; import java.net.URISyntaxException; +import java.nio.file.Path; import java.util.Collections; import java.util.List; import java.util.Set; @@ -47,7 +47,7 @@ public class ReplicationFileBasedConfig implements ReplicationConfig { static final Logger log = LoggerFactory.getLogger(ReplicationFileBasedConfig.class); private List<Destination> destinations; - private File cfgPath; + private Path cfgPath; private boolean replicateAllOnPluginStart; private boolean defaultForceUpdate; private Injector injector; @@ -56,6 +56,7 @@ private final GitRepositoryManager gitRepositoryManager; private final GroupBackend groupBackend; private final FileBasedConfig config; + private final ReplicationStateListener stateLog; private final GroupIncludeCache groupIncludeCache; @Inject @@ -63,17 +64,18 @@ final RemoteSiteUser.Factory ruf, final PluginUser pu, final GitRepositoryManager grm, final GroupBackend gb, - final GroupIncludeCache groupIncludeCache) throws ConfigInvalidException, - IOException { - this.cfgPath = new File(site.etc_dir, "replication.config"); + final ReplicationStateListener stateLog, + final GroupIncludeCache groupIncludeCache) throws ConfigInvalidException, IOException { + this.cfgPath = site.etc_dir.resolve("replication.config"); this.groupIncludeCache = groupIncludeCache; this.injector = injector; this.replicationUserFactory = ruf; this.pluginUser = pu; this.gitRepositoryManager = grm; this.groupBackend = gb; - this.config = new FileBasedConfig(cfgPath, FS.DETECTED); + this.config = new FileBasedConfig(cfgPath.toFile(), FS.DETECTED); this.destinations = allDestinations(); + this.stateLog = stateLog; } /* @@ -120,7 +122,7 @@ private List<Destination> allDestinations() throws ConfigInvalidException, IOException { if (!config.getFile().exists()) { - log.warn("Config file " + config.getFile() + "does not exist; not replicating"); + log.warn("Config file " + config.getFile() + " does not exist; not replicating"); return Collections.emptyList(); } if (config.getFile().length() == 0) { @@ -164,7 +166,7 @@ Destination destination = new Destination(injector, c, config, replicationUserFactory, - pluginUser, gitRepositoryManager, groupBackend, groupIncludeCache); + pluginUser, gitRepositoryManager, groupBackend, stateLog, groupIncludeCache); if (!destination.isSingleProjectMatch()) { for (URIish u : c.getURIs()) { @@ -220,7 +222,7 @@ return destinations.isEmpty(); } - File getCfgPath() { + Path getCfgPath() { return cfgPath; }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationLogFile.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationLogFile.java index 50f1b8b..fcc3437 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationLogFile.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationLogFile.java
@@ -14,55 +14,19 @@ package com.googlesource.gerrit.plugins.replication; -import com.google.gerrit.extensions.events.LifecycleListener; import com.google.gerrit.extensions.systemstatus.ServerInformation; +import com.google.gerrit.server.util.PluginLogFile; import com.google.gerrit.server.util.SystemLog; import com.google.inject.Inject; -import org.apache.log4j.AsyncAppender; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; import org.apache.log4j.PatternLayout; -public class ReplicationLogFile implements LifecycleListener { - - private final SystemLog systemLog; - private final ServerInformation serverInfo; - private static boolean started; +public class ReplicationLogFile extends PluginLogFile { @Inject - public ReplicationLogFile(final SystemLog systemLog, + public ReplicationLogFile(SystemLog systemLog, ServerInformation serverInfo) { - this.systemLog = systemLog; - this.serverInfo = serverInfo; - } - - @Override - public void start() { - if (!started) { - Logger replicationLogger = - LogManager.getLogger(ReplicationQueue.REPLICATION_LOG_NAME); - String loggerName = replicationLogger.getName(); - AsyncAppender asyncAppender = systemLog.createAsyncAppender( - loggerName, new PatternLayout("[%d] [%X{" - + PushOne.ID_MDC_KEY + "}] %m%n")); - replicationLogger.removeAppender(loggerName); - replicationLogger.addAppender(asyncAppender); - replicationLogger.setAdditivity(false); - started = true; - } - } - - @Override - public void stop() { - // stop is called when plugin is unloaded or when the server shutdown. - // Only clean up when the server is shutting down to prevent issue when a - // plugin is reloaded. The issue is that gerrit load the new plugin and then - // unload the old one so because loggers are static, the unload of the old - // plugin would remove the appenders just created by the new plugin. - if (serverInfo.getState() == ServerInformation.State.SHUTDOWN) { - LogManager.getLogger(ReplicationQueue.repLog.getName()) - .removeAllAppenders(); - } + super(systemLog, serverInfo, ReplicationQueue.REPLICATION_LOG_NAME, + new PatternLayout("[%d] [%X{" + PushOne.ID_MDC_KEY + "}] %m%n")); } }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationModule.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationModule.java index b9575b9..a5d0b82 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationModule.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationModule.java
@@ -31,6 +31,8 @@ import com.google.inject.assistedinject.FactoryModuleBuilder; import com.google.inject.internal.UniqueAnnotations; +import org.eclipse.jgit.transport.RemoteRefUpdate; + class ReplicationModule extends AbstractModule { @Override @@ -62,8 +64,10 @@ install(new FactoryModuleBuilder().build(RemoteSiteUser.Factory.class)); bind(ReplicationConfig.class).to(AutoReloadConfigDecorator.class); + bind(ReplicationStateListener.class).to(ReplicationStateLogger.class); - EventTypes.registerClass(new RefReplicatedEvent(null, null, null, SUCCEEDED)); + EventTypes.registerClass(new RefReplicatedEvent(null, null, null, + SUCCEEDED, RemoteRefUpdate.Status.OK)); EventTypes.registerClass(new RefReplicationDoneEvent(null, null, 0)); } }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java index 95693d9..67d172f 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java
@@ -63,8 +63,8 @@ static final String REPLICATION_LOG_NAME = "replication_log"; static final Logger repLog = LoggerFactory.getLogger(REPLICATION_LOG_NAME); private static final int SSH_REMOTE_TIMEOUT = 120 * 1000; - private static final ReplicationStateLogger stateLog = - new ReplicationStateLogger(repLog); + + private final ReplicationStateListener stateLog; static String replaceName(String in, String name, boolean keyIsOptional) { String key = "${name}"; @@ -85,12 +85,16 @@ private volatile boolean running; @Inject - ReplicationQueue(final WorkQueue wq, final ReplicationConfig rc, - final SchemaFactory<ReviewDb> db, final EventDispatcher dis) { + ReplicationQueue(final WorkQueue wq, + final ReplicationConfig rc, + final SchemaFactory<ReviewDb> db, + final EventDispatcher dis, + final ReplicationStateListener sl) { workQueue = wq; database = db; dispatcher = dis; config = rc; + stateLog = sl; } @Override @@ -256,18 +260,13 @@ } private static void createLocally(URIish uri, String head) { - try { - Repository repo = new FileRepository(uri.getPath()); - try { - repo.create(true /* bare */); + try (Repository repo = new FileRepository(uri.getPath())) { + repo.create(true /* bare */); - if (head != null) { - RefUpdate u = repo.updateRef(Constants.HEAD); - u.disableRefLog(); - u.link(head); - } - } finally { - repo.close(); + if (head != null) { + RefUpdate u = repo.updateRef(Constants.HEAD); + u.disableRefLog(); + u.link(head); } } catch (IOException e) { repLog.error(String.format( @@ -385,15 +384,10 @@ } private static void updateHeadLocally(URIish uri, String newHead) { - try { - Repository repo = new FileRepository(uri.getPath()); - try { - if (newHead != null) { - RefUpdate u = repo.updateRef(Constants.HEAD); - u.link(newHead); - } - } finally { - repo.close(); + try (Repository repo = new FileRepository(uri.getPath())) { + if (newHead != null) { + RefUpdate u = repo.updateRef(Constants.HEAD); + u.link(newHead); } } catch (IOException e) { repLog.error(
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationState.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationState.java index c851db6..b29456d 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationState.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationState.java
@@ -17,6 +17,7 @@ import com.google.common.collect.HashBasedTable; import com.google.common.collect.Table; +import org.eclipse.jgit.transport.RemoteRefUpdate; import org.eclipse.jgit.transport.URIish; import java.util.concurrent.CountDownLatch; @@ -69,8 +70,9 @@ } public void notifyRefReplicated(String project, String ref, URIish uri, - RefPushResult status) { - pushResultProcessing.onRefReplicatedToOneNode(project, ref, uri, status); + RefPushResult status, RemoteRefUpdate.Status refUpdateStatus) { + pushResultProcessing.onRefReplicatedToOneNode(project, ref, uri, status, + refUpdateStatus); RefReplicationStatus completedRefStatus = null; boolean allPushTaksCompleted = false;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationStateListener.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationStateListener.java new file mode 100644 index 0000000..e5ac9d5 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationStateListener.java
@@ -0,0 +1,56 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// 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.googlesource.gerrit.plugins.replication; + +/** + * Interface for notifying replication status updates. + */ +public interface ReplicationStateListener { + + /** + * Notify a non-fatal replication error. + * + * Replication states received a non-fatal error with an associated + * warning message. + * + * @param msg message description of the error + * @param states replication states impacted + */ + public abstract void warn(String msg, ReplicationState... states); + + /** + * Notify a fatal replication error. + * + * Replication states have received a fatal error and replication has + * failed. + * + * @param msg message description of the error + * @param states replication states impacted + */ + public abstract void error(String msg, ReplicationState... states); + + /** + * Notify a fatal replication error with the associated exception. + * + * Replication states have received a fatal exception and replication has failed. + * + * @param msg message description of the error + * @param t exception that caused the replication to fail + * @param states replication states impacted + */ + public abstract void error(String msg, Throwable t, + ReplicationState... states); + +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationStateLogger.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationStateLogger.java index cb1d4ce..0a59ad3 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationStateLogger.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationStateLogger.java
@@ -14,7 +14,9 @@ package com.googlesource.gerrit.plugins.replication; -import org.slf4j.Logger; +import static com.googlesource.gerrit.plugins.replication.ReplicationQueue.repLog; + +import com.google.inject.Singleton; /** * Wrapper around a Logger that also logs out the replication state. @@ -24,32 +26,25 @@ * and logs additional information about the replication state to the * stderr console. */ -public class ReplicationStateLogger { +@Singleton +class ReplicationStateLogger implements ReplicationStateListener { - private final Logger logger; - - public ReplicationStateLogger(Logger logger) { - this.logger = logger; - } - + @Override public void warn(String msg, ReplicationState... states) { stateWriteErr("Warning: " + msg, states); - logger.warn(msg); + repLog.warn(msg); } - public void warn(String msg, Throwable t, ReplicationState... states) { - stateWriteErr("Warning: " + msg, states); - logger.warn(msg, t); - } - + @Override public void error(String msg, ReplicationState... states) { stateWriteErr("Error: " + msg, states); - logger.error(msg); + repLog.error(msg); } + @Override public void error(String msg, Throwable t, ReplicationState... states) { stateWriteErr("Error: " + msg, states); - logger.error(msg, t); + repLog.error(msg, t); } private void stateWriteErr(String msg, ReplicationState[] states) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/SecureCredentialsFactory.java b/src/main/java/com/googlesource/gerrit/plugins/replication/SecureCredentialsFactory.java index 32d3905..a10f62f 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/SecureCredentialsFactory.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/SecureCredentialsFactory.java
@@ -36,7 +36,8 @@ private static Config load(SitePaths site) throws ConfigInvalidException, IOException { - FileBasedConfig cfg = new FileBasedConfig(site.secure_config, FS.DETECTED); + FileBasedConfig cfg = + new FileBasedConfig(site.secure_config.toFile(), FS.DETECTED); if (cfg.getFile().exists() && cfg.getFile().length() > 0) { try { cfg.load();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/SshModule.java b/src/main/java/com/googlesource/gerrit/plugins/replication/SshModule.java index dd33049..0cab7b1 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/SshModule.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/SshModule.java
@@ -20,5 +20,6 @@ @Override protected void configureCommands() { command(StartCommand.class); + command(ListCommand.class); } }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/StartCommand.java b/src/main/java/com/googlesource/gerrit/plugins/replication/StartCommand.java index 17a2df9..be5242e 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/StartCommand.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/StartCommand.java
@@ -23,8 +23,6 @@ import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Option; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; @@ -35,8 +33,9 @@ @RequiresCapability(StartReplicationCapability.START_REPLICATION) @CommandMetaData(name = "start", description = "Start replication for specific project or all projects") final class StartCommand extends SshCommand { - private static final Logger log = LoggerFactory.getLogger(StartCommand.class); - private static final ReplicationStateLogger stateLog = new ReplicationStateLogger(log); + @Inject + private ReplicationStateLogger stateLog; + @Option(name = "--all", usage = "push all known projects") private boolean all;
diff --git a/src/main/resources/Documentation/cmd-list.md b/src/main/resources/Documentation/cmd-list.md new file mode 100644 index 0000000..84bb56b --- /dev/null +++ b/src/main/resources/Documentation/cmd-list.md
@@ -0,0 +1,76 @@ +@PLUGIN@ list +============== + +NAME +---- +@PLUGIN@ list - List specific remote destinations information + +SYNOPSIS +-------- +``` +ssh -p @SSH_PORT@ @SSH_HOST@ @PLUGIN@ list + [--remote <PATTERN>] + [--detail] + [--json] +``` + +DESCRIPTION +----------- +List all remote destinations information, or only those whose +name match the pattern given on the command line. + +ACCESS +------ +Caller must be a member of the privileged 'Administrators' group. + +SCRIPTING +--------- +This command is intended to be used in scripts. It is very useful +for replication status check for administrators as well. + +OPTIONS +------- + +`--remote <PATTERN>` +: Only print destinations whose remote name contains + the substring `PATTERN`. + +`--detail` +: Print remote detail information: Name, Url, AdminUrl, + AuthGroup and Project. + +`--json` +: Output in json format. + +EXAMPLES +-------- +List all destinations: + +``` + $ ssh -p @SSH_PORT@ @SSH_HOST@ @PLUGIN@ list +``` + +List all destinations detail information: + +``` + $ ssh -p @SSH_PORT@ @SSH_HOST@ @PLUGIN@ list --detail +``` + +List all destinations detail information in json format: + +``` + $ ssh -p @SSH_PORT@ @SSH_HOST@ @PLUGIN@ list --detail --json +``` + +List destinations whose name contains mirror: + +``` + $ ssh -p @SSH_PORT@ @SSH_HOST@ @PLUGIN@ list --remote mirror + $ ssh -p @SSH_PORT@ @SSH_HOST@ @PLUGIN@ list --remote ^.*mirror.* +``` + +SEE ALSO +-------- + +* [Replication Configuration](config.html) +* [Access Control](../../../Documentation/access-control.html)
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/GitUpdateProcessingTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/GitUpdateProcessingTest.java index a400dca..c6b2eb6 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/replication/GitUpdateProcessingTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/replication/GitUpdateProcessingTest.java
@@ -39,6 +39,7 @@ import junit.framework.TestCase; +import org.eclipse.jgit.transport.RemoteRefUpdate; import org.eclipse.jgit.transport.URIish; import java.net.URISyntaxException; @@ -73,14 +74,15 @@ reset(dispatcherMock); RefReplicatedEvent expectedEvent = new RefReplicatedEvent("someProject", "refs/heads/master", "someHost", - RefPushResult.SUCCEEDED); + RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); dispatcherMock.postEvent(anyObject(Branch.NameKey.class), RefReplicatedEventEquals.eqEvent(expectedEvent)); expectLastCall().once(); replay(dispatcherMock); - gitUpdateProcessing.onRefReplicatedToOneNode("someProject", "refs/heads/master", - new URIish("git://someHost/someProject.git"), RefPushResult.SUCCEEDED); + gitUpdateProcessing.onRefReplicatedToOneNode("someProject", + "refs/heads/master", new URIish("git://someHost/someProject.git"), + RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); verify(dispatcherMock); } @@ -93,7 +95,7 @@ reset(dispatcherMock); RefReplicatedEvent expectedEvent = new RefReplicatedEvent("someProject", "refs/changes/01/1/1", "someHost", - RefPushResult.FAILED); + RefPushResult.FAILED, RemoteRefUpdate.Status.REJECTED_NONFASTFORWARD); dispatcherMock.postEvent(eq(expectedChange), RefReplicatedEventEquals.eqEvent(expectedEvent), anyObject(ReviewDb.class)); @@ -102,7 +104,7 @@ gitUpdateProcessing.onRefReplicatedToOneNode("someProject", "refs/changes/01/1/1", new URIish("git://someHost/someProject.git"), - RefPushResult.FAILED); + RefPushResult.FAILED, RemoteRefUpdate.Status.REJECTED_NONFASTFORWARD); verify(dispatcherMock); }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/ReplicationStateTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/ReplicationStateTest.java index a0bf576..1408ed6 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/replication/ReplicationStateTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/replication/ReplicationStateTest.java
@@ -23,6 +23,7 @@ import com.googlesource.gerrit.plugins.replication.ReplicationState.RefPushResult; +import org.eclipse.jgit.transport.RemoteRefUpdate; import org.eclipse.jgit.transport.URIish; import org.junit.Before; import org.junit.Test; @@ -73,7 +74,7 @@ //expected events pushResultProcessingMock.onRefReplicatedToOneNode("someProject", "someRef", - uri, RefPushResult.SUCCEEDED); + uri, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); pushResultProcessingMock.onRefReplicatedToAllNodes("someProject", "someRef", 1); pushResultProcessingMock.onAllRefsReplicatedToAllNodes(1); @@ -83,7 +84,7 @@ replicationState.increasePushTaskCount("someProject", "someRef"); replicationState.markAllPushTasksScheduled(); replicationState.notifyRefReplicated("someProject", "someRef", uri, - RefPushResult.SUCCEEDED); + RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); verify(pushResultProcessingMock); } @@ -96,9 +97,9 @@ //expected events pushResultProcessingMock.onRefReplicatedToOneNode("someProject", "someRef", - uri1, RefPushResult.SUCCEEDED); + uri1, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); pushResultProcessingMock.onRefReplicatedToOneNode("someProject", "someRef", - uri2, RefPushResult.FAILED); + uri2, RefPushResult.FAILED, RemoteRefUpdate.Status.NON_EXISTING); pushResultProcessingMock.onRefReplicatedToAllNodes("someProject", "someRef", 2); pushResultProcessingMock.onAllRefsReplicatedToAllNodes(2); @@ -109,9 +110,9 @@ replicationState.increasePushTaskCount("someProject", "someRef"); replicationState.markAllPushTasksScheduled(); replicationState.notifyRefReplicated("someProject", "someRef", uri1, - RefPushResult.SUCCEEDED); + RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); replicationState.notifyRefReplicated("someProject", "someRef", uri2, - RefPushResult.FAILED); + RefPushResult.FAILED, RemoteRefUpdate.Status.NON_EXISTING); verify(pushResultProcessingMock); } @@ -125,15 +126,15 @@ //expected events pushResultProcessingMock.onRefReplicatedToOneNode("someProject", "ref1", - uri1, RefPushResult.SUCCEEDED); + uri1, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); pushResultProcessingMock.onRefReplicatedToOneNode("someProject", "ref1", - uri2, RefPushResult.SUCCEEDED); + uri2, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); pushResultProcessingMock.onRefReplicatedToOneNode("someProject", "ref1", - uri3, RefPushResult.SUCCEEDED); + uri3, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); pushResultProcessingMock.onRefReplicatedToOneNode("someProject", "ref2", - uri1, RefPushResult.SUCCEEDED); + uri1, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); pushResultProcessingMock.onRefReplicatedToOneNode("someProject", "ref2", - uri2, RefPushResult.SUCCEEDED); + uri2, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); pushResultProcessingMock .onRefReplicatedToAllNodes("someProject", "ref1", 3); pushResultProcessingMock @@ -149,15 +150,15 @@ replicationState.increasePushTaskCount("someProject", "ref2"); replicationState.markAllPushTasksScheduled(); replicationState.notifyRefReplicated("someProject", "ref1", uri1, - RefPushResult.SUCCEEDED); + RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); replicationState.notifyRefReplicated("someProject", "ref1", uri2, - RefPushResult.SUCCEEDED); + RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); replicationState.notifyRefReplicated("someProject", "ref1", uri3, - RefPushResult.SUCCEEDED); + RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); replicationState.notifyRefReplicated("someProject", "ref2", uri1, - RefPushResult.SUCCEEDED); + RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); replicationState.notifyRefReplicated("someProject", "ref2", uri2, - RefPushResult.SUCCEEDED); + RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); verify(pushResultProcessingMock); } @@ -169,9 +170,9 @@ //expected events pushResultProcessingMock.onRefReplicatedToOneNode("project1", "ref1", uri, - RefPushResult.SUCCEEDED); + RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); pushResultProcessingMock.onRefReplicatedToOneNode("project2", "ref2", uri, - RefPushResult.SUCCEEDED); + RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); pushResultProcessingMock.onRefReplicatedToAllNodes("project1", "ref1", 1); pushResultProcessingMock.onRefReplicatedToAllNodes("project2", "ref2", 1); pushResultProcessingMock.onAllRefsReplicatedToAllNodes(2); @@ -182,9 +183,9 @@ replicationState.increasePushTaskCount("project2", "ref2"); replicationState.markAllPushTasksScheduled(); replicationState.notifyRefReplicated("project1", "ref1", uri, - RefPushResult.SUCCEEDED); + RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); replicationState.notifyRefReplicated("project2", "ref2", uri, - RefPushResult.SUCCEEDED); + RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); verify(pushResultProcessingMock); } @@ -196,9 +197,9 @@ //expected events pushResultProcessingMock.onRefReplicatedToOneNode("someProject", "ref1", - uri1, RefPushResult.SUCCEEDED); + uri1, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); pushResultProcessingMock.onRefReplicatedToOneNode("someProject", "ref2", - uri1, RefPushResult.SUCCEEDED); + uri1, RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); pushResultProcessingMock .onRefReplicatedToAllNodes("someProject", "ref1", 1); pushResultProcessingMock @@ -210,9 +211,9 @@ replicationState.increasePushTaskCount("someProject", "ref1"); replicationState.increasePushTaskCount("someProject", "ref2"); replicationState.notifyRefReplicated("someProject", "ref1", uri1, - RefPushResult.SUCCEEDED); + RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); replicationState.notifyRefReplicated("someProject", "ref2", uri1, - RefPushResult.SUCCEEDED); + RefPushResult.SUCCEEDED, RemoteRefUpdate.Status.OK); replicationState.markAllPushTasksScheduled(); verify(pushResultProcessingMock); }