diff options
author | Chad Horohoe <chorohoe@wikimedia.org> | 2013-06-07 20:56:23 -0400 |
---|---|---|
committer | Ismo Haataja <ismo.haataja@digia.com> | 2014-10-28 14:34:54 +0100 |
commit | dc296fdabc5f55adff75a9e59c5f1c20b5a9802f (patch) | |
tree | 69f6f0af65a61ac2ce65fe55658987dd50dbfc39 /src | |
parent | df8cb393676880b6e27b42d4b49492be0804c0ee (diff) |
Implement pattern-based project matching in replication.config
This allows you to use remote.$name.projects to either
- Do wildcard-style matching, such as foo/*
- Do regular-expression matching, such as ^foo/(bar|baz)$
Task-number: QTQAINFRA-892
Change-Id: I453d99ca354afeaf6dfbe467c7a81d2eb5440a74
(cherry picked from commit 0b9811b3bcd13e9d858d341935e660117c735569)
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Reviewed-by: Ismo Haataja <ismo.haataja@digia.com>
Diffstat (limited to 'src')
3 files changed, 76 insertions, 4 deletions
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 8256282..5032dd8 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java @@ -18,6 +18,7 @@ import com.google.common.base.Objects; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; +import com.google.gerrit.common.data.AccessSection; import com.google.gerrit.common.data.GroupReference; import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.reviewdb.client.Project; @@ -66,6 +67,7 @@ class Destination { private final RemoteConfig remote; private final String[] adminUrls; + private final String[] projects; private final int delay; private final int retryDelay; private final Map<URIish, PushOne> pending = new HashMap<URIish, PushOne>(); @@ -97,6 +99,7 @@ class Destination { cfg.getBoolean("remote", rc.getName(), "replicatePermissions", true); remoteNameStyle = Objects.firstNonNull( cfg.getString("remote", rc.getName(), "remoteNameStyle"), "slash"); + projects = cfg.getStringList("remote", rc.getName(), "projects"); final CurrentUser remoteUser; String[] authGroupNames = cfg.getStringList("remote", rc.getName(), "authGroup"); @@ -333,6 +336,45 @@ class Destination { } } + boolean wouldPushProject(Project.NameKey project) { + // by default push all projects + if (projects.length < 1) { + return true; + } + + String projectName = project.get(); + for (final String projectMatch : projects) { + if (isRE(projectMatch)) { + // projectMatch is a regular expression + if (projectName.matches(projectMatch)) { + return true; + } + } else if (isWildcard(projectMatch)) { + // projectMatch is a wildcard + if (projectName.startsWith( + projectMatch.substring(0, projectMatch.length() - 1))) { + return true; + } + } else { + // No special case, so we try to match directly + if (projectName.equals(projectMatch)) { + return true; + } + } + } + + // Nothing matched, so don't push the project + return false; + } + + private static boolean isRE(String str) { + return str.startsWith(AccessSection.REGEX_PREFIX); + } + + private static boolean isWildcard(String str) { + return str.endsWith("*"); + } + boolean wouldPushRef(String ref) { if (!replicatePermissions && GitRepositoryManager.REF_CONFIG.equals(ref)) { return false; 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 a6599fa..8991b7c 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java @@ -129,8 +129,10 @@ class ReplicationQueue implements } for (Destination cfg : configs) { - for (URIish uri : cfg.getURIs(project, urlMatch)) { - cfg.schedule(project, PushOne.ALL_REFS, uri); + if (cfg.wouldPushProject(project)) { + for (URIish uri : cfg.getURIs(project, urlMatch)) { + cfg.schedule(project, PushOne.ALL_REFS, uri); + } } } } @@ -145,7 +147,7 @@ class ReplicationQueue implements Project.NameKey project = new Project.NameKey(event.getProjectName()); for (GitReferenceUpdatedListener.Update u : event.getUpdates()) { for (Destination cfg : configs) { - if (cfg.wouldPushRef(u.getRefName())) { + if (cfg.wouldPushProject(project) && cfg.wouldPushRef(u.getRefName())) { for (URIish uri : cfg.getURIs(project, null)) { cfg.schedule(project, u.getRefName(), uri); } @@ -241,6 +243,9 @@ class ReplicationQueue implements Project.NameKey projectName = new Project.NameKey(event.getProjectName()); for (Destination config : configs) { + if (!config.wouldPushProject(projectName)) { + continue; + } List<URIish> uriList = config.getURIs(projectName, "*"); String[] adminUrls = config.getAdminUrls(); boolean adminURLUsed = false; diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md index fd90581..4efcebe 100644 --- a/src/main/resources/Documentation/config.md +++ b/src/main/resources/Documentation/config.md @@ -198,7 +198,7 @@ remote.NAME.authGroup can be specified for this group to control if a project should be replicated or not to the remote. - By default, replicates without group control, i.e replicates + By default, replicates without group control, i.e. replicates everything to all remotes. remote.NAME.replicatePermissions @@ -229,6 +229,31 @@ remote.NAME.remoteNameStyle By default, "slash," remote name will contain slashes as they do in Gerrit. +remote.NAME.projects +: Specifies which repositories should be replicated to the + remote. It can be provided more than once, and supports three + formats: regular expressions, wildcard matching, and single + project matching. All three formats match case-sensitive. + + Values starting with a caret `^` are treated as regular + expressions. `^foo/(bar|baz)` would match the projects + `foo/bar`, and `foo/baz`. Regular expressions have to fully + match the project name. So the above example would not match + `foo/bar2`, while `^foo/(bar|baz).*` would. + + Values that are not regular expressions and end in `*` are + treated as wildcard matches. Wildcards match projects whose + name agrees from the beginning until the trailing `*`. So + `foo/b*` would match the projects `foo/b`, `foo/bar`, and + `foo/baz`, but neither `foobar`, nor `bar/foo/baz`. + + Values that are neither regular expressions nor wildcards are + treated as single project matches. So `foo/bar` matches only + the project `foo/bar`, but no other project. + + By default, replicates without matching, i.e. replicates + everything to all remotes. + File `secure.config` -------------------- |