Merge changes If541bc32,I5a34a35f,I3ac34367
* changes:
Use PerThreadCache to create code-owners plugin config only once per request
Reduce number of CodeOwnersPluginConfiguration#getProjectConfig calls
Refactor config reading as preparation to reduce plugin config loads
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/AbstractFileBasedCodeOwnerBackend.java b/java/com/google/gerrit/plugins/codeowners/backend/AbstractFileBasedCodeOwnerBackend.java
index 34f4e0d..2824246 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/AbstractFileBasedCodeOwnerBackend.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/AbstractFileBasedCodeOwnerBackend.java
@@ -171,7 +171,8 @@
String quotedFileExtension =
Pattern.quote(
codeOwnersPluginConfiguration
- .getFileExtension(project)
+ .getProjectConfig(project)
+ .getFileExtension()
.map(ext -> "." + ext)
.orElse(""));
String nameExtension = "(\\w)+";
@@ -188,7 +189,11 @@
private String getFileName(Project.NameKey project) {
return defaultFileName
- + codeOwnersPluginConfiguration.getFileExtension(project).map(ext -> "." + ext).orElse("");
+ + codeOwnersPluginConfiguration
+ .getProjectConfig(project)
+ .getFileExtension()
+ .map(ext -> "." + ext)
+ .orElse("");
}
@Override
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/BackendModule.java b/java/com/google/gerrit/plugins/codeowners/backend/BackendModule.java
index 3bdb518..c22dafe 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/BackendModule.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/BackendModule.java
@@ -19,6 +19,7 @@
import com.google.gerrit.extensions.events.ReviewerAddedListener;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfigSnapshot;
import com.google.gerrit.server.ExceptionHook;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.ServerInitiated;
@@ -32,6 +33,7 @@
protected void configure() {
factory(CodeOwnersUpdate.Factory.class);
factory(CodeOwnerConfigScanner.Factory.class);
+ factory(CodeOwnersPluginConfigSnapshot.Factory.class);
DynamicMap.mapOf(binder(), CodeOwnerBackend.class);
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/ChangedFiles.java b/java/com/google/gerrit/plugins/codeowners/backend/ChangedFiles.java
index 787e452..cf88e62 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/ChangedFiles.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/ChangedFiles.java
@@ -127,7 +127,7 @@
repoConfig,
revWalk,
revCommit,
- codeOwnersPluginConfiguration.getMergeCommitStrategy(project));
+ codeOwnersPluginConfiguration.getProjectConfig(project).getMergeCommitStrategy());
}
public ImmutableSet<ChangedFile> compute(
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerApprovalCheck.java b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerApprovalCheck.java
index 45023fc..c25fe52 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerApprovalCheck.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerApprovalCheck.java
@@ -34,6 +34,7 @@
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.metrics.Timer0;
+import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfigSnapshot;
import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfiguration;
import com.google.gerrit.plugins.codeowners.backend.config.RequiredApproval;
import com.google.gerrit.plugins.codeowners.common.ChangedFile;
@@ -234,13 +235,14 @@
"prepare stream to compute file statuses (project = %s, change = %d)",
changeNotes.getProjectName(), changeNotes.getChangeId().get());
- if (codeOwnersPluginConfiguration.arePureRevertsExempted(changeNotes.getProjectName())
- && isPureRevert(changeNotes)) {
+ CodeOwnersPluginConfigSnapshot codeOwnersConfig =
+ codeOwnersPluginConfiguration.getProjectConfig(changeNotes.getProjectName());
+
+ if (codeOwnersConfig.arePureRevertsExempted() && isPureRevert(changeNotes)) {
return getAllPathsAsApproved(changeNotes, changeNotes.getCurrentPatchSet());
}
- boolean enableImplicitApprovalFromUploader =
- codeOwnersPluginConfiguration.areImplicitApprovalsEnabled(changeNotes.getProjectName());
+ boolean enableImplicitApprovalFromUploader = codeOwnersConfig.areImplicitApprovalsEnabled();
Account.Id patchSetUploader = changeNotes.getCurrentPatchSet().uploader();
logger.atFine().log(
"patchSetUploader = %d, implicit approval from uploader is %s",
@@ -249,12 +251,10 @@
ImmutableList<PatchSetApproval> currentPatchSetApprovals =
getCurrentPatchSetApprovals(changeNotes);
- RequiredApproval requiredApproval =
- codeOwnersPluginConfiguration.getRequiredApproval(changeNotes.getProjectName());
+ RequiredApproval requiredApproval = codeOwnersConfig.getRequiredApproval();
logger.atFine().log("requiredApproval = %s", requiredApproval);
- ImmutableSet<RequiredApproval> overrideApprovals =
- codeOwnersPluginConfiguration.getOverrideApproval(changeNotes.getProjectName());
+ ImmutableSet<RequiredApproval> overrideApprovals = codeOwnersConfig.getOverrideApproval();
boolean hasOverride =
hasOverride(currentPatchSetApprovals, overrideApprovals, changeNotes, patchSetUploader);
logger.atFine().log(
@@ -286,8 +286,7 @@
currentPatchSetApprovals, requiredApproval, changeNotes, patchSetUploader);
logger.atFine().log("reviewers = %s, approvers = %s", reviewerAccountIds, approverAccountIds);
- FallbackCodeOwners fallbackCodeOwners =
- codeOwnersPluginConfiguration.getFallbackCodeOwners(branch.project());
+ FallbackCodeOwners fallbackCodeOwners = codeOwnersConfig.getFallbackCodeOwners();
CodeOwnerConfigHierarchy codeOwnerConfigHierarchy = codeOwnerConfigHierarchyProvider.get();
return changedFiles
@@ -339,8 +338,10 @@
changeNotes.getChangeId().get(),
patchSet.id().get());
- RequiredApproval requiredApproval =
- codeOwnersPluginConfiguration.getRequiredApproval(changeNotes.getProjectName());
+ CodeOwnersPluginConfigSnapshot codeOwnersConfig =
+ codeOwnersPluginConfiguration.getProjectConfig(changeNotes.getProjectName());
+
+ RequiredApproval requiredApproval = codeOwnersConfig.getRequiredApproval();
logger.atFine().log("requiredApproval = %s", requiredApproval);
BranchNameKey branch = changeNotes.getChange().getDest();
@@ -348,8 +349,7 @@
logger.atFine().log("dest branch %s has revision %s", branch.branch(), revision.name());
boolean isProjectOwner = isProjectOwner(changeNotes.getProjectName(), accountId);
- FallbackCodeOwners fallbackCodeOwners =
- codeOwnersPluginConfiguration.getFallbackCodeOwners(branch.project());
+ FallbackCodeOwners fallbackCodeOwners = codeOwnersConfig.getFallbackCodeOwners();
logger.atFine().log(
"fallbackCodeOwner = %s, isProjectOwner = %s", fallbackCodeOwners, isProjectOwner);
if (fallbackCodeOwners.equals(FallbackCodeOwners.PROJECT_OWNERS) && isProjectOwner) {
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerConfigFileUpdateScanner.java b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerConfigFileUpdateScanner.java
index 60d1220..9e15746 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerConfigFileUpdateScanner.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerConfigFileUpdateScanner.java
@@ -92,7 +92,10 @@
requireNonNull(commitMessage, "commitMessage");
requireNonNull(codeOwnerConfigFileUpdater, "codeOwnerConfigFileUpdater");
- CodeOwnerBackend codeOwnerBackend = codeOwnersPluginConfiguration.getBackend(branchNameKey);
+ CodeOwnerBackend codeOwnerBackend =
+ codeOwnersPluginConfiguration
+ .getProjectConfig(branchNameKey.project())
+ .getBackend(branchNameKey.branch());
logger.atFine().log(
"updating code owner files in branch %s of project %s",
branchNameKey.branch(), branchNameKey.project());
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerConfigScanner.java b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerConfigScanner.java
index e28625e..4df1696 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerConfigScanner.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerConfigScanner.java
@@ -106,7 +106,10 @@
requireNonNull(codeOwnerConfigVisitor, "codeOwnerConfigVisitor");
requireNonNull(invalidCodeOwnerConfigCallback, "invalidCodeOwnerConfigCallback");
- CodeOwnerBackend codeOwnerBackend = codeOwnersPluginConfiguration.getBackend(branchNameKey);
+ CodeOwnerBackend codeOwnerBackend =
+ codeOwnersPluginConfiguration
+ .getProjectConfig(branchNameKey.project())
+ .getBackend(branchNameKey.branch());
logger.atFine().log(
"scanning code owner files in branch %s of project %s (path glob = %s)",
branchNameKey.branch(), branchNameKey.project(), pathGlob);
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerResolver.java b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerResolver.java
index 1fece0d..e7e18e5 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerResolver.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerResolver.java
@@ -191,7 +191,8 @@
* @return the resolved global code owners of the given project
*/
public CodeOwnerResolverResult resolveGlobalCodeOwners(Project.NameKey projectName) {
- return resolve(codeOwnersPluginConfiguration.getGlobalCodeOwners(projectName));
+ return resolve(
+ codeOwnersPluginConfiguration.getProjectConfig(projectName).getGlobalCodeOwners());
}
/**
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerSubmitRule.java b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerSubmitRule.java
index 2dc2d37..0683b25 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerSubmitRule.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerSubmitRule.java
@@ -82,7 +82,9 @@
"run code owner submit rule (project = %s, change = %d)",
changeData.project().get(), changeData.getId().get());
- if (codeOwnersPluginConfiguration.isDisabled(changeData.change().getDest())) {
+ if (codeOwnersPluginConfiguration
+ .getProjectConfig(changeData.project())
+ .isDisabled(changeData.change().getDest().branch())) {
logger.atFine().log(
"code owners functionality is disabled for branch %s", changeData.change().getDest());
return Optional.empty();
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwners.java b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwners.java
index 9315523..4247849 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwners.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwners.java
@@ -54,7 +54,9 @@
requireNonNull(revision, "revision");
codeOwnerMetrics.countCodeOwnerConfigReads.increment();
CodeOwnerBackend codeOwnerBackend =
- codeOwnersPluginConfiguration.getBackend(codeOwnerConfigKey.branchNameKey());
+ codeOwnersPluginConfiguration
+ .getProjectConfig(codeOwnerConfigKey.project())
+ .getBackend(codeOwnerConfigKey.branchNameKey().branch());
return codeOwnerBackend.getCodeOwnerConfig(codeOwnerConfigKey, revision);
}
@@ -63,7 +65,9 @@
requireNonNull(codeOwnerConfigKey, "codeOwnerConfigKey");
codeOwnerMetrics.countCodeOwnerConfigReads.increment();
CodeOwnerBackend codeOwnerBackend =
- codeOwnersPluginConfiguration.getBackend(codeOwnerConfigKey.branchNameKey());
+ codeOwnersPluginConfiguration
+ .getProjectConfig(codeOwnerConfigKey.project())
+ .getBackend(codeOwnerConfigKey.branchNameKey().branch());
return codeOwnerBackend.getCodeOwnerConfig(codeOwnerConfigKey, /* revision= */ null);
}
@@ -82,7 +86,9 @@
public Path getFilePath(CodeOwnerConfig.Key codeOwnerConfigKey) {
requireNonNull(codeOwnerConfigKey, "codeOwnerConfigKey");
CodeOwnerBackend codeOwnerBackend =
- codeOwnersPluginConfiguration.getBackend(codeOwnerConfigKey.branchNameKey());
+ codeOwnersPluginConfiguration
+ .getProjectConfig(codeOwnerConfigKey.project())
+ .getBackend(codeOwnerConfigKey.branchNameKey().branch());
return codeOwnerBackend.getFilePath(codeOwnerConfigKey);
}
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnersOnAddReviewer.java b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnersOnAddReviewer.java
index 8e57412..a7c2f27 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnersOnAddReviewer.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnersOnAddReviewer.java
@@ -19,13 +19,13 @@
import com.google.common.collect.ImmutableList;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.Account;
-import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.ChangeMessage;
import com.google.gerrit.entities.Project;
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.events.ReviewerAddedListener;
import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfigSnapshot;
import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfiguration;
import com.google.gerrit.plugins.codeowners.util.JgitPath;
import com.google.gerrit.server.ChangeMessagesUtil;
@@ -88,10 +88,11 @@
public void onReviewersAdded(Event event) {
Change.Id changeId = Change.id(event.getChange()._number);
Project.NameKey projectName = Project.nameKey(event.getChange().project);
- BranchNameKey branchNameKey = BranchNameKey.create(projectName, event.getChange().branch);
- if (codeOwnersPluginConfiguration.isDisabled(branchNameKey)
- || codeOwnersPluginConfiguration.getMaxPathsInChangeMessages(projectName) <= 0) {
+ CodeOwnersPluginConfigSnapshot codeOwnersConfig =
+ codeOwnersPluginConfiguration.getProjectConfig(projectName);
+ if (codeOwnersConfig.isDisabled(event.getChange().branch)
+ || codeOwnersConfig.getMaxPathsInChangeMessages() <= 0) {
return;
}
@@ -176,7 +177,7 @@
reviewerAccount.getName()));
int maxPathsInChangeMessage =
- codeOwnersPluginConfiguration.getMaxPathsInChangeMessages(projectName);
+ codeOwnersPluginConfiguration.getProjectConfig(projectName).getMaxPathsInChangeMessages();
if (ownedPaths.size() <= maxPathsInChangeMessage) {
appendPaths(message, ownedPaths.stream());
} else {
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnersUpdate.java b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnersUpdate.java
index d2a7f01..5e41d70 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnersUpdate.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnersUpdate.java
@@ -96,7 +96,9 @@
public Optional<CodeOwnerConfig> upsertCodeOwnerConfig(
CodeOwnerConfig.Key codeOwnerConfigKey, CodeOwnerConfigUpdate codeOwnerConfigUpdate) {
CodeOwnerBackend codeOwnerBackend =
- codeOwnersPluginConfiguration.getBackend(codeOwnerConfigKey.branchNameKey());
+ codeOwnersPluginConfiguration
+ .getProjectConfig(codeOwnerConfigKey.project())
+ .getBackend(codeOwnerConfigKey.branchNameKey().branch());
return codeOwnerBackend.upsertCodeOwnerConfig(
codeOwnerConfigKey, codeOwnerConfigUpdate, currentUser.orElse(null));
}
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/OnCodeOwnerApproval.java b/java/com/google/gerrit/plugins/codeowners/backend/OnCodeOwnerApproval.java
index 1cf59ce..7f2cd2b 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/OnCodeOwnerApproval.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/OnCodeOwnerApproval.java
@@ -20,6 +20,7 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfigSnapshot;
import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfiguration;
import com.google.gerrit.plugins.codeowners.backend.config.RequiredApproval;
import com.google.gerrit.plugins.codeowners.util.JgitPath;
@@ -69,7 +70,9 @@
PatchSet patchSet,
Map<String, Short> oldApprovals,
Map<String, Short> approvals) {
- if (codeOwnersPluginConfiguration.isDisabled(changeNotes.getChange().getDest())) {
+ CodeOwnersPluginConfigSnapshot codeOwnersConfig =
+ codeOwnersPluginConfiguration.getProjectConfig(changeNotes.getProjectName());
+ if (codeOwnersConfig.isDisabled(changeNotes.getChange().getDest().branch())) {
return Optional.empty();
}
@@ -78,8 +81,7 @@
return Optional.empty();
}
- RequiredApproval requiredApproval =
- codeOwnersPluginConfiguration.getRequiredApproval(changeNotes.getProjectName());
+ RequiredApproval requiredApproval = codeOwnersConfig.getRequiredApproval();
if (oldApprovals.get(requiredApproval.labelType().getName()) == null) {
// If oldApprovals doesn't contain the label or if the labels value in it is null, the label
@@ -99,8 +101,9 @@
Map<String, Short> oldApprovals,
Map<String, Short> approvals,
RequiredApproval requiredApproval) {
- int maxPathsInChangeMessage =
- codeOwnersPluginConfiguration.getMaxPathsInChangeMessages(changeNotes.getProjectName());
+ CodeOwnersPluginConfigSnapshot codeOwnersConfig =
+ codeOwnersPluginConfiguration.getProjectConfig(changeNotes.getProjectName());
+ int maxPathsInChangeMessage = codeOwnersConfig.getMaxPathsInChangeMessages();
if (maxPathsInChangeMessage <= 0) {
return Optional.empty();
}
@@ -137,7 +140,7 @@
}
boolean hasImplicitApprovalByUser =
- codeOwnersPluginConfiguration.areImplicitApprovalsEnabled(changeNotes.getProjectName())
+ codeOwnersConfig.areImplicitApprovalsEnabled()
&& patchSet.uploader().equals(user.getAccountId());
boolean noLongerExplicitlyApproved = false;
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/OnCodeOwnerOverride.java b/java/com/google/gerrit/plugins/codeowners/backend/OnCodeOwnerOverride.java
index 8a8c702..c06e760 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/OnCodeOwnerOverride.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/OnCodeOwnerOverride.java
@@ -21,6 +21,7 @@
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.entities.PatchSet;
+import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfigSnapshot;
import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfiguration;
import com.google.gerrit.plugins.codeowners.backend.config.RequiredApproval;
import com.google.gerrit.server.IdentifiedUser;
@@ -57,7 +58,9 @@
PatchSet patchSet,
Map<String, Short> oldApprovals,
Map<String, Short> approvals) {
- if (codeOwnersPluginConfiguration.isDisabled(changeNotes.getChange().getDest())) {
+ CodeOwnersPluginConfigSnapshot codeOwnersConfig =
+ codeOwnersPluginConfiguration.getProjectConfig(changeNotes.getProjectName());
+ if (codeOwnersConfig.isDisabled(changeNotes.getChange().getDest().branch())) {
return Optional.empty();
}
@@ -67,7 +70,7 @@
}
ImmutableList<RequiredApproval> overrideApprovals =
- codeOwnersPluginConfiguration.getOverrideApproval(changeNotes.getProjectName()).stream()
+ codeOwnersConfig.getOverrideApproval().stream()
.sorted(comparing(RequiredApproval::toString))
.collect(toImmutableList());
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/PathCodeOwners.java b/java/com/google/gerrit/plugins/codeowners/backend/PathCodeOwners.java
index c382801..91b0f6f 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/PathCodeOwners.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/PathCodeOwners.java
@@ -127,7 +127,9 @@
*/
private PathExpressionMatcher getMatcher(CodeOwnerConfig.Key codeOwnerConfigKey) {
CodeOwnerBackend codeOwnerBackend =
- codeOwnersPluginConfiguration.getBackend(codeOwnerConfigKey.branchNameKey());
+ codeOwnersPluginConfiguration
+ .getProjectConfig(codeOwnerConfigKey.project())
+ .getBackend(codeOwnerConfigKey.branchNameKey().branch());
return codeOwnerBackend
.getPathExpressionMatcher()
.orElse((pathExpression, relativePath) -> false);
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/UnresolvedImportFormatter.java b/java/com/google/gerrit/plugins/codeowners/backend/UnresolvedImportFormatter.java
index 0029d9e..52958d9 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/UnresolvedImportFormatter.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/UnresolvedImportFormatter.java
@@ -61,7 +61,9 @@
*/
private CodeOwnerBackend getBackend(CodeOwnerConfig.Key codeOwnerConfigKey) {
if (projectCache.get(codeOwnerConfigKey.project()).isPresent()) {
- return codeOwnersPluginConfiguration.getBackend(codeOwnerConfigKey.branchNameKey());
+ return codeOwnersPluginConfiguration
+ .getProjectConfig(codeOwnerConfigKey.project())
+ .getBackend(codeOwnerConfigKey.branchNameKey().branch());
}
return backendConfig.getDefaultBackend();
}
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigSnapshot.java b/java/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigSnapshot.java
new file mode 100644
index 0000000..666b2c1
--- /dev/null
+++ b/java/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigSnapshot.java
@@ -0,0 +1,416 @@
+// Copyright (C) 2021 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.google.gerrit.plugins.codeowners.backend.config;
+
+import static com.google.gerrit.server.project.ProjectCache.illegalState;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.entities.BranchNameKey;
+import com.google.gerrit.entities.LabelType;
+import com.google.gerrit.entities.Project;
+import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.plugins.codeowners.backend.CodeOwnerBackend;
+import com.google.gerrit.plugins.codeowners.backend.CodeOwnerReference;
+import com.google.gerrit.plugins.codeowners.backend.EnableImplicitApprovals;
+import com.google.gerrit.plugins.codeowners.backend.FallbackCodeOwners;
+import com.google.gerrit.plugins.codeowners.common.CodeOwnerConfigValidationPolicy;
+import com.google.gerrit.plugins.codeowners.common.MergeCommitStrategy;
+import com.google.gerrit.server.config.PluginConfigFactory;
+import com.google.gerrit.server.project.NoSuchProjectException;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.project.ProjectState;
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import org.eclipse.jgit.lib.Config;
+
+/** Snapshot of the code-owners plugin configuration for one project. */
+public class CodeOwnersPluginConfigSnapshot {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ public interface Factory {
+ CodeOwnersPluginConfigSnapshot create(Project.NameKey projectName);
+ }
+
+ private final String pluginName;
+ private final PluginConfigFactory pluginConfigFactory;
+ private final ProjectCache projectCache;
+ private final BackendConfig backendConfig;
+ private final GeneralConfig generalConfig;
+ private final OverrideApprovalConfig overrideApprovalConfig;
+ private final RequiredApprovalConfig requiredApprovalConfig;
+ private final StatusConfig statusConfig;
+ private final Project.NameKey projectName;
+ private final Config pluginConfig;
+
+ @Inject
+ CodeOwnersPluginConfigSnapshot(
+ @PluginName String pluginName,
+ PluginConfigFactory pluginConfigFactory,
+ ProjectCache projectCache,
+ BackendConfig backendConfig,
+ GeneralConfig generalConfig,
+ OverrideApprovalConfig overrideApprovalConfig,
+ RequiredApprovalConfig requiredApprovalConfig,
+ StatusConfig statusConfig,
+ @Assisted Project.NameKey projectName) {
+ this.pluginName = pluginName;
+ this.pluginConfigFactory = pluginConfigFactory;
+ this.projectCache = projectCache;
+ this.backendConfig = backendConfig;
+ this.generalConfig = generalConfig;
+ this.overrideApprovalConfig = overrideApprovalConfig;
+ this.requiredApprovalConfig = requiredApprovalConfig;
+ this.statusConfig = statusConfig;
+ this.projectName = projectName;
+ this.pluginConfig = loadPluginConfig();
+ }
+
+ /** Gets the file extension of code owner config files, if any configured. */
+ public Optional<String> getFileExtension() {
+ return generalConfig.getFileExtension(pluginConfig);
+ }
+
+ /** Checks whether code owner configs are read-only. */
+ public boolean areCodeOwnerConfigsReadOnly() {
+ return generalConfig.getReadOnly(projectName, pluginConfig);
+ }
+
+ /**
+ * Checks whether pure revert changes are exempted from needing code owner approvals for submit.
+ */
+ public boolean arePureRevertsExempted() {
+ return generalConfig.getExemptPureReverts(projectName, pluginConfig);
+ }
+
+ /**
+ * Checks whether newly added non-resolvable code owners should be rejected on commit received and
+ * submit.
+ */
+ public boolean rejectNonResolvableCodeOwners() {
+ return generalConfig.getRejectNonResolvableCodeOwners(projectName, pluginConfig);
+ }
+
+ /**
+ * Checks whether newly added non-resolvable imports should be rejected on commit received and
+ * submit.
+ */
+ public boolean rejectNonResolvableImports() {
+ return generalConfig.getRejectNonResolvableImports(projectName, pluginConfig);
+ }
+
+ /** Whether code owner configs should be validated when a commit is received. */
+ public CodeOwnerConfigValidationPolicy getCodeOwnerConfigValidationPolicyForCommitReceived() {
+ return generalConfig.getCodeOwnerConfigValidationPolicyForCommitReceived(
+ projectName, pluginConfig);
+ }
+
+ /** Whether code owner configs should be validated when a change is submitted. */
+ public CodeOwnerConfigValidationPolicy getCodeOwnerConfigValidationPolicyForSubmit() {
+ return generalConfig.getCodeOwnerConfigValidationPolicyForSubmit(projectName, pluginConfig);
+ }
+
+ /** Gets the merge commit strategy. */
+ public MergeCommitStrategy getMergeCommitStrategy() {
+ return generalConfig.getMergeCommitStrategy(projectName, pluginConfig);
+ }
+
+ /** Gets the fallback code owners. */
+ public FallbackCodeOwners getFallbackCodeOwners() {
+ return generalConfig.getFallbackCodeOwners(projectName, pluginConfig);
+ }
+
+ /** Gets the max paths in change messages. */
+ public int getMaxPathsInChangeMessages() {
+ return generalConfig.getMaxPathsInChangeMessages(projectName, pluginConfig);
+ }
+
+ /** Gets the global code owners. */
+ public ImmutableSet<CodeOwnerReference> getGlobalCodeOwners() {
+ return generalConfig.getGlobalCodeOwners(pluginConfig);
+ }
+
+ /** Gets the override info URL that is configured. */
+ public Optional<String> getOverrideInfoUrl() {
+ return generalConfig.getOverrideInfoUrl(pluginConfig);
+ }
+
+ /**
+ * Whether the code owners functionality is disabled for the given branch.
+ *
+ * <p>Callers must ensure that the project of the specified branch exists. If the project doesn't
+ * exist the call fails with {@link IllegalStateException}.
+ *
+ * <p>The configuration is evaluated in the following order:
+ *
+ * <ul>
+ * <li>disabled configuration for the branch (with inheritance)
+ * <li>disabled configuration for the project (with inheritance)
+ * <li>hard-coded default (not disabled)
+ * </ul>
+ *
+ * <p>The first disabled configuration that exists counts and the evaluation is stopped.
+ *
+ * @param branchName the branch for which it should be checked whether the code owners
+ * functionality is disabled
+ * @return {@code true} if the code owners functionality is disabled for the given branch,
+ * otherwise {@code false}
+ */
+ public boolean isDisabled(String branchName) {
+ requireNonNull(branchName, "branchName");
+
+ boolean isDisabled =
+ statusConfig.isDisabledForBranch(
+ pluginConfig, BranchNameKey.create(projectName, branchName));
+ if (isDisabled) {
+ return true;
+ }
+
+ return isDisabled();
+ }
+
+ /**
+ * Whether the code owners functionality is disabled for the given project.
+ *
+ * <p>The configuration is evaluated in the following order:
+ *
+ * <ul>
+ * <li>disabled configuration for the project (with inheritance)
+ * <li>hard-coded default (not disabled)
+ * </ul>
+ *
+ * <p>The first disabled configuration that exists counts and the evaluation is stopped.
+ *
+ * @return {@code true} if the code owners functionality is disabled, otherwise {@code false}
+ */
+ public boolean isDisabled() {
+ return statusConfig.isDisabledForProject(pluginConfig, projectName);
+ }
+
+ /**
+ * Returns the configured {@link CodeOwnerBackend} for the given branch.
+ *
+ * <p>The code owner backend configuration is evaluated in the following order:
+ *
+ * <ul>
+ * <li>backend configuration for branch (with inheritance, first by full branch name, then by
+ * short branch name)
+ * <li>backend configuration for project (with inheritance)
+ * <li>default backend (first globally configured backend, then hard-coded default backend)
+ * </ul>
+ *
+ * <p>The first code owner backend configuration that exists counts and the evaluation is stopped.
+ *
+ * @param branchName the branch for which the configured code owner backend should be returned
+ * @return the {@link CodeOwnerBackend} that should be used for the branch
+ */
+ public CodeOwnerBackend getBackend(String branchName) {
+ // check if a branch specific backend is configured
+ Optional<CodeOwnerBackend> codeOwnerBackend =
+ backendConfig.getBackendForBranch(
+ pluginConfig, BranchNameKey.create(projectName, branchName));
+ if (codeOwnerBackend.isPresent()) {
+ return codeOwnerBackend.get();
+ }
+
+ return getBackend();
+ }
+
+ /**
+ * Returns the configured {@link CodeOwnerBackend}.
+ *
+ * <p>The code owner backend configuration is evaluated in the following order:
+ *
+ * <ul>
+ * <li>backend configuration for project (with inheritance)
+ * <li>default backend (first globally configured backend, then hard-coded default backend)
+ * </ul>
+ *
+ * <p>The first code owner backend configuration that exists counts and the evaluation is stopped.
+ *
+ * @return the {@link CodeOwnerBackend} that should be used
+ */
+ public CodeOwnerBackend getBackend() {
+ // check if a project specific backend is configured
+ Optional<CodeOwnerBackend> codeOwnerBackend =
+ backendConfig.getBackendForProject(pluginConfig, projectName);
+ if (codeOwnerBackend.isPresent()) {
+ return codeOwnerBackend.get();
+ }
+
+ // fall back to the default backend
+ return backendConfig.getDefaultBackend();
+ }
+
+ /** Checks whether an implicit code owner approval from the last uploader is assumed. */
+ public boolean areImplicitApprovalsEnabled() {
+ EnableImplicitApprovals enableImplicitApprovals =
+ generalConfig.getEnableImplicitApprovals(projectName, pluginConfig);
+ switch (enableImplicitApprovals) {
+ case FALSE:
+ logger.atFine().log("implicit approvals on project %s are disabled", projectName);
+ return false;
+ case TRUE:
+ LabelType requiredLabel = getRequiredApproval().labelType();
+ if (requiredLabel.isIgnoreSelfApproval()) {
+ logger.atFine().log(
+ "ignoring implicit approval configuration on project %s since the label of the required"
+ + " approval (%s) is configured to ignore self approvals",
+ projectName, requiredLabel);
+ return false;
+ }
+ return true;
+ case FORCED:
+ logger.atFine().log("implicit approvals on project %s are enforced", projectName);
+ return true;
+ }
+ throw new IllegalStateException(
+ String.format(
+ "unknown value %s for enableImplicitApprovals configuration in project %s",
+ enableImplicitApprovals, projectName));
+ }
+
+ /**
+ * Returns the approval that is required from code owners to approve the files in a change.
+ *
+ * <p>Defines which approval counts as code owner approval.
+ *
+ * <p>The code owner required approval configuration is evaluated in the following order:
+ *
+ * <ul>
+ * <li>required approval configuration for project (with inheritance)
+ * <li>globally configured required approval
+ * <li>hard-coded default required approval
+ * </ul>
+ *
+ * <p>The first required code owner approval configuration that exists counts and the evaluation
+ * is stopped.
+ *
+ * <p>If the code owner configuration contains multiple required approvals values, the last value
+ * is used.
+ *
+ * @return the required code owner approval that should be used
+ */
+ public RequiredApproval getRequiredApproval() {
+ ImmutableList<RequiredApproval> configuredRequiredApprovalConfig =
+ getConfiguredRequiredApproval(requiredApprovalConfig);
+ if (!configuredRequiredApprovalConfig.isEmpty()) {
+ // There can be only one required approval. If multiple ones are configured just use the last
+ // one, this is also what Config#getString(String, String, String) does.
+ return Iterables.getLast(configuredRequiredApprovalConfig);
+ }
+
+ // fall back to hard-coded default required approval
+ ProjectState projectState =
+ projectCache.get(projectName).orElseThrow(illegalState(projectName));
+ return requiredApprovalConfig.createDefault(projectState);
+ }
+
+ /**
+ * Returns the approvals that are required to override the code owners submit check for a change.
+ *
+ * <p>If multiple approvals are returned, any of them is sufficient to override the code owners
+ * submit check.
+ *
+ * <p>The override approval configuration is evaluated in the following order:
+ *
+ * <ul>
+ * <li>override approval configuration for project (with inheritance)
+ * <li>globally configured override approval
+ * </ul>
+ *
+ * <p>The first override approval configuration that exists counts and the evaluation is stopped.
+ *
+ * @return the override approvals that should be used, an empty set if no override approval is
+ * configured, in this case the override functionality is disabled
+ */
+ public ImmutableSet<RequiredApproval> getOverrideApproval() {
+ try {
+ return filterOutDuplicateRequiredApprovals(
+ getConfiguredRequiredApproval(overrideApprovalConfig));
+ } catch (InvalidPluginConfigurationException e) {
+ logger.atWarning().withCause(e).log(
+ "Ignoring invalid override approval configuration for project %s."
+ + " Overrides are disabled.",
+ projectName.get());
+ }
+
+ return ImmutableSet.of();
+ }
+
+ /**
+ * Filters out duplicate required approvals from the input list.
+ *
+ * <p>The following entries are considered as duplicate:
+ *
+ * <ul>
+ * <li>exact identical required approvals (e.g. "Code-Review+2" and "Code-Review+2")
+ * <li>required approvals with the same label name and a higher value (e.g. "Code-Review+2" is
+ * not needed if "Code-Review+1" is already contained, since "Code-Review+1" covers all
+ * "Code-Review" approvals >= 1)
+ * </ul>
+ */
+ private ImmutableSet<RequiredApproval> filterOutDuplicateRequiredApprovals(
+ ImmutableList<RequiredApproval> requiredApprovals) {
+ Map<String, RequiredApproval> requiredApprovalsByLabel = new HashMap<>();
+ for (RequiredApproval requiredApproval : requiredApprovals) {
+ String labelName = requiredApproval.labelType().getName();
+ RequiredApproval otherRequiredApproval = requiredApprovalsByLabel.get(labelName);
+ if (otherRequiredApproval != null
+ && otherRequiredApproval.value() <= requiredApproval.value()) {
+ continue;
+ }
+ requiredApprovalsByLabel.put(labelName, requiredApproval);
+ }
+ return ImmutableSet.copyOf(requiredApprovalsByLabel.values());
+ }
+
+ /**
+ * Gets the required approvals that are configured.
+ *
+ * @param requiredApprovalConfig the config from which the required approvals should be read
+ * @return the required approvals that is configured, an empty list if no required approvals are
+ * configured
+ */
+ private ImmutableList<RequiredApproval> getConfiguredRequiredApproval(
+ AbstractRequiredApprovalConfig requiredApprovalConfig) {
+ ProjectState projectState =
+ projectCache.get(projectName).orElseThrow(illegalState(projectName));
+ return requiredApprovalConfig.get(projectState, pluginConfig);
+ }
+
+ /**
+ * Reads and returns the config from the {@code code-owners.config} file in {@code
+ * refs/meta/config} branch.
+ *
+ * @return the code owners configurations
+ */
+ private Config loadPluginConfig() {
+ try {
+ return pluginConfigFactory.getProjectPluginConfigWithInheritance(projectName, pluginName);
+ } catch (NoSuchProjectException e) {
+ throw new IllegalStateException(
+ String.format(
+ "cannot get %s plugin config for non-existing project %s", pluginName, projectName),
+ e);
+ }
+ }
+}
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfiguration.java b/java/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfiguration.java
index a9b5ea6..0855baf 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfiguration.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfiguration.java
@@ -14,35 +14,18 @@
package com.google.gerrit.plugins.codeowners.backend.config;
-import static com.google.gerrit.server.project.ProjectCache.illegalState;
import static java.util.Objects.requireNonNull;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.entities.BranchNameKey;
-import com.google.gerrit.entities.LabelType;
import com.google.gerrit.entities.Project;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
-import com.google.gerrit.plugins.codeowners.backend.CodeOwnerBackend;
-import com.google.gerrit.plugins.codeowners.backend.CodeOwnerReference;
-import com.google.gerrit.plugins.codeowners.backend.EnableImplicitApprovals;
-import com.google.gerrit.plugins.codeowners.backend.FallbackCodeOwners;
-import com.google.gerrit.plugins.codeowners.common.CodeOwnerConfigValidationPolicy;
-import com.google.gerrit.plugins.codeowners.common.MergeCommitStrategy;
+import com.google.gerrit.server.cache.PerThreadCache;
import com.google.gerrit.server.config.PluginConfigFactory;
-import com.google.gerrit.server.project.NoSuchProjectException;
-import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectState;
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-import org.eclipse.jgit.lib.Config;
/**
* The configuration of the code-owners plugin.
@@ -65,213 +48,34 @@
@VisibleForTesting
static final String KEY_ENABLE_EXPERIMENTAL_REST_ENDPOINTS = "enableExperimentalRestEndpoints";
+ private final CodeOwnersPluginConfigSnapshot.Factory codeOwnersPluginConfigSnapshotFactory;
private final String pluginName;
private final PluginConfigFactory pluginConfigFactory;
- private final ProjectCache projectCache;
private final GeneralConfig generalConfig;
- private final StatusConfig statusConfig;
- private final BackendConfig backendConfig;
- private final RequiredApprovalConfig requiredApprovalConfig;
- private final OverrideApprovalConfig overrideApprovalConfig;
@Inject
CodeOwnersPluginConfiguration(
+ CodeOwnersPluginConfigSnapshot.Factory codeOwnersPluginConfigSnapshotFactory,
@PluginName String pluginName,
PluginConfigFactory pluginConfigFactory,
- ProjectCache projectCache,
- GeneralConfig generalConfig,
- StatusConfig statusConfig,
- BackendConfig backendConfig,
- RequiredApprovalConfig requiredApprovalConfig,
- OverrideApprovalConfig overrideApprovalConfig) {
+ GeneralConfig generalConfig) {
+ this.codeOwnersPluginConfigSnapshotFactory = codeOwnersPluginConfigSnapshotFactory;
this.pluginName = pluginName;
this.pluginConfigFactory = pluginConfigFactory;
- this.projectCache = projectCache;
this.generalConfig = generalConfig;
- this.statusConfig = statusConfig;
- this.backendConfig = backendConfig;
- this.requiredApprovalConfig = requiredApprovalConfig;
- this.overrideApprovalConfig = overrideApprovalConfig;
}
/**
- * Gets the file extension that is configured for the given project.
+ * Returns the code-owner plugin configuration for the given projects.
*
- * @param project the project for which the configured file extension should be returned
- * @return the file extension that is configured for the given project
+ * <p>Callers must ensure that the project of the specified branch exists. If the project doesn't
+ * exist the call fails with {@link IllegalStateException}.
*/
- public Optional<String> getFileExtension(Project.NameKey project) {
- requireNonNull(project, "project");
- return generalConfig.getFileExtension(getPluginConfig(project));
- }
-
- /**
- * Checks whether code owner configs in the given project are read-only.
- *
- * @param project the project for which it should be checked whether code owner configs are
- * read-only
- * @return whether code owner configs in the given project are read-only
- */
- public boolean areCodeOwnerConfigsReadOnly(Project.NameKey project) {
- requireNonNull(project, "project");
- return generalConfig.getReadOnly(project, getPluginConfig(project));
- }
-
- /**
- * Checks whether pure revert changes are exempted from needing code owner approvals for submit.
- *
- * @param project the project for which it should be checked whether pure revert changes are
- * exempted from needing code owner approvals for submit
- * @return whether pure revert changes are exempted from needing code owner approvals for submit
- */
- public boolean arePureRevertsExempted(Project.NameKey project) {
- requireNonNull(project, "project");
- return generalConfig.getExemptPureReverts(project, getPluginConfig(project));
- }
-
- /**
- * Checks whether newly added non-resolvable code owners should be rejected on commit received and
- * submit.
- *
- * @param project the project for which it should be checked whether non-resolvable code owners
- * should be rejected
- * @return whether newly added non-resolvable code owners should be rejected on commit received
- * and submit
- */
- public boolean rejectNonResolvableCodeOwners(Project.NameKey project) {
- requireNonNull(project, "project");
- return generalConfig.getRejectNonResolvableCodeOwners(project, getPluginConfig(project));
- }
-
- /**
- * Checks whether newly added non-resolvable imports should be rejected on commit received and
- * submit.
- *
- * @param project the project for which it should be checked whether non-resolvable imports should
- * be rejected
- * @return whether newly added non-resolvable imports should be rejected on commit received and
- * submit
- */
- public boolean rejectNonResolvableImports(Project.NameKey project) {
- requireNonNull(project, "project");
- return generalConfig.getRejectNonResolvableImports(project, getPluginConfig(project));
- }
-
- /**
- * Whether code owner configs should be validated when a commit is received.
- *
- * @param project the project for it should be checked whether code owner configs should be
- * validated when a commit is received
- * @return whether code owner configs should be validated when a commit is received
- */
- public CodeOwnerConfigValidationPolicy getCodeOwnerConfigValidationPolicyForCommitReceived(
- Project.NameKey project) {
- requireNonNull(project, "project");
- return generalConfig.getCodeOwnerConfigValidationPolicyForCommitReceived(
- project, getPluginConfig(project));
- }
-
- /**
- * Whether code owner configs should be validated when a change is submitted.
- *
- * @param project the project for it should be checked whether code owner configs should be
- * validated when a change is submitted
- * @return whether code owner configs should be validated when a change is submitted
- */
- public CodeOwnerConfigValidationPolicy getCodeOwnerConfigValidationPolicyForSubmit(
- Project.NameKey project) {
- requireNonNull(project, "project");
- return generalConfig.getCodeOwnerConfigValidationPolicyForSubmit(
- project, getPluginConfig(project));
- }
-
- /**
- * Gets the merge commit strategy for the given project.
- *
- * @param project the project for which the merge commit strategy should be retrieved
- * @return the merge commit strategy for the given project
- */
- public MergeCommitStrategy getMergeCommitStrategy(Project.NameKey project) {
- requireNonNull(project, "project");
- return generalConfig.getMergeCommitStrategy(project, getPluginConfig(project));
- }
-
- /**
- * Gets the fallback code owners for the given project.
- *
- * @param project the project for which the fallback code owners should be retrieved
- * @return the fallback code owners for the given project
- */
- public FallbackCodeOwners getFallbackCodeOwners(Project.NameKey project) {
- requireNonNull(project, "project");
- return generalConfig.getFallbackCodeOwners(project, getPluginConfig(project));
- }
-
- /**
- * Gets the max paths in change messages for the given project.
- *
- * @param project the project for which the fallback code owners should be retrieved
- * @return the fallback code owners for the given project
- */
- public int getMaxPathsInChangeMessages(Project.NameKey project) {
- requireNonNull(project, "project");
- return generalConfig.getMaxPathsInChangeMessages(project, getPluginConfig(project));
- }
-
- /**
- * Checks whether an implicit code owner approval from the last uploader is assumed.
- *
- * @param project the project for it should be checked whether implicit approvals are enabled
- * @return whether an implicit code owner approval from the last uploader is assumed
- */
- public boolean areImplicitApprovalsEnabled(Project.NameKey project) {
- requireNonNull(project, "project");
- EnableImplicitApprovals enableImplicitApprovals =
- generalConfig.getEnableImplicitApprovals(project, getPluginConfig(project));
- switch (enableImplicitApprovals) {
- case FALSE:
- logger.atFine().log("implicit approvals on project %s are disabled", project);
- return false;
- case TRUE:
- LabelType requiredLabel = getRequiredApproval(project).labelType();
- if (requiredLabel.isIgnoreSelfApproval()) {
- logger.atFine().log(
- "ignoring implicit approval configuration on project %s since the label of the required"
- + " approval (%s) is configured to ignore self approvals",
- project, requiredLabel);
- return false;
- }
- return true;
- case FORCED:
- logger.atFine().log("implicit approvals on project %s are enforced", project);
- return true;
- }
- throw new IllegalStateException(
- String.format(
- "unknown value %s for enableImplicitApprovals configuration in project %s",
- enableImplicitApprovals, project));
- }
-
- /**
- * Gets the global code owners of the given project.
- *
- * @param project the project for which the global code owners should be returned
- * @return the global code owners of the given project
- */
- public ImmutableSet<CodeOwnerReference> getGlobalCodeOwners(Project.NameKey project) {
- requireNonNull(project, "project");
- return generalConfig.getGlobalCodeOwners(getPluginConfig(project));
- }
-
- /**
- * Gets the override info URL that is configured for the given project.
- *
- * @param project the project for which the configured override info URL should be returned
- * @return the override info URL that is configured for the given project
- */
- public Optional<String> getOverrideInfoUrl(Project.NameKey project) {
- requireNonNull(project, "project");
- return generalConfig.getOverrideInfoUrl(getPluginConfig(project));
+ public CodeOwnersPluginConfigSnapshot getProjectConfig(Project.NameKey projectName) {
+ requireNonNull(projectName, "projectName");
+ return PerThreadCache.getOrCompute(
+ PerThreadCache.Key.create(CodeOwnersPluginConfigSnapshot.class, projectName),
+ () -> codeOwnersPluginConfigSnapshotFactory.create(projectName));
}
/**
@@ -286,252 +90,6 @@
}
/**
- * Whether the code owners functionality is disabled for the given branch.
- *
- * <p>Callers must ensure that the project of the specified branch exists. If the project doesn't
- * exist the call fails with {@link IllegalStateException}.
- *
- * <p>The configuration is evaluated in the following order:
- *
- * <ul>
- * <li>disabled configuration for the branch (with inheritance)
- * <li>disabled configuration for the project (with inheritance)
- * <li>hard-coded default (not disabled)
- * </ul>
- *
- * <p>The first disabled configuration that exists counts and the evaluation is stopped.
- *
- * @param branchNameKey the branch and project for which it should be checked whether the code
- * owners functionality is disabled
- * @return {@code true} if the code owners functionality is disabled for the given branch,
- * otherwise {@code false}
- */
- public boolean isDisabled(BranchNameKey branchNameKey) {
- requireNonNull(branchNameKey, "branchNameKey");
-
- Config pluginConfig = getPluginConfig(branchNameKey.project());
-
- boolean isDisabled = statusConfig.isDisabledForBranch(pluginConfig, branchNameKey);
- if (isDisabled) {
- return true;
- }
-
- return isDisabled(branchNameKey.project());
- }
-
- /**
- * Whether the code owners functionality is disabled for the given project.
- *
- * <p>Callers must ensure that the project of the specified branch exists. If the project doesn't
- * exist the call fails with {@link IllegalStateException}.
- *
- * <p>The configuration is evaluated in the following order:
- *
- * <ul>
- * <li>disabled configuration for the project (with inheritance)
- * <li>hard-coded default (not disabled)
- * </ul>
- *
- * <p>The first disabled configuration that exists counts and the evaluation is stopped.
- *
- * @param project the project for which it should be checked whether the code owners functionality
- * is disabled
- * @return {@code true} if the code owners functionality is disabled for the given project,
- * otherwise {@code false}
- */
- public boolean isDisabled(Project.NameKey project) {
- requireNonNull(project, "project");
-
- Config pluginConfig = getPluginConfig(project);
- return statusConfig.isDisabledForProject(pluginConfig, project);
- }
-
- /**
- * Returns the configured {@link CodeOwnerBackend} for the given branch.
- *
- * <p>Callers must ensure that the project of the specified branch exists. If the project doesn't
- * exist the call fails with {@link IllegalStateException}.
- *
- * <p>The code owner backend configuration is evaluated in the following order:
- *
- * <ul>
- * <li>backend configuration for branch (with inheritance, first by full branch name, then by
- * short branch name)
- * <li>backend configuration for project (with inheritance)
- * <li>default backend (first globally configured backend, then hard-coded default backend)
- * </ul>
- *
- * <p>The first code owner backend configuration that exists counts and the evaluation is stopped.
- *
- * @param branchNameKey project and branch for which the configured code owner backend should be
- * returned
- * @return the {@link CodeOwnerBackend} that should be used for the branch
- */
- public CodeOwnerBackend getBackend(BranchNameKey branchNameKey) {
- Config pluginConfig = getPluginConfig(branchNameKey.project());
-
- // check if a branch specific backend is configured
- Optional<CodeOwnerBackend> codeOwnerBackend =
- backendConfig.getBackendForBranch(pluginConfig, branchNameKey);
- if (codeOwnerBackend.isPresent()) {
- return codeOwnerBackend.get();
- }
-
- return getBackend(branchNameKey.project());
- }
-
- /**
- * Returns the configured {@link CodeOwnerBackend} for the given project.
- *
- * <p>Callers must ensure that the project exists. If the project doesn't exist the call fails
- * with {@link IllegalStateException}.
- *
- * <p>The code owner backend configuration is evaluated in the following order:
- *
- * <ul>
- * <li>backend configuration for project (with inheritance)
- * <li>default backend (first globally configured backend, then hard-coded default backend)
- * </ul>
- *
- * <p>The first code owner backend configuration that exists counts and the evaluation is stopped.
- *
- * @param project project for which the configured code owner backend should be returned
- * @return the {@link CodeOwnerBackend} that should be used for the project
- */
- public CodeOwnerBackend getBackend(Project.NameKey project) {
- Config pluginConfig = getPluginConfig(project);
-
- // check if a project specific backend is configured
- Optional<CodeOwnerBackend> codeOwnerBackend =
- backendConfig.getBackendForProject(pluginConfig, project);
- if (codeOwnerBackend.isPresent()) {
- return codeOwnerBackend.get();
- }
-
- // fall back to the default backend
- return backendConfig.getDefaultBackend();
- }
-
- /**
- * Returns the approval that is required from code owners to approve the files in a change of the
- * given project.
- *
- * <p>Defines which approval counts as code owner approval.
- *
- * <p>Callers must ensure that the project of the specified branch exists. If the project doesn't
- * exist the call fails with {@link IllegalStateException}.
- *
- * <p>The code owner required approval configuration is evaluated in the following order:
- *
- * <ul>
- * <li>required approval configuration for project (with inheritance)
- * <li>globally configured required approval
- * <li>hard-coded default required approval
- * </ul>
- *
- * <p>The first required code owner approval configuration that exists counts and the evaluation
- * is stopped.
- *
- * <p>If the code owner configuration contains multiple required approvals values, the last value
- * is used.
- *
- * @param project project for which the required approval should be returned
- * @return the required code owner approval that should be used for the given project
- */
- public RequiredApproval getRequiredApproval(Project.NameKey project) {
- ImmutableList<RequiredApproval> configuredRequiredApprovalConfig =
- getConfiguredRequiredApproval(requiredApprovalConfig, project);
- if (!configuredRequiredApprovalConfig.isEmpty()) {
- // There can be only one required approval. If multiple ones are configured just use the last
- // one, this is also what Config#getString(String, String, String) does.
- return Iterables.getLast(configuredRequiredApprovalConfig);
- }
-
- // fall back to hard-coded default required approval
- ProjectState projectState = projectCache.get(project).orElseThrow(illegalState(project));
- return requiredApprovalConfig.createDefault(projectState);
- }
-
- /**
- * Returns the approvals that are required to override the code owners submit check for a change
- * of the given project.
- *
- * <p>If multiple approvals are returned, any of them is sufficient to override the code owners
- * submit check.
- *
- * <p>Callers must ensure that the project of the specified branch exists. If the project doesn't
- * exist the call fails with {@link IllegalStateException}.
- *
- * <p>The override approval configuration is evaluated in the following order:
- *
- * <ul>
- * <li>override approval configuration for project (with inheritance)
- * <li>globally configured override approval
- * </ul>
- *
- * <p>The first override approval configuration that exists counts and the evaluation is stopped.
- *
- * @param project project for which the override approval should be returned
- * @return the override approvals that should be used for the given project, an empty set if no
- * override approval is configured, in this case the override functionality is disabled
- */
- public ImmutableSet<RequiredApproval> getOverrideApproval(Project.NameKey project) {
- try {
- return filterOutDuplicateRequiredApprovals(
- getConfiguredRequiredApproval(overrideApprovalConfig, project));
- } catch (InvalidPluginConfigurationException e) {
- logger.atWarning().withCause(e).log(
- "Ignoring invalid override approval configuration for project %s."
- + " Overrides are disabled.",
- project.get());
- }
-
- return ImmutableSet.of();
- }
-
- /**
- * Filters out duplicate required approvals from the input list.
- *
- * <p>The following entries are considered as duplicate:
- *
- * <ul>
- * <li>exact identical required approvals (e.g. "Code-Review+2" and "Code-Review+2")
- * <li>required approvals with the same label name and a higher value (e.g. "Code-Review+2" is
- * not needed if "Code-Review+1" is already contained, since "Code-Review+1" covers all
- * "Code-Review" approvals >= 1)
- * </ul>
- */
- private ImmutableSet<RequiredApproval> filterOutDuplicateRequiredApprovals(
- ImmutableList<RequiredApproval> requiredApprovals) {
- Map<String, RequiredApproval> requiredApprovalsByLabel = new HashMap<>();
- for (RequiredApproval requiredApproval : requiredApprovals) {
- String labelName = requiredApproval.labelType().getName();
- RequiredApproval otherRequiredApproval = requiredApprovalsByLabel.get(labelName);
- if (otherRequiredApproval != null
- && otherRequiredApproval.value() <= requiredApproval.value()) {
- continue;
- }
- requiredApprovalsByLabel.put(labelName, requiredApproval);
- }
- return ImmutableSet.copyOf(requiredApprovalsByLabel.values());
- }
-
- /**
- * Gets the required approvals that are configured for the given project.
- *
- * @param requiredApprovalConfig the config from which the required approvals should be read
- * @param project the project for which the configured required approvals should be returned
- * @return the required approvals that is configured for the given project, an empty list if no
- * required approvals are configured
- */
- private ImmutableList<RequiredApproval> getConfiguredRequiredApproval(
- AbstractRequiredApprovalConfig requiredApprovalConfig, Project.NameKey project) {
- Config pluginConfig = getPluginConfig(project);
- ProjectState projectState = projectCache.get(project).orElseThrow(illegalState(project));
- return requiredApprovalConfig.get(projectState, pluginConfig);
- }
-
- /**
* Checks whether experimental REST endpoints are enabled.
*
* @throws MethodNotAllowedException thrown if experimental REST endpoints are disabled
@@ -559,22 +117,4 @@
return false;
}
}
-
- /**
- * Reads and returns the config from the {@code code-owners.config} file in {@code
- * refs/meta/config} branch of the given project.
- *
- * @param project the project for which the code owners configurations should be returned
- * @return the code owners configurations for the given project
- */
- private Config getPluginConfig(Project.NameKey project) {
- try {
- return pluginConfigFactory.getProjectPluginConfigWithInheritance(project, pluginName);
- } catch (NoSuchProjectException e) {
- throw new IllegalStateException(
- String.format(
- "cannot get %s plugin config for non-existing project %s", pluginName, project),
- e);
- }
- }
}
diff --git a/java/com/google/gerrit/plugins/codeowners/restapi/AbstractGetCodeOwnersForPath.java b/java/com/google/gerrit/plugins/codeowners/restapi/AbstractGetCodeOwnersForPath.java
index d406be1..6fb8c15 100644
--- a/java/com/google/gerrit/plugins/codeowners/restapi/AbstractGetCodeOwnersForPath.java
+++ b/java/com/google/gerrit/plugins/codeowners/restapi/AbstractGetCodeOwnersForPath.java
@@ -237,7 +237,8 @@
CodeOwnerResolverResult globalCodeOwners =
codeOwnerResolver
.get()
- .resolve(codeOwnersPluginConfiguration.getGlobalCodeOwners(projectName));
+ .resolve(
+ codeOwnersPluginConfiguration.getProjectConfig(projectName).getGlobalCodeOwners());
logger.atFine().log("including global code owners = %s", globalCodeOwners);
return globalCodeOwners;
}
diff --git a/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwner.java b/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwner.java
index d326da6..9ab1ed1 100644
--- a/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwner.java
+++ b/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwner.java
@@ -239,7 +239,8 @@
}
private boolean isGlobalCodeOwner(Project.NameKey projectName) {
- return codeOwnersPluginConfiguration.getGlobalCodeOwners(projectName).stream()
+ return codeOwnersPluginConfiguration.getProjectConfig(projectName).getGlobalCodeOwners()
+ .stream()
.filter(cor -> cor.email().equals(email))
.findAny()
.isPresent();
@@ -247,7 +248,7 @@
private boolean isFallbackCodeOwner(Project.NameKey projectName) {
FallbackCodeOwners fallbackCodeOwners =
- codeOwnersPluginConfiguration.getFallbackCodeOwners(projectName);
+ codeOwnersPluginConfiguration.getProjectConfig(projectName).getFallbackCodeOwners();
switch (fallbackCodeOwners) {
case NONE:
return false;
diff --git a/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwnerConfigFiles.java b/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwnerConfigFiles.java
index ae55e82..306442a 100644
--- a/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwnerConfigFiles.java
+++ b/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwnerConfigFiles.java
@@ -135,7 +135,9 @@
.filter(
branchNameKey ->
validateDisabledBranches(input)
- || !codeOwnersPluginConfiguration.isDisabled(branchNameKey))
+ || !codeOwnersPluginConfiguration
+ .getProjectConfig(branchNameKey.project())
+ .isDisabled(branchNameKey.branch()))
.forEach(
branchNameKey ->
resultsByBranchBuilder.put(
@@ -159,7 +161,10 @@
BranchNameKey branchNameKey,
@Nullable ConsistencyProblemInfo.Status verbosity) {
ListMultimap<String, ConsistencyProblemInfo> problemsByPath = LinkedListMultimap.create();
- CodeOwnerBackend codeOwnerBackend = codeOwnersPluginConfiguration.getBackend(branchNameKey);
+ CodeOwnerBackend codeOwnerBackend =
+ codeOwnersPluginConfiguration
+ .getProjectConfig(branchNameKey.project())
+ .getBackend(branchNameKey.branch());
codeOwnerConfigScannerFactory
.create()
// Do not check the default code owner config file in refs/meta/config, as this config is
@@ -260,7 +265,7 @@
}
if ((input.validateDisabledBranches == null || !input.validateDisabledBranches)
- && codeOwnersPluginConfiguration.isDisabled(branchNameKey)) {
+ && codeOwnersPluginConfiguration.getProjectConfig(projectName).isDisabled(branchName)) {
throw new BadRequestException(
String.format(
"code owners functionality for branch %s is disabled,"
diff --git a/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwnerConfigFilesInRevision.java b/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwnerConfigFilesInRevision.java
index d960595..db939c4 100644
--- a/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwnerConfigFilesInRevision.java
+++ b/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwnerConfigFilesInRevision.java
@@ -84,7 +84,9 @@
input.path);
CodeOwnerBackend codeOwnerBackend =
- codeOwnersPluginConfiguration.getBackend(revisionResource.getChange().getDest());
+ codeOwnersPluginConfiguration
+ .getProjectConfig(revisionResource.getProject())
+ .getBackend(revisionResource.getChange().getDest().branch());
IdentifiedUser uploader = genericUserFactory.create(revisionResource.getPatchSet().uploader());
logger.atFine().log("uploader = %s", uploader.getLoggableName());
diff --git a/java/com/google/gerrit/plugins/codeowners/restapi/CodeOwnerProjectConfigJson.java b/java/com/google/gerrit/plugins/codeowners/restapi/CodeOwnerProjectConfigJson.java
index 2f649f9..e233344 100644
--- a/java/com/google/gerrit/plugins/codeowners/restapi/CodeOwnerProjectConfigJson.java
+++ b/java/com/google/gerrit/plugins/codeowners/restapi/CodeOwnerProjectConfigJson.java
@@ -33,6 +33,7 @@
import com.google.gerrit.plugins.codeowners.api.GeneralInfo;
import com.google.gerrit.plugins.codeowners.api.RequiredApprovalInfo;
import com.google.gerrit.plugins.codeowners.backend.CodeOwnerBackendId;
+import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfigSnapshot;
import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfiguration;
import com.google.gerrit.plugins.codeowners.backend.config.RequiredApproval;
import com.google.gerrit.server.permissions.PermissionBackendException;
@@ -65,7 +66,7 @@
CodeOwnerProjectConfigInfo info = new CodeOwnerProjectConfigInfo();
info.status = formatStatusInfo(projectResource);
- if (codeOwnersPluginConfiguration.isDisabled(projectResource.getNameKey())) {
+ if (codeOwnersPluginConfiguration.getProjectConfig(projectResource.getNameKey()).isDisabled()) {
return info;
}
@@ -78,9 +79,12 @@
}
CodeOwnerBranchConfigInfo format(BranchResource branchResource) {
+ CodeOwnersPluginConfigSnapshot codeOwnersConfig =
+ codeOwnersPluginConfiguration.getProjectConfig(branchResource.getNameKey());
+
CodeOwnerBranchConfigInfo info = new CodeOwnerBranchConfigInfo();
- boolean disabled = codeOwnersPluginConfiguration.isDisabled(branchResource.getBranchKey());
+ boolean disabled = codeOwnersConfig.isDisabled(branchResource.getBranchKey().branch());
info.disabled = disabled ? disabled : null;
if (disabled) {
@@ -90,7 +94,7 @@
info.general = formatGeneralInfo(branchResource.getNameKey());
info.backendId =
CodeOwnerBackendId.getBackendId(
- codeOwnersPluginConfiguration.getBackend(branchResource.getBranchKey()).getClass());
+ codeOwnersConfig.getBackend(branchResource.getBranchKey().branch()).getClass());
info.requiredApproval = formatRequiredApprovalInfo(branchResource.getNameKey());
info.overrideApproval = formatOverrideApprovalInfo(branchResource.getNameKey());
@@ -98,17 +102,15 @@
}
private GeneralInfo formatGeneralInfo(Project.NameKey projectName) {
+ CodeOwnersPluginConfigSnapshot codeOwnersConfig =
+ codeOwnersPluginConfiguration.getProjectConfig(projectName);
+
GeneralInfo generalInfo = new GeneralInfo();
- generalInfo.fileExtension =
- codeOwnersPluginConfiguration.getFileExtension(projectName).orElse(null);
- generalInfo.mergeCommitStrategy =
- codeOwnersPluginConfiguration.getMergeCommitStrategy(projectName);
- generalInfo.implicitApprovals =
- codeOwnersPluginConfiguration.areImplicitApprovalsEnabled(projectName) ? true : null;
- generalInfo.overrideInfoUrl =
- codeOwnersPluginConfiguration.getOverrideInfoUrl(projectName).orElse(null);
- generalInfo.fallbackCodeOwners =
- codeOwnersPluginConfiguration.getFallbackCodeOwners(projectName);
+ generalInfo.fileExtension = codeOwnersConfig.getFileExtension().orElse(null);
+ generalInfo.mergeCommitStrategy = codeOwnersConfig.getMergeCommitStrategy();
+ generalInfo.implicitApprovals = codeOwnersConfig.areImplicitApprovalsEnabled() ? true : null;
+ generalInfo.overrideInfoUrl = codeOwnersConfig.getOverrideInfoUrl().orElse(null);
+ generalInfo.fallbackCodeOwners = codeOwnersConfig.getFallbackCodeOwners();
return generalInfo;
}
@@ -117,7 +119,9 @@
throws RestApiException, PermissionBackendException, IOException {
CodeOwnersStatusInfo info = new CodeOwnersStatusInfo();
info.disabled =
- codeOwnersPluginConfiguration.isDisabled(projectResource.getNameKey()) ? true : null;
+ codeOwnersPluginConfiguration.getProjectConfig(projectResource.getNameKey()).isDisabled()
+ ? true
+ : null;
if (info.disabled == null) {
ImmutableList<BranchNameKey> disabledBranches = getDisabledBranches(projectResource);
@@ -135,7 +139,10 @@
BackendInfo info = new BackendInfo();
info.id =
CodeOwnerBackendId.getBackendId(
- codeOwnersPluginConfiguration.getBackend(projectResource.getNameKey()).getClass());
+ codeOwnersPluginConfiguration
+ .getProjectConfig(projectResource.getNameKey())
+ .getBackend()
+ .getClass());
ImmutableMap<String, String> idsByBranch =
getBackendIdsPerBranch(projectResource).entrySet().stream()
@@ -147,14 +154,15 @@
}
private RequiredApprovalInfo formatRequiredApprovalInfo(Project.NameKey projectName) {
- return formatRequiredApproval(codeOwnersPluginConfiguration.getRequiredApproval(projectName));
+ return formatRequiredApproval(
+ codeOwnersPluginConfiguration.getProjectConfig(projectName).getRequiredApproval());
}
@VisibleForTesting
@Nullable
ImmutableList<RequiredApprovalInfo> formatOverrideApprovalInfo(Project.NameKey projectName) {
ImmutableList<RequiredApprovalInfo> overrideApprovalInfos =
- codeOwnersPluginConfiguration.getOverrideApproval(projectName).stream()
+ codeOwnersPluginConfiguration.getProjectConfig(projectName).getOverrideApproval().stream()
.sorted(comparing(requiredApproval -> requiredApproval.toString()))
.map(CodeOwnerProjectConfigJson::formatRequiredApproval)
.collect(toImmutableList());
@@ -174,7 +182,11 @@
private ImmutableList<BranchNameKey> getDisabledBranches(ProjectResource projectResource)
throws RestApiException, PermissionBackendException, IOException {
return branches(projectResource)
- .filter(codeOwnersPluginConfiguration::isDisabled)
+ .filter(
+ branchNameKey ->
+ codeOwnersPluginConfiguration
+ .getProjectConfig(branchNameKey.project())
+ .isDisabled(branchNameKey.branch()))
.collect(toImmutableList());
}
@@ -187,7 +199,10 @@
Function.identity(),
branchNameKey ->
CodeOwnerBackendId.getBackendId(
- codeOwnersPluginConfiguration.getBackend(branchNameKey).getClass())));
+ codeOwnersPluginConfiguration
+ .getProjectConfig(branchNameKey.project())
+ .getBackend(branchNameKey.branch())
+ .getClass())));
}
private Stream<BranchNameKey> branches(ProjectResource projectResource)
diff --git a/java/com/google/gerrit/plugins/codeowners/restapi/GetCodeOwnerConfigFiles.java b/java/com/google/gerrit/plugins/codeowners/restapi/GetCodeOwnerConfigFiles.java
index ef08584..54d305a 100644
--- a/java/com/google/gerrit/plugins/codeowners/restapi/GetCodeOwnerConfigFiles.java
+++ b/java/com/google/gerrit/plugins/codeowners/restapi/GetCodeOwnerConfigFiles.java
@@ -86,11 +86,13 @@
}
@Override
- public Response<List<String>> apply(BranchResource resource) throws BadRequestException {
+ public Response<List<String>> apply(BranchResource branchResource) throws BadRequestException {
validateOptions();
CodeOwnerBackend codeOwnerBackend =
- codeOwnersPluginConfiguration.getBackend(resource.getBranchKey());
+ codeOwnersPluginConfiguration
+ .getProjectConfig(branchResource.getNameKey())
+ .getBackend(branchResource.getBranchKey().branch());
ImmutableList.Builder<Path> codeOwnerConfigs = ImmutableList.builder();
if (email != null) {
@@ -106,7 +108,7 @@
// files in refs/meta/config explicitly.
.includeDefaultCodeOwnerConfig(false)
.visit(
- resource.getBranchKey(),
+ branchResource.getBranchKey(),
codeOwnerConfig -> {
Path codeOwnerConfigPath = codeOwnerBackend.getFilePath(codeOwnerConfig.key());
if (email == null || containsEmail(codeOwnerConfig, codeOwnerConfigPath, email)) {
diff --git a/java/com/google/gerrit/plugins/codeowners/restapi/RenameEmail.java b/java/com/google/gerrit/plugins/codeowners/restapi/RenameEmail.java
index 6f597fd..e338543 100644
--- a/java/com/google/gerrit/plugins/codeowners/restapi/RenameEmail.java
+++ b/java/com/google/gerrit/plugins/codeowners/restapi/RenameEmail.java
@@ -99,7 +99,9 @@
validateInput(input);
CodeOwnerBackend codeOwnerBackend =
- codeOwnersPluginConfiguration.getBackend(branchResource.getBranchKey());
+ codeOwnersPluginConfiguration
+ .getProjectConfig(branchResource.getNameKey())
+ .getBackend(branchResource.getBranchKey().branch());
Account.Id accountOwningOldEmail = resolveEmail(input.oldEmail);
Account.Id accountOwningNewEmail = resolveEmail(input.newEmail);
diff --git a/java/com/google/gerrit/plugins/codeowners/validation/CodeOwnerConfigValidator.java b/java/com/google/gerrit/plugins/codeowners/validation/CodeOwnerConfigValidator.java
index f230eb9..3f79135 100644
--- a/java/com/google/gerrit/plugins/codeowners/validation/CodeOwnerConfigValidator.java
+++ b/java/com/google/gerrit/plugins/codeowners/validation/CodeOwnerConfigValidator.java
@@ -38,6 +38,7 @@
import com.google.gerrit.plugins.codeowners.backend.CodeOwnerResolver;
import com.google.gerrit.plugins.codeowners.backend.CodeOwnersInternalServerErrorException;
import com.google.gerrit.plugins.codeowners.backend.PathCodeOwners;
+import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfigSnapshot;
import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfiguration;
import com.google.gerrit.plugins.codeowners.backend.config.InvalidPluginConfigurationException;
import com.google.gerrit.plugins.codeowners.common.ChangedFile;
@@ -174,8 +175,9 @@
.username(receiveEvent.user.getLoggableName())
.build())) {
CodeOwnerConfigValidationPolicy codeOwnerConfigValidationPolicy =
- codeOwnersPluginConfiguration.getCodeOwnerConfigValidationPolicyForCommitReceived(
- receiveEvent.getProjectNameKey());
+ codeOwnersPluginConfiguration
+ .getProjectConfig(receiveEvent.getProjectNameKey())
+ .getCodeOwnerConfigValidationPolicyForCommitReceived();
logger.atFine().log("codeOwnerConfigValidationPolicy = %s", codeOwnerConfigValidationPolicy);
Optional<ValidationResult> validationResult;
if (!codeOwnerConfigValidationPolicy.runValidation()) {
@@ -243,8 +245,9 @@
.patchSetId(patchSetId.get())
.build())) {
CodeOwnerConfigValidationPolicy codeOwnerConfigValidationPolicy =
- codeOwnersPluginConfiguration.getCodeOwnerConfigValidationPolicyForSubmit(
- branchNameKey.project());
+ codeOwnersPluginConfiguration
+ .getProjectConfig(branchNameKey.project())
+ .getCodeOwnerConfigValidationPolicyForSubmit();
logger.atFine().log("codeOwnerConfigValidationPolicy = %s", codeOwnerConfigValidationPolicy);
Optional<ValidationResult> validationResult;
if (!codeOwnerConfigValidationPolicy.runValidation()) {
@@ -303,7 +306,9 @@
RevWalk revWalk,
RevCommit revCommit,
IdentifiedUser user) {
- if (codeOwnersPluginConfiguration.isDisabled(branchNameKey)) {
+ CodeOwnersPluginConfigSnapshot codeOwnersConfig =
+ codeOwnersPluginConfiguration.getProjectConfig(branchNameKey.project());
+ if (codeOwnersConfig.isDisabled(branchNameKey.branch())) {
return Optional.of(
ValidationResult.create(
pluginName,
@@ -311,7 +316,7 @@
new CommitValidationMessage(
"code-owners functionality is disabled", ValidationMessage.Type.HINT)));
}
- if (codeOwnersPluginConfiguration.areCodeOwnerConfigsReadOnly(branchNameKey.project())) {
+ if (codeOwnersConfig.areCodeOwnerConfigsReadOnly()) {
return Optional.of(
ValidationResult.create(
pluginName,
@@ -322,7 +327,7 @@
}
try {
- CodeOwnerBackend codeOwnerBackend = codeOwnersPluginConfiguration.getBackend(branchNameKey);
+ CodeOwnerBackend codeOwnerBackend = codeOwnersConfig.getBackend(branchNameKey.branch());
// For merge commits, always do the comparison against the destination branch
// (MergeCommitStrategy.ALL_CHANGED_FILES). Doing the comparison against the auto-merge
@@ -922,7 +927,9 @@
}
CodeOwnerBackend codeOwnerBackend =
- codeOwnersPluginConfiguration.getBackend(keyOfImportedCodeOwnerConfig.branchNameKey());
+ codeOwnersPluginConfiguration
+ .getProjectConfig(keyOfImportedCodeOwnerConfig.project())
+ .getBackend(keyOfImportedCodeOwnerConfig.branchNameKey().branch());
if (!codeOwnerBackend.isCodeOwnerConfigFile(
keyOfImportedCodeOwnerConfig.project(), codeOwnerConfigReference.fileName())) {
return nonResolvableImport(
@@ -983,11 +990,13 @@
return keyOfImportingCodeOwnerConfig.project().equals(keyOfImportedCodeOwnerConfig.project())
&& keyOfImportingCodeOwnerConfig.ref().equals(keyOfImportedCodeOwnerConfig.ref())
&& codeOwnersPluginConfiguration
- .getBackend(keyOfImportingCodeOwnerConfig.branchNameKey())
+ .getProjectConfig(keyOfImportingCodeOwnerConfig.project())
+ .getBackend(keyOfImportingCodeOwnerConfig.branchNameKey().branch())
.getFilePath(keyOfImportingCodeOwnerConfig)
.equals(
codeOwnersPluginConfiguration
- .getBackend(keyOfImportedCodeOwnerConfig.branchNameKey())
+ .getProjectConfig(keyOfImportedCodeOwnerConfig.project())
+ .getBackend(keyOfImportedCodeOwnerConfig.branchNameKey().branch())
.getFilePath(keyOfImportedCodeOwnerConfig));
}
@@ -1046,7 +1055,7 @@
importType,
codeOwnerConfigFilePath,
message,
- codeOwnersPluginConfiguration.rejectNonResolvableImports(project)
+ codeOwnersPluginConfiguration.getProjectConfig(project).rejectNonResolvableImports()
? ValidationMessage.Type.ERROR
: ValidationMessage.Type.WARNING);
}
@@ -1069,7 +1078,7 @@
return Optional.of(
new CommitValidationMessage(
message,
- codeOwnersPluginConfiguration.rejectNonResolvableCodeOwners(project)
+ codeOwnersPluginConfiguration.getProjectConfig(project).rejectNonResolvableCodeOwners()
? ValidationMessage.Type.ERROR
: ValidationMessage.Type.WARNING));
}
diff --git a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnersPluginConfigValidatorIT.java b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnersPluginConfigValidatorIT.java
index be0f13b..90f950a 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnersPluginConfigValidatorIT.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnersPluginConfigValidatorIT.java
@@ -27,7 +27,6 @@
import com.google.gerrit.acceptance.GitUtil;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.config.GerritConfig;
-import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.extensions.api.changes.RebaseInput;
import com.google.gerrit.extensions.common.ChangeInfo;
@@ -101,7 +100,7 @@
PushResult r = pushRefsMetaConfig();
assertThat(r.getRemoteUpdate(RefNames.REFS_CONFIG).getStatus()).isEqualTo(Status.OK);
- assertThat(codeOwnersPluginConfiguration.isDisabled(project)).isTrue();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).isDisabled()).isTrue();
}
@Test
@@ -118,7 +117,7 @@
PushResult r = pushRefsMetaConfig();
assertThat(r.getRemoteUpdate(RefNames.REFS_CONFIG).getStatus()).isEqualTo(Status.OK);
- assertThat(codeOwnersPluginConfiguration.isDisabled(BranchNameKey.create(project, "master")))
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).isDisabled("master"))
.isTrue();
}
@@ -178,7 +177,7 @@
PushResult r = pushRefsMetaConfig();
assertThat(r.getRemoteUpdate(RefNames.REFS_CONFIG).getStatus()).isEqualTo(Status.OK);
- assertThat(codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")))
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).getBackend("master"))
.isInstanceOf(ProtoBackend.class);
}
@@ -196,7 +195,7 @@
PushResult r = pushRefsMetaConfig();
assertThat(r.getRemoteUpdate(RefNames.REFS_CONFIG).getStatus()).isEqualTo(Status.OK);
- assertThat(codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")))
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).getBackend("master"))
.isInstanceOf(ProtoBackend.class);
}
@@ -256,7 +255,8 @@
PushResult r = pushRefsMetaConfig();
assertThat(r.getRemoteUpdate(RefNames.REFS_CONFIG).getStatus()).isEqualTo(Status.OK);
- RequiredApproval requiredApproval = codeOwnersPluginConfiguration.getRequiredApproval(project);
+ RequiredApproval requiredApproval =
+ codeOwnersPluginConfiguration.getProjectConfig(project).getRequiredApproval();
assertThat(requiredApproval).hasLabelNameThat().isEqualTo("Code-Review");
assertThat(requiredApproval).hasValueThat().isEqualTo(2);
}
@@ -327,7 +327,7 @@
PushResult r = pushRefsMetaConfig();
assertThat(r.getRemoteUpdate(RefNames.REFS_CONFIG).getStatus()).isEqualTo(Status.OK);
ImmutableSet<RequiredApproval> overrideApproval =
- codeOwnersPluginConfiguration.getOverrideApproval(project);
+ codeOwnersPluginConfiguration.getProjectConfig(project).getOverrideApproval();
assertThat(overrideApproval).hasSize(1);
assertThat(overrideApproval).element(0).hasLabelNameThat().isEqualTo("Code-Review");
assertThat(overrideApproval).element(0).hasValueThat().isEqualTo(2);
@@ -424,7 +424,7 @@
PushResult r = pushRefsMetaConfig();
assertThat(r.getRemoteUpdate(RefNames.REFS_CONFIG).getStatus()).isEqualTo(Status.OK);
ImmutableSet<RequiredApproval> overrideApproval =
- codeOwnersPluginConfiguration.getOverrideApproval(project);
+ codeOwnersPluginConfiguration.getProjectConfig(project).getOverrideApproval();
assertThat(overrideApproval).hasSize(1);
assertThat(overrideApproval).element(0).hasLabelNameThat().isEqualTo("Owners-Override");
assertThat(overrideApproval).element(0).hasValueThat().isEqualTo(1);
@@ -444,7 +444,7 @@
PushResult r = pushRefsMetaConfig();
assertThat(r.getRemoteUpdate(RefNames.REFS_CONFIG).getStatus()).isEqualTo(Status.OK);
- assertThat(codeOwnersPluginConfiguration.getMergeCommitStrategy(project))
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).getMergeCommitStrategy())
.isEqualTo(MergeCommitStrategy.ALL_CHANGED_FILES);
}
@@ -483,7 +483,7 @@
PushResult r = pushRefsMetaConfig();
assertThat(r.getRemoteUpdate(RefNames.REFS_CONFIG).getStatus()).isEqualTo(Status.OK);
- assertThat(codeOwnersPluginConfiguration.getFallbackCodeOwners(project))
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).getFallbackCodeOwners())
.isEqualTo(FallbackCodeOwners.ALL_USERS);
}
@@ -522,7 +522,9 @@
PushResult r = pushRefsMetaConfig();
assertThat(r.getRemoteUpdate(RefNames.REFS_CONFIG).getStatus()).isEqualTo(Status.OK);
- assertThat(codeOwnersPluginConfiguration.getMaxPathsInChangeMessages(project)).isEqualTo(50);
+ assertThat(
+ codeOwnersPluginConfiguration.getProjectConfig(project).getMaxPathsInChangeMessages())
+ .isEqualTo(50);
}
@Test
diff --git a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/PutCodeOwnerProjectConfigIT.java b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/PutCodeOwnerProjectConfigIT.java
index c09a8ae..d8eefd3 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/PutCodeOwnerProjectConfigIT.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/PutCodeOwnerProjectConfigIT.java
@@ -85,29 +85,27 @@
@Test
public void disableAndReenableCodeOwnersFunctionality() throws Exception {
- assertThat(codeOwnersPluginConfiguration.isDisabled(project)).isFalse();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).isDisabled()).isFalse();
CodeOwnerProjectConfigInput input = new CodeOwnerProjectConfigInput();
input.disabled = true;
CodeOwnerProjectConfigInfo updatedConfig =
projectCodeOwnersApiFactory.project(project).updateConfig(input);
assertThat(updatedConfig.status.disabled).isTrue();
- assertThat(codeOwnersPluginConfiguration.isDisabled(project)).isTrue();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).isDisabled()).isTrue();
input.disabled = false;
updatedConfig = projectCodeOwnersApiFactory.project(project).updateConfig(input);
assertThat(updatedConfig.status.disabled).isNull();
- assertThat(codeOwnersPluginConfiguration.isDisabled(project)).isFalse();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).isDisabled()).isFalse();
}
@Test
public void setDisabledBranches() throws Exception {
- BranchNameKey masterBranch = BranchNameKey.create(project, "master");
- BranchNameKey fooBranch = BranchNameKey.create(project, "foo");
-
- createBranch(fooBranch);
- assertThat(codeOwnersPluginConfiguration.isDisabled(masterBranch)).isFalse();
- assertThat(codeOwnersPluginConfiguration.isDisabled(fooBranch)).isFalse();
+ createBranch(BranchNameKey.create(project, "foo"));
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).isDisabled("master"))
+ .isFalse();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).isDisabled("foo")).isFalse();
CodeOwnerProjectConfigInput input = new CodeOwnerProjectConfigInput();
input.disabledBranches = ImmutableList.of("refs/heads/master", "refs/heads/foo");
@@ -115,25 +113,25 @@
projectCodeOwnersApiFactory.project(project).updateConfig(input);
assertThat(updatedConfig.status.disabledBranches)
.containsExactly("refs/heads/master", "refs/heads/foo");
- assertThat(codeOwnersPluginConfiguration.isDisabled(masterBranch)).isTrue();
- assertThat(codeOwnersPluginConfiguration.isDisabled(fooBranch)).isTrue();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).isDisabled("master"))
+ .isTrue();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).isDisabled("foo")).isTrue();
input = new CodeOwnerProjectConfigInput();
input.disabledBranches = ImmutableList.of();
updatedConfig = projectCodeOwnersApiFactory.project(project).updateConfig(input);
assertThat(updatedConfig.status.disabledBranches).isNull();
- assertThat(codeOwnersPluginConfiguration.isDisabled(masterBranch)).isFalse();
- assertThat(codeOwnersPluginConfiguration.isDisabled(fooBranch)).isFalse();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).isDisabled("master"))
+ .isFalse();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).isDisabled("foo")).isFalse();
}
@Test
public void setDisabledBranchesRegEx() throws Exception {
- BranchNameKey masterBranch = BranchNameKey.create(project, "master");
- BranchNameKey fooBranch = BranchNameKey.create(project, "foo");
-
- createBranch(fooBranch);
- assertThat(codeOwnersPluginConfiguration.isDisabled(masterBranch)).isFalse();
- assertThat(codeOwnersPluginConfiguration.isDisabled(fooBranch)).isFalse();
+ createBranch(BranchNameKey.create(project, "foo"));
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).isDisabled("master"))
+ .isFalse();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).isDisabled("foo")).isFalse();
CodeOwnerProjectConfigInput input = new CodeOwnerProjectConfigInput();
input.disabledBranches = ImmutableList.of("refs/heads/*");
@@ -141,15 +139,14 @@
projectCodeOwnersApiFactory.project(project).updateConfig(input);
assertThat(updatedConfig.status.disabledBranches)
.containsExactly("refs/heads/master", "refs/heads/foo");
- assertThat(codeOwnersPluginConfiguration.isDisabled(masterBranch)).isTrue();
- assertThat(codeOwnersPluginConfiguration.isDisabled(fooBranch)).isTrue();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).isDisabled("master"))
+ .isTrue();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).isDisabled("foo")).isTrue();
}
@Test
public void setDisabledBranchThatDoesntExist() throws Exception {
- BranchNameKey fooBranch = BranchNameKey.create(project, "foo");
-
- assertThat(codeOwnersPluginConfiguration.isDisabled(fooBranch)).isFalse();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).isDisabled("foo")).isFalse();
CodeOwnerProjectConfigInput input = new CodeOwnerProjectConfigInput();
input.disabledBranches = ImmutableList.of("refs/heads/foo");
@@ -157,9 +154,9 @@
projectCodeOwnersApiFactory.project(project).updateConfig(input);
// status.disabledBranches does only contain existing branches
assertThat(updatedConfig.status.disabledBranches).isNull();
- assertThat(codeOwnersPluginConfiguration.isDisabled(fooBranch)).isTrue();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).isDisabled("foo")).isTrue();
- createBranch(fooBranch);
+ createBranch(BranchNameKey.create(project, "foo"));
assertThat(projectCodeOwnersApiFactory.project(project).getConfig().status.disabledBranches)
.containsExactly("refs/heads/foo");
}
@@ -183,24 +180,29 @@
@Test
public void setFileExtension() throws Exception {
- assertThat(codeOwnersPluginConfiguration.getFileExtension(project)).isEmpty();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).getFileExtension())
+ .isEmpty();
CodeOwnerProjectConfigInput input = new CodeOwnerProjectConfigInput();
input.fileExtension = "foo";
CodeOwnerProjectConfigInfo updatedConfig =
projectCodeOwnersApiFactory.project(project).updateConfig(input);
assertThat(updatedConfig.general.fileExtension).isEqualTo("foo");
- assertThat(codeOwnersPluginConfiguration.getFileExtension(project)).value().isEqualTo("foo");
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).getFileExtension())
+ .value()
+ .isEqualTo("foo");
input.fileExtension = "";
updatedConfig = projectCodeOwnersApiFactory.project(project).updateConfig(input);
assertThat(updatedConfig.general.fileExtension).isNull();
- assertThat(codeOwnersPluginConfiguration.getFileExtension(project)).isEmpty();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).getFileExtension())
+ .isEmpty();
}
@Test
public void setRequiredApproval() throws Exception {
- RequiredApproval requiredApproval = codeOwnersPluginConfiguration.getRequiredApproval(project);
+ RequiredApproval requiredApproval =
+ codeOwnersPluginConfiguration.getProjectConfig(project).getRequiredApproval();
assertThat(requiredApproval).hasLabelNameThat().isEqualTo("Code-Review");
assertThat(requiredApproval).hasValueThat().isEqualTo(1);
@@ -215,7 +217,8 @@
projectCodeOwnersApiFactory.project(project).updateConfig(input);
assertThat(updatedConfig.requiredApproval.label).isEqualTo(otherLabel);
assertThat(updatedConfig.requiredApproval.value).isEqualTo(2);
- requiredApproval = codeOwnersPluginConfiguration.getRequiredApproval(project);
+ requiredApproval =
+ codeOwnersPluginConfiguration.getProjectConfig(project).getRequiredApproval();
assertThat(requiredApproval).hasLabelNameThat().isEqualTo(otherLabel);
assertThat(requiredApproval).hasValueThat().isEqualTo(2);
@@ -223,7 +226,8 @@
updatedConfig = projectCodeOwnersApiFactory.project(project).updateConfig(input);
assertThat(updatedConfig.requiredApproval.label).isEqualTo("Code-Review");
assertThat(updatedConfig.requiredApproval.value).isEqualTo(1);
- requiredApproval = codeOwnersPluginConfiguration.getRequiredApproval(project);
+ requiredApproval =
+ codeOwnersPluginConfiguration.getProjectConfig(project).getRequiredApproval();
assertThat(requiredApproval).hasLabelNameThat().isEqualTo("Code-Review");
assertThat(requiredApproval).hasValueThat().isEqualTo(1);
}
@@ -249,7 +253,8 @@
@Test
public void setOverrideApproval() throws Exception {
- assertThat(codeOwnersPluginConfiguration.getOverrideApproval(project)).isEmpty();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).getOverrideApproval())
+ .isEmpty();
String overrideLabel1 = "Bypass-Owners";
String overrideLabel2 = "Owners-Override";
@@ -265,12 +270,14 @@
assertThat(updatedConfig.overrideApproval.get(0).value).isEqualTo(1);
assertThat(updatedConfig.overrideApproval.get(1).label).isEqualTo(overrideLabel2);
assertThat(updatedConfig.overrideApproval.get(1).value).isEqualTo(1);
- assertThat(codeOwnersPluginConfiguration.getOverrideApproval(project)).hasSize(2);
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).getOverrideApproval())
+ .hasSize(2);
input.overrideApprovals = ImmutableList.of();
updatedConfig = projectCodeOwnersApiFactory.project(project).updateConfig(input);
assertThat(updatedConfig.overrideApproval).isNull();
- assertThat(codeOwnersPluginConfiguration.getOverrideApproval(project)).isEmpty();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).getOverrideApproval())
+ .isEmpty();
}
@Test
@@ -294,7 +301,7 @@
@Test
public void setFallbackCodeOwners() throws Exception {
- assertThat(codeOwnersPluginConfiguration.getFallbackCodeOwners(project))
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).getFallbackCodeOwners())
.isEqualTo(FallbackCodeOwners.NONE);
CodeOwnerProjectConfigInput input = new CodeOwnerProjectConfigInput();
@@ -302,37 +309,39 @@
CodeOwnerProjectConfigInfo updatedConfig =
projectCodeOwnersApiFactory.project(project).updateConfig(input);
assertThat(updatedConfig.general.fallbackCodeOwners).isEqualTo(FallbackCodeOwners.ALL_USERS);
- assertThat(codeOwnersPluginConfiguration.getFallbackCodeOwners(project))
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).getFallbackCodeOwners())
.isEqualTo(FallbackCodeOwners.ALL_USERS);
input.fallbackCodeOwners = FallbackCodeOwners.NONE;
updatedConfig = projectCodeOwnersApiFactory.project(project).updateConfig(input);
assertThat(updatedConfig.general.fallbackCodeOwners).isEqualTo(FallbackCodeOwners.NONE);
- assertThat(codeOwnersPluginConfiguration.getFallbackCodeOwners(project))
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).getFallbackCodeOwners())
.isEqualTo(FallbackCodeOwners.NONE);
}
@Test
public void setGlobalCodeOwners() throws Exception {
- assertThat(codeOwnersPluginConfiguration.getGlobalCodeOwners(project)).isEmpty();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).getGlobalCodeOwners())
+ .isEmpty();
CodeOwnerProjectConfigInput input = new CodeOwnerProjectConfigInput();
input.globalCodeOwners = ImmutableList.of(user.email(), "foo.bar@example.com");
projectCodeOwnersApiFactory.project(project).updateConfig(input);
assertThat(
- codeOwnersPluginConfiguration.getGlobalCodeOwners(project).stream()
+ codeOwnersPluginConfiguration.getProjectConfig(project).getGlobalCodeOwners().stream()
.map(CodeOwnerReference::email)
.collect(toImmutableSet()))
.containsExactly(user.email(), "foo.bar@example.com");
input.globalCodeOwners = ImmutableList.of();
projectCodeOwnersApiFactory.project(project).updateConfig(input);
- assertThat(codeOwnersPluginConfiguration.getGlobalCodeOwners(project)).isEmpty();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).getGlobalCodeOwners())
+ .isEmpty();
}
@Test
public void setMergeCommitStrategy() throws Exception {
- assertThat(codeOwnersPluginConfiguration.getMergeCommitStrategy(project))
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).getMergeCommitStrategy())
.isEqualTo(MergeCommitStrategy.ALL_CHANGED_FILES);
CodeOwnerProjectConfigInput input = new CodeOwnerProjectConfigInput();
@@ -341,166 +350,210 @@
projectCodeOwnersApiFactory.project(project).updateConfig(input);
assertThat(updatedConfig.general.mergeCommitStrategy)
.isEqualTo(MergeCommitStrategy.FILES_WITH_CONFLICT_RESOLUTION);
- assertThat(codeOwnersPluginConfiguration.getMergeCommitStrategy(project))
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).getMergeCommitStrategy())
.isEqualTo(MergeCommitStrategy.FILES_WITH_CONFLICT_RESOLUTION);
input.mergeCommitStrategy = MergeCommitStrategy.ALL_CHANGED_FILES;
updatedConfig = projectCodeOwnersApiFactory.project(project).updateConfig(input);
assertThat(updatedConfig.general.mergeCommitStrategy)
.isEqualTo(MergeCommitStrategy.ALL_CHANGED_FILES);
- assertThat(codeOwnersPluginConfiguration.getMergeCommitStrategy(project))
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).getMergeCommitStrategy())
.isEqualTo(MergeCommitStrategy.ALL_CHANGED_FILES);
}
@Test
public void setImplicitApprovals() throws Exception {
- assertThat(codeOwnersPluginConfiguration.areImplicitApprovalsEnabled(project)).isFalse();
+ assertThat(
+ codeOwnersPluginConfiguration.getProjectConfig(project).areImplicitApprovalsEnabled())
+ .isFalse();
CodeOwnerProjectConfigInput input = new CodeOwnerProjectConfigInput();
input.implicitApprovals = true;
CodeOwnerProjectConfigInfo updatedConfig =
projectCodeOwnersApiFactory.project(project).updateConfig(input);
assertThat(updatedConfig.general.implicitApprovals).isTrue();
- assertThat(codeOwnersPluginConfiguration.areImplicitApprovalsEnabled(project)).isTrue();
+ assertThat(
+ codeOwnersPluginConfiguration.getProjectConfig(project).areImplicitApprovalsEnabled())
+ .isTrue();
input.implicitApprovals = false;
updatedConfig = projectCodeOwnersApiFactory.project(project).updateConfig(input);
assertThat(updatedConfig.general.implicitApprovals).isNull();
- assertThat(codeOwnersPluginConfiguration.areImplicitApprovalsEnabled(project)).isFalse();
+ assertThat(
+ codeOwnersPluginConfiguration.getProjectConfig(project).areImplicitApprovalsEnabled())
+ .isFalse();
}
@Test
public void setOverrideInfoUrl() throws Exception {
- assertThat(codeOwnersPluginConfiguration.getOverrideInfoUrl(project)).isEmpty();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).getOverrideInfoUrl())
+ .isEmpty();
CodeOwnerProjectConfigInput input = new CodeOwnerProjectConfigInput();
input.overrideInfoUrl = "http://foo.bar";
CodeOwnerProjectConfigInfo updatedConfig =
projectCodeOwnersApiFactory.project(project).updateConfig(input);
assertThat(updatedConfig.general.overrideInfoUrl).isEqualTo("http://foo.bar");
- assertThat(codeOwnersPluginConfiguration.getOverrideInfoUrl(project))
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).getOverrideInfoUrl())
.value()
.isEqualTo("http://foo.bar");
input.overrideInfoUrl = "";
updatedConfig = projectCodeOwnersApiFactory.project(project).updateConfig(input);
assertThat(updatedConfig.general.overrideInfoUrl).isNull();
- assertThat(codeOwnersPluginConfiguration.getOverrideInfoUrl(project)).isEmpty();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).getOverrideInfoUrl())
+ .isEmpty();
}
@Test
public void setReadOnly() throws Exception {
- assertThat(codeOwnersPluginConfiguration.areCodeOwnerConfigsReadOnly(project)).isFalse();
+ assertThat(
+ codeOwnersPluginConfiguration.getProjectConfig(project).areCodeOwnerConfigsReadOnly())
+ .isFalse();
CodeOwnerProjectConfigInput input = new CodeOwnerProjectConfigInput();
input.readOnly = true;
projectCodeOwnersApiFactory.project(project).updateConfig(input);
- assertThat(codeOwnersPluginConfiguration.areCodeOwnerConfigsReadOnly(project)).isTrue();
+ assertThat(
+ codeOwnersPluginConfiguration.getProjectConfig(project).areCodeOwnerConfigsReadOnly())
+ .isTrue();
input.readOnly = false;
projectCodeOwnersApiFactory.project(project).updateConfig(input);
- assertThat(codeOwnersPluginConfiguration.areCodeOwnerConfigsReadOnly(project)).isFalse();
+ assertThat(
+ codeOwnersPluginConfiguration.getProjectConfig(project).areCodeOwnerConfigsReadOnly())
+ .isFalse();
}
@Test
public void setExemptPureReverts() throws Exception {
- assertThat(codeOwnersPluginConfiguration.arePureRevertsExempted(project)).isFalse();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).arePureRevertsExempted())
+ .isFalse();
CodeOwnerProjectConfigInput input = new CodeOwnerProjectConfigInput();
input.exemptPureReverts = true;
projectCodeOwnersApiFactory.project(project).updateConfig(input);
- assertThat(codeOwnersPluginConfiguration.arePureRevertsExempted(project)).isTrue();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).arePureRevertsExempted())
+ .isTrue();
input.exemptPureReverts = false;
projectCodeOwnersApiFactory.project(project).updateConfig(input);
- assertThat(codeOwnersPluginConfiguration.arePureRevertsExempted(project)).isFalse();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).arePureRevertsExempted())
+ .isFalse();
}
@Test
public void setEnableValidationOnCommitReceived() throws Exception {
assertThat(
- codeOwnersPluginConfiguration.getCodeOwnerConfigValidationPolicyForCommitReceived(
- project))
+ codeOwnersPluginConfiguration
+ .getProjectConfig(project)
+ .getCodeOwnerConfigValidationPolicyForCommitReceived())
.isEqualTo(CodeOwnerConfigValidationPolicy.TRUE);
CodeOwnerProjectConfigInput input = new CodeOwnerProjectConfigInput();
input.enableValidationOnCommitReceived = CodeOwnerConfigValidationPolicy.FALSE;
projectCodeOwnersApiFactory.project(project).updateConfig(input);
assertThat(
- codeOwnersPluginConfiguration.getCodeOwnerConfigValidationPolicyForCommitReceived(
- project))
+ codeOwnersPluginConfiguration
+ .getProjectConfig(project)
+ .getCodeOwnerConfigValidationPolicyForCommitReceived())
.isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
input.enableValidationOnCommitReceived = CodeOwnerConfigValidationPolicy.TRUE;
projectCodeOwnersApiFactory.project(project).updateConfig(input);
assertThat(
- codeOwnersPluginConfiguration.getCodeOwnerConfigValidationPolicyForCommitReceived(
- project))
+ codeOwnersPluginConfiguration
+ .getProjectConfig(project)
+ .getCodeOwnerConfigValidationPolicyForCommitReceived())
.isEqualTo(CodeOwnerConfigValidationPolicy.TRUE);
}
@Test
public void setEnableValidationOnSubmit() throws Exception {
- assertThat(codeOwnersPluginConfiguration.getCodeOwnerConfigValidationPolicyForSubmit(project))
+ assertThat(
+ codeOwnersPluginConfiguration
+ .getProjectConfig(project)
+ .getCodeOwnerConfigValidationPolicyForSubmit())
.isEqualTo(CodeOwnerConfigValidationPolicy.TRUE);
CodeOwnerProjectConfigInput input = new CodeOwnerProjectConfigInput();
input.enableValidationOnSubmit = CodeOwnerConfigValidationPolicy.FALSE;
projectCodeOwnersApiFactory.project(project).updateConfig(input);
- assertThat(codeOwnersPluginConfiguration.getCodeOwnerConfigValidationPolicyForSubmit(project))
+ assertThat(
+ codeOwnersPluginConfiguration
+ .getProjectConfig(project)
+ .getCodeOwnerConfigValidationPolicyForSubmit())
.isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
input.enableValidationOnSubmit = CodeOwnerConfigValidationPolicy.TRUE;
projectCodeOwnersApiFactory.project(project).updateConfig(input);
- assertThat(codeOwnersPluginConfiguration.getCodeOwnerConfigValidationPolicyForSubmit(project))
+ assertThat(
+ codeOwnersPluginConfiguration
+ .getProjectConfig(project)
+ .getCodeOwnerConfigValidationPolicyForSubmit())
.isEqualTo(CodeOwnerConfigValidationPolicy.TRUE);
}
@Test
public void setRejectNonResolvableCodeOwners() throws Exception {
- assertThat(codeOwnersPluginConfiguration.rejectNonResolvableCodeOwners(project)).isTrue();
+ assertThat(
+ codeOwnersPluginConfiguration.getProjectConfig(project).rejectNonResolvableCodeOwners())
+ .isTrue();
CodeOwnerProjectConfigInput input = new CodeOwnerProjectConfigInput();
input.rejectNonResolvableCodeOwners = false;
projectCodeOwnersApiFactory.project(project).updateConfig(input);
- assertThat(codeOwnersPluginConfiguration.rejectNonResolvableCodeOwners(project)).isFalse();
+ assertThat(
+ codeOwnersPluginConfiguration.getProjectConfig(project).rejectNonResolvableCodeOwners())
+ .isFalse();
input.rejectNonResolvableCodeOwners = true;
projectCodeOwnersApiFactory.project(project).updateConfig(input);
- assertThat(codeOwnersPluginConfiguration.rejectNonResolvableCodeOwners(project)).isTrue();
+ assertThat(
+ codeOwnersPluginConfiguration.getProjectConfig(project).rejectNonResolvableCodeOwners())
+ .isTrue();
}
@Test
public void setRejectNonResolvableImports() throws Exception {
- assertThat(codeOwnersPluginConfiguration.rejectNonResolvableImports(project)).isTrue();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).rejectNonResolvableImports())
+ .isTrue();
CodeOwnerProjectConfigInput input = new CodeOwnerProjectConfigInput();
input.rejectNonResolvableImports = false;
projectCodeOwnersApiFactory.project(project).updateConfig(input);
- assertThat(codeOwnersPluginConfiguration.rejectNonResolvableImports(project)).isFalse();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).rejectNonResolvableImports())
+ .isFalse();
input.rejectNonResolvableImports = true;
projectCodeOwnersApiFactory.project(project).updateConfig(input);
- assertThat(codeOwnersPluginConfiguration.rejectNonResolvableImports(project)).isTrue();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).rejectNonResolvableImports())
+ .isTrue();
}
@Test
public void setMaxPathsInChangeMessages() throws Exception {
- assertThat(codeOwnersPluginConfiguration.getMaxPathsInChangeMessages(project))
+ assertThat(
+ codeOwnersPluginConfiguration.getProjectConfig(project).getMaxPathsInChangeMessages())
.isEqualTo(GeneralConfig.DEFAULT_MAX_PATHS_IN_CHANGE_MESSAGES);
CodeOwnerProjectConfigInput input = new CodeOwnerProjectConfigInput();
input.maxPathsInChangeMessages = 10;
projectCodeOwnersApiFactory.project(project).updateConfig(input);
- assertThat(codeOwnersPluginConfiguration.getMaxPathsInChangeMessages(project)).isEqualTo(10);
+ assertThat(
+ codeOwnersPluginConfiguration.getProjectConfig(project).getMaxPathsInChangeMessages())
+ .isEqualTo(10);
input.maxPathsInChangeMessages = 0;
projectCodeOwnersApiFactory.project(project).updateConfig(input);
- assertThat(codeOwnersPluginConfiguration.getMaxPathsInChangeMessages(project)).isEqualTo(0);
+ assertThat(
+ codeOwnersPluginConfiguration.getProjectConfig(project).getMaxPathsInChangeMessages())
+ .isEqualTo(0);
input.maxPathsInChangeMessages = GeneralConfig.DEFAULT_MAX_PATHS_IN_CHANGE_MESSAGES;
projectCodeOwnersApiFactory.project(project).updateConfig(input);
- assertThat(codeOwnersPluginConfiguration.getMaxPathsInChangeMessages(project))
+ assertThat(
+ codeOwnersPluginConfiguration.getProjectConfig(project).getMaxPathsInChangeMessages())
.isEqualTo(GeneralConfig.DEFAULT_MAX_PATHS_IN_CHANGE_MESSAGES);
}
@@ -544,12 +597,12 @@
ProjectState projectState = projectCache.get(project).orElseThrow(illegalState(project));
deleteRef.deleteSingleRef(projectState, RefNames.REFS_CONFIG);
- assertThat(codeOwnersPluginConfiguration.isDisabled(project)).isFalse();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).isDisabled()).isFalse();
CodeOwnerProjectConfigInput input = new CodeOwnerProjectConfigInput();
input.disabled = true;
projectCodeOwnersApiFactory.project(project).updateConfig(input);
- assertThat(codeOwnersPluginConfiguration.isDisabled(project)).isTrue();
+ assertThat(codeOwnersPluginConfiguration.getProjectConfig(project).isDisabled()).isTrue();
}
}
diff --git a/javatests/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigSnapshotTest.java b/javatests/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigSnapshotTest.java
new file mode 100644
index 0000000..997eb19
--- /dev/null
+++ b/javatests/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigSnapshotTest.java
@@ -0,0 +1,874 @@
+// Copyright (C) 2021 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.google.gerrit.plugins.codeowners.backend.config;
+
+import static com.google.common.collect.ImmutableSet.toImmutableSet;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.plugins.codeowners.testing.RequiredApprovalSubject.assertThat;
+import static com.google.gerrit.testing.GerritJUnit.assertThrows;
+import static com.google.gerrit.truth.OptionalSubject.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.gerrit.acceptance.config.GerritConfig;
+import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
+import com.google.gerrit.common.Nullable;
+import com.google.gerrit.entities.Project;
+import com.google.gerrit.entities.Project.NameKey;
+import com.google.gerrit.entities.RefNames;
+import com.google.gerrit.extensions.common.LabelDefinitionInput;
+import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.registration.PrivateInternals_DynamicMapImpl;
+import com.google.gerrit.extensions.registration.RegistrationHandle;
+import com.google.gerrit.plugins.codeowners.acceptance.AbstractCodeOwnersTest;
+import com.google.gerrit.plugins.codeowners.backend.CodeOwnerBackend;
+import com.google.gerrit.plugins.codeowners.backend.CodeOwnerConfig;
+import com.google.gerrit.plugins.codeowners.backend.CodeOwnerConfigUpdate;
+import com.google.gerrit.plugins.codeowners.backend.FallbackCodeOwners;
+import com.google.gerrit.plugins.codeowners.backend.PathExpressionMatcher;
+import com.google.gerrit.plugins.codeowners.backend.findowners.FindOwnersBackend;
+import com.google.gerrit.plugins.codeowners.common.MergeCommitStrategy;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.inject.Inject;
+import com.google.inject.Key;
+import com.google.inject.util.Providers;
+import java.nio.file.Path;
+import java.util.Optional;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.junit.Before;
+import org.junit.Test;
+
+/** Tests for {@link CodeOwnersPluginConfigSnapshot}. */
+public class CodeOwnersPluginConfigSnapshotTest extends AbstractCodeOwnersTest {
+ @Inject private ProjectOperations projectOperations;
+
+ private CodeOwnersPluginConfigSnapshot.Factory codeOwnersPluginConfigSnapshotFactory;
+ private DynamicMap<CodeOwnerBackend> codeOwnerBackends;
+
+ @Before
+ public void setUpCodeOwnersPlugin() throws Exception {
+ codeOwnersPluginConfigSnapshotFactory =
+ plugin.getSysInjector().getInstance(CodeOwnersPluginConfigSnapshot.Factory.class);
+ codeOwnerBackends =
+ plugin.getSysInjector().getInstance(new Key<DynamicMap<CodeOwnerBackend>>() {});
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.fileExtension", value = "foo")
+ public void getFileExtensionIfNoneIsConfiguredOnProjectLevel() throws Exception {
+ assertThat(cfgSnapshot().getFileExtension()).value().isEqualTo("foo");
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.fileExtension", value = "foo")
+ public void fileExtensionOnProjectLevelOverridesDefaultFileExtension() throws Exception {
+ configureFileExtension(project, "bar");
+ assertThat(cfgSnapshot().getFileExtension()).value().isEqualTo("bar");
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.fileExtension", value = "foo")
+ public void fileExtensionIsInheritedFromParentProject() throws Exception {
+ configureFileExtension(allProjects, "bar");
+ assertThat(cfgSnapshot().getFileExtension()).value().isEqualTo("bar");
+ }
+
+ @Test
+ public void inheritedFileExtensionCanBeOverridden() throws Exception {
+ configureFileExtension(allProjects, "foo");
+ configureFileExtension(project, "bar");
+ assertThat(cfgSnapshot().getFileExtension()).value().isEqualTo("bar");
+ }
+
+ @Test
+ public void getMergeCommitStrategyIfNoneIsConfigured() throws Exception {
+ assertThat(cfgSnapshot().getMergeCommitStrategy())
+ .isEqualTo(MergeCommitStrategy.ALL_CHANGED_FILES);
+ }
+
+ @Test
+ @GerritConfig(
+ name = "plugin.code-owners.mergeCommitStrategy",
+ value = "FILES_WITH_CONFLICT_RESOLUTION")
+ public void getMergeCommitStrategyIfNoneIsConfiguredOnProjectLevel() throws Exception {
+ assertThat(cfgSnapshot().getMergeCommitStrategy())
+ .isEqualTo(MergeCommitStrategy.FILES_WITH_CONFLICT_RESOLUTION);
+ }
+
+ @Test
+ @GerritConfig(
+ name = "plugin.code-owners.mergeCommitStrategy",
+ value = "FILES_WITH_CONFLICT_RESOLUTION")
+ public void mergeCommitStrategyOnProjectLevelOverridesGlobalMergeCommitStrategy()
+ throws Exception {
+ configureMergeCommitStrategy(project, MergeCommitStrategy.ALL_CHANGED_FILES);
+ assertThat(cfgSnapshot().getMergeCommitStrategy())
+ .isEqualTo(MergeCommitStrategy.ALL_CHANGED_FILES);
+ }
+
+ @Test
+ @GerritConfig(
+ name = "plugin.code-owners.mergeCommitStrategy",
+ value = "FILES_WITH_CONFLICT_RESOLUTION")
+ public void mergeCommitStrategyIsInheritedFromParentProject() throws Exception {
+ configureMergeCommitStrategy(allProjects, MergeCommitStrategy.ALL_CHANGED_FILES);
+ assertThat(cfgSnapshot().getMergeCommitStrategy())
+ .isEqualTo(MergeCommitStrategy.ALL_CHANGED_FILES);
+ }
+
+ @Test
+ public void inheritedMergeCommitStrategyCanBeOverridden() throws Exception {
+ configureMergeCommitStrategy(allProjects, MergeCommitStrategy.FILES_WITH_CONFLICT_RESOLUTION);
+ configureMergeCommitStrategy(project, MergeCommitStrategy.ALL_CHANGED_FILES);
+ assertThat(cfgSnapshot().getMergeCommitStrategy())
+ .isEqualTo(MergeCommitStrategy.ALL_CHANGED_FILES);
+ }
+
+ @Test
+ public void getFallbackCodeOwnersIfNoneIsConfigured() throws Exception {
+ assertThat(cfgSnapshot().getFallbackCodeOwners()).isEqualTo(FallbackCodeOwners.NONE);
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.fallbackCodeOwners", value = "ALL_USERS")
+ public void getFallbackCodeOwnersIfNoneIsConfiguredOnProjectLevel() throws Exception {
+ assertThat(cfgSnapshot().getFallbackCodeOwners()).isEqualTo(FallbackCodeOwners.ALL_USERS);
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.fallbackCodeOwners", value = "ALL_USERS")
+ public void fallbackCodeOnwersOnProjectLevelOverridesGlobalFallbackCodeOwners() throws Exception {
+ configureFallbackCodeOwners(project, FallbackCodeOwners.NONE);
+ assertThat(cfgSnapshot().getFallbackCodeOwners()).isEqualTo(FallbackCodeOwners.NONE);
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.fallbackCodeOwners", value = "ALL_USERS")
+ public void fallbackCodeOwnersIsInheritedFromParentProject() throws Exception {
+ configureFallbackCodeOwners(allProjects, FallbackCodeOwners.NONE);
+ assertThat(cfgSnapshot().getFallbackCodeOwners()).isEqualTo(FallbackCodeOwners.NONE);
+ }
+
+ @Test
+ public void inheritedFallbackCodeOwnersCanBeOverridden() throws Exception {
+ configureFallbackCodeOwners(allProjects, FallbackCodeOwners.ALL_USERS);
+ configureFallbackCodeOwners(project, FallbackCodeOwners.NONE);
+ assertThat(cfgSnapshot().getFallbackCodeOwners()).isEqualTo(FallbackCodeOwners.NONE);
+ }
+
+ @Test
+ public void getMaxPathsInChangeMessagesIfNoneIsConfigured() throws Exception {
+ assertThat(cfgSnapshot().getMaxPathsInChangeMessages())
+ .isEqualTo(GeneralConfig.DEFAULT_MAX_PATHS_IN_CHANGE_MESSAGES);
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.maxPathsInChangeMessages", value = "50")
+ public void getMaxPathsInChangeMessagesIfNoneIsConfiguredOnProjectLevel() throws Exception {
+ assertThat(cfgSnapshot().getMaxPathsInChangeMessages()).isEqualTo(50);
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.maxPathsInChangeMessages", value = "50")
+ public void maxPathInChangeMessagesOnProjectLevelOverridesGlobalMaxPathInChangeMessages()
+ throws Exception {
+ configureMaxPathsInChangeMessages(project, 20);
+ assertThat(cfgSnapshot().getMaxPathsInChangeMessages()).isEqualTo(20);
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.maxPathsInChangeMessages", value = "50")
+ public void maxPathInChangeMessagesIsInheritedFromParentProject() throws Exception {
+ configureMaxPathsInChangeMessages(allProjects, 20);
+ assertThat(cfgSnapshot().getMaxPathsInChangeMessages()).isEqualTo(20);
+ }
+
+ @Test
+ public void inheritedMaxPathInChangeMessagesCanBeOverridden() throws Exception {
+ configureMaxPathsInChangeMessages(allProjects, 50);
+ configureMaxPathsInChangeMessages(project, 20);
+ assertThat(cfgSnapshot().getMaxPathsInChangeMessages()).isEqualTo(20);
+ }
+
+ @Test
+ public void cannotCheckForNullBranchIfCodeOwnersFunctionalityIsDisabled() throws Exception {
+ NullPointerException npe =
+ assertThrows(
+ NullPointerException.class, () -> cfgSnapshot().isDisabled(/* branchName= */ null));
+ assertThat(npe).hasMessageThat().isEqualTo("branchName");
+ }
+
+ @Test
+ public void checkIfCodeOwnersFunctionalityIsDisabledForNonExistingBranch() throws Exception {
+ assertThat(cfgSnapshot().isDisabled("non-existing")).isFalse();
+ }
+
+ @Test
+ public void checkIfCodeOwnersFunctionalityIsDisabledForProjectWithEmptyConfig() throws Exception {
+ assertThat(cfgSnapshot().isDisabled()).isFalse();
+ }
+
+ @Test
+ public void checkIfCodeOwnersFunctionalityIsDisabledForBranchWithEmptyConfig() throws Exception {
+ assertThat(cfgSnapshot().isDisabled("master")).isFalse();
+ }
+
+ @Test
+ public void codeOwnersFunctionalityIsDisabledForProject() throws Exception {
+ disableCodeOwnersForProject(project);
+ assertThat(cfgSnapshot().isDisabled()).isTrue();
+ }
+
+ @Test
+ public void codeOwnersFunctionalityIsDisabledForBranchIfItIsDisabledForProject()
+ throws Exception {
+ disableCodeOwnersForProject(project);
+ assertThat(cfgSnapshot().isDisabled("master")).isTrue();
+ }
+
+ @Test
+ public void codeOwnersFunctionalityIsDisabledForBranch_exactRef() throws Exception {
+ configureDisabledBranch(project, "refs/heads/master");
+ assertThat(cfgSnapshot().isDisabled("master")).isTrue();
+ assertThat(cfgSnapshot().isDisabled("other")).isFalse();
+ }
+
+ @Test
+ public void codeOwnersFunctionalityIsDisabledForBranch_refPattern() throws Exception {
+ configureDisabledBranch(project, "refs/heads/*");
+ assertThat(cfgSnapshot().isDisabled("master")).isTrue();
+ assertThat(cfgSnapshot().isDisabled("other")).isTrue();
+ assertThat(cfgSnapshot().isDisabled(RefNames.REFS_META)).isFalse();
+ }
+
+ @Test
+ public void codeOwnersFunctionalityIsDisabledForBranch_regularExpression() throws Exception {
+ configureDisabledBranch(project, "^refs/heads/.*");
+ assertThat(cfgSnapshot().isDisabled("master")).isTrue();
+ assertThat(cfgSnapshot().isDisabled("other")).isTrue();
+ assertThat(cfgSnapshot().isDisabled(RefNames.REFS_META)).isFalse();
+ }
+
+ @Test
+ public void codeOwnersFunctionalityIsDisabledForBranch_invalidRegularExpression()
+ throws Exception {
+ configureDisabledBranch(project, "^refs/heads/[");
+ assertThat(cfgSnapshot().isDisabled("master")).isFalse();
+ }
+
+ @Test
+ public void disabledIsInheritedFromParentProject() throws Exception {
+ disableCodeOwnersForProject(allProjects);
+ assertThat(cfgSnapshot().isDisabled()).isTrue();
+ }
+
+ @Test
+ public void inheritedDisabledAlsoCountsForBranch() throws Exception {
+ disableCodeOwnersForProject(allProjects);
+ assertThat(cfgSnapshot().isDisabled("master")).isTrue();
+ }
+
+ @Test
+ public void inheritedDisabledValueIsIgnoredIfInvalid() throws Exception {
+ configureDisabled(project, "invalid");
+ assertThat(cfgSnapshot().isDisabled()).isFalse();
+ }
+
+ @Test
+ public void inheritedDisabledValueIsIgnoredForBranchIfInvalid() throws Exception {
+ configureDisabled(project, "invalid");
+ assertThat(cfgSnapshot().isDisabled("master")).isFalse();
+ }
+
+ @Test
+ public void disabledForOtherProjectHasNoEffect() throws Exception {
+ Project.NameKey otherProject = projectOperations.newProject().create();
+ disableCodeOwnersForProject(otherProject);
+ assertThat(cfgSnapshot().isDisabled()).isFalse();
+ }
+
+ @Test
+ public void disabledBranchForOtherProjectHasNoEffect() throws Exception {
+ Project.NameKey otherProject = projectOperations.newProject().create();
+ configureDisabledBranch(otherProject, "refs/heads/master");
+ assertThat(cfgSnapshot().isDisabled("master")).isFalse();
+ }
+
+ @Test
+ public void disabledBranchIsInheritedFromParentProject() throws Exception {
+ configureDisabledBranch(allProjects, "refs/heads/master");
+ assertThat(cfgSnapshot().isDisabled("master")).isTrue();
+ }
+
+ @Test
+ public void inheritedDisabledCanBeOverridden() throws Exception {
+ disableCodeOwnersForProject(allProjects);
+ enableCodeOwnersForProject(project);
+ assertThat(cfgSnapshot().isDisabled("master")).isFalse();
+ }
+
+ @Test
+ public void inheritedDisabledBranchCanBeOverridden() throws Exception {
+ configureDisabledBranch(allProjects, "refs/heads/master");
+ enableCodeOwnersForAllBranches(project);
+ assertThat(cfgSnapshot().isDisabled("master")).isFalse();
+ }
+
+ @Test
+ public void getBackendForNonExistingBranch() throws Exception {
+ assertThat(cfgSnapshot().getBackend("non-existing")).isInstanceOf(FindOwnersBackend.class);
+ }
+
+ @Test
+ public void getDefaultBackendWhenNoBackendIsConfigured() throws Exception {
+ assertThat(cfgSnapshot().getBackend("master")).isInstanceOf(FindOwnersBackend.class);
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.backend", value = TestCodeOwnerBackend.ID)
+ public void getConfiguredDefaultBackend() throws Exception {
+ try (AutoCloseable registration = registerTestBackend()) {
+ assertThat(cfgSnapshot().getBackend("master")).isInstanceOf(TestCodeOwnerBackend.class);
+ }
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.backend", value = "non-existing-backend")
+ public void cannotGetBackendIfNonExistingBackendIsConfigured() throws Exception {
+ InvalidPluginConfigurationException exception =
+ assertThrows(
+ InvalidPluginConfigurationException.class, () -> cfgSnapshot().getBackend("master"));
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo(
+ "Invalid configuration of the code-owners plugin. Code owner backend"
+ + " 'non-existing-backend' that is configured in gerrit.config (parameter"
+ + " plugin.code-owners.backend) not found.");
+ }
+
+ @Test
+ public void getBackendConfiguredOnProjectLevel() throws Exception {
+ configureBackend(project, TestCodeOwnerBackend.ID);
+ try (AutoCloseable registration = registerTestBackend()) {
+ assertThat(cfgSnapshot().getBackend("master")).isInstanceOf(TestCodeOwnerBackend.class);
+ }
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.backend", value = FindOwnersBackend.ID)
+ public void backendConfiguredOnProjectLevelOverridesDefaultBackend() throws Exception {
+ configureBackend(project, TestCodeOwnerBackend.ID);
+ try (AutoCloseable registration = registerTestBackend()) {
+ assertThat(cfgSnapshot().getBackend("master")).isInstanceOf(TestCodeOwnerBackend.class);
+ }
+ }
+
+ @Test
+ public void backendIsInheritedFromParentProject() throws Exception {
+ configureBackend(allProjects, TestCodeOwnerBackend.ID);
+ try (AutoCloseable registration = registerTestBackend()) {
+ assertThat(cfgSnapshot().getBackend("master")).isInstanceOf(TestCodeOwnerBackend.class);
+ }
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.backend", value = FindOwnersBackend.ID)
+ public void inheritedBackendOverridesDefaultBackend() throws Exception {
+ configureBackend(allProjects, TestCodeOwnerBackend.ID);
+ try (AutoCloseable registration = registerTestBackend()) {
+ assertThat(cfgSnapshot().getBackend("master")).isInstanceOf(TestCodeOwnerBackend.class);
+ }
+ }
+
+ @Test
+ public void projectLevelBackendOverridesInheritedBackend() throws Exception {
+ configureBackend(allProjects, TestCodeOwnerBackend.ID);
+ configureBackend(project, FindOwnersBackend.ID);
+ try (AutoCloseable registration = registerTestBackend()) {
+ assertThat(cfgSnapshot().getBackend("master")).isInstanceOf(FindOwnersBackend.class);
+ }
+ }
+
+ @Test
+ public void cannotGetBackendIfNonExistingBackendIsConfiguredOnProjectLevel() throws Exception {
+ configureBackend(project, "non-existing-backend");
+ InvalidPluginConfigurationException exception =
+ assertThrows(
+ InvalidPluginConfigurationException.class, () -> cfgSnapshot().getBackend("master"));
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo(
+ String.format(
+ "Invalid configuration of the code-owners plugin. Code owner backend"
+ + " 'non-existing-backend' that is configured for project %s in"
+ + " code-owners.config (parameter codeOwners.backend) not found.",
+ project));
+ }
+
+ @Test
+ public void projectLevelBackendForOtherProjectHasNoEffect() throws Exception {
+ Project.NameKey otherProject = projectOperations.newProject().create();
+ configureBackend(otherProject, TestCodeOwnerBackend.ID);
+ try (AutoCloseable registration = registerTestBackend()) {
+ assertThat(cfgSnapshot().getBackend("master")).isInstanceOf(FindOwnersBackend.class);
+ }
+ }
+
+ @Test
+ public void getBackendConfiguredOnBranchLevel() throws Exception {
+ configureBackend(project, "refs/heads/master", TestCodeOwnerBackend.ID);
+ try (AutoCloseable registration = registerTestBackend()) {
+ assertThat(cfgSnapshot().getBackend("master")).isInstanceOf(TestCodeOwnerBackend.class);
+ }
+ }
+
+ @Test
+ public void getBackendConfiguredOnBranchLevelShortName() throws Exception {
+ configureBackend(project, "master", TestCodeOwnerBackend.ID);
+ try (AutoCloseable registration = registerTestBackend()) {
+ assertThat(cfgSnapshot().getBackend("master")).isInstanceOf(TestCodeOwnerBackend.class);
+ }
+ }
+
+ @Test
+ public void branchLevelBackendOnFullNameTakesPrecedenceOverBranchLevelBackendOnShortName()
+ throws Exception {
+ configureBackend(project, "master", TestCodeOwnerBackend.ID);
+ configureBackend(project, "refs/heads/master", FindOwnersBackend.ID);
+ try (AutoCloseable registration = registerTestBackend()) {
+ assertThat(cfgSnapshot().getBackend("master")).isInstanceOf(FindOwnersBackend.class);
+ }
+ }
+
+ @Test
+ public void branchLevelBackendOverridesProjectLevelBackend() throws Exception {
+ configureBackend(project, TestCodeOwnerBackend.ID);
+ configureBackend(project, "master", FindOwnersBackend.ID);
+ try (AutoCloseable registration = registerTestBackend()) {
+ assertThat(cfgSnapshot().getBackend("master")).isInstanceOf(FindOwnersBackend.class);
+ }
+ }
+
+ @Test
+ public void cannotGetBackendIfNonExistingBackendIsConfiguredOnBranchLevel() throws Exception {
+ configureBackend(project, "master", "non-existing-backend");
+ InvalidPluginConfigurationException exception =
+ assertThrows(
+ InvalidPluginConfigurationException.class, () -> cfgSnapshot().getBackend("master"));
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo(
+ String.format(
+ "Invalid configuration of the code-owners plugin. Code owner backend"
+ + " 'non-existing-backend' that is configured for project %s in"
+ + " code-owners.config (parameter codeOwners.master.backend) not found.",
+ project));
+ }
+
+ @Test
+ public void branchLevelBackendForOtherBranchHasNoEffect() throws Exception {
+ configureBackend(project, "foo", TestCodeOwnerBackend.ID);
+ try (AutoCloseable registration = registerTestBackend()) {
+ assertThat(cfgSnapshot().getBackend("master")).isInstanceOf(FindOwnersBackend.class);
+ }
+ }
+
+ @Test
+ public void getDefaultRequiredApprovalWhenNoRequiredApprovalIsConfigured() throws Exception {
+ RequiredApproval requiredApproval = cfgSnapshot().getRequiredApproval();
+ assertThat(requiredApproval).hasLabelNameThat().isEqualTo(RequiredApprovalConfig.DEFAULT_LABEL);
+ assertThat(requiredApproval).hasValueThat().isEqualTo(RequiredApprovalConfig.DEFAULT_VALUE);
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.requiredApproval", value = "Code-Review+2")
+ public void getConfiguredDefaultRequireApproval() throws Exception {
+ RequiredApproval requiredApproval = cfgSnapshot().getRequiredApproval();
+ assertThat(requiredApproval).hasLabelNameThat().isEqualTo("Code-Review");
+ assertThat(requiredApproval).hasValueThat().isEqualTo(2);
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.requiredApproval", value = "Foo-Bar+1")
+ public void cannotGetRequiredApprovalIfNonExistingLabelIsConfiguredAsRequiredApproval()
+ throws Exception {
+ InvalidPluginConfigurationException exception =
+ assertThrows(
+ InvalidPluginConfigurationException.class, () -> cfgSnapshot().getRequiredApproval());
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo(
+ String.format(
+ "Invalid configuration of the code-owners plugin. Required approval 'Foo-Bar+1'"
+ + " that is configured in gerrit.config (parameter"
+ + " plugin.code-owners.requiredApproval) is invalid: Label Foo-Bar doesn't exist"
+ + " for project %s.",
+ project.get()));
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.requiredApproval", value = "Code-Review+3")
+ public void cannotGetRequiredApprovalIfNonExistingLabelValueIsConfiguredAsRequiredApproval()
+ throws Exception {
+ InvalidPluginConfigurationException exception =
+ assertThrows(
+ InvalidPluginConfigurationException.class, () -> cfgSnapshot().getRequiredApproval());
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo(
+ String.format(
+ "Invalid configuration of the code-owners plugin. Required approval"
+ + " 'Code-Review+3' that is configured in gerrit.config (parameter"
+ + " plugin.code-owners.requiredApproval) is invalid: Label Code-Review on"
+ + " project %s doesn't allow value 3.",
+ project.get()));
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.requiredApproval", value = "INVALID")
+ public void cannotGetRequiredApprovalIfInvalidRequiredApprovalIsConfigured() throws Exception {
+ InvalidPluginConfigurationException exception =
+ assertThrows(
+ InvalidPluginConfigurationException.class, () -> cfgSnapshot().getRequiredApproval());
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo(
+ "Invalid configuration of the code-owners plugin. Required approval 'INVALID' that is"
+ + " configured in gerrit.config (parameter plugin.code-owners.requiredApproval) is"
+ + " invalid: Invalid format, expected '<label-name>+<label-value>'.");
+ }
+
+ @Test
+ public void getRequiredApprovalConfiguredOnProjectLevel() throws Exception {
+ configureRequiredApproval(project, "Code-Review+2");
+ RequiredApproval requiredApproval = cfgSnapshot().getRequiredApproval();
+ assertThat(requiredApproval).hasLabelNameThat().isEqualTo("Code-Review");
+ assertThat(requiredApproval).hasValueThat().isEqualTo(2);
+ }
+
+ @Test
+ public void getRequiredApprovalMultipleConfiguredOnProjectLevel() throws Exception {
+ setCodeOwnersConfig(
+ project,
+ /* subsection= */ null,
+ RequiredApprovalConfig.KEY_REQUIRED_APPROVAL,
+ ImmutableList.of("Code-Review+2", "Code-Review+1"));
+
+ // If multiple values are set for a key, the last value wins.
+ RequiredApproval requiredApproval = cfgSnapshot().getRequiredApproval();
+ assertThat(requiredApproval).hasLabelNameThat().isEqualTo("Code-Review");
+ assertThat(requiredApproval).hasValueThat().isEqualTo(1);
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.requiredApproval", value = "Code-Review+1")
+ public void requiredApprovalConfiguredOnProjectLevelOverridesDefaultRequiredApproval()
+ throws Exception {
+ configureRequiredApproval(project, "Code-Review+2");
+ RequiredApproval requiredApproval = cfgSnapshot().getRequiredApproval();
+ assertThat(requiredApproval).hasLabelNameThat().isEqualTo("Code-Review");
+ assertThat(requiredApproval).hasValueThat().isEqualTo(2);
+ }
+
+ @Test
+ public void requiredApprovalIsInheritedFromParentProject() throws Exception {
+ configureRequiredApproval(allProjects, "Code-Review+2");
+ RequiredApproval requiredApproval = cfgSnapshot().getRequiredApproval();
+ assertThat(requiredApproval).hasLabelNameThat().isEqualTo("Code-Review");
+ assertThat(requiredApproval).hasValueThat().isEqualTo(2);
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.backend", value = FindOwnersBackend.ID)
+ public void inheritedRequiredApprovalOverridesDefaultRequiredApproval() throws Exception {
+ configureRequiredApproval(allProjects, "Code-Review+2");
+ RequiredApproval requiredApproval = cfgSnapshot().getRequiredApproval();
+ assertThat(requiredApproval).hasLabelNameThat().isEqualTo("Code-Review");
+ assertThat(requiredApproval).hasValueThat().isEqualTo(2);
+ }
+
+ @Test
+ public void projectLevelRequiredApprovalOverridesInheritedRequiredApproval() throws Exception {
+ configureRequiredApproval(allProjects, "Code-Review+1");
+ configureRequiredApproval(project, "Code-Review+2");
+ RequiredApproval requiredApproval = cfgSnapshot().getRequiredApproval();
+ assertThat(requiredApproval).hasLabelNameThat().isEqualTo("Code-Review");
+ assertThat(requiredApproval).hasValueThat().isEqualTo(2);
+ }
+
+ @Test
+ public void
+ cannotGetRequiredApprovalIfNonExistingLabelIsConfiguredAsRequiredApprovalOnProjectLevel()
+ throws Exception {
+ configureRequiredApproval(project, "Foo-Bar+1");
+ InvalidPluginConfigurationException exception =
+ assertThrows(
+ InvalidPluginConfigurationException.class, () -> cfgSnapshot().getRequiredApproval());
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo(
+ String.format(
+ "Invalid configuration of the code-owners plugin. Required approval 'Foo-Bar+1'"
+ + " that is configured in code-owners.config (parameter"
+ + " codeOwners.requiredApproval) is invalid: Label Foo-Bar doesn't exist for"
+ + " project %s.",
+ project.get()));
+ }
+
+ @Test
+ public void
+ cannotGetRequiredApprovalIfNonExistingLabelValueIsConfiguredAsRequiredApprovalOnProjectLevel()
+ throws Exception {
+ configureRequiredApproval(project, "Code-Review+3");
+ InvalidPluginConfigurationException exception =
+ assertThrows(
+ InvalidPluginConfigurationException.class, () -> cfgSnapshot().getRequiredApproval());
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo(
+ String.format(
+ "Invalid configuration of the code-owners plugin. Required approval"
+ + " 'Code-Review+3' that is configured in code-owners.config (parameter"
+ + " codeOwners.requiredApproval) is invalid: Label Code-Review on project %s"
+ + " doesn't allow value 3.",
+ project.get()));
+ }
+
+ @Test
+ public void cannotGetRequiredApprovalIfInvalidRequiredApprovalIsConfiguredOnProjectLevel()
+ throws Exception {
+ configureRequiredApproval(project, "INVALID");
+ InvalidPluginConfigurationException exception =
+ assertThrows(
+ InvalidPluginConfigurationException.class, () -> cfgSnapshot().getRequiredApproval());
+ assertThat(exception)
+ .hasMessageThat()
+ .isEqualTo(
+ "Invalid configuration of the code-owners plugin. Required approval 'INVALID' that is"
+ + " configured in code-owners.config (parameter codeOwners.requiredApproval) is"
+ + " invalid: Invalid format, expected '<label-name>+<label-value>'.");
+ }
+
+ @Test
+ public void projectLevelRequiredApprovalForOtherProjectHasNoEffect() throws Exception {
+ Project.NameKey otherProject = projectOperations.newProject().create();
+ configureRequiredApproval(otherProject, "Code-Review+2");
+ RequiredApproval requiredApproval = cfgSnapshot().getRequiredApproval();
+ assertThat(requiredApproval).hasLabelNameThat().isEqualTo("Code-Review");
+ assertThat(requiredApproval).hasValueThat().isEqualTo(1);
+ }
+
+ @Test
+ public void getOverrideApprovalWhenNoRequiredApprovalIsConfigured() throws Exception {
+ assertThat(cfgSnapshot().getOverrideApproval()).isEmpty();
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.overrideApproval", value = "Code-Review+2")
+ public void getConfiguredDefaultOverrideApproval() throws Exception {
+ ImmutableSet<RequiredApproval> requiredApproval = cfgSnapshot().getOverrideApproval();
+ assertThat(requiredApproval).hasSize(1);
+ assertThat(requiredApproval).element(0).hasLabelNameThat().isEqualTo("Code-Review");
+ assertThat(requiredApproval).element(0).hasValueThat().isEqualTo(2);
+ }
+
+ @Test
+ public void getOverrideApprovalConfiguredOnProjectLevel() throws Exception {
+ configureOverrideApproval(project, "Code-Review+2");
+ ImmutableSet<RequiredApproval> requiredApproval = cfgSnapshot().getOverrideApproval();
+ assertThat(requiredApproval).hasSize(1);
+ assertThat(requiredApproval).element(0).hasLabelNameThat().isEqualTo("Code-Review");
+ assertThat(requiredApproval).element(0).hasValueThat().isEqualTo(2);
+ }
+
+ @Test
+ public void getOverrideApprovalMultipleConfiguredOnProjectLevel() throws Exception {
+ createOwnersOverrideLabel();
+ createOwnersOverrideLabel("Other-Override");
+
+ setCodeOwnersConfig(
+ project,
+ /* subsection= */ null,
+ OverrideApprovalConfig.KEY_OVERRIDE_APPROVAL,
+ ImmutableList.of("Owners-Override+1", "Other-Override+1"));
+
+ ImmutableSet<RequiredApproval> requiredApprovals = cfgSnapshot().getOverrideApproval();
+ assertThat(
+ requiredApprovals.stream()
+ .map(requiredApproval -> requiredApproval.toString())
+ .collect(toImmutableSet()))
+ .containsExactly("Owners-Override+1", "Other-Override+1");
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.overrideApproval", value = "INVALID")
+ public void getOverrideApprovalIfInvalidOverrideApprovalIsConfigured() throws Exception {
+ assertThat(cfgSnapshot().getOverrideApproval()).isEmpty();
+ }
+
+ @Test
+ public void getOverrideApprovalIfInvalidOverrideApprovalIsConfiguredOnProjectLevel()
+ throws Exception {
+ configureOverrideApproval(project, "INVALID");
+ assertThat(cfgSnapshot().getOverrideApproval()).isEmpty();
+ }
+
+ @Test
+ public void getOverrideApprovalDuplicatesAreFilteredOut() throws Exception {
+ setCodeOwnersConfig(
+ project,
+ /* subsection= */ null,
+ OverrideApprovalConfig.KEY_OVERRIDE_APPROVAL,
+ ImmutableList.of("Code-Review+2", "Code-Review+1", "Code-Review+2"));
+
+ // If multiple values are set for a key, the last value wins.
+ ImmutableSet<RequiredApproval> requiredApproval = cfgSnapshot().getOverrideApproval();
+ assertThat(requiredApproval).hasSize(1);
+ assertThat(requiredApproval).element(0).hasLabelNameThat().isEqualTo("Code-Review");
+ assertThat(requiredApproval).element(0).hasValueThat().isEqualTo(1);
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.enableImplicitApprovals", value = "true")
+ public void implicitApprovalsAreDisabledIfRequiredLabelIgnoresSelfApprovals() throws Exception {
+ assertThat(cfgSnapshot().areImplicitApprovalsEnabled()).isTrue();
+
+ LabelDefinitionInput input = new LabelDefinitionInput();
+ input.ignoreSelfApproval = true;
+ gApi.projects().name(allProjects.get()).label("Code-Review").update(input);
+ assertThat(cfgSnapshot().areImplicitApprovalsEnabled()).isFalse();
+ }
+
+ private CodeOwnersPluginConfigSnapshot cfgSnapshot() {
+ return codeOwnersPluginConfigSnapshotFactory.create(project);
+ }
+
+ private void configureFileExtension(Project.NameKey project, String fileExtension)
+ throws Exception {
+ setCodeOwnersConfig(
+ project, /* subsection= */ null, GeneralConfig.KEY_FILE_EXTENSION, fileExtension);
+ }
+
+ private void configureMergeCommitStrategy(
+ Project.NameKey project, MergeCommitStrategy mergeCommitStrategy) throws Exception {
+ setCodeOwnersConfig(
+ project,
+ /* subsection= */ null,
+ GeneralConfig.KEY_MERGE_COMMIT_STRATEGY,
+ mergeCommitStrategy.name());
+ }
+
+ private void configureFallbackCodeOwners(
+ Project.NameKey project, FallbackCodeOwners fallbackCodeOwners) throws Exception {
+ setCodeOwnersConfig(
+ project,
+ /* subsection= */ null,
+ GeneralConfig.KEY_FALLBACK_CODE_OWNERS,
+ fallbackCodeOwners.name());
+ }
+
+ private void configureMaxPathsInChangeMessages(
+ Project.NameKey project, int maxPathsInChangeMessages) throws Exception {
+ setCodeOwnersConfig(
+ project,
+ /* subsection= */ null,
+ GeneralConfig.KEY_MAX_PATHS_IN_CHANGE_MESSAGES,
+ Integer.toString(maxPathsInChangeMessages));
+ }
+
+ private void configureDisabled(Project.NameKey project, String disabled) throws Exception {
+ setCodeOwnersConfig(project, /* subsection= */ null, StatusConfig.KEY_DISABLED, disabled);
+ }
+
+ private void configureDisabledBranch(Project.NameKey project, String disabledBranch)
+ throws Exception {
+ setCodeOwnersConfig(
+ project, /* subsection= */ null, StatusConfig.KEY_DISABLED_BRANCH, disabledBranch);
+ }
+
+ private void enableCodeOwnersForAllBranches(Project.NameKey project) throws Exception {
+ setCodeOwnersConfig(project, /* subsection= */ null, StatusConfig.KEY_DISABLED_BRANCH, "");
+ }
+
+ private void configureBackend(Project.NameKey project, String backendName) throws Exception {
+ configureBackend(project, /* branch= */ null, backendName);
+ }
+
+ private void configureBackend(
+ Project.NameKey project, @Nullable String branch, String backendName) throws Exception {
+ setCodeOwnersConfig(project, branch, BackendConfig.KEY_BACKEND, backendName);
+ }
+
+ private void configureRequiredApproval(Project.NameKey project, String requiredApproval)
+ throws Exception {
+ setCodeOwnersConfig(
+ project,
+ /* subsection= */ null,
+ RequiredApprovalConfig.KEY_REQUIRED_APPROVAL,
+ requiredApproval);
+ }
+
+ private void configureOverrideApproval(Project.NameKey project, String requiredApproval)
+ throws Exception {
+ setCodeOwnersConfig(
+ project,
+ /* subsection= */ null,
+ OverrideApprovalConfig.KEY_OVERRIDE_APPROVAL,
+ requiredApproval);
+ }
+
+ private AutoCloseable registerTestBackend() {
+ RegistrationHandle registrationHandle =
+ ((PrivateInternals_DynamicMapImpl<CodeOwnerBackend>) codeOwnerBackends)
+ .put("gerrit", TestCodeOwnerBackend.ID, Providers.of(new TestCodeOwnerBackend()));
+ return registrationHandle::remove;
+ }
+
+ private static class TestCodeOwnerBackend implements CodeOwnerBackend {
+ static final String ID = "test-backend";
+
+ @Override
+ public Optional<CodeOwnerConfig> getCodeOwnerConfig(
+ CodeOwnerConfig.Key codeOwnerConfigKey,
+ @Nullable RevWalk revWalk,
+ @Nullable ObjectId revision) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ public Optional<CodeOwnerConfig> upsertCodeOwnerConfig(
+ CodeOwnerConfig.Key codeOwnerConfigKey,
+ CodeOwnerConfigUpdate codeOwnerConfigUpdate,
+ @Nullable IdentifiedUser currentUser) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ public boolean isCodeOwnerConfigFile(NameKey project, String fileName) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ public Path getFilePath(CodeOwnerConfig.Key codeOwnerConfigKey) {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ @Override
+ public Optional<PathExpressionMatcher> getPathExpressionMatcher() {
+ return Optional.empty();
+ }
+ }
+}
diff --git a/javatests/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigurationTest.java b/javatests/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigurationTest.java
index 72d6d75..71c6849 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigurationTest.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigurationTest.java
@@ -14,42 +14,13 @@
package com.google.gerrit.plugins.codeowners.backend.config;
-import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.plugins.codeowners.testing.RequiredApprovalSubject.assertThat;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
-import static com.google.gerrit.truth.OptionalSubject.assertThat;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
import com.google.gerrit.acceptance.config.GerritConfig;
-import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
-import com.google.gerrit.common.Nullable;
-import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.entities.Project;
-import com.google.gerrit.entities.Project.NameKey;
-import com.google.gerrit.entities.RefNames;
-import com.google.gerrit.extensions.common.LabelDefinitionInput;
-import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.registration.PrivateInternals_DynamicMapImpl;
-import com.google.gerrit.extensions.registration.RegistrationHandle;
import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
import com.google.gerrit.plugins.codeowners.acceptance.AbstractCodeOwnersTest;
-import com.google.gerrit.plugins.codeowners.backend.CodeOwnerBackend;
-import com.google.gerrit.plugins.codeowners.backend.CodeOwnerConfig;
-import com.google.gerrit.plugins.codeowners.backend.CodeOwnerConfigUpdate;
-import com.google.gerrit.plugins.codeowners.backend.FallbackCodeOwners;
-import com.google.gerrit.plugins.codeowners.backend.PathExpressionMatcher;
-import com.google.gerrit.plugins.codeowners.backend.findowners.FindOwnersBackend;
-import com.google.gerrit.plugins.codeowners.common.MergeCommitStrategy;
-import com.google.gerrit.server.IdentifiedUser;
-import com.google.inject.Inject;
-import com.google.inject.Key;
-import com.google.inject.util.Providers;
-import java.nio.file.Path;
-import java.util.Optional;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.revwalk.RevWalk;
import org.junit.Before;
import org.junit.Test;
@@ -58,408 +29,30 @@
* com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfiguration}.
*/
public class CodeOwnersPluginConfigurationTest extends AbstractCodeOwnersTest {
- @Inject private ProjectOperations projectOperations;
-
private CodeOwnersPluginConfiguration codeOwnersPluginConfiguration;
- private DynamicMap<CodeOwnerBackend> codeOwnerBackends;
@Before
public void setUpCodeOwnersPlugin() throws Exception {
codeOwnersPluginConfiguration =
plugin.getSysInjector().getInstance(CodeOwnersPluginConfiguration.class);
- codeOwnerBackends =
- plugin.getSysInjector().getInstance(new Key<DynamicMap<CodeOwnerBackend>>() {});
}
@Test
- public void cannotCheckForNullProjectIfCodeOwnersFunctionalityIsDisabled() throws Exception {
+ public void cannotGetProjectConfigForNullProject() throws Exception {
NullPointerException npe =
assertThrows(
NullPointerException.class,
- () -> codeOwnersPluginConfiguration.isDisabled(/* project= */ (Project.NameKey) null));
- assertThat(npe).hasMessageThat().isEqualTo("project");
+ () -> codeOwnersPluginConfiguration.getProjectConfig(/* projectName= */ null));
+ assertThat(npe).hasMessageThat().isEqualTo("projectName");
}
@Test
- public void cannotCheckForNullBranchIfCodeOwnersFunctionalityIsDisabled() throws Exception {
- NullPointerException npe =
- assertThrows(
- NullPointerException.class,
- () ->
- codeOwnersPluginConfiguration.isDisabled(
- /* branchNameKey= */ (BranchNameKey) null));
- assertThat(npe).hasMessageThat().isEqualTo("branchNameKey");
- }
-
- @Test
- public void cannotCheckIfCodeOwnersFunctionalityIsDisabledForNonExistingProject()
- throws Exception {
+ public void cannotGetProjectConfigForNonExistingProject() throws Exception {
IllegalStateException exception =
assertThrows(
IllegalStateException.class,
() ->
- codeOwnersPluginConfiguration.isDisabled(Project.nameKey("non-existing-project")));
- assertThat(exception)
- .hasMessageThat()
- .isEqualTo(
- "cannot get code-owners plugin config for non-existing project non-existing-project");
- }
-
- @Test
- public void cannotCheckIfCodeOwnersFunctionalityIsDisabledForBranchOfNonExistingProject()
- throws Exception {
- IllegalStateException exception =
- assertThrows(
- IllegalStateException.class,
- () ->
- codeOwnersPluginConfiguration.isDisabled(
- BranchNameKey.create(Project.nameKey("non-existing-project"), "master")));
- assertThat(exception)
- .hasMessageThat()
- .isEqualTo(
- "cannot get code-owners plugin config for non-existing project non-existing-project");
- }
-
- @Test
- public void checkIfCodeOwnersFunctionalityIsDisabledForNonExistingBranch() throws Exception {
- assertThat(
- codeOwnersPluginConfiguration.isDisabled(BranchNameKey.create(project, "non-existing")))
- .isFalse();
- }
-
- @Test
- public void checkIfCodeOwnersFunctionalityIsDisabledForProjectWithEmptyConfig() throws Exception {
- assertThat(codeOwnersPluginConfiguration.isDisabled(project)).isFalse();
- }
-
- @Test
- public void checkIfCodeOwnersFunctionalityIsDisabledForBranchWithEmptyConfig() throws Exception {
- assertThat(codeOwnersPluginConfiguration.isDisabled(BranchNameKey.create(project, "master")))
- .isFalse();
- }
-
- @Test
- public void codeOwnersFunctionalityIsDisabledForProject() throws Exception {
- disableCodeOwnersForProject(project);
- assertThat(codeOwnersPluginConfiguration.isDisabled(project)).isTrue();
- }
-
- @Test
- public void codeOwnersFunctionalityIsDisabledForBranchIfItIsDisabledForProject()
- throws Exception {
- disableCodeOwnersForProject(project);
- assertThat(codeOwnersPluginConfiguration.isDisabled(BranchNameKey.create(project, "master")))
- .isTrue();
- }
-
- @Test
- public void codeOwnersFunctionalityIsDisabledForBranch_exactRef() throws Exception {
- configureDisabledBranch(project, "refs/heads/master");
- assertThat(codeOwnersPluginConfiguration.isDisabled(BranchNameKey.create(project, "master")))
- .isTrue();
- assertThat(codeOwnersPluginConfiguration.isDisabled(BranchNameKey.create(project, "other")))
- .isFalse();
- }
-
- @Test
- public void codeOwnersFunctionalityIsDisabledForBranch_refPattern() throws Exception {
- configureDisabledBranch(project, "refs/heads/*");
- assertThat(codeOwnersPluginConfiguration.isDisabled(BranchNameKey.create(project, "master")))
- .isTrue();
- assertThat(codeOwnersPluginConfiguration.isDisabled(BranchNameKey.create(project, "other")))
- .isTrue();
- assertThat(
- codeOwnersPluginConfiguration.isDisabled(
- BranchNameKey.create(project, RefNames.REFS_META)))
- .isFalse();
- }
-
- @Test
- public void codeOwnersFunctionalityIsDisabledForBranch_regularExpression() throws Exception {
- configureDisabledBranch(project, "^refs/heads/.*");
- assertThat(codeOwnersPluginConfiguration.isDisabled(BranchNameKey.create(project, "master")))
- .isTrue();
- assertThat(codeOwnersPluginConfiguration.isDisabled(BranchNameKey.create(project, "other")))
- .isTrue();
- assertThat(
- codeOwnersPluginConfiguration.isDisabled(
- BranchNameKey.create(project, RefNames.REFS_META)))
- .isFalse();
- }
-
- @Test
- public void codeOwnersFunctionalityIsDisabledForBranch_invalidRegularExpression()
- throws Exception {
- configureDisabledBranch(project, "^refs/heads/[");
- assertThat(codeOwnersPluginConfiguration.isDisabled(BranchNameKey.create(project, "master")))
- .isFalse();
- }
-
- @Test
- public void disabledIsInheritedFromParentProject() throws Exception {
- disableCodeOwnersForProject(allProjects);
- assertThat(codeOwnersPluginConfiguration.isDisabled(project)).isTrue();
- }
-
- @Test
- public void inheritedDisabledAlsoCountsForBranch() throws Exception {
- disableCodeOwnersForProject(allProjects);
- assertThat(codeOwnersPluginConfiguration.isDisabled(BranchNameKey.create(project, "master")))
- .isTrue();
- }
-
- @Test
- public void inheritedDisabledValueIsIgnoredIfInvalid() throws Exception {
- configureDisabled(project, "invalid");
- assertThat(codeOwnersPluginConfiguration.isDisabled(project)).isFalse();
- }
-
- @Test
- public void inheritedDisabledValueIsIgnoredForBranchIfInvalid() throws Exception {
- configureDisabled(project, "invalid");
- assertThat(codeOwnersPluginConfiguration.isDisabled(BranchNameKey.create(project, "master")))
- .isFalse();
- }
-
- @Test
- public void disabledForOtherProjectHasNoEffect() throws Exception {
- Project.NameKey otherProject = projectOperations.newProject().create();
- disableCodeOwnersForProject(otherProject);
- assertThat(codeOwnersPluginConfiguration.isDisabled(project)).isFalse();
- }
-
- @Test
- public void disabledBranchForOtherProjectHasNoEffect() throws Exception {
- Project.NameKey otherProject = projectOperations.newProject().create();
- configureDisabledBranch(otherProject, "refs/heads/master");
- assertThat(codeOwnersPluginConfiguration.isDisabled(BranchNameKey.create(project, "master")))
- .isFalse();
- }
-
- @Test
- public void disabledBranchIsInheritedFromParentProject() throws Exception {
- configureDisabledBranch(allProjects, "refs/heads/master");
- assertThat(codeOwnersPluginConfiguration.isDisabled(BranchNameKey.create(project, "master")))
- .isTrue();
- }
-
- @Test
- public void inheritedDisabledCanBeOverridden() throws Exception {
- disableCodeOwnersForProject(allProjects);
- enableCodeOwnersForProject(project);
- assertThat(codeOwnersPluginConfiguration.isDisabled(BranchNameKey.create(project, "master")))
- .isFalse();
- }
-
- @Test
- public void inheritedDisabledBranchCanBeOverridden() throws Exception {
- configureDisabledBranch(allProjects, "refs/heads/master");
- enableCodeOwnersForAllBranches(project);
- assertThat(codeOwnersPluginConfiguration.isDisabled(BranchNameKey.create(project, "master")))
- .isFalse();
- }
-
- @Test
- public void cannotGetBackendForNonExistingProject() throws Exception {
- IllegalStateException exception =
- assertThrows(
- IllegalStateException.class,
- () ->
- codeOwnersPluginConfiguration.getBackend(
- BranchNameKey.create(Project.nameKey("non-existing-project"), "master")));
- assertThat(exception)
- .hasMessageThat()
- .isEqualTo(
- "cannot get code-owners plugin config for non-existing project non-existing-project");
- }
-
- @Test
- public void getBackendForNonExistingBranch() throws Exception {
- assertThat(
- codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "non-existing")))
- .isInstanceOf(FindOwnersBackend.class);
- }
-
- @Test
- public void getDefaultBackendWhenNoBackendIsConfigured() throws Exception {
- assertThat(codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")))
- .isInstanceOf(FindOwnersBackend.class);
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.backend", value = TestCodeOwnerBackend.ID)
- public void getConfiguredDefaultBackend() throws Exception {
- try (AutoCloseable registration = registerTestBackend()) {
- assertThat(codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")))
- .isInstanceOf(TestCodeOwnerBackend.class);
- }
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.backend", value = "non-existing-backend")
- public void cannotGetBackendIfNonExistingBackendIsConfigured() throws Exception {
- InvalidPluginConfigurationException exception =
- assertThrows(
- InvalidPluginConfigurationException.class,
- () ->
- codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")));
- assertThat(exception)
- .hasMessageThat()
- .isEqualTo(
- "Invalid configuration of the code-owners plugin. Code owner backend"
- + " 'non-existing-backend' that is configured in gerrit.config (parameter"
- + " plugin.code-owners.backend) not found.");
- }
-
- @Test
- public void getBackendConfiguredOnProjectLevel() throws Exception {
- configureBackend(project, TestCodeOwnerBackend.ID);
- try (AutoCloseable registration = registerTestBackend()) {
- assertThat(codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")))
- .isInstanceOf(TestCodeOwnerBackend.class);
- }
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.backend", value = FindOwnersBackend.ID)
- public void backendConfiguredOnProjectLevelOverridesDefaultBackend() throws Exception {
- configureBackend(project, TestCodeOwnerBackend.ID);
- try (AutoCloseable registration = registerTestBackend()) {
- assertThat(codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")))
- .isInstanceOf(TestCodeOwnerBackend.class);
- }
- }
-
- @Test
- public void backendIsInheritedFromParentProject() throws Exception {
- configureBackend(allProjects, TestCodeOwnerBackend.ID);
- try (AutoCloseable registration = registerTestBackend()) {
- assertThat(codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")))
- .isInstanceOf(TestCodeOwnerBackend.class);
- }
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.backend", value = FindOwnersBackend.ID)
- public void inheritedBackendOverridesDefaultBackend() throws Exception {
- configureBackend(allProjects, TestCodeOwnerBackend.ID);
- try (AutoCloseable registration = registerTestBackend()) {
- assertThat(codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")))
- .isInstanceOf(TestCodeOwnerBackend.class);
- }
- }
-
- @Test
- public void projectLevelBackendOverridesInheritedBackend() throws Exception {
- configureBackend(allProjects, TestCodeOwnerBackend.ID);
- configureBackend(project, FindOwnersBackend.ID);
- try (AutoCloseable registration = registerTestBackend()) {
- assertThat(codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")))
- .isInstanceOf(FindOwnersBackend.class);
- }
- }
-
- @Test
- public void cannotGetBackendIfNonExistingBackendIsConfiguredOnProjectLevel() throws Exception {
- configureBackend(project, "non-existing-backend");
- InvalidPluginConfigurationException exception =
- assertThrows(
- InvalidPluginConfigurationException.class,
- () ->
- codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")));
- assertThat(exception)
- .hasMessageThat()
- .isEqualTo(
- String.format(
- "Invalid configuration of the code-owners plugin. Code owner backend"
- + " 'non-existing-backend' that is configured for project %s in"
- + " code-owners.config (parameter codeOwners.backend) not found.",
- project));
- }
-
- @Test
- public void projectLevelBackendForOtherProjectHasNoEffect() throws Exception {
- Project.NameKey otherProject = projectOperations.newProject().create();
- configureBackend(otherProject, TestCodeOwnerBackend.ID);
- try (AutoCloseable registration = registerTestBackend()) {
- assertThat(codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")))
- .isInstanceOf(FindOwnersBackend.class);
- }
- }
-
- @Test
- public void getBackendConfiguredOnBranchLevel() throws Exception {
- configureBackend(project, "refs/heads/master", TestCodeOwnerBackend.ID);
- try (AutoCloseable registration = registerTestBackend()) {
- assertThat(codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")))
- .isInstanceOf(TestCodeOwnerBackend.class);
- }
- }
-
- @Test
- public void getBackendConfiguredOnBranchLevelShortName() throws Exception {
- configureBackend(project, "master", TestCodeOwnerBackend.ID);
- try (AutoCloseable registration = registerTestBackend()) {
- assertThat(codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")))
- .isInstanceOf(TestCodeOwnerBackend.class);
- }
- }
-
- @Test
- public void branchLevelBackendOnFullNameTakesPrecedenceOverBranchLevelBackendOnShortName()
- throws Exception {
- configureBackend(project, "master", TestCodeOwnerBackend.ID);
- configureBackend(project, "refs/heads/master", FindOwnersBackend.ID);
- try (AutoCloseable registration = registerTestBackend()) {
- assertThat(codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")))
- .isInstanceOf(FindOwnersBackend.class);
- }
- }
-
- @Test
- public void branchLevelBackendOverridesProjectLevelBackend() throws Exception {
- configureBackend(project, TestCodeOwnerBackend.ID);
- configureBackend(project, "master", FindOwnersBackend.ID);
- try (AutoCloseable registration = registerTestBackend()) {
- assertThat(codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")))
- .isInstanceOf(FindOwnersBackend.class);
- }
- }
-
- @Test
- public void cannotGetBackendIfNonExistingBackendIsConfiguredOnBranchLevel() throws Exception {
- configureBackend(project, "master", "non-existing-backend");
- InvalidPluginConfigurationException exception =
- assertThrows(
- InvalidPluginConfigurationException.class,
- () ->
- codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")));
- assertThat(exception)
- .hasMessageThat()
- .isEqualTo(
- String.format(
- "Invalid configuration of the code-owners plugin. Code owner backend"
- + " 'non-existing-backend' that is configured for project %s in"
- + " code-owners.config (parameter codeOwners.master.backend) not found.",
- project));
- }
-
- @Test
- public void branchLevelBackendForOtherBranchHasNoEffect() throws Exception {
- configureBackend(project, "foo", TestCodeOwnerBackend.ID);
- try (AutoCloseable registration = registerTestBackend()) {
- assertThat(codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")))
- .isInstanceOf(FindOwnersBackend.class);
- }
- }
-
- @Test
- public void cannotGetRequiredApprovalForNonExistingProject() throws Exception {
- IllegalStateException exception =
- assertThrows(
- IllegalStateException.class,
- () ->
- codeOwnersPluginConfiguration.getRequiredApproval(
+ codeOwnersPluginConfiguration.getProjectConfig(
Project.nameKey("non-existing-project")));
assertThat(exception)
.hasMessageThat()
@@ -468,285 +61,6 @@
}
@Test
- public void getDefaultRequiredApprovalWhenNoRequiredApprovalIsConfigured() throws Exception {
- RequiredApproval requiredApproval = codeOwnersPluginConfiguration.getRequiredApproval(project);
- assertThat(requiredApproval).hasLabelNameThat().isEqualTo(RequiredApprovalConfig.DEFAULT_LABEL);
- assertThat(requiredApproval).hasValueThat().isEqualTo(RequiredApprovalConfig.DEFAULT_VALUE);
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.requiredApproval", value = "Code-Review+2")
- public void getConfiguredDefaultRequireApproval() throws Exception {
- RequiredApproval requiredApproval = codeOwnersPluginConfiguration.getRequiredApproval(project);
- assertThat(requiredApproval).hasLabelNameThat().isEqualTo("Code-Review");
- assertThat(requiredApproval).hasValueThat().isEqualTo(2);
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.requiredApproval", value = "Foo-Bar+1")
- public void cannotGetRequiredApprovalIfNonExistingLabelIsConfiguredAsRequiredApproval()
- throws Exception {
- InvalidPluginConfigurationException exception =
- assertThrows(
- InvalidPluginConfigurationException.class,
- () -> codeOwnersPluginConfiguration.getRequiredApproval(project));
- assertThat(exception)
- .hasMessageThat()
- .isEqualTo(
- String.format(
- "Invalid configuration of the code-owners plugin. Required approval 'Foo-Bar+1'"
- + " that is configured in gerrit.config (parameter"
- + " plugin.code-owners.requiredApproval) is invalid: Label Foo-Bar doesn't exist"
- + " for project %s.",
- project.get()));
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.requiredApproval", value = "Code-Review+3")
- public void cannotGetRequiredApprovalIfNonExistingLabelValueIsConfiguredAsRequiredApproval()
- throws Exception {
- InvalidPluginConfigurationException exception =
- assertThrows(
- InvalidPluginConfigurationException.class,
- () -> codeOwnersPluginConfiguration.getRequiredApproval(project));
- assertThat(exception)
- .hasMessageThat()
- .isEqualTo(
- String.format(
- "Invalid configuration of the code-owners plugin. Required approval"
- + " 'Code-Review+3' that is configured in gerrit.config (parameter"
- + " plugin.code-owners.requiredApproval) is invalid: Label Code-Review on"
- + " project %s doesn't allow value 3.",
- project.get()));
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.requiredApproval", value = "INVALID")
- public void cannotGetRequiredApprovalIfInvalidRequiredApprovalIsConfigured() throws Exception {
- InvalidPluginConfigurationException exception =
- assertThrows(
- InvalidPluginConfigurationException.class,
- () -> codeOwnersPluginConfiguration.getRequiredApproval(project));
- assertThat(exception)
- .hasMessageThat()
- .isEqualTo(
- "Invalid configuration of the code-owners plugin. Required approval 'INVALID' that is"
- + " configured in gerrit.config (parameter plugin.code-owners.requiredApproval) is"
- + " invalid: Invalid format, expected '<label-name>+<label-value>'.");
- }
-
- @Test
- public void getRequiredApprovalConfiguredOnProjectLevel() throws Exception {
- configureRequiredApproval(project, "Code-Review+2");
- RequiredApproval requiredApproval = codeOwnersPluginConfiguration.getRequiredApproval(project);
- assertThat(requiredApproval).hasLabelNameThat().isEqualTo("Code-Review");
- assertThat(requiredApproval).hasValueThat().isEqualTo(2);
- }
-
- @Test
- public void getRequiredApprovalMultipleConfiguredOnProjectLevel() throws Exception {
- setCodeOwnersConfig(
- project,
- /* subsection= */ null,
- RequiredApprovalConfig.KEY_REQUIRED_APPROVAL,
- ImmutableList.of("Code-Review+2", "Code-Review+1"));
-
- // If multiple values are set for a key, the last value wins.
- RequiredApproval requiredApproval = codeOwnersPluginConfiguration.getRequiredApproval(project);
- assertThat(requiredApproval).hasLabelNameThat().isEqualTo("Code-Review");
- assertThat(requiredApproval).hasValueThat().isEqualTo(1);
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.requiredApproval", value = "Code-Review+1")
- public void requiredApprovalConfiguredOnProjectLevelOverridesDefaultRequiredApproval()
- throws Exception {
- configureRequiredApproval(project, "Code-Review+2");
- RequiredApproval requiredApproval = codeOwnersPluginConfiguration.getRequiredApproval(project);
- assertThat(requiredApproval).hasLabelNameThat().isEqualTo("Code-Review");
- assertThat(requiredApproval).hasValueThat().isEqualTo(2);
- }
-
- @Test
- public void requiredApprovalIsInheritedFromParentProject() throws Exception {
- configureRequiredApproval(allProjects, "Code-Review+2");
- RequiredApproval requiredApproval = codeOwnersPluginConfiguration.getRequiredApproval(project);
- assertThat(requiredApproval).hasLabelNameThat().isEqualTo("Code-Review");
- assertThat(requiredApproval).hasValueThat().isEqualTo(2);
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.backend", value = FindOwnersBackend.ID)
- public void inheritedRequiredApprovalOverridesDefaultRequiredApproval() throws Exception {
- configureRequiredApproval(allProjects, "Code-Review+2");
- RequiredApproval requiredApproval = codeOwnersPluginConfiguration.getRequiredApproval(project);
- assertThat(requiredApproval).hasLabelNameThat().isEqualTo("Code-Review");
- assertThat(requiredApproval).hasValueThat().isEqualTo(2);
- }
-
- @Test
- public void projectLevelRequiredApprovalOverridesInheritedRequiredApproval() throws Exception {
- configureRequiredApproval(allProjects, "Code-Review+1");
- configureRequiredApproval(project, "Code-Review+2");
- RequiredApproval requiredApproval = codeOwnersPluginConfiguration.getRequiredApproval(project);
- assertThat(requiredApproval).hasLabelNameThat().isEqualTo("Code-Review");
- assertThat(requiredApproval).hasValueThat().isEqualTo(2);
- }
-
- @Test
- public void
- cannotGetRequiredApprovalIfNonExistingLabelIsConfiguredAsRequiredApprovalOnProjectLevel()
- throws Exception {
- configureRequiredApproval(project, "Foo-Bar+1");
- InvalidPluginConfigurationException exception =
- assertThrows(
- InvalidPluginConfigurationException.class,
- () -> codeOwnersPluginConfiguration.getRequiredApproval(project));
- assertThat(exception)
- .hasMessageThat()
- .isEqualTo(
- String.format(
- "Invalid configuration of the code-owners plugin. Required approval 'Foo-Bar+1'"
- + " that is configured in code-owners.config (parameter"
- + " codeOwners.requiredApproval) is invalid: Label Foo-Bar doesn't exist for"
- + " project %s.",
- project.get()));
- }
-
- @Test
- public void
- cannotGetRequiredApprovalIfNonExistingLabelValueIsConfiguredAsRequiredApprovalOnProjectLevel()
- throws Exception {
- configureRequiredApproval(project, "Code-Review+3");
- InvalidPluginConfigurationException exception =
- assertThrows(
- InvalidPluginConfigurationException.class,
- () -> codeOwnersPluginConfiguration.getRequiredApproval(project));
- assertThat(exception)
- .hasMessageThat()
- .isEqualTo(
- String.format(
- "Invalid configuration of the code-owners plugin. Required approval"
- + " 'Code-Review+3' that is configured in code-owners.config (parameter"
- + " codeOwners.requiredApproval) is invalid: Label Code-Review on project %s"
- + " doesn't allow value 3.",
- project.get()));
- }
-
- @Test
- public void cannotGetRequiredApprovalIfInvalidRequiredApprovalIsConfiguredOnProjectLevel()
- throws Exception {
- configureRequiredApproval(project, "INVALID");
- InvalidPluginConfigurationException exception =
- assertThrows(
- InvalidPluginConfigurationException.class,
- () -> codeOwnersPluginConfiguration.getRequiredApproval(project));
- assertThat(exception)
- .hasMessageThat()
- .isEqualTo(
- "Invalid configuration of the code-owners plugin. Required approval 'INVALID' that is"
- + " configured in code-owners.config (parameter codeOwners.requiredApproval) is"
- + " invalid: Invalid format, expected '<label-name>+<label-value>'.");
- }
-
- @Test
- public void projectLevelRequiredApprovalForOtherProjectHasNoEffect() throws Exception {
- Project.NameKey otherProject = projectOperations.newProject().create();
- configureRequiredApproval(otherProject, "Code-Review+2");
- RequiredApproval requiredApproval = codeOwnersPluginConfiguration.getRequiredApproval(project);
- assertThat(requiredApproval).hasLabelNameThat().isEqualTo("Code-Review");
- assertThat(requiredApproval).hasValueThat().isEqualTo(1);
- }
-
- @Test
- public void cannotGetOverrideApprovalForNonExistingProject() throws Exception {
- IllegalStateException exception =
- assertThrows(
- IllegalStateException.class,
- () ->
- codeOwnersPluginConfiguration.getOverrideApproval(
- Project.nameKey("non-existing-project")));
- assertThat(exception)
- .hasMessageThat()
- .isEqualTo(
- "cannot get code-owners plugin config for non-existing project non-existing-project");
- }
-
- @Test
- public void getOverrideApprovalWhenNoRequiredApprovalIsConfigured() throws Exception {
- assertThat(codeOwnersPluginConfiguration.getOverrideApproval(project)).isEmpty();
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.overrideApproval", value = "Code-Review+2")
- public void getConfiguredDefaultOverrideApproval() throws Exception {
- ImmutableSet<RequiredApproval> requiredApproval =
- codeOwnersPluginConfiguration.getOverrideApproval(project);
- assertThat(requiredApproval).hasSize(1);
- assertThat(requiredApproval).element(0).hasLabelNameThat().isEqualTo("Code-Review");
- assertThat(requiredApproval).element(0).hasValueThat().isEqualTo(2);
- }
-
- @Test
- public void getOverrideApprovalConfiguredOnProjectLevel() throws Exception {
- configureOverrideApproval(project, "Code-Review+2");
- ImmutableSet<RequiredApproval> requiredApproval =
- codeOwnersPluginConfiguration.getOverrideApproval(project);
- assertThat(requiredApproval).hasSize(1);
- assertThat(requiredApproval).element(0).hasLabelNameThat().isEqualTo("Code-Review");
- assertThat(requiredApproval).element(0).hasValueThat().isEqualTo(2);
- }
-
- @Test
- public void getOverrideApprovalMultipleConfiguredOnProjectLevel() throws Exception {
- createOwnersOverrideLabel();
- createOwnersOverrideLabel("Other-Override");
-
- setCodeOwnersConfig(
- project,
- /* subsection= */ null,
- OverrideApprovalConfig.KEY_OVERRIDE_APPROVAL,
- ImmutableList.of("Owners-Override+1", "Other-Override+1"));
-
- ImmutableSet<RequiredApproval> requiredApprovals =
- codeOwnersPluginConfiguration.getOverrideApproval(project);
- assertThat(
- requiredApprovals.stream()
- .map(requiredApproval -> requiredApproval.toString())
- .collect(toImmutableSet()))
- .containsExactly("Owners-Override+1", "Other-Override+1");
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.overrideApproval", value = "INVALID")
- public void getOverrideApprovalIfInvalidOverrideApprovalIsConfigured() throws Exception {
- assertThat(codeOwnersPluginConfiguration.getOverrideApproval(project)).isEmpty();
- }
-
- @Test
- public void getOverrideApprovalIfInvalidOverrideApprovalIsConfiguredOnProjectLevel()
- throws Exception {
- configureOverrideApproval(project, "INVALID");
- assertThat(codeOwnersPluginConfiguration.getOverrideApproval(project)).isEmpty();
- }
-
- @Test
- public void getOverrideApprovalDuplicatesAreFilteredOut() throws Exception {
- setCodeOwnersConfig(
- project,
- /* subsection= */ null,
- OverrideApprovalConfig.KEY_OVERRIDE_APPROVAL,
- ImmutableList.of("Code-Review+2", "Code-Review+1", "Code-Review+2"));
-
- // If multiple values are set for a key, the last value wins.
- ImmutableSet<RequiredApproval> requiredApproval =
- codeOwnersPluginConfiguration.getOverrideApproval(project);
- assertThat(requiredApproval).hasSize(1);
- assertThat(requiredApproval).element(0).hasLabelNameThat().isEqualTo("Code-Review");
- assertThat(requiredApproval).element(0).hasValueThat().isEqualTo(1);
- }
-
- @Test
@GerritConfig(name = "plugin.code-owners.enableExperimentalRestEndpoints", value = "false")
public void checkExperimentalRestEndpointsEnabledThrowsExceptionIfDisabled() throws Exception {
MethodNotAllowedException exception =
@@ -774,315 +88,4 @@
public void experimentalRestEndpointsNotEnabled_invalidConfig() throws Exception {
assertThat(codeOwnersPluginConfiguration.areExperimentalRestEndpointsEnabled()).isFalse();
}
-
- @Test
- public void cannotGetFileExtensionForNullProject() throws Exception {
- NullPointerException npe =
- assertThrows(
- NullPointerException.class,
- () -> codeOwnersPluginConfiguration.getFileExtension(/* project= */ null));
- assertThat(npe).hasMessageThat().isEqualTo("project");
- }
-
- @Test
- public void getFileExtensionIfNoneIsConfigured() throws Exception {
- assertThat(codeOwnersPluginConfiguration.getFileExtension(project)).isEmpty();
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.fileExtension", value = "foo")
- public void getFileExtensionIfNoneIsConfiguredOnProjectLevel() throws Exception {
- assertThat(codeOwnersPluginConfiguration.getFileExtension(project)).value().isEqualTo("foo");
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.fileExtension", value = "foo")
- public void fileExtensionOnProjectLevelOverridesDefaultFileExtension() throws Exception {
- configureFileExtension(project, "bar");
- assertThat(codeOwnersPluginConfiguration.getFileExtension(project)).value().isEqualTo("bar");
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.fileExtension", value = "foo")
- public void fileExtensionIsInheritedFromParentProject() throws Exception {
- configureFileExtension(allProjects, "bar");
- assertThat(codeOwnersPluginConfiguration.getFileExtension(project)).value().isEqualTo("bar");
- }
-
- @Test
- public void inheritedFileExtensionCanBeOverridden() throws Exception {
- configureFileExtension(allProjects, "foo");
- configureFileExtension(project, "bar");
- assertThat(codeOwnersPluginConfiguration.getFileExtension(project)).value().isEqualTo("bar");
- }
-
- @Test
- public void cannotGetMergeCommitStrategyForNullProject() throws Exception {
- NullPointerException npe =
- assertThrows(
- NullPointerException.class,
- () -> codeOwnersPluginConfiguration.getMergeCommitStrategy(/* project= */ null));
- assertThat(npe).hasMessageThat().isEqualTo("project");
- }
-
- @Test
- public void getMergeCommitStrategyIfNoneIsConfigured() throws Exception {
- assertThat(codeOwnersPluginConfiguration.getMergeCommitStrategy(project))
- .isEqualTo(MergeCommitStrategy.ALL_CHANGED_FILES);
- }
-
- @Test
- @GerritConfig(
- name = "plugin.code-owners.mergeCommitStrategy",
- value = "FILES_WITH_CONFLICT_RESOLUTION")
- public void getMergeCommitStrategyIfNoneIsConfiguredOnProjectLevel() throws Exception {
- assertThat(codeOwnersPluginConfiguration.getMergeCommitStrategy(project))
- .isEqualTo(MergeCommitStrategy.FILES_WITH_CONFLICT_RESOLUTION);
- }
-
- @Test
- @GerritConfig(
- name = "plugin.code-owners.mergeCommitStrategy",
- value = "FILES_WITH_CONFLICT_RESOLUTION")
- public void mergeCommitStrategyOnProjectLevelOverridesGlobalMergeCommitStrategy()
- throws Exception {
- configureMergeCommitStrategy(project, MergeCommitStrategy.ALL_CHANGED_FILES);
- assertThat(codeOwnersPluginConfiguration.getMergeCommitStrategy(project))
- .isEqualTo(MergeCommitStrategy.ALL_CHANGED_FILES);
- }
-
- @Test
- @GerritConfig(
- name = "plugin.code-owners.mergeCommitStrategy",
- value = "FILES_WITH_CONFLICT_RESOLUTION")
- public void mergeCommitStrategyIsInheritedFromParentProject() throws Exception {
- configureMergeCommitStrategy(allProjects, MergeCommitStrategy.ALL_CHANGED_FILES);
- assertThat(codeOwnersPluginConfiguration.getMergeCommitStrategy(project))
- .isEqualTo(MergeCommitStrategy.ALL_CHANGED_FILES);
- }
-
- @Test
- public void inheritedMergeCommitStrategyCanBeOverridden() throws Exception {
- configureMergeCommitStrategy(allProjects, MergeCommitStrategy.FILES_WITH_CONFLICT_RESOLUTION);
- configureMergeCommitStrategy(project, MergeCommitStrategy.ALL_CHANGED_FILES);
- assertThat(codeOwnersPluginConfiguration.getMergeCommitStrategy(project))
- .isEqualTo(MergeCommitStrategy.ALL_CHANGED_FILES);
- }
-
- @Test
- public void cannotGetFallbackCodeOwnersForNullProject() throws Exception {
- NullPointerException npe =
- assertThrows(
- NullPointerException.class,
- () -> codeOwnersPluginConfiguration.getFallbackCodeOwners(/* project= */ null));
- assertThat(npe).hasMessageThat().isEqualTo("project");
- }
-
- @Test
- public void getFallbackCodeOwnersIfNoneIsConfigured() throws Exception {
- assertThat(codeOwnersPluginConfiguration.getFallbackCodeOwners(project))
- .isEqualTo(FallbackCodeOwners.NONE);
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.fallbackCodeOwners", value = "ALL_USERS")
- public void getFallbackCodeOwnersIfNoneIsConfiguredOnProjectLevel() throws Exception {
- assertThat(codeOwnersPluginConfiguration.getFallbackCodeOwners(project))
- .isEqualTo(FallbackCodeOwners.ALL_USERS);
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.fallbackCodeOwners", value = "ALL_USERS")
- public void fallbackCodeOnwersOnProjectLevelOverridesGlobalFallbackCodeOwners() throws Exception {
- configureFallbackCodeOwners(project, FallbackCodeOwners.NONE);
- assertThat(codeOwnersPluginConfiguration.getFallbackCodeOwners(project))
- .isEqualTo(FallbackCodeOwners.NONE);
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.fallbackCodeOwners", value = "ALL_USERS")
- public void fallbackCodeOwnersIsInheritedFromParentProject() throws Exception {
- configureFallbackCodeOwners(allProjects, FallbackCodeOwners.NONE);
- assertThat(codeOwnersPluginConfiguration.getFallbackCodeOwners(project))
- .isEqualTo(FallbackCodeOwners.NONE);
- }
-
- @Test
- public void inheritedFallbackCodeOwnersCanBeOverridden() throws Exception {
- configureFallbackCodeOwners(allProjects, FallbackCodeOwners.ALL_USERS);
- configureFallbackCodeOwners(project, FallbackCodeOwners.NONE);
- assertThat(codeOwnersPluginConfiguration.getFallbackCodeOwners(project))
- .isEqualTo(FallbackCodeOwners.NONE);
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.enableImplicitApprovals", value = "true")
- public void implicitApprovalsAreDisabledIfRequiredLabelIgnoresSelfApprovals() throws Exception {
- assertThat(codeOwnersPluginConfiguration.areImplicitApprovalsEnabled(project)).isTrue();
-
- LabelDefinitionInput input = new LabelDefinitionInput();
- input.ignoreSelfApproval = true;
- gApi.projects().name(allProjects.get()).label("Code-Review").update(input);
- assertThat(codeOwnersPluginConfiguration.areImplicitApprovalsEnabled(project)).isFalse();
- }
-
- @Test
- public void cannotGetMaxPathsInChangeMessagesForNullProject() throws Exception {
- NullPointerException npe =
- assertThrows(
- NullPointerException.class,
- () -> codeOwnersPluginConfiguration.getMaxPathsInChangeMessages(/* project= */ null));
- assertThat(npe).hasMessageThat().isEqualTo("project");
- }
-
- @Test
- public void getMaxPathsInChangeMessagesIfNoneIsConfigured() throws Exception {
- assertThat(codeOwnersPluginConfiguration.getMaxPathsInChangeMessages(project))
- .isEqualTo(GeneralConfig.DEFAULT_MAX_PATHS_IN_CHANGE_MESSAGES);
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.maxPathsInChangeMessages", value = "50")
- public void getMaxPathsInChangeMessagesIfNoneIsConfiguredOnProjectLevel() throws Exception {
- assertThat(codeOwnersPluginConfiguration.getMaxPathsInChangeMessages(project)).isEqualTo(50);
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.maxPathsInChangeMessages", value = "50")
- public void maxPathInChangeMessagesOnProjectLevelOverridesGlobalMaxPathInChangeMessages()
- throws Exception {
- configureFallbackCodeOwners(project, FallbackCodeOwners.NONE);
- assertThat(codeOwnersPluginConfiguration.getFallbackCodeOwners(project))
- .isEqualTo(FallbackCodeOwners.NONE);
- }
-
- @Test
- @GerritConfig(name = "plugin.code-owners.maxPathsInChangeMessages", value = "50")
- public void maxPathInChangeMessagesIsInheritedFromParentProject() throws Exception {
- configureMaxPathsInChangeMessages(allProjects, 20);
- assertThat(codeOwnersPluginConfiguration.getMaxPathsInChangeMessages(project)).isEqualTo(20);
- }
-
- @Test
- public void inheritedMaxPathInChangeMessagesCanBeOverridden() throws Exception {
- configureMaxPathsInChangeMessages(allProjects, 50);
- configureMaxPathsInChangeMessages(project, 20);
- assertThat(codeOwnersPluginConfiguration.getMaxPathsInChangeMessages(project)).isEqualTo(20);
- }
-
- private void configureDisabled(Project.NameKey project, String disabled) throws Exception {
- setCodeOwnersConfig(project, /* subsection= */ null, StatusConfig.KEY_DISABLED, disabled);
- }
-
- private void configureDisabledBranch(Project.NameKey project, String disabledBranch)
- throws Exception {
- setCodeOwnersConfig(
- project, /* subsection= */ null, StatusConfig.KEY_DISABLED_BRANCH, disabledBranch);
- }
-
- private void enableCodeOwnersForAllBranches(Project.NameKey project) throws Exception {
- setCodeOwnersConfig(project, /* subsection= */ null, StatusConfig.KEY_DISABLED_BRANCH, "");
- }
-
- private void configureBackend(Project.NameKey project, String backendName) throws Exception {
- configureBackend(project, /* branch= */ null, backendName);
- }
-
- private void configureBackend(
- Project.NameKey project, @Nullable String branch, String backendName) throws Exception {
- setCodeOwnersConfig(project, branch, BackendConfig.KEY_BACKEND, backendName);
- }
-
- private void configureRequiredApproval(Project.NameKey project, String requiredApproval)
- throws Exception {
- setCodeOwnersConfig(
- project,
- /* subsection= */ null,
- RequiredApprovalConfig.KEY_REQUIRED_APPROVAL,
- requiredApproval);
- }
-
- private void configureOverrideApproval(Project.NameKey project, String requiredApproval)
- throws Exception {
- setCodeOwnersConfig(
- project,
- /* subsection= */ null,
- OverrideApprovalConfig.KEY_OVERRIDE_APPROVAL,
- requiredApproval);
- }
-
- private void configureFileExtension(Project.NameKey project, String fileExtension)
- throws Exception {
- setCodeOwnersConfig(
- project, /* subsection= */ null, GeneralConfig.KEY_FILE_EXTENSION, fileExtension);
- }
-
- private void configureMergeCommitStrategy(
- Project.NameKey project, MergeCommitStrategy mergeCommitStrategy) throws Exception {
- setCodeOwnersConfig(
- project,
- /* subsection= */ null,
- GeneralConfig.KEY_MERGE_COMMIT_STRATEGY,
- mergeCommitStrategy.name());
- }
-
- private void configureFallbackCodeOwners(
- Project.NameKey project, FallbackCodeOwners fallbackCodeOwners) throws Exception {
- setCodeOwnersConfig(
- project,
- /* subsection= */ null,
- GeneralConfig.KEY_FALLBACK_CODE_OWNERS,
- fallbackCodeOwners.name());
- }
-
- private void configureMaxPathsInChangeMessages(
- Project.NameKey project, int maxPathsInChangeMessages) throws Exception {
- setCodeOwnersConfig(
- project,
- /* subsection= */ null,
- GeneralConfig.KEY_MAX_PATHS_IN_CHANGE_MESSAGES,
- Integer.toString(maxPathsInChangeMessages));
- }
-
- private AutoCloseable registerTestBackend() {
- RegistrationHandle registrationHandle =
- ((PrivateInternals_DynamicMapImpl<CodeOwnerBackend>) codeOwnerBackends)
- .put("gerrit", TestCodeOwnerBackend.ID, Providers.of(new TestCodeOwnerBackend()));
- return registrationHandle::remove;
- }
-
- private static class TestCodeOwnerBackend implements CodeOwnerBackend {
- static final String ID = "test-backend";
-
- @Override
- public Optional<CodeOwnerConfig> getCodeOwnerConfig(
- CodeOwnerConfig.Key codeOwnerConfigKey,
- @Nullable RevWalk revWalk,
- @Nullable ObjectId revision) {
- throw new UnsupportedOperationException("not implemented");
- }
-
- @Override
- public Optional<CodeOwnerConfig> upsertCodeOwnerConfig(
- CodeOwnerConfig.Key codeOwnerConfigKey,
- CodeOwnerConfigUpdate codeOwnerConfigUpdate,
- @Nullable IdentifiedUser currentUser) {
- throw new UnsupportedOperationException("not implemented");
- }
-
- @Override
- public boolean isCodeOwnerConfigFile(NameKey project, String fileName) {
- throw new UnsupportedOperationException("not implemented");
- }
-
- @Override
- public Path getFilePath(CodeOwnerConfig.Key codeOwnerConfigKey) {
- throw new UnsupportedOperationException("not implemented");
- }
-
- @Override
- public Optional<PathExpressionMatcher> getPathExpressionMatcher() {
- return Optional.empty();
- }
- }
}
diff --git a/javatests/com/google/gerrit/plugins/codeowners/restapi/CodeOwnerProjectConfigJsonTest.java b/javatests/com/google/gerrit/plugins/codeowners/restapi/CodeOwnerProjectConfigJsonTest.java
index 13a326d..313bef4 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/restapi/CodeOwnerProjectConfigJsonTest.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/restapi/CodeOwnerProjectConfigJsonTest.java
@@ -34,6 +34,7 @@
import com.google.gerrit.plugins.codeowners.api.RequiredApprovalInfo;
import com.google.gerrit.plugins.codeowners.backend.CodeOwnerBackendId;
import com.google.gerrit.plugins.codeowners.backend.FallbackCodeOwners;
+import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfigSnapshot;
import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfiguration;
import com.google.gerrit.plugins.codeowners.backend.config.RequiredApproval;
import com.google.gerrit.plugins.codeowners.backend.findowners.FindOwnersBackend;
@@ -63,6 +64,7 @@
@Rule public final MockitoRule mockito = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
@Mock private CodeOwnersPluginConfiguration codeOwnersPluginConfiguration;
+ @Mock private CodeOwnersPluginConfigSnapshot codeOwnersPluginConfigSnapshot;
@Inject private CurrentUser currentUser;
@@ -106,14 +108,15 @@
public void formatBackendIds() throws Exception {
createBranch(BranchNameKey.create(project, "stable-2.10"));
- when(codeOwnersPluginConfiguration.getBackend(project)).thenReturn(findOwnersBackend);
- when(codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")))
+ when(codeOwnersPluginConfigSnapshot.getBackend()).thenReturn(findOwnersBackend);
+ when(codeOwnersPluginConfigSnapshot.getBackend("refs/heads/master"))
.thenReturn(findOwnersBackend);
- when(codeOwnersPluginConfiguration.getBackend(
- BranchNameKey.create(project, "refs/meta/config")))
+ when(codeOwnersPluginConfigSnapshot.getBackend("refs/meta/config"))
.thenReturn(findOwnersBackend);
- when(codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "stable-2.10")))
+ when(codeOwnersPluginConfigSnapshot.getBackend("refs/heads/stable-2.10"))
.thenReturn(protoBackend);
+ when(codeOwnersPluginConfiguration.getProjectConfig(project))
+ .thenReturn(codeOwnersPluginConfigSnapshot);
BackendInfo backendInfo = codeOwnerProjectConfigJson.formatBackendInfo(createProjectResource());
assertThat(backendInfo.id).isEqualTo(CodeOwnerBackendId.FIND_OWNERS.getBackendId());
@@ -129,12 +132,13 @@
@Test
public void idsPerBranchNotSetIfThereIsNoBranchSpecificBackendConfiguration() throws Exception {
- when(codeOwnersPluginConfiguration.getBackend(project)).thenReturn(findOwnersBackend);
- when(codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")))
+ when(codeOwnersPluginConfigSnapshot.getBackend()).thenReturn(findOwnersBackend);
+ when(codeOwnersPluginConfigSnapshot.getBackend("refs/heads/master"))
.thenReturn(findOwnersBackend);
- when(codeOwnersPluginConfiguration.getBackend(
- BranchNameKey.create(project, "refs/meta/config")))
+ when(codeOwnersPluginConfigSnapshot.getBackend("refs/meta/config"))
.thenReturn(findOwnersBackend);
+ when(codeOwnersPluginConfiguration.getProjectConfig(project))
+ .thenReturn(codeOwnersPluginConfigSnapshot);
BackendInfo backendInfo = codeOwnerProjectConfigJson.formatBackendInfo(createProjectResource());
assertThat(backendInfo.id).isEqualTo(CodeOwnerBackendId.FIND_OWNERS.getBackendId());
@@ -146,31 +150,32 @@
createOwnersOverrideLabel();
createBranch(BranchNameKey.create(project, "stable-2.10"));
- when(codeOwnersPluginConfiguration.isDisabled(project)).thenReturn(false);
- when(codeOwnersPluginConfiguration.isDisabled(any(BranchNameKey.class))).thenReturn(false);
- when(codeOwnersPluginConfiguration.getBackend(project)).thenReturn(findOwnersBackend);
- when(codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")))
- .thenReturn(findOwnersBackend);
- when(codeOwnersPluginConfiguration.getBackend(
- BranchNameKey.create(project, "refs/meta/config")))
- .thenReturn(findOwnersBackend);
- when(codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "stable-2.10")))
- .thenReturn(protoBackend);
- when(codeOwnersPluginConfiguration.getFileExtension(project)).thenReturn(Optional.of("foo"));
- when(codeOwnersPluginConfiguration.getOverrideInfoUrl(project))
- .thenReturn(Optional.of("http://foo.example.com"));
- when(codeOwnersPluginConfiguration.getMergeCommitStrategy(project))
+ when(codeOwnersPluginConfigSnapshot.getFileExtension()).thenReturn(Optional.of("foo"));
+ when(codeOwnersPluginConfigSnapshot.getMergeCommitStrategy())
.thenReturn(MergeCommitStrategy.FILES_WITH_CONFLICT_RESOLUTION);
- when(codeOwnersPluginConfiguration.getFallbackCodeOwners(project))
+ when(codeOwnersPluginConfigSnapshot.getFallbackCodeOwners())
.thenReturn(FallbackCodeOwners.ALL_USERS);
- when(codeOwnersPluginConfiguration.areImplicitApprovalsEnabled(project)).thenReturn(true);
- when(codeOwnersPluginConfiguration.getRequiredApproval(project))
+ when(codeOwnersPluginConfigSnapshot.getOverrideInfoUrl())
+ .thenReturn(Optional.of("http://foo.example.com"));
+ when(codeOwnersPluginConfigSnapshot.isDisabled()).thenReturn(false);
+ when(codeOwnersPluginConfigSnapshot.isDisabled(any(String.class))).thenReturn(false);
+ when(codeOwnersPluginConfigSnapshot.getBackend()).thenReturn(findOwnersBackend);
+ when(codeOwnersPluginConfigSnapshot.getBackend("refs/heads/master"))
+ .thenReturn(findOwnersBackend);
+ when(codeOwnersPluginConfigSnapshot.getBackend("refs/meta/config"))
+ .thenReturn(findOwnersBackend);
+ when(codeOwnersPluginConfigSnapshot.getBackend("refs/heads/stable-2.10"))
+ .thenReturn(protoBackend);
+ when(codeOwnersPluginConfigSnapshot.areImplicitApprovalsEnabled()).thenReturn(true);
+ when(codeOwnersPluginConfigSnapshot.getRequiredApproval())
.thenReturn(RequiredApproval.create(getDefaultCodeReviewLabel(), (short) 2));
- when(codeOwnersPluginConfiguration.getOverrideApproval(project))
+ when(codeOwnersPluginConfigSnapshot.getOverrideApproval())
.thenReturn(
ImmutableSet.of(
RequiredApproval.create(
LabelType.withDefaultValues("Owners-Override"), (short) 1)));
+ when(codeOwnersPluginConfiguration.getProjectConfig(project))
+ .thenReturn(codeOwnersPluginConfigSnapshot);
CodeOwnerProjectConfigInfo codeOwnerProjectConfigInfo =
codeOwnerProjectConfigJson.format(createProjectResource());
@@ -198,7 +203,9 @@
@Test
public void disabledBranchesNotSetIfDisabledOnProjectLevel() throws Exception {
- when(codeOwnersPluginConfiguration.isDisabled(project)).thenReturn(true);
+ when(codeOwnersPluginConfigSnapshot.isDisabled()).thenReturn(true);
+ when(codeOwnersPluginConfiguration.getProjectConfig(project))
+ .thenReturn(codeOwnersPluginConfigSnapshot);
CodeOwnersStatusInfo statusInfo =
codeOwnerProjectConfigJson.formatStatusInfo(createProjectResource());
assertThat(statusInfo.disabled).isTrue();
@@ -207,12 +214,11 @@
@Test
public void emptyStatus() throws Exception {
- when(codeOwnersPluginConfiguration.isDisabled(project)).thenReturn(false);
- when(codeOwnersPluginConfiguration.isDisabled(BranchNameKey.create(project, "master")))
- .thenReturn(false);
- when(codeOwnersPluginConfiguration.isDisabled(
- BranchNameKey.create(project, "refs/meta/config")))
- .thenReturn(false);
+ when(codeOwnersPluginConfigSnapshot.isDisabled()).thenReturn(false);
+ when(codeOwnersPluginConfigSnapshot.isDisabled("refs/heads/master")).thenReturn(false);
+ when(codeOwnersPluginConfigSnapshot.isDisabled("refs/meta/config")).thenReturn(false);
+ when(codeOwnersPluginConfiguration.getProjectConfig(project))
+ .thenReturn(codeOwnersPluginConfigSnapshot);
CodeOwnersStatusInfo statusInfo =
codeOwnerProjectConfigJson.formatStatusInfo(createProjectResource());
assertThat(statusInfo.disabled).isNull();
@@ -221,12 +227,11 @@
@Test
public void withDisabledBranches() throws Exception {
- when(codeOwnersPluginConfiguration.isDisabled(project)).thenReturn(false);
- when(codeOwnersPluginConfiguration.isDisabled(BranchNameKey.create(project, "master")))
- .thenReturn(true);
- when(codeOwnersPluginConfiguration.isDisabled(
- BranchNameKey.create(project, "refs/meta/config")))
- .thenReturn(false);
+ when(codeOwnersPluginConfigSnapshot.isDisabled()).thenReturn(false);
+ when(codeOwnersPluginConfigSnapshot.isDisabled("refs/heads/master")).thenReturn(true);
+ when(codeOwnersPluginConfigSnapshot.isDisabled("refs/meta/config")).thenReturn(false);
+ when(codeOwnersPluginConfiguration.getProjectConfig(project))
+ .thenReturn(codeOwnersPluginConfigSnapshot);
CodeOwnersStatusInfo statusInfo =
codeOwnerProjectConfigJson.formatStatusInfo(createProjectResource());
assertThat(statusInfo.disabled).isNull();
@@ -237,11 +242,13 @@
public void withMultipleOverrides() throws Exception {
createOwnersOverrideLabel();
- when(codeOwnersPluginConfiguration.getOverrideApproval(project))
+ when(codeOwnersPluginConfigSnapshot.getOverrideApproval())
.thenReturn(
ImmutableSet.of(
RequiredApproval.create(LabelType.withDefaultValues("Owners-Override"), (short) 1),
RequiredApproval.create(LabelType.withDefaultValues("Code-Review"), (short) 2)));
+ when(codeOwnersPluginConfiguration.getProjectConfig(project))
+ .thenReturn(codeOwnersPluginConfigSnapshot);
ImmutableList<RequiredApprovalInfo> requiredApprovalInfos =
codeOwnerProjectConfigJson.formatOverrideApprovalInfo(project);
@@ -264,24 +271,26 @@
.addCodeOwnerEmail(admin.email())
.create();
- when(codeOwnersPluginConfiguration.isDisabled(any(BranchNameKey.class))).thenReturn(false);
- when(codeOwnersPluginConfiguration.getBackend(BranchNameKey.create(project, "master")))
- .thenReturn(findOwnersBackend);
- when(codeOwnersPluginConfiguration.getFileExtension(project)).thenReturn(Optional.of("foo"));
- when(codeOwnersPluginConfiguration.getOverrideInfoUrl(project))
- .thenReturn(Optional.of("http://foo.example.com"));
- when(codeOwnersPluginConfiguration.getMergeCommitStrategy(project))
+ when(codeOwnersPluginConfigSnapshot.getFileExtension()).thenReturn(Optional.of("foo"));
+ when(codeOwnersPluginConfigSnapshot.getMergeCommitStrategy())
.thenReturn(MergeCommitStrategy.FILES_WITH_CONFLICT_RESOLUTION);
- when(codeOwnersPluginConfiguration.getFallbackCodeOwners(project))
+ when(codeOwnersPluginConfigSnapshot.getFallbackCodeOwners())
.thenReturn(FallbackCodeOwners.ALL_USERS);
- when(codeOwnersPluginConfiguration.areImplicitApprovalsEnabled(project)).thenReturn(true);
- when(codeOwnersPluginConfiguration.getRequiredApproval(project))
+ when(codeOwnersPluginConfigSnapshot.getOverrideInfoUrl())
+ .thenReturn(Optional.of("http://foo.example.com"));
+ when(codeOwnersPluginConfigSnapshot.isDisabled(any(String.class))).thenReturn(false);
+ when(codeOwnersPluginConfigSnapshot.getBackend("refs/heads/master"))
+ .thenReturn(findOwnersBackend);
+ when(codeOwnersPluginConfigSnapshot.areImplicitApprovalsEnabled()).thenReturn(true);
+ when(codeOwnersPluginConfigSnapshot.getRequiredApproval())
.thenReturn(RequiredApproval.create(getDefaultCodeReviewLabel(), (short) 2));
- when(codeOwnersPluginConfiguration.getOverrideApproval(project))
+ when(codeOwnersPluginConfigSnapshot.getOverrideApproval())
.thenReturn(
ImmutableSet.of(
RequiredApproval.create(
LabelType.withDefaultValues("Owners-Override"), (short) 1)));
+ when(codeOwnersPluginConfiguration.getProjectConfig(project))
+ .thenReturn(codeOwnersPluginConfigSnapshot);
CodeOwnerBranchConfigInfo codeOwnerBranchConfigInfo =
codeOwnerProjectConfigJson.format(createBranchResource("refs/heads/master"));
@@ -306,7 +315,9 @@
@Test
public void formatCodeOwnerBranchConfig_disabled() throws Exception {
- when(codeOwnersPluginConfiguration.isDisabled(any(BranchNameKey.class))).thenReturn(true);
+ when(codeOwnersPluginConfigSnapshot.isDisabled(any(String.class))).thenReturn(true);
+ when(codeOwnersPluginConfiguration.getProjectConfig(project))
+ .thenReturn(codeOwnersPluginConfigSnapshot);
CodeOwnerBranchConfigInfo codeOwnerBranchConfigInfo =
codeOwnerProjectConfigJson.format(createBranchResource("refs/heads/master"));