Merge branch 'stable-3.3'
* stable-3.3:
ContentTypeUtil: Add singleton scope
Upgrade bazlets to latest stable-3.1 to build with 3.1.12 API
Upgrade bazlets to latest stable-3.0 to build with 3.0.15 API
Upgrade bazlets to latest stable-2.16 to build with 2.16.26 API
Upgrade bazlets to latest stable-3.2 to build with 3.2.6 API
Upgrade bazlets to latest stable-3.1 to build with 3.1.11 API
Upgrade bazlets to latest stable-2.16 to build with 2.16.23 API
Change-Id: Ifed03352924be4a62978f2672d3c50d5ad9e0505
diff --git a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/BlockedKeywordValidator.java b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/BlockedKeywordValidator.java
index 288afcf..1e805e9 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/BlockedKeywordValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/BlockedKeywordValidator.java
@@ -21,6 +21,7 @@
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.flogger.FluentLogger;
@@ -30,6 +31,7 @@
import com.google.gerrit.extensions.annotations.Exports;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.api.projects.ProjectConfigEntryType;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.validators.CommentForValidation;
import com.google.gerrit.extensions.validators.CommentValidationContext;
@@ -43,6 +45,10 @@
import com.google.gerrit.server.git.validators.CommitValidationException;
import com.google.gerrit.server.git.validators.CommitValidationListener;
import com.google.gerrit.server.git.validators.CommitValidationMessage;
+import com.google.gerrit.server.patch.PatchList;
+import com.google.gerrit.server.patch.PatchListCache;
+import com.google.gerrit.server.patch.PatchListKey;
+import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
@@ -65,6 +71,7 @@
import java.util.concurrent.ExecutionException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.eclipse.jgit.diff.Edit;
import org.eclipse.jgit.diff.RawText;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
@@ -115,6 +122,7 @@
private final GitRepositoryManager repoManager;
private final LoadingCache<String, Pattern> patternCache;
private final ContentTypeUtil contentTypeUtil;
+ private final PatchListCache patchListCache;
private final ValidatorConfig validatorConfig;
@Inject
@@ -124,12 +132,14 @@
@Named(CACHE_NAME) LoadingCache<String, Pattern> patternCache,
PluginConfigFactory cfgFactory,
GitRepositoryManager repoManager,
+ PatchListCache patchListCache,
ValidatorConfig validatorConfig) {
this.pluginName = pluginName;
this.patternCache = patternCache;
this.cfgFactory = cfgFactory;
this.repoManager = repoManager;
this.contentTypeUtil = contentTypeUtil;
+ this.patchListCache = patchListCache;
this.validatorConfig = validatorConfig;
}
@@ -149,13 +159,15 @@
receiveEvent.user,
receiveEvent.getProjectNameKey(),
receiveEvent.getRefName(),
- KEY_CHECK_BLOCKED_KEYWORD)) {
+ KEY_CHECK_BLOCKED_KEYWORD,
+ receiveEvent.pushOptions)) {
ImmutableMap<String, Pattern> blockedKeywordPatterns =
patternCache.getAll(
Arrays.asList(cfg.getStringList(KEY_CHECK_BLOCKED_KEYWORD_PATTERN)));
try (Repository repo = repoManager.openRepository(receiveEvent.project.getNameKey())) {
List<CommitValidationMessage> messages =
performValidation(
+ receiveEvent.project.getNameKey(),
repo,
receiveEvent.commit,
receiveEvent.revWalk,
@@ -167,7 +179,10 @@
}
}
}
- } catch (NoSuchProjectException | IOException | ExecutionException e) {
+ } catch (NoSuchProjectException
+ | IOException
+ | ExecutionException
+ | PatchListNotAvailableException e) {
throw new CommitValidationException("failed to check on blocked keywords", e);
}
return Collections.emptyList();
@@ -181,7 +196,11 @@
PluginConfig cfg = cfgFactory.getFromProjectConfigWithInheritance(projectNameKey, pluginName);
if (isActive(cfg)
&& validatorConfig.isEnabled(
- null, projectNameKey, "", KEY_CHECK_COMMENT_BLOCKED_KEYWORD)) {
+ null,
+ projectNameKey,
+ "",
+ KEY_CHECK_COMMENT_BLOCKED_KEYWORD,
+ ImmutableListMultimap.of())) {
ImmutableMap<String, Pattern> blockedKeywordPatterns =
patternCache.getAll(
Arrays.asList(cfg.getStringList(KEY_CHECK_BLOCKED_KEYWORD_PATTERN)));
@@ -199,15 +218,21 @@
@VisibleForTesting
List<CommitValidationMessage> performValidation(
+ Project.NameKey project,
Repository repo,
RevCommit c,
RevWalk revWalk,
ImmutableCollection<Pattern> blockedKeywordPatterns,
PluginConfig cfg)
- throws IOException, ExecutionException {
+ throws IOException, ExecutionException, PatchListNotAvailableException {
List<CommitValidationMessage> messages = new LinkedList<>();
checkCommitMessageForBlockedKeywords(blockedKeywordPatterns, messages, c.getFullMessage());
Map<String, ObjectId> content = CommitUtils.getChangedContent(repo, c, revWalk);
+ PatchList patchList =
+ patchListCache.get(
+ PatchListKey.againstDefaultBase(c, DiffPreferencesInfo.Whitespace.IGNORE_NONE),
+ project);
+
for (String path : content.keySet()) {
ObjectLoader ol = revWalk.getObjectReader().open(content.get(path));
try (InputStream in = ol.openStream()) {
@@ -215,21 +240,25 @@
continue;
}
}
- checkFileForBlockedKeywords(blockedKeywordPatterns, messages, path, ol);
+ checkLineDiffForBlockedKeywords(
+ patchList.get(path).getEdits(), blockedKeywordPatterns, messages, path, ol);
}
return messages;
}
private static Optional<CommentValidationFailure> validateComment(
- ImmutableMap<String, Pattern> blockedKeywordPatterns, CommentForValidation comment) {
+ ImmutableMap<String, Pattern> blockedKeywordPatterns, CommentForValidation comment) {
// Uses HashSet data structure for de-duping found blocked keywords.
- Set<String> findings = new LinkedHashSet<String>(
- findBlockedKeywordsInString(blockedKeywordPatterns.values(), comment.getText()));
+ Set<String> findings =
+ new LinkedHashSet<String>(
+ findBlockedKeywordsInString(blockedKeywordPatterns.values(), comment.getText()));
if (findings.isEmpty()) {
return Optional.empty();
}
- return Optional.of(comment.failValidation(
- String.format("banned words found in your comment (%s)", Iterables.toString(findings))));
+ return Optional.of(
+ comment.failValidation(
+ String.format(
+ "banned words found in your comment (%s)", Iterables.toString(findings))));
}
private static void checkCommitMessageForBlockedKeywords(
@@ -243,18 +272,23 @@
}
}
- private static void checkFileForBlockedKeywords(
+ private static void checkLineDiffForBlockedKeywords(
+ List<Edit> edits,
ImmutableCollection<Pattern> blockedKeywordPatterns,
List<CommitValidationMessage> messages,
String path,
ObjectLoader ol)
throws IOException {
+ List<String> lines = new ArrayList<>();
try (BufferedReader br =
new BufferedReader(new InputStreamReader(ol.openStream(), StandardCharsets.UTF_8))) {
- int line = 0;
for (String l = br.readLine(); l != null; l = br.readLine()) {
- line++;
- checkLineForBlockedKeywords(blockedKeywordPatterns, messages, path, line, l);
+ lines.add(l);
+ }
+ }
+ for (Edit edit : edits) {
+ for (int i = edit.getBeginB(); i < edit.getEndB(); i++) {
+ checkLineForBlockedKeywords(blockedKeywordPatterns, messages, path, i + 1, lines.get(i));
}
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/ChangeEmailValidator.java b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/ChangeEmailValidator.java
index 04525ec..b872620 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/ChangeEmailValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/ChangeEmailValidator.java
@@ -49,7 +49,8 @@
ProjectConfigEntryType.ARRAY,
null,
false,
- "Commits with author email not matching one of these pattterns will be rejected."));
+ "Commits with author email not matching one of these pattterns will be"
+ + " rejected."));
bind(ProjectConfigEntry.class)
.annotatedWith(Exports.named(KEY_ALLOWED_COMMITTER_EMAIL_PATTERN))
.toInstance(
@@ -59,7 +60,8 @@
ProjectConfigEntryType.ARRAY,
null,
false,
- "Commits with committer email not matching one of these patterns will be rejected."));
+ "Commits with committer email not matching one of these patterns will be"
+ + " rejected."));
}
};
}
@@ -112,7 +114,8 @@
receiveEvent.user,
receiveEvent.getProjectNameKey(),
receiveEvent.getRefName(),
- KEY_ALLOWED_AUTHOR_EMAIL_PATTERN)) {
+ KEY_ALLOWED_AUTHOR_EMAIL_PATTERN,
+ receiveEvent.pushOptions)) {
if (!performValidation(
receiveEvent.commit.getAuthorIdent().getEmailAddress(),
getAllowedAuthorEmailPatterns(cfg))) {
@@ -127,7 +130,8 @@
receiveEvent.user,
receiveEvent.getProjectNameKey(),
receiveEvent.getRefName(),
- KEY_ALLOWED_COMMITTER_EMAIL_PATTERN)) {
+ KEY_ALLOWED_COMMITTER_EMAIL_PATTERN,
+ receiveEvent.pushOptions)) {
if (!performValidation(
receiveEvent.commit.getCommitterIdent().getEmailAddress(),
getAllowedCommitterEmailPatterns(cfg))) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/ContentTypeValidator.java b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/ContentTypeValidator.java
index df1b633..3044ccd 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/ContentTypeValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/ContentTypeValidator.java
@@ -127,7 +127,8 @@
receiveEvent.user,
receiveEvent.getProjectNameKey(),
receiveEvent.getRefName(),
- KEY_BLOCKED_CONTENT_TYPE)) {
+ KEY_BLOCKED_CONTENT_TYPE,
+ receiveEvent.pushOptions)) {
try (Repository repo = repoManager.openRepository(receiveEvent.project.getNameKey())) {
List<CommitValidationMessage> messages =
performValidation(
diff --git a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/DuplicatePathnameValidator.java b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/DuplicatePathnameValidator.java
index 8a9ea2b..d8dd451 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/DuplicatePathnameValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/DuplicatePathnameValidator.java
@@ -185,7 +185,8 @@
receiveEvent.user,
receiveEvent.getProjectNameKey(),
receiveEvent.getRefName(),
- KEY_REJECT_DUPLICATE_PATHNAMES)) {
+ KEY_REJECT_DUPLICATE_PATHNAMES,
+ receiveEvent.pushOptions)) {
locale = getLocale(cfg);
try (Repository repo = repoManager.openRepository(receiveEvent.project.getNameKey())) {
List<CommitValidationMessage> messages =
diff --git a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/FileExtensionValidator.java b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/FileExtensionValidator.java
index 4b29b1f..5fc1657 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/FileExtensionValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/FileExtensionValidator.java
@@ -104,7 +104,8 @@
receiveEvent.user,
receiveEvent.getProjectNameKey(),
receiveEvent.getRefName(),
- KEY_BLOCKED_FILE_EXTENSION)) {
+ KEY_BLOCKED_FILE_EXTENSION,
+ receiveEvent.pushOptions)) {
try (Repository repo = repoManager.openRepository(receiveEvent.project.getNameKey())) {
List<CommitValidationMessage> messages =
performValidation(
diff --git a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/FooterValidator.java b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/FooterValidator.java
index b5b92c2..67d49a6 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/FooterValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/FooterValidator.java
@@ -89,7 +89,8 @@
receiveEvent.user,
receiveEvent.getProjectNameKey(),
receiveEvent.getRefName(),
- KEY_REQUIRED_FOOTER)) {
+ KEY_REQUIRED_FOOTER,
+ receiveEvent.pushOptions)) {
List<CommitValidationMessage> messages = new LinkedList<>();
Set<String> footers =
FluentIterable.from(receiveEvent.commit.getFooterLines())
diff --git a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/InvalidFilenameValidator.java b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/InvalidFilenameValidator.java
index c6371df..f624830 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/InvalidFilenameValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/InvalidFilenameValidator.java
@@ -99,7 +99,8 @@
receiveEvent.user,
receiveEvent.getProjectNameKey(),
receiveEvent.getRefName(),
- KEY_INVALID_FILENAME)) {
+ KEY_INVALID_FILENAME,
+ receiveEvent.pushOptions)) {
try (Repository repo = repoManager.openRepository(receiveEvent.project.getNameKey())) {
List<CommitValidationMessage> messages =
performValidation(
diff --git a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/InvalidLineEndingValidator.java b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/InvalidLineEndingValidator.java
index aa72ee0..4bffce6 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/InvalidLineEndingValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/InvalidLineEndingValidator.java
@@ -109,7 +109,8 @@
receiveEvent.user,
receiveEvent.getProjectNameKey(),
receiveEvent.getRefName(),
- KEY_CHECK_REJECT_WINDOWS_LINE_ENDINGS)) {
+ KEY_CHECK_REJECT_WINDOWS_LINE_ENDINGS,
+ receiveEvent.pushOptions)) {
try (Repository repo = repoManager.openRepository(receiveEvent.project.getNameKey())) {
List<CommitValidationMessage> messages =
performValidation(repo, receiveEvent.commit, receiveEvent.revWalk, cfg);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/MaxPathLengthValidator.java b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/MaxPathLengthValidator.java
index a3db8f4..6183317 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/MaxPathLengthValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/MaxPathLengthValidator.java
@@ -93,7 +93,8 @@
receiveEvent.user,
receiveEvent.getProjectNameKey(),
receiveEvent.getRefName(),
- KEY_MAX_PATH_LENGTH)) {
+ KEY_MAX_PATH_LENGTH,
+ receiveEvent.pushOptions)) {
int maxPathLength = cfg.getInt(KEY_MAX_PATH_LENGTH, 0);
try (Repository repo = repoManager.openRepository(receiveEvent.project.getNameKey())) {
List<CommitValidationMessage> messages =
diff --git a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/Module.java b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/Module.java
index e15ecb2..98261ea 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/Module.java
@@ -14,6 +14,8 @@
package com.googlesource.gerrit.plugins.uploadvalidator;
+import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.server.git.receive.PluginPushOption;
import com.google.inject.AbstractModule;
import com.google.inject.Scopes;
@@ -38,5 +40,7 @@
install(ValidatorConfig.module());
bind(ConfigFactory.class).to(PluginConfigWithInheritanceFactory.class).in(Scopes.SINGLETON);
+
+ DynamicSet.bind(binder(), PluginPushOption.class).to(SkipValidationPushOption.class);
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/SkipValidationPushOption.java b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/SkipValidationPushOption.java
new file mode 100644
index 0000000..b690bd4
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/SkipValidationPushOption.java
@@ -0,0 +1,30 @@
+// 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.googlesource.gerrit.plugins.uploadvalidator;
+
+import com.google.gerrit.server.git.receive.PluginPushOption;
+
+/** Push option that allows to skip the uploadvalidator plugin validation. */
+public final class SkipValidationPushOption implements PluginPushOption {
+ public static final String NAME = "skip";
+
+ public String getName() {
+ return NAME;
+ }
+
+ public String getDescription() {
+ return "skip uploadvalidator validation";
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/SubmoduleValidator.java b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/SubmoduleValidator.java
index f96d325..99e2641 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/SubmoduleValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/SubmoduleValidator.java
@@ -96,7 +96,8 @@
receiveEvent.user,
receiveEvent.getProjectNameKey(),
receiveEvent.getRefName(),
- KEY_CHECK_SUBMODULE)) {
+ KEY_CHECK_SUBMODULE,
+ receiveEvent.pushOptions)) {
try (Repository repo = repoManager.openRepository(receiveEvent.project.getNameKey())) {
List<CommitValidationMessage> messages =
performValidation(repo, receiveEvent.commit, receiveEvent.revWalk);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/SymlinkValidator.java b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/SymlinkValidator.java
index 85a8151..31faa75 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/SymlinkValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/SymlinkValidator.java
@@ -97,7 +97,8 @@
receiveEvent.user,
receiveEvent.getProjectNameKey(),
receiveEvent.getRefName(),
- KEY_CHECK_SYMLINK)) {
+ KEY_CHECK_SYMLINK,
+ receiveEvent.pushOptions)) {
try (Repository repo = repoManager.openRepository(receiveEvent.project.getNameKey())) {
List<CommitValidationMessage> messages =
performValidation(repo, receiveEvent.commit, receiveEvent.revWalk);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/ValidatorConfig.java b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/ValidatorConfig.java
index d1c5f7e..d7cca55 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/ValidatorConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/ValidatorConfig.java
@@ -17,18 +17,20 @@
import static com.google.common.collect.ImmutableList.toImmutableList;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableListMultimap;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.AccessSection;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.AccountGroup.UUID;
+import com.google.gerrit.entities.InternalGroup;
import com.google.gerrit.entities.Project;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.annotations.Exports;
+import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.api.projects.ProjectConfigEntryType;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.config.PluginConfig;
import com.google.gerrit.server.config.ProjectConfigEntry;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.project.RefPatternMatcher;
import com.google.gerrit.server.query.group.InternalGroupQuery;
import com.google.inject.AbstractModule;
@@ -44,6 +46,7 @@
private static final Logger log = LoggerFactory.getLogger(ValidatorConfig.class);
private static final String KEY_PROJECT = "project";
private static final String KEY_REF = "ref";
+ private final String pluginName;
private final ConfigFactory configFactory;
private final GroupByNameFinder groupByNameFinder;
@@ -77,7 +80,11 @@
}
@Inject
- public ValidatorConfig(ConfigFactory configFactory, GroupByNameFinder groupByNameFinder) {
+ public ValidatorConfig(
+ @PluginName String pluginName,
+ ConfigFactory configFactory,
+ GroupByNameFinder groupByNameFinder) {
+ this.pluginName = pluginName;
this.configFactory = configFactory;
this.groupByNameFinder = groupByNameFinder;
}
@@ -96,15 +103,18 @@
@Nullable IdentifiedUser user,
Project.NameKey projectName,
String refName,
- String validatorOp) {
+ String validatorOp,
+ ImmutableListMultimap<String, String> pushOptions) {
PluginConfig conf = configFactory.get(projectName);
return conf != null
&& isValidConfig(conf, projectName)
- && (activeForRef(conf, refName))
+ && !isDisabledByPushOption(conf, pushOptions)
+ && activeForRef(conf, refName)
&& (user == null || activeForEmail(conf, user.getAccount().preferredEmail()))
- && (activeForProject(conf, projectName.get()))
- && (!isDisabledValidatorOp(conf, validatorOp))
+ && activeForGroup(conf, user)
+ && activeForProject(conf, projectName.get())
+ && !isDisabledValidatorOp(conf, validatorOp)
&& (!hasCriteria(conf, "skipGroup")
|| !canSkipValidation(conf, validatorOp)
|| !canSkipRef(conf, refName)
@@ -141,6 +151,15 @@
return Arrays.asList(c).contains(validatorOp);
}
+ private boolean isDisabledByPushOption(
+ PluginConfig config, ImmutableListMultimap<String, String> pushOptions) {
+ String qualifiedName = pluginName + "~" + SkipValidationPushOption.NAME;
+ if (!config.getBoolean("skipViaPushOption", false)) {
+ return false;
+ }
+ return pushOptions.containsKey(qualifiedName);
+ }
+
private boolean activeForProject(PluginConfig config, String project) {
return matchCriteria(config, "project", project, true, false);
}
@@ -153,6 +172,22 @@
return matchCriteria(config, "email", email, true, false);
}
+ private boolean activeForGroup(PluginConfig config, @Nullable IdentifiedUser user) {
+ if (user == null) {
+ return true;
+ }
+
+ ImmutableList<UUID> groups =
+ Arrays.stream(config.getStringList("group"))
+ .map(this::groupUUID)
+ .collect(toImmutableList());
+ if (groups.isEmpty()) {
+ return true;
+ }
+
+ return user.getEffectiveGroups().containsAnyOf(groups);
+ }
+
private boolean canSkipValidation(PluginConfig config, String validatorOp) {
return matchCriteria(config, "skipValidation", validatorOp, false, false);
}
@@ -188,7 +223,7 @@
}
private boolean canSkipGroup(PluginConfig conf, @Nullable IdentifiedUser user) {
- if (user == null || !user.isIdentifiedUser()) {
+ if (user == null) {
return false;
}
@@ -196,7 +231,7 @@
Arrays.stream(conf.getStringList("skipGroup"))
.map(this::groupUUID)
.collect(toImmutableList());
- return user.asIdentifiedUser().getEffectiveGroups().containsAnyOf(skipGroups);
+ return user.getEffectiveGroups().containsAnyOf(skipGroups);
}
private AccountGroup.UUID groupUUID(String groupNameOrUUID) {
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 878b272..aa7b0cf 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -143,7 +143,7 @@
: Patterns for blocked keywords.
This check looks for blocked keywords in files. If the check finds an
- blocked keyword the push will be rejected.
+ blocked keyword in the diff between the pushed commit and it's parent.
To find a keyword it is possible to pass a regular expressions by
blockedKeywordPattern.
@@ -290,12 +290,33 @@
project = ^platform/.*
```
+Group-specific validations
+---------------------------
+
+By default, the validation will be enabled for all users. However, it can be
+limited to particular user group by setting `plugin.@PLUGIN@.group`. The group
+may be configured using a specific group name or UUID. Multiple groups may
+be specified.
+
+NOTE: For [system groups](../../../Documentation/access-control.html#system_groups)
+and external groups (e.g.
+[LDAP groups](../../../Documentation/access-control.html#ldap_groups)) the use
+of UUIDs is required. This is because group names are resolved through the
+group index and the group index only contains Gerrit internal groups.
+
+E.g. to limit the validation to all users that are part of group `foo` the
+following could be configured:
+
+```
+ [plugin "@PLUGIN@"]
+ group = foo
+```
+
Permission to skip the rules
----------------------------
-Some users may be allowed to skip some of the rules on a per project and
-per repository basis by configuring the appropriate "skip" settings in the
-project.config.
+Some users may be allowed to skip some of the rules by configuring the
+appropriate "skip" settings in the project.config.
Skip of the rules is controlled by:
@@ -309,6 +330,9 @@
NOTE: When skipGroup isn't defined, all the other skip settings are ignored.
+NOTE: If skipGroup is the same as group, all users are able to skip validations
+based on other skip rules.
+
NOTE: For [system groups](../../../Documentation/access-control.html#system_groups)
and external groups (e.g.
[LDAP groups](../../../Documentation/access-control.html#ldap_groups)) the use
@@ -394,3 +418,12 @@
skipGroup = ldap/GerritAdmins
skipRef = refs/heads/master
```
+
+plugin.@PLUGIN@.skipViaPushOption
+: Allow all users to skip validation using push options
+
+ This check allows all users to bypass all validation rules if they set push
+ option "@PLUGIN@~skip" (e.g. git push -o "@PLUGIN@~skip"), regardless of
+ other skip rules.
+
+ Default: false
diff --git a/src/main/resources/Documentation/toc.md b/src/main/resources/Documentation/toc.md
new file mode 100644
index 0000000..2490085
--- /dev/null
+++ b/src/main/resources/Documentation/toc.md
@@ -0,0 +1,6 @@
+### Admin Guides
+* [Configuration](config.html)
+
+### Contributor Guides
+* [Build](build.html)
+
diff --git a/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/BlockedKeywordValidatorTest.java b/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/BlockedKeywordValidatorTest.java
index c709622..245f2dc 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/BlockedKeywordValidatorTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/BlockedKeywordValidatorTest.java
@@ -17,11 +17,19 @@
import static com.google.common.truth.Truth.assertThat;
import static com.googlesource.gerrit.plugins.uploadvalidator.TestUtils.EMPTY_PLUGIN_CONFIG;
import static com.googlesource.gerrit.plugins.uploadvalidator.TestUtils.PATTERN_CACHE;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.entities.Patch;
+import com.google.gerrit.entities.Project;
import com.google.gerrit.server.git.validators.CommitValidationMessage;
+import com.google.gerrit.server.patch.PatchList;
+import com.google.gerrit.server.patch.PatchListCache;
+import com.google.gerrit.server.patch.PatchListEntry;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@@ -31,11 +39,26 @@
import java.util.Set;
import java.util.regex.Pattern;
import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.diff.Edit;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.junit.Test;
public class BlockedKeywordValidatorTest extends ValidatorTestCase {
+ /** Maps file names to content. */
+ private static final Map<String, String> FILE_CONTENTS =
+ ImmutableMap.of(
+ "bar.txt",
+ "$Id$\n"
+ + "$Header$\n"
+ + "$Author$\n"
+ + "processXFile($File::Find::name, $Config{$type});\n"
+ + "$Id: foo bar$\n",
+ "foo.txt",
+ "http://foo.bar.tld/?pw=myp4ssw0rdTefoobarstline2\n",
+ "foobar.txt",
+ "Testline1\n" + "Testline2\n" + "Testline3\n" + "Testline4");
+
private static ImmutableMap<String, Pattern> getPatterns() {
return ImmutableMap.<String, Pattern>builder()
.put("myp4ssw0rd", Pattern.compile("myp4ssw0rd"))
@@ -46,39 +69,42 @@
private RevCommit makeCommit(RevWalk rw) throws IOException, GitAPIException {
Map<File, byte[]> files = new HashMap<>();
- // invalid files
- String content = "http://foo.bar.tld/?pw=myp4ssw0rdTefoobarstline2\n";
- files.put(
- new File(repo.getDirectory().getParent(), "foo.txt"),
- content.getBytes(StandardCharsets.UTF_8));
-
- content =
- "$Id$\n"
- + "$Header$\n"
- + "$Author$\n"
- + "processXFile($File::Find::name, $Config{$type});\n"
- + "$Id: foo bar$\n";
- files.put(
- new File(repo.getDirectory().getParent(), "bar.txt"),
- content.getBytes(StandardCharsets.UTF_8));
-
- // valid file
- content = "Testline1\n" + "Testline2\n" + "Testline3\n" + "Testline4";
- files.put(
- new File(repo.getDirectory().getParent(), "foobar.txt"),
- content.getBytes(StandardCharsets.UTF_8));
+ for (Map.Entry<String, String> fileContents : FILE_CONTENTS.entrySet()) {
+ files.put(
+ new File(repo.getDirectory().getParent(), fileContents.getKey()),
+ fileContents.getValue().getBytes(StandardCharsets.UTF_8));
+ }
return TestUtils.makeCommit(rw, repo, "Commit foobar with test files.", files);
}
@Test
- public void testKeywords() throws Exception {
+ public void keywords() throws Exception {
+ // Mock the PatchListCache to return a diff for each file in our new commit
+ PatchListCache patchListCacheMock = mock(PatchListCache.class);
+ PatchList mockPatchList = mock(PatchList.class);
+ when(patchListCacheMock.get(any(), any(Project.NameKey.class))).thenReturn(mockPatchList);
+ for (Map.Entry<String, String> fileContent : FILE_CONTENTS.entrySet()) {
+ PatchListEntry file = mock(PatchListEntry.class);
+ when(file.getEdits())
+ .thenReturn(
+ ImmutableList.of(new Edit(0, 0, 0, numberOfLinesInString(fileContent.getValue()))));
+ when(mockPatchList.get(fileContent.getKey())).thenReturn(file);
+ }
+
try (RevWalk rw = new RevWalk(repo)) {
RevCommit c = makeCommit(rw);
BlockedKeywordValidator validator =
new BlockedKeywordValidator(
- null, new ContentTypeUtil(PATTERN_CACHE), PATTERN_CACHE, null, null, null);
+ null,
+ new ContentTypeUtil(PATTERN_CACHE),
+ PATTERN_CACHE,
+ null,
+ null,
+ patchListCacheMock,
+ null);
List<CommitValidationMessage> m =
- validator.performValidation(repo, c, rw, getPatterns().values(), EMPTY_PLUGIN_CONFIG);
+ validator.performValidation(
+ Project.nameKey("project"), repo, c, rw, getPatterns().values(), EMPTY_PLUGIN_CONFIG);
Set<String> expected =
ImmutableSet.of(
"ERROR: blocked keyword(s) found in: foo.txt (Line: 1)"
@@ -95,4 +121,8 @@
public void validatorInactiveWhenConfigEmpty() {
assertThat(BlockedKeywordValidator.isActive(EMPTY_PLUGIN_CONFIG)).isFalse();
}
+
+ public static int numberOfLinesInString(String str) {
+ return str.length() - str.replace("\n", "").length();
+ }
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/EmailAwareValidatorConfigTest.java b/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/EmailAwareValidatorConfigTest.java
index 8c00744..88ce317 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/EmailAwareValidatorConfigTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/EmailAwareValidatorConfigTest.java
@@ -16,6 +16,7 @@
import static com.google.common.truth.Truth.assertThat;
+import com.google.common.collect.ImmutableListMultimap;
import com.google.gerrit.entities.Project;
import com.google.gerrit.server.IdentifiedUser;
import org.eclipse.jgit.errors.ConfigInvalidException;
@@ -30,7 +31,9 @@
ValidatorConfig config =
getConfig("[plugin \"uploadvalidator\"]\n" + "blockedFileExtension = jar");
- assertThat(config.isEnabled(anyUser, projectName, "anyRef", "blockedFileExtension"))
+ assertThat(
+ config.isEnabled(
+ anyUser, projectName, "anyRef", "blockedFileExtension", ImmutableListMultimap.of()))
.isTrue();
}
@@ -40,7 +43,13 @@
ValidatorConfig config =
getConfig("[plugin \"uploadvalidator\"]\n" + "blockedFileExtension = jar");
- assertThat(config.isEnabled(missingEmail, projectName, "anyRef", "blockedFileExtension"))
+ assertThat(
+ config.isEnabled(
+ missingEmail,
+ projectName,
+ "anyRef",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
.isTrue();
}
@@ -56,7 +65,11 @@
assertThat(
config.isEnabled(
- anyUser, projectName, "refs/heads/anyref", "blockedFileExtension"))
+ anyUser,
+ projectName,
+ "refs/heads/anyref",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
.isTrue();
}
@@ -70,7 +83,11 @@
assertThat(
config.isEnabled(
- anyUser, projectName, "refs/heads/anyref", "blockedFileExtension"))
+ anyUser,
+ projectName,
+ "refs/heads/anyref",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
.isFalse();
}
@@ -85,11 +102,19 @@
assertThat(
config.isEnabled(
- anyUser, projectName, "refs/heads/anyref", "blockedFileExtension"))
+ anyUser,
+ projectName,
+ "refs/heads/anyref",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
.isFalse();
assertThat(
config.isEnabled(
- exampleOrgUser, projectName, "refs/heads/anyref", "blockedFileExtension"))
+ exampleOrgUser,
+ projectName,
+ "refs/heads/anyref",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
.isTrue();
}
@@ -104,7 +129,11 @@
assertThat(
config.isEnabled(
- missingEmail, projectName, "refs/heads/anyref", "blockedFileExtension"))
+ missingEmail,
+ projectName,
+ "refs/heads/anyref",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
.isFalse();
}
@@ -121,19 +150,34 @@
assertThat(
config.isEnabled(
- exampleOrgUser, projectName, "refs/heads/anyref", "blockedFileExtension"))
- .isTrue();
- assertThat(
- config.isEnabled(xUser, projectName, "refs/heads/anyref", "blockedFileExtension"))
+ exampleOrgUser,
+ projectName,
+ "refs/heads/anyref",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
.isTrue();
assertThat(
config.isEnabled(
- anyUser, projectName, "refs/heads/anyref", "blockedFileExtension"))
+ xUser,
+ projectName,
+ "refs/heads/anyref",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
+ .isTrue();
+ assertThat(
+ config.isEnabled(
+ anyUser,
+ projectName,
+ "refs/heads/anyref",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
.isFalse();
}
private ValidatorConfig getConfig(String defaultConfig) throws ConfigInvalidException {
return new ValidatorConfig(
- new FakeConfigFactory(projectName, defaultConfig), new FakeGroupByNameFinder());
+ "uploadvalidator",
+ new FakeConfigFactory(projectName, defaultConfig),
+ new FakeGroupByNameFinder());
}
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/FakeGroupByNameFinder.java b/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/FakeGroupByNameFinder.java
index 2d3fed6..b028f5d 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/FakeGroupByNameFinder.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/FakeGroupByNameFinder.java
@@ -16,7 +16,7 @@
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.entities.AccountGroup;
-import com.google.gerrit.server.group.InternalGroup;
+import com.google.gerrit.entities.InternalGroup;
import java.sql.Timestamp;
import java.util.Objects;
import java.util.Optional;
diff --git a/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/GroupAwareValidatorConfigTest.java b/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/GroupAwareValidatorConfigTest.java
new file mode 100644
index 0000000..c78b64b
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/GroupAwareValidatorConfigTest.java
@@ -0,0 +1,115 @@
+// 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.googlesource.gerrit.plugins.uploadvalidator;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableListMultimap;
+import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.Project;
+import com.google.gerrit.server.util.time.TimeUtil;
+import org.junit.Test;
+
+public class GroupAwareValidatorConfigTest {
+ private Project.NameKey projectName = Project.nameKey("testProject");
+ private static final String pluginName = "uploadvalidator";
+
+ @Test
+ public void isEnabledForNoGroupsByDefault() throws Exception {
+ String config = "[plugin \"uploadvalidator\"]\n" + "blockedFileExtension = jar\n";
+
+ ValidatorConfig validatorConfig =
+ new ValidatorConfig(
+ pluginName, new FakeConfigFactory(projectName, config), new FakeGroupByNameFinder());
+
+ assertThat(
+ validatorConfig.isEnabled(
+ new FakeUserProvider().get(),
+ projectName,
+ "anyRef",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
+ .isTrue();
+ }
+
+ @Test
+ public void isEnabledWhenUserBelongsToOneGroup() throws Exception {
+ String config =
+ "[plugin \"uploadvalidator\"]\n"
+ + "blockedFileExtension = jar\n"
+ + "group=fooGroup\n"
+ + "group=barGroup\n";
+
+ ValidatorConfig validatorConfig =
+ new ValidatorConfig(
+ pluginName, new FakeConfigFactory(projectName, config), new FakeGroupByNameFinder());
+
+ assertThat(
+ validatorConfig.isEnabled(
+ new FakeUserProvider("fooGroup", "bazGroup").get(),
+ projectName,
+ "anyRef",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
+ .isTrue();
+ }
+
+ @Test
+ public void isEnabledWhenUserInGroupUUID() throws Exception {
+ String config =
+ "[plugin \"uploadvalidator\"]\n" + "blockedFileExtension = jar\n" + "group=testGroupName\n";
+
+ ValidatorConfig validatorConfig =
+ new ValidatorConfig(
+ pluginName,
+ new FakeConfigFactory(projectName, config),
+ new FakeGroupByNameFinder(
+ AccountGroup.nameKey("testGroupName"),
+ AccountGroup.id(1),
+ AccountGroup.uuid("testGroupId"),
+ TimeUtil.nowTs()));
+
+ assertThat(
+ validatorConfig.isEnabled(
+ new FakeUserProvider("testGroupId").get(),
+ projectName,
+ "anyRef",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
+ .isTrue();
+ }
+
+ @Test
+ public void isDisabledWhenUserNotInGroup() throws Exception {
+ String config =
+ "[plugin \"uploadvalidator\"]\n"
+ + "blockedFileExtension = jar\n"
+ + "group=fooGroup\n"
+ + "group=barGroup\n";
+
+ ValidatorConfig validatorConfig =
+ new ValidatorConfig(
+ pluginName, new FakeConfigFactory(projectName, config), new FakeGroupByNameFinder());
+
+ assertThat(
+ validatorConfig.isEnabled(
+ new FakeUserProvider("bazGroup").get(),
+ projectName,
+ "anyRef",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
+ .isFalse();
+ }
+}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/ProjectAwareValidatorConfigTest.java b/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/ProjectAwareValidatorConfigTest.java
index c968ec5..6c3a059 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/ProjectAwareValidatorConfigTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/ProjectAwareValidatorConfigTest.java
@@ -16,6 +16,7 @@
import static com.google.common.truth.Truth.assertThat;
+import com.google.common.collect.ImmutableListMultimap;
import com.google.gerrit.entities.Project;
import com.google.gerrit.server.IdentifiedUser;
import org.eclipse.jgit.errors.ConfigInvalidException;
@@ -30,7 +31,9 @@
ValidatorConfig config =
getConfig("[plugin \"uploadvalidator\"]\n" + "blockedFileExtension = jar", projectName);
- assertThat(config.isEnabled(anyUser, projectName, "anyRef", "blockedFileExtension"))
+ assertThat(
+ config.isEnabled(
+ anyUser, projectName, "anyRef", "blockedFileExtension", ImmutableListMultimap.of()))
.isTrue();
}
@@ -43,7 +46,9 @@
+ " blockedFileExtension = jar",
projectName);
- assertThat(config.isEnabled(anyUser, projectName, "anyRef", "blockedFileExtension"))
+ assertThat(
+ config.isEnabled(
+ anyUser, projectName, "anyRef", "blockedFileExtension", ImmutableListMultimap.of()))
.isTrue();
}
@@ -56,7 +61,9 @@
+ " blockedFileExtension = jar",
projectName);
- assertThat(config.isEnabled(anyUser, projectName, "anyRef", "blockedFileExtension"))
+ assertThat(
+ config.isEnabled(
+ anyUser, projectName, "anyRef", "blockedFileExtension", ImmutableListMultimap.of()))
.isFalse();
}
@@ -70,9 +77,17 @@
ValidatorConfig config = getConfig(configString, projectName);
ValidatorConfig config2 = getConfig(configString, otherNameKey);
- assertThat(config.isEnabled(anyUser, projectName, "anyRef", "blockedFileExtension"))
+ assertThat(
+ config.isEnabled(
+ anyUser, projectName, "anyRef", "blockedFileExtension", ImmutableListMultimap.of()))
.isTrue();
- assertThat(config2.isEnabled(anyUser, otherNameKey, "anyRef", "blockedFileExtension"))
+ assertThat(
+ config2.isEnabled(
+ anyUser,
+ otherNameKey,
+ "anyRef",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
.isFalse();
}
@@ -89,17 +104,33 @@
ValidatorConfig config2 = getConfig(configString, anotherNameKey);
ValidatorConfig config3 = getConfig(configString, someOtherNameKey);
- assertThat(config.isEnabled(anyUser, projectName, "anyRef", "blockedFileExtension"))
+ assertThat(
+ config.isEnabled(
+ anyUser, projectName, "anyRef", "blockedFileExtension", ImmutableListMultimap.of()))
.isTrue();
- assertThat(config2.isEnabled(anyUser, anotherNameKey, "anyRef", "blockedFileExtension"))
+ assertThat(
+ config2.isEnabled(
+ anyUser,
+ anotherNameKey,
+ "anyRef",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
.isTrue();
- assertThat(config3.isEnabled(anyUser, someOtherNameKey, "anyRef", "blockedFileExtension"))
+ assertThat(
+ config3.isEnabled(
+ anyUser,
+ someOtherNameKey,
+ "anyRef",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
.isFalse();
}
private ValidatorConfig getConfig(String defaultConfig, Project.NameKey projName)
throws ConfigInvalidException {
return new ValidatorConfig(
- new FakeConfigFactory(projName, defaultConfig), new FakeGroupByNameFinder());
+ "uploadvalidator",
+ new FakeConfigFactory(projName, defaultConfig),
+ new FakeGroupByNameFinder());
}
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/RefAwareValidatorConfigTest.java b/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/RefAwareValidatorConfigTest.java
index f74d346..97ae747 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/RefAwareValidatorConfigTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/RefAwareValidatorConfigTest.java
@@ -16,6 +16,7 @@
import static com.google.common.truth.Truth.assertThat;
+import com.google.common.collect.ImmutableListMultimap;
import com.google.gerrit.entities.Project;
import com.google.gerrit.server.IdentifiedUser;
import org.eclipse.jgit.errors.ConfigInvalidException;
@@ -30,7 +31,9 @@
ValidatorConfig config =
getConfig("[plugin \"uploadvalidator\"]\n" + "blockedFileExtension = jar");
- assertThat(config.isEnabled(anyUser, projectName, "anyRef", "blockedFileExtension"))
+ assertThat(
+ config.isEnabled(
+ anyUser, projectName, "anyRef", "blockedFileExtension", ImmutableListMultimap.of()))
.isTrue();
}
@@ -44,7 +47,11 @@
assertThat(
config.isEnabled(
- anyUser, projectName, "refs/heads/anyref", "blockedFileExtension"))
+ anyUser,
+ projectName,
+ "refs/heads/anyref",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
.isTrue();
}
@@ -58,7 +65,11 @@
assertThat(
config.isEnabled(
- anyUser, projectName, "refs/heads/anyref", "blockedFileExtension"))
+ anyUser,
+ projectName,
+ "refs/heads/anyref",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
.isFalse();
}
@@ -72,11 +83,19 @@
assertThat(
config.isEnabled(
- anyUser, projectName, "refs/heads/anotherref", "blockedFileExtension"))
+ anyUser,
+ projectName,
+ "refs/heads/anotherref",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
.isFalse();
assertThat(
config.isEnabled(
- anyUser, projectName, "refs/heads/mybranch123", "blockedFileExtension"))
+ anyUser,
+ projectName,
+ "refs/heads/mybranch123",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
.isTrue();
}
@@ -91,20 +110,34 @@
assertThat(
config.isEnabled(
- anyUser, projectName, "refs/heads/branch1", "blockedFileExtension"))
+ anyUser,
+ projectName,
+ "refs/heads/branch1",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
.isTrue();
assertThat(
config.isEnabled(
- anyUser, projectName, "refs/heads/branch2", "blockedFileExtension"))
+ anyUser,
+ projectName,
+ "refs/heads/branch2",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
.isTrue();
assertThat(
config.isEnabled(
- anyUser, projectName, "refs/heads/branch3", "blockedFileExtension"))
+ anyUser,
+ projectName,
+ "refs/heads/branch3",
+ "blockedFileExtension",
+ ImmutableListMultimap.of()))
.isFalse();
}
private ValidatorConfig getConfig(String defaultConfig) throws ConfigInvalidException {
return new ValidatorConfig(
- new FakeConfigFactory(projectName, defaultConfig), new FakeGroupByNameFinder());
+ "uploadvalidator",
+ new FakeConfigFactory(projectName, defaultConfig),
+ new FakeGroupByNameFinder());
}
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/SkipValidationTest.java b/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/SkipValidationTest.java
index b46ac86..81a4ddc 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/SkipValidationTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/SkipValidationTest.java
@@ -16,6 +16,7 @@
import static com.google.common.truth.Truth.assertThat;
+import com.google.common.collect.ImmutableListMultimap;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.Project;
import com.google.gerrit.server.IdentifiedUser;
@@ -25,13 +26,18 @@
public class SkipValidationTest {
private final Project.NameKey projectName = Project.nameKey("testProject");
private final IdentifiedUser anyUser = new FakeUserProvider().get();
+ private static final String pluginName = "uploadvalidator";
@Test
public void dontSkipByDefault() throws Exception {
ValidatorConfig validatorConfig =
- new ValidatorConfig(new FakeConfigFactory(projectName, ""), new FakeGroupByNameFinder());
+ new ValidatorConfig(
+ pluginName, new FakeConfigFactory(projectName, ""), new FakeGroupByNameFinder());
- assertThat(validatorConfig.isEnabled(anyUser, projectName, "anyRef", "anyOp")).isTrue();
+ assertThat(
+ validatorConfig.isEnabled(
+ anyUser, projectName, "anyRef", "anyOp", ImmutableListMultimap.of()))
+ .isTrue();
}
@Test
@@ -44,14 +50,15 @@
ValidatorConfig validatorConfig =
new ValidatorConfig(
- new FakeConfigFactory(projectName, config), new FakeGroupByNameFinder());
+ pluginName, new FakeConfigFactory(projectName, config), new FakeGroupByNameFinder());
assertThat(
validatorConfig.isEnabled(
new FakeUserProvider("testGroup", "yetAnotherGroup").get(),
projectName,
"anyRef",
- "testOp"))
+ "testOp",
+ ImmutableListMultimap.of()))
.isFalse();
}
@@ -62,6 +69,7 @@
ValidatorConfig validatorConfig =
new ValidatorConfig(
+ pluginName,
new FakeConfigFactory(projectName, config),
new FakeGroupByNameFinder(
AccountGroup.nameKey("testGroupName"),
@@ -71,7 +79,11 @@
assertThat(
validatorConfig.isEnabled(
- new FakeUserProvider("testGroupId").get(), projectName, "anyRef", "testOp"))
+ new FakeUserProvider("testGroupId").get(),
+ projectName,
+ "anyRef",
+ "testOp",
+ ImmutableListMultimap.of()))
.isFalse();
}
@@ -85,11 +97,15 @@
ValidatorConfig validatorConfig =
new ValidatorConfig(
- new FakeConfigFactory(projectName, config), new FakeGroupByNameFinder());
+ pluginName, new FakeConfigFactory(projectName, config), new FakeGroupByNameFinder());
assertThat(
validatorConfig.isEnabled(
- new FakeUserProvider("yetAnotherGroup").get(), projectName, "anyRef", "testOp"))
+ new FakeUserProvider("yetAnotherGroup").get(),
+ projectName,
+ "anyRef",
+ "testOp",
+ ImmutableListMultimap.of()))
.isTrue();
}
@@ -103,9 +119,11 @@
ValidatorConfig validatorConfig =
new ValidatorConfig(
- new FakeConfigFactory(projectName, config), new FakeGroupByNameFinder());
+ pluginName, new FakeConfigFactory(projectName, config), new FakeGroupByNameFinder());
- assertThat(validatorConfig.isEnabled(anyUser, projectName, "anyRef", "anotherOp"))
+ assertThat(
+ validatorConfig.isEnabled(
+ anyUser, projectName, "anyRef", "anotherOp", ImmutableListMultimap.of()))
.isTrue();
}
@@ -119,11 +137,15 @@
ValidatorConfig validatorConfig =
new ValidatorConfig(
- new FakeConfigFactory(projectName, config), new FakeGroupByNameFinder());
+ pluginName, new FakeConfigFactory(projectName, config), new FakeGroupByNameFinder());
assertThat(
validatorConfig.isEnabled(
- new FakeUserProvider("testGroup").get(), projectName, "refs/heads/myref", "testOp"))
+ new FakeUserProvider("testGroup").get(),
+ projectName,
+ "refs/heads/myref",
+ "testOp",
+ ImmutableListMultimap.of()))
.isFalse();
}
@@ -137,11 +159,48 @@
ValidatorConfig validatorConfig =
new ValidatorConfig(
- new FakeConfigFactory(projectName, config), new FakeGroupByNameFinder());
+ pluginName, new FakeConfigFactory(projectName, config), new FakeGroupByNameFinder());
assertThat(
validatorConfig.isEnabled(
- anyUser, projectName, "refs/heads/anotherRef", "testOp"))
+ anyUser,
+ projectName,
+ "refs/heads/anotherRef",
+ "testOp",
+ ImmutableListMultimap.of()))
.isTrue();
}
+
+ @Test
+ public void dontSkipOnPushOptionIfNotEnabled() throws Exception {
+ ValidatorConfig validatorConfig =
+ new ValidatorConfig(
+ pluginName, new FakeConfigFactory(projectName, ""), new FakeGroupByNameFinder());
+
+ assertThat(
+ validatorConfig.isEnabled(
+ anyUser,
+ projectName,
+ "anyRef",
+ "anyOp",
+ ImmutableListMultimap.of("uploadvalidator~skip", "")))
+ .isTrue();
+ }
+
+ @Test
+ public void skipOnPushOptionEnabled() throws Exception {
+ String config = "[plugin \"uploadvalidator\"]\n" + "skipViaPushOption=true";
+ ValidatorConfig validatorConfig =
+ new ValidatorConfig(
+ pluginName, new FakeConfigFactory(projectName, config), new FakeGroupByNameFinder());
+
+ assertThat(
+ validatorConfig.isEnabled(
+ anyUser,
+ projectName,
+ "anyRef",
+ "anyOp",
+ ImmutableListMultimap.of("uploadvalidator~skip", "")))
+ .isFalse();
+ }
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/UploadValidatorIT.java b/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/UploadValidatorIT.java
index a558336..0e9bf85 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/UploadValidatorIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/uploadvalidator/UploadValidatorIT.java
@@ -19,6 +19,7 @@
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gerrit.acceptance.GitUtil;
import com.google.gerrit.acceptance.LightweightPluginDaemonTest;
@@ -30,11 +31,16 @@
import com.google.gerrit.extensions.api.changes.DraftInput;
import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.api.changes.ReviewInput.DraftHandling;
+import com.google.gerrit.extensions.client.ChangeStatus;
+import com.google.gerrit.extensions.common.ChangeInput;
+import com.google.gerrit.extensions.common.MergeInput;
import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.inject.Inject;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Before;
import org.junit.Test;
@@ -48,30 +54,17 @@
TestRepository<InMemoryRepository> clone;
void pushConfig(String config) throws Exception {
- TestRepository<InMemoryRepository> allProjectRepo = cloneProject(allProjects, admin);
- GitUtil.fetch(allProjectRepo, RefNames.REFS_CONFIG + ":config");
- allProjectRepo.reset("config");
+ TestRepository<InMemoryRepository> repo = cloneProject(project, admin);
+ GitUtil.fetch(repo, RefNames.REFS_CONFIG + ":config");
+ repo.reset("config");
PushOneCommit push =
- pushFactory.create(admin.newIdent(), allProjectRepo, "Subject", "project.config", config);
+ pushFactory.create(admin.newIdent(), repo, "Subject", "project.config", config);
PushOneCommit.Result res = push.to(RefNames.REFS_CONFIG);
res.assertOkStatus();
}
@Before
public void setup() throws Exception {
-
- pushConfig(
- Joiner.on("\n")
- .join(
- "[plugin \"uploadvalidator\"]",
- " blockedFileExtension = jar",
- " blockedFileExtension = .zip",
- " blockedKeywordPattern = secr3t",
- " invalidFilenamePattern = [%:@]",
- " rejectWindowsLineEndings = true",
- " maxPathLength = 20",
- " rejectDuplicatePathnames = true"));
-
projectOperations
.project(allProjects)
.forUpdate()
@@ -84,20 +77,37 @@
}
@Test
- public void testFileExtension() throws Exception {
+ public void fileExtension() throws Exception {
+ pushConfig(
+ Joiner.on("\n")
+ .join(
+ "[plugin \"uploadvalidator\"]",
+ " blockedFileExtension = jar",
+ " blockedFileExtension = .zip"));
+ RevCommit head = getHead(testRepo.getRepository(), "HEAD");
pushFactory
.create(admin.newIdent(), clone, "Subject", "file.jar", "content")
.to("refs/heads/master")
.assertErrorStatus("blocked file extensions");
+ clone.reset(head);
pushFactory
.create(admin.newIdent(), clone, "Subject", "file.zip", "content")
.to("refs/heads/master")
.assertErrorStatus("blocked file extensions");
+
+ clone.reset(head);
+ pushFactory
+ .create(admin.newIdent(), clone, "Subject", "file.txt", "content")
+ .to("refs/heads/master")
+ .assertOkStatus();
}
@Test
- public void testKeywordInComment() throws Exception {
+ public void keywordInComment() throws Exception {
+ pushConfig(
+ Joiner.on("\n").join("[plugin \"uploadvalidator\"]", " blockedKeywordPattern = secr3t"));
+
PushOneCommit.Result r1 = createChange("Subject", "file.txt", "content");
DraftInput in = new DraftInput();
in.message = "the password is secr3t ! ";
@@ -114,7 +124,10 @@
}
@Test
- public void testKeywordInFile() throws Exception {
+ public void keywordInNewFile() throws Exception {
+ pushConfig(
+ Joiner.on("\n").join("[plugin \"uploadvalidator\"]", " blockedKeywordPattern = secr3t"));
+
pushFactory
.create(admin.newIdent(), clone, "Subject", "file.txt", "blah secr3t blah")
.to("refs/heads/master")
@@ -122,23 +135,47 @@
}
@Test
- public void testFilenamePattern() throws Exception {
+ public void filenamePattern() throws Exception {
+ pushConfig(
+ Joiner.on("\n").join("[plugin \"uploadvalidator\"]", " invalidFilenamePattern = [%:@]"));
+
+ RevCommit head = getHead(testRepo.getRepository(), "HEAD");
pushFactory
.create(admin.newIdent(), clone, "Subject", "f:le.txt", "content")
.to("refs/heads/master")
.assertErrorStatus("invalid filename");
+
+ clone.reset(head);
+ pushFactory
+ .create(admin.newIdent(), clone, "Subject", "file.txt", "content")
+ .to("refs/heads/master")
+ .assertOkStatus();
}
@Test
- public void testWindowsLineEndings() throws Exception {
+ public void windowsLineEndings() throws Exception {
+ pushConfig(
+ Joiner.on("\n")
+ .join("[plugin \"uploadvalidator\"]", " rejectWindowsLineEndings = true"));
+
+ RevCommit head = getHead(testRepo.getRepository(), "HEAD");
pushFactory
.create(admin.newIdent(), clone, "Subject", "win.ini", "content\r\nline2\r\n")
.to("refs/heads/master")
.assertErrorStatus("Windows line ending");
+
+ clone.reset(head);
+ pushFactory
+ .create(admin.newIdent(), clone, "Subject", "file.txt", "content\nline2\n")
+ .to("refs/heads/master")
+ .assertOkStatus();
}
@Test
- public void testPathLength() throws Exception {
+ public void pathLength() throws Exception {
+ pushConfig(Joiner.on("\n").join("[plugin \"uploadvalidator\"]", " maxPathLength = 20"));
+
+ RevCommit head = getHead(testRepo.getRepository(), "HEAD");
pushFactory
.create(
admin.newIdent(),
@@ -148,10 +185,20 @@
"content\nline2\n")
.to("refs/heads/master")
.assertErrorStatus("too long paths");
+
+ clone.reset(head);
+ pushFactory
+ .create(admin.newIdent(), clone, "Subject", "file.txt", "content\nline2\n")
+ .to("refs/heads/master")
+ .assertOkStatus();
}
@Test
- public void testUniqueName() throws Exception {
+ public void uniqueName() throws Exception {
+ pushConfig(
+ Joiner.on("\n")
+ .join("[plugin \"uploadvalidator\"]", " rejectDuplicatePathnames = true"));
+
pushFactory
.create(
admin.newIdent(),
@@ -161,4 +208,244 @@
.to("refs/heads/master")
.assertErrorStatus("duplicate pathnames");
}
+
+ @Test
+ public void rulesNotEnforcedForNonGroupMembers() throws Exception {
+ pushConfig(
+ Joiner.on("\n")
+ .join(
+ "[plugin \"uploadvalidator\"]",
+ " group = " + adminGroupUuid(),
+ " rejectDuplicatePathnames = true"));
+
+ TestRepository<InMemoryRepository> userClone =
+ GitUtil.cloneProject(project, registerRepoConnection(project, user));
+ pushFactory
+ .create(
+ user.newIdent(),
+ userClone,
+ "Subject",
+ ImmutableMap.of("a.txt", "content\nline2\n", "A.TXT", "content"))
+ .to("refs/heads/master")
+ .assertOkStatus();
+ }
+
+ @Test
+ public void rulesNotEnforcedForSkipPushOption() throws Exception {
+ pushConfig(
+ Joiner.on("\n")
+ .join(
+ "[plugin \"uploadvalidator\"]",
+ " skipViaPushOption = true",
+ " rejectDuplicatePathnames = true"));
+
+ PushOneCommit push =
+ pushFactory.create(
+ admin.newIdent(),
+ clone,
+ "Subject",
+ ImmutableMap.of("a.txt", "content\nline2\n", "A.TXT", "content"));
+ push.setPushOptions(ImmutableList.of("uploadvalidator~skip"));
+ push.to("refs/heads/master").assertOkStatus();
+ }
+
+ @Test
+ public void keywordExistsInFileButNotInDiff() throws Exception {
+ pushFactory
+ .create(
+ admin.newIdent(),
+ clone,
+ "Subject",
+ "file.txt",
+ "" + "blah \n" + "secr3t\n" + "blah" + "")
+ .to("refs/heads/master")
+ .assertOkStatus();
+ pushConfig(
+ Joiner.on("\n").join("[plugin \"uploadvalidator\"]", " blockedKeywordPattern = secr3t"));
+ pushFactory
+ .create(
+ admin.newIdent(),
+ clone,
+ "Subject",
+ "file.txt",
+ "" + "blah \n" + "secr3t\n" + "foo" + "")
+ .to("refs/heads/master")
+ .assertOkStatus();
+ }
+
+ @Test
+ public void keywordExistsInNewFile() throws Exception {
+ pushConfig(
+ Joiner.on("\n").join("[plugin \"uploadvalidator\"]", " blockedKeywordPattern = secr3t"));
+ pushFactory
+ .create(
+ admin.newIdent(),
+ clone,
+ "Subject",
+ "file.txt",
+ "" + "blah \n" + "secr3t\n" + "foo\n" + "secr3t")
+ .to("refs/heads/master")
+ .assertErrorStatus("blocked keywords");
+ }
+
+ @Test
+ public void keywordExistsInFileAndInDiff() throws Exception {
+ pushFactory
+ .create(
+ admin.newIdent(),
+ clone,
+ "Subject",
+ "file.txt",
+ "" + "blah \n" + "secr3t\n" + "blah" + "")
+ .to("refs/heads/master")
+ .assertOkStatus();
+ pushConfig(
+ Joiner.on("\n").join("[plugin \"uploadvalidator\"]", " blockedKeywordPattern = secr3t"));
+ pushFactory
+ .create(
+ admin.newIdent(),
+ clone,
+ "Subject",
+ "file.txt",
+ "" + "blah \n" + "secr3t\n" + "blah\n" + "secr3t")
+ .to("refs/heads/master")
+ .assertErrorStatus("blocked keywords");
+ }
+
+ @Test
+ public void keywordExistsInFileAndIsRemoved() throws Exception {
+ pushFactory
+ .create(
+ admin.newIdent(), clone, "Subject", "file.txt", "" + "blah \n" + "secr3t\n" + "blah")
+ .to("refs/heads/master")
+ .assertOkStatus();
+ pushConfig(
+ Joiner.on("\n").join("[plugin \"uploadvalidator\"]", " blockedKeywordPattern = secr3t"));
+ pushFactory
+ .create(admin.newIdent(), clone, "Subject", "file.txt", "" + "blah \n" + "blah\n")
+ .to("refs/heads/master")
+ .assertOkStatus();
+ }
+
+ @Test
+ public void keywordExistsInFileAndSameLineIsModified() throws Exception {
+ pushFactory
+ .create(
+ admin.newIdent(),
+ clone,
+ "Subject",
+ "file.txt",
+ "" + "blah \n" + "secr3t\n" + "blah" + "")
+ .to("refs/heads/master")
+ .assertOkStatus();
+ pushConfig(
+ Joiner.on("\n").join("[plugin \"uploadvalidator\"]", " blockedKeywordPattern = secr3t"));
+ // This could be further improved using intra-line diffs
+ pushFactory
+ .create(
+ admin.newIdent(),
+ clone,
+ "Subject",
+ "file.txt",
+ "" + "blah \n" + "secr3t foobar\n" + "blah" + "")
+ .to("refs/heads/master")
+ .assertErrorStatus("blocked keywords");
+ }
+
+ @Test
+ public void keywordExistsInOldAndFileIsDeleted() throws Exception {
+ pushFactory
+ .create(
+ admin.newIdent(),
+ clone,
+ "Subject",
+ "file.txt",
+ "" + "blah \n" + "secr3t\n" + "blah" + "")
+ .to("refs/heads/master")
+ .assertOkStatus();
+ pushConfig(
+ Joiner.on("\n").join("[plugin \"uploadvalidator\"]", " blockedKeywordPattern = secr3t"));
+ pushFactory
+ .create(admin.newIdent(), clone, "Subject", "foo.txt", "blah")
+ .rmFile("file.txt")
+ .to("refs/heads/master")
+ .assertOkStatus();
+ }
+
+ @Test
+ public void createChangeSucceedsWhenKeywordDoesNotExistInFileAndDiff() throws Exception {
+ RevCommit head = getHead(testRepo.getRepository(), "HEAD");
+ pushConfig(
+ Joiner.on("\n").join("[plugin \"uploadvalidator\"]", " blockedKeywordPattern = secr3t"));
+ pushFactory
+ .create(admin.newIdent(), clone, "Subject", "file.txt", "" + "blah \n")
+ .to("refs/heads/master")
+ .assertOkStatus();
+ clone.reset(head);
+ pushFactory
+ .create(admin.newIdent(), clone, "Subject", "foo.txt", "" + "blah \n")
+ .to("refs/heads/stable")
+ .assertOkStatus();
+ ChangeInput changeInput = new ChangeInput();
+ changeInput.project = project.get();
+ changeInput.branch = "master";
+ changeInput.subject = "A change";
+ changeInput.status = ChangeStatus.NEW;
+ MergeInput mergeInput = new MergeInput();
+ mergeInput.source = gApi.projects().name(project.get()).branch("stable").get().revision;
+ changeInput.merge = mergeInput;
+ gApi.changes().create(changeInput);
+ }
+
+ @Test
+ public void createChangeSucceedsWhenKeywordExistsInFileButNotInDiff() throws Exception {
+ RevCommit head = getHead(testRepo.getRepository(), "HEAD");
+ pushFactory
+ .create(admin.newIdent(), clone, "Subject", "file.txt", "" + "secr3t \n")
+ .to("refs/heads/master")
+ .assertOkStatus();
+ pushConfig(
+ Joiner.on("\n").join("[plugin \"uploadvalidator\"]", " blockedKeywordPattern = secr3t"));
+ clone.reset(head);
+ pushFactory
+ .create(admin.newIdent(), clone, "Subject", "foo.txt", "" + "blah \n")
+ .to("refs/heads/stable")
+ .assertOkStatus();
+ ChangeInput changeInput = new ChangeInput();
+ changeInput.project = project.get();
+ changeInput.branch = "master";
+ changeInput.subject = "A change";
+ changeInput.status = ChangeStatus.NEW;
+ MergeInput mergeInput = new MergeInput();
+ mergeInput.source = gApi.projects().name(project.get()).branch("stable").get().revision;
+ changeInput.merge = mergeInput;
+ gApi.changes().create(changeInput);
+ }
+
+ @Test
+ public void createChangeWithKeywordInMessageFails() throws Exception {
+ RevCommit head = getHead(testRepo.getRepository(), "HEAD");
+ pushConfig(
+ Joiner.on("\n").join("[plugin \"uploadvalidator\"]", " blockedKeywordPattern = secr3t"));
+ pushFactory
+ .create(admin.newIdent(), clone, "Subject", "file.txt", "" + "blah \n")
+ .to("refs/heads/master")
+ .assertOkStatus();
+ clone.reset(head);
+ pushFactory
+ .create(admin.newIdent(), clone, "Subject", "foo.txt", "" + "blah \n")
+ .to("refs/heads/stable")
+ .assertOkStatus();
+ ChangeInput changeInput = new ChangeInput();
+ changeInput.project = project.get();
+ changeInput.branch = "master";
+ changeInput.subject = "A secr3t change";
+ changeInput.status = ChangeStatus.NEW;
+ MergeInput mergeInput = new MergeInput();
+ mergeInput.source = gApi.projects().name(project.get()).branch("stable").get().revision;
+ changeInput.merge = mergeInput;
+ ResourceConflictException e =
+ assertThrows(ResourceConflictException.class, () -> gApi.changes().create(changeInput));
+ assertThat(e).hasMessageThat().contains("blocked keyword(s) found");
+ }
}