Return more project settings from /project/*/config

Include the project state, the default submit type and the max object
size limit into the result of the /projects/*/config REST endpoint.

Change-Id: I5228cf7c11646b74234b8edd49ba1f76c965239d
diff --git a/Documentation/rest-api-projects.txt b/Documentation/rest-api-projects.txt
index 412b60f..57d6290 100644
--- a/Documentation/rest-api-projects.txt
+++ b/Documentation/rest-api-projects.txt
@@ -455,7 +455,14 @@
       "value": false,
       "configured_value": "FALSE",
       "inherited_value": true
-    }
+    },
+    "max_object_size_limit": {
+      "value": "15m",
+      "configured_value": "15m",
+      "inherited_value": "20m"
+    },
+    "submit_type": "MERGE_IF_NECESSARY",
+    "state": "ACTIVE",
     "commentlinks": {}
   }
 ----
@@ -1086,6 +1093,17 @@
 valid link:user-changeid.html[Change-Id] footer in any commit uploaded
 for review is required. This does not apply to commits pushed directly
 to a branch or tag.
+|`max_object_size_limit`     ||
+The link:config-gerrit.html#receive.maxObjectSizeLimit[max object size
+limit] of this project as a link:#max-object-size-limit-info[
+MaxObjectSizeLimitInfo] entity.
+|`submit_type`               ||
+The default submit type of the project, can be `MERGE_IF_NECESSARY`,
+`FAST_FORWARD_ONLY`, `REBASE_IF_NECESSARY`, `MERGE_ALWAYS` or
+`CHERRY_PICK`.
+|`state`                     |optional|
+The state of the project, can be `ACTIVE`, `READ_ONLY` or `HIDDEN`. +
+Not set if the project state is `ACTIVE`.
 |`commentlinks`              ||
 Map with the comment link configurations of the project. The name of
 the comment link configuration is mapped to the comment link
@@ -1196,6 +1214,29 @@
 Not set if there is no parent.
 |================================
 
+[[max-object-size-limit-info]]
+MaxObjectSizeLimitInfo
+~~~~~~~~~~~~~~~~~~~~~~
+The `MaxObjectSizeLimitInfo` entity contains information about the
+link:config-gerrit.html#receive.maxObjectSizeLimit[max object size
+limit] of a project.
+
+[options="header",width="50%",cols="1,^2,4"]
+|===============================
+|Field Name        ||Description
+|`value`           |optional|
+The effective value of the max object size limit as a formatted string. +
+Not set if there is no limit for the object size.
+|`configured_value`|optional|
+The max object size limit that is configured on the project as a
+formatted string. +
+Not set if there is no limit for the object size configured on project
+level.
+|`inherited_value` |optional|
+The max object size limit that is inherited as a formatted string. +
+Not set if there is no global limit for the object size.
+|===============================
+
 [[project-description-input]]
 ProjectDescriptionInput
 ~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/TransferConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/TransferConfig.java
index af404b5..8be0a10 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/TransferConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/TransferConfig.java
@@ -16,6 +16,7 @@
 
 import com.google.gerrit.server.config.ConfigUtil;
 import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.project.ProjectState;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
@@ -29,12 +30,14 @@
   private final int timeout;
   private final PackConfig packConfig;
   private final long maxObjectSizeLimit;
+  private final String maxObjectSizeLimitFormatted;
 
   @Inject
   TransferConfig(@GerritServerConfig final Config cfg) {
     timeout = (int) ConfigUtil.getTimeUnit(cfg, "transfer", null, "timeout", //
         0, TimeUnit.SECONDS);
     maxObjectSizeLimit = cfg.getLong("receive", "maxObjectSizeLimit", 0);
+    maxObjectSizeLimitFormatted = cfg.getString("receive", null, "maxObjectSizeLimit");
 
     packConfig = new PackConfig();
     packConfig.setDeltaCompress(false);
@@ -54,4 +57,19 @@
   public long getMaxObjectSizeLimit() {
     return maxObjectSizeLimit;
   }
+
+  public String getFormattedMaxObjectSizeLimit() {
+    return maxObjectSizeLimitFormatted;
+  }
+
+  public long getEffectiveMaxObjectSizeLimit(ProjectState p) {
+    long global = getMaxObjectSizeLimit();
+    long local = p.getMaxObjectSizeLimit();
+    if (global > 0 && local > 0) {
+      return Math.min(global, local);
+    } else {
+      // zero means "no limit", in this case the max is more limiting
+      return Math.max(global, local);
+    }
+  }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetConfig.java
index ee14d71..9193fd9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetConfig.java
@@ -19,15 +19,26 @@
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.Project.InheritableBoolean;
+import com.google.gerrit.reviewdb.client.Project.SubmitType;
+import com.google.gerrit.server.git.TransferConfig;
+import com.google.inject.Inject;
 
 import java.util.Map;
 
 public class GetConfig implements RestReadView<ProjectResource> {
 
+  private final TransferConfig config;
+
+  @Inject
+  public GetConfig(TransferConfig config) {
+    this.config = config;
+  }
+
   @Override
   public ConfigInfo apply(ProjectResource resource) {
     ConfigInfo result = new ConfigInfo();
     ProjectState state = resource.getControl().getProjectState();
+    Project p = state.getProject();
     InheritedBooleanInfo useContributorAgreements = new InheritedBooleanInfo();
     InheritedBooleanInfo useSignedOffBy = new InheritedBooleanInfo();
     InheritedBooleanInfo useContentMerge = new InheritedBooleanInfo();
@@ -38,7 +49,6 @@
     useContentMerge.value = state.isUseContentMerge();
     requireChangeId.value = state.isRequireChangeID();
 
-    Project p = state.getProject();
     useContributorAgreements.configuredValue = p.getUseContributorAgreements();
     useSignedOffBy.configuredValue = p.getUseSignedOffBy();
     useContentMerge.configuredValue = p.getUseContentMerge();
@@ -57,6 +67,18 @@
     result.useContentMerge = useContentMerge;
     result.requireChangeId = requireChangeId;
 
+    MaxObjectSizeLimitInfo maxObjectSizeLimit = new MaxObjectSizeLimitInfo();
+    maxObjectSizeLimit.value =
+        config.getEffectiveMaxObjectSizeLimit(state) == config.getMaxObjectSizeLimit()
+            ? config.getFormattedMaxObjectSizeLimit()
+            : p.getMaxObjectSizeLimit();
+    maxObjectSizeLimit.configuredValue = p.getMaxObjectSizeLimit();
+    maxObjectSizeLimit.inheritedValue = config.getFormattedMaxObjectSizeLimit();
+    result.maxObjectSizeLimit = maxObjectSizeLimit;
+
+    result.submitType = p.getSubmitType();
+    result.state = p.getState() != Project.State.ACTIVE ? p.getState() : null;
+
     result.commentlinks = Maps.newLinkedHashMap();
     for (CommentLinkInfo cl : state.getCommentLinks()) {
       result.commentlinks.put(cl.name, cl);
@@ -73,6 +95,9 @@
     public InheritedBooleanInfo useContentMerge;
     public InheritedBooleanInfo useSignedOffBy;
     public InheritedBooleanInfo requireChangeId;
+    public MaxObjectSizeLimitInfo maxObjectSizeLimit;
+    public SubmitType submitType;
+    public Project.State state;
 
     public Map<String, CommentLinkInfo> commentlinks;
     public ThemeInfo theme;
@@ -83,4 +108,10 @@
     public InheritableBoolean configuredValue;
     public Boolean inheritedValue;
   }
+
+  public static class MaxObjectSizeLimitInfo {
+    public String value;
+    public String configuredValue;
+    public String inheritedValue;
+  }
 }
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java
index 28f20cf..f9d5ac1 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java
@@ -94,7 +94,8 @@
     final ReceivePack rp = receive.getReceivePack();
     rp.setRefLogIdent(currentUser.newRefLogIdent());
     rp.setTimeout(config.getTimeout());
-    rp.setMaxObjectSizeLimit(getMaxObjectSizeLimit());
+    rp.setMaxObjectSizeLimit(config.getEffectiveMaxObjectSizeLimit(
+        projectControl.getProjectState()));
     try {
       receive.advertiseHistory();
       rp.receive(in, out, err);
@@ -170,15 +171,4 @@
       }
     }
   }
-
-  private long getMaxObjectSizeLimit() {
-    long global = config.getMaxObjectSizeLimit();
-    long local = projectControl.getProjectState().getMaxObjectSizeLimit();
-    if (global > 0 && local > 0) {
-      return Math.min(global, local);
-    } else {
-      // zero means "no limit", in this case the max is more limiting
-      return Math.max(global, local);
-    }
-  }
 }