Use refs/meta/config/OWNERS as global default
Allow to have project global default for the OWNERS file configuration
stored under refs/meta/config.
Enable the definition of global policies, regardless of the branch
name, to owners of specific pattern-matching files.
Change-Id: Iae5c73e902f155dd264227eb866474d7805b9016
diff --git a/config.md b/config.md
index 99337ad..59d4a9c 100644
--- a/config.md
+++ b/config.md
@@ -63,6 +63,26 @@
If for each patch there is a reviewer who gave a Code-Review +2 then the plugin
will not add any labels, otherwise, it will add ```label('Code-Review from owners', need(_)).```
+## Global project OWNERS
+
+Set a OWNERS file into the project refs/meta/config to define a global set of
+rules applied to every change pushed, regardless of the folder or target branch.
+
+Example of assigning every configuration files to a specific owner group:
+```yaml
+matchers:
+- suffix: *.config
+ owners:
+ - Configuration Managers
+```
+
+Global refs/meta/config OWNERS configuration is inherited only when the OWNERS file
+contain the 'inherited: true' condition at the top of the file or if they are absent.
+
+That means that in the absence of any OWNERS file in the target branch, the refs/meta/config
+OWNERS is used as global default.
+
+
## Example 1 - OWNERS file without matchers and default Gerrit submit rules
Given an OWNERS configuration of:
diff --git a/owners-common/src/main/java/com/vmware/gerrit/owners/common/PathOwners.java b/owners-common/src/main/java/com/vmware/gerrit/owners/common/PathOwners.java
index 17d6fdd..8413704 100644
--- a/owners-common/src/main/java/com/vmware/gerrit/owners/common/PathOwners.java
+++ b/owners-common/src/main/java/com/vmware/gerrit/owners/common/PathOwners.java
@@ -37,6 +37,7 @@
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Account.Id;
import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.patch.PatchList;
import com.google.gerrit.server.patch.PatchListEntry;
@@ -100,6 +101,12 @@
OwnersMap ownersMap = new OwnersMap();
try {
String rootPath = "OWNERS";
+
+ PathOwnersEntry projectEntry =
+ getOwnersConfig(rootPath, RefNames.REFS_CONFIG)
+ .map(conf -> new PathOwnersEntry(rootPath, conf, accounts, Collections.emptySet()))
+ .orElse(new PathOwnersEntry());
+
PathOwnersEntry rootEntry =
getOwnersConfig(rootPath, branch).map(
conf -> new PathOwnersEntry(rootPath, conf, accounts, Collections
@@ -109,7 +116,7 @@
Map<String, PathOwnersEntry> entries = new HashMap<>();
PathOwnersEntry currentEntry = null;
for (String path : modifiedPaths) {
- currentEntry = resolvePathEntry(path, branch, rootEntry, entries);
+ currentEntry = resolvePathEntry(path, branch, projectEntry, rootEntry, entries);
// add owners to file for matcher predicates
ownersMap.addFileOwners(path,currentEntry.getOwners());
@@ -155,12 +162,32 @@
}
private PathOwnersEntry resolvePathEntry(
- String path, String branch, PathOwnersEntry rootEntry, Map<String, PathOwnersEntry> entries)
+ String path,
+ String branch,
+ PathOwnersEntry projectEntry,
+ PathOwnersEntry rootEntry,
+ Map<String, PathOwnersEntry> entries)
throws IOException {
String[] parts = path.split("/");
PathOwnersEntry currentEntry = rootEntry;
Set<Id> currentOwners = currentEntry.getOwners();
StringBuilder builder = new StringBuilder();
+
+ if (rootEntry.isInherited()) {
+ for(Matcher matcher : projectEntry.getMatchers().values()) {
+ if(!currentEntry.hasMatcher(matcher.getPath())) {
+ currentEntry.addMatcher(matcher);
+ }
+ }
+ if (currentEntry.getOwners().isEmpty()) {
+ currentEntry.setOwners(projectEntry.getOwners());
+ currentOwners = currentEntry.getOwners();
+ }
+ if (currentEntry.getOwnersPath() == null) {
+ currentEntry.setOwnersPath(projectEntry.getOwnersPath());
+ }
+ }
+
// Iterate through the parent paths, not including the file name
// itself
for (int i = 0; i < parts.length - 1; i++) {
@@ -174,9 +201,9 @@
} else {
String ownersPath = partial + "OWNERS";
Optional<OwnersConfig> conf = getOwnersConfig(ownersPath, branch);
+ final Set<Id> owners = currentOwners;
currentEntry =
- conf.map(
- c -> new PathOwnersEntry(ownersPath, c, accounts, currentOwners))
+ conf.map(c -> new PathOwnersEntry(ownersPath, c, accounts, owners))
.orElse(currentEntry);
if (conf.map(OwnersConfig::isInherited).orElse(false)) {
for (Matcher m : currentEntry.getMatchers().values()) {
diff --git a/owners-common/src/main/java/com/vmware/gerrit/owners/common/PathOwnersEntry.java b/owners-common/src/main/java/com/vmware/gerrit/owners/common/PathOwnersEntry.java
index 407584e..c56d5fd 100644
--- a/owners-common/src/main/java/com/vmware/gerrit/owners/common/PathOwnersEntry.java
+++ b/owners-common/src/main/java/com/vmware/gerrit/owners/common/PathOwnersEntry.java
@@ -20,6 +20,7 @@
import com.google.common.collect.Sets;
import com.google.gerrit.reviewdb.client.Account;
+import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@@ -31,8 +32,10 @@
* specific path.
*/
class PathOwnersEntry {
+ private final boolean inherited;
public PathOwnersEntry() {
+ inherited = true;
}
public PathOwnersEntry(String path, OwnersConfig config, Accounts accounts,
@@ -45,6 +48,7 @@
this.owners.addAll(inheritedOwners);
}
this.matchers = config.getMatchers();
+ this.inherited = config.isInherited();
}
@Override
@@ -86,4 +90,18 @@
public void setMatchers(Map<String, Matcher> matchers) {
this.matchers = matchers;
}
+
+ public boolean isInherited() {
+ return inherited;
+ }
+
+ public void addMatchers(Collection<Matcher> values) {
+ for (Matcher matcher : values) {
+ addMatcher(matcher);
+ }
+ }
+
+ public boolean hasMatcher(String path) {
+ return this.matchers.containsKey(path);
+ }
}
diff --git a/owners-common/src/test/java/com/vmware/gerrit/owners/common/Config.java b/owners-common/src/test/java/com/vmware/gerrit/owners/common/Config.java
index 8048391..148e116 100644
--- a/owners-common/src/test/java/com/vmware/gerrit/owners/common/Config.java
+++ b/owners-common/src/test/java/com/vmware/gerrit/owners/common/Config.java
@@ -30,7 +30,6 @@
import com.google.common.base.Charsets;
import com.google.gerrit.reviewdb.client.Patch;
-import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.patch.PatchList;
import com.google.gerrit.server.patch.PatchListEntry;