Add support for project inheritance

Make it so that the plugin configurations can be inherited
from parent projects.

Feature: issue 3704
Change-Id: I7c9fc062f1b144eb61f0aa0d35280f11057b3e68
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 e98046e..b6c581c 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/BlockedKeywordValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/BlockedKeywordValidator.java
@@ -106,7 +106,8 @@
       CommitReceivedEvent receiveEvent) throws CommitValidationException {
     try {
       PluginConfig cfg = cfgFactory
-          .getFromProjectConfig(receiveEvent.project.getNameKey(), pluginName);
+          .getFromProjectConfigWithInheritance(
+              receiveEvent.project.getNameKey(), pluginName);
       if (!isActive(cfg)) {
         return Collections.emptyList();
       }
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 f5b9a3c..ee598c3 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/ContentTypeValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/ContentTypeValidator.java
@@ -109,7 +109,8 @@
       CommitReceivedEvent receiveEvent) throws CommitValidationException {
     try {
       PluginConfig cfg = cfgFactory
-          .getFromProjectConfig(receiveEvent.project.getNameKey(), pluginName);
+          .getFromProjectConfigWithInheritance(
+              receiveEvent.project.getNameKey(), pluginName);
       if (!isActive(cfg)) {
         return Collections.emptyList();
       }
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 833549a..75c18d2 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/DuplicatePathnameValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/DuplicatePathnameValidator.java
@@ -166,7 +166,8 @@
       CommitReceivedEvent receiveEvent) throws CommitValidationException {
     try {
       PluginConfig cfg = cfgFactory
-          .getFromProjectConfig(receiveEvent.project.getNameKey(), pluginName);
+          .getFromProjectConfigWithInheritance(
+              receiveEvent.project.getNameKey(), pluginName);
       if (!isActive(cfg)) {
         return Collections.emptyList();
       }
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 d43016f..3f455bd 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/FileExtensionValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/FileExtensionValidator.java
@@ -90,7 +90,8 @@
       CommitReceivedEvent receiveEvent) throws CommitValidationException {
     try {
       PluginConfig cfg = cfgFactory
-          .getFromProjectConfig(receiveEvent.project.getNameKey(), pluginName);
+          .getFromProjectConfigWithInheritance(
+              receiveEvent.project.getNameKey(), pluginName);
       if (!isActive(cfg)) {
         return Collections.emptyList();
       }
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 0b62af3..420e47a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/FooterValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/FooterValidator.java
@@ -74,7 +74,7 @@
       CommitReceivedEvent receiveEvent) throws CommitValidationException {
     try {
       PluginConfig cfg =
-          cfgFactory.getFromProjectConfig(
+          cfgFactory.getFromProjectConfigWithInheritance(
               receiveEvent.project.getNameKey(), pluginName);
       String[] requiredFooters =
           cfg.getStringList(KEY_REQUIRED_FOOTER);
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 60a859e..973be15 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/InvalidFilenameValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/InvalidFilenameValidator.java
@@ -82,7 +82,7 @@
       CommitReceivedEvent receiveEvent) throws CommitValidationException {
     try {
       PluginConfig cfg =
-          cfgFactory.getFromProjectConfig(
+          cfgFactory.getFromProjectConfigWithInheritance(
               receiveEvent.project.getNameKey(), pluginName);
       if (!isActive(cfg)) {
         return Collections.emptyList();
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 a0eabaa..7183b69 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/InvalidLineEndingValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/InvalidLineEndingValidator.java
@@ -94,7 +94,7 @@
       CommitReceivedEvent receiveEvent) throws CommitValidationException {
     try {
       PluginConfig cfg =
-          cfgFactory.getFromProjectConfig(
+          cfgFactory.getFromProjectConfigWithInheritance(
               receiveEvent.project.getNameKey(), pluginName);
       if (!isActive(cfg)) {
         return Collections.emptyList();
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 08d42f7..aa898dd 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/MaxPathLengthValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/MaxPathLengthValidator.java
@@ -79,7 +79,7 @@
       CommitReceivedEvent receiveEvent) throws CommitValidationException {
     try {
       PluginConfig cfg =
-          cfgFactory.getFromProjectConfig(
+          cfgFactory.getFromProjectConfigWithInheritance(
               receiveEvent.project.getNameKey(), pluginName);
       if (!isActive(cfg)) {
         return Collections.emptyList();
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 fc6b539..b58418d 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/SubmoduleValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/SubmoduleValidator.java
@@ -81,7 +81,8 @@
       CommitReceivedEvent receiveEvent) throws CommitValidationException {
     try {
       PluginConfig cfg = cfgFactory
-          .getFromProjectConfig(receiveEvent.project.getNameKey(), pluginName);
+          .getFromProjectConfigWithInheritance(
+              receiveEvent.project.getNameKey(), pluginName);
       if (!isActive(cfg)) {
         return Collections.emptyList();
       }
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 5d90465..b5a090d 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/SymlinkValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/uploadvalidator/SymlinkValidator.java
@@ -82,7 +82,7 @@
       CommitReceivedEvent receiveEvent) throws CommitValidationException {
     try {
       PluginConfig cfg =
-          cfgFactory.getFromProjectConfig(
+          cfgFactory.getFromProjectConfigWithInheritance(
               receiveEvent.project.getNameKey(), pluginName);
       if (!isActive(cfg)) {
         return Collections.emptyList();
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index faa4498..2fafca7 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -1,5 +1,8 @@
+@PLUGIN@
+========
+
 Configuration
-=============
+-------------
 
 The configuration of the @PLUGIN@ plugin is done on project level in
 the `project.config` file of the project.
@@ -41,29 +44,22 @@
 	blocked file extensions with or without a leading dot. This check
 	only test if the filename ends with one of the defined values.
 
-	Blocked file extensions are *not* inherited by child projects.
-
 plugin.@PLUGIN@.requiredFooter
 :	Footer that is required.
 
-	Required footers are *not* inherited by child projects.
+	This is the footer in the commit message.
 
 plugin.@PLUGIN@.maxPathLength
 :	Maximum allowed path length. '0' means no limit.
 
 	Defaults to '0'.
 
-	The maximum allowed path length is *not* inherited by child
-	projects.
-
 plugin.@PLUGIN@.invalidFilenamePattern
 :	Patterns for invalid filenames.
 
 	This check is using `java.util.regex.Pattern` which is described
 	[here][1].
 
-	Defined patterns are *not* inherited by child projects.
-
 plugin.@PLUGIN@.rejectWindowsLineEndings
 :	Reject Windows line endings.
 
@@ -75,8 +71,6 @@
 
 	The default value is false. This means the check will not be executed.
 
-	This option is *not* inherited by child projects.
-
 <a name="binary_type">
 plugin.@PLUGIN@.binaryType
 :	Binary types.
@@ -99,8 +93,6 @@
 
 	Full list of supported content types can be found [here][3].
 
-	This option is *not* inherited by child projects.
-
 plugin.@PLUGIN@.rejectSymlink
 :	Reject symbolic links.
 
@@ -109,8 +101,6 @@
 
 	The default value is false. This means the check will not be executed.
 
-	This option is *not* inherited by child projects.
-
 plugin.@PLUGIN@.rejectSubmodule
 :	Reject submodules.
 
@@ -119,8 +109,6 @@
 
 	The default value is false. This means the check will not be executed.
 
-	This option is *not* inherited by child projects.
-
 plugin.@PLUGIN@.blockedKeywordPattern
 :	Patterns for blocked keywords.
 
@@ -135,8 +123,6 @@
 
 	This check does not run on [binary files][4]
 
-	Defined patterns are *not* inherited by child projects.
-
 [1]: https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html
 [2]: https://tika.apache.org/
 [3]: https://tika.apache.org/1.12/formats.html#Full_list_of_Supported_Formats
@@ -162,8 +148,6 @@
 
 	Full list of supported content types can be found [here][3].
 
-	Defined patterns are *not* inherited by child projects.
-
 plugin.@PLUGIN@.blockedContentTypeWhitelist
 :	Blocked content type whitelist.
 
@@ -178,8 +162,6 @@
 	The default value is false. This means the entered content types are
 	interpreted as a blacklist.
 
-	Defined patterns are *not* inherited by child projects.
-
 plugin.@PLUGIN@.rejectDuplicatePathnames
 :	Reject duplicate pathnames.
 
@@ -191,8 +173,6 @@
 	The default value is false. This means duplicate pathnames ignoring
 	case are allowed.
 
-	This option is *not* inherited by child projects.
-
 plugin.@PLUGIN@.rejectDuplicatePathnamesLocale
 :	Reject duplicate pathnames locale.
 
@@ -206,7 +186,23 @@
 
 	The default value is "en" (English).
 
-	This option is *not* inherited by child projects.
-
 [5]: http://bugs.java.com/view_bug.do?bug_id=6208680
 [6]: http://www.oracle.com/technetwork/java/javase/javase7locales-334809.html
+
+
+UI Integration
+--------------
+
+This @PLUGIN@ configuration is read from the project.config, editable from
+the general project settings screen.
+E.g. /admin/projects/myrepo for a project named 'myrepo'
+
+Inheritance
+-----------
+
+The configuration parameters for this plugin are inheritable, meaning that
+child projects can inherit settings from a parent project.
+The mechanism for evaluating the combined parameters follows the standard
+[Project's inheritance rules][7].
+
+[7]: config-project-config.html#file-project_config