Merge "Move Truth to nongoogle.bzl"
diff --git a/java/com/google/gerrit/server/query/project/ProjectQueryProcessor.java b/java/com/google/gerrit/server/query/project/ProjectQueryProcessor.java
index 66eab7b..8e6d8a1 100644
--- a/java/com/google/gerrit/server/query/project/ProjectQueryProcessor.java
+++ b/java/com/google/gerrit/server/query/project/ProjectQueryProcessor.java
@@ -38,6 +38,8 @@
  *
  * <p>Instances are one-time-use. Other singleton classes should inject a Provider rather than
  * holding on to a single instance.
+ *
+ * <p>By default, enforces visibility to CurrentUser.
  */
 public class ProjectQueryProcessor extends QueryProcessor<ProjectData> {
   private final PermissionBackend permissionBackend;
diff --git a/java/com/google/gerrit/server/restapi/change/CherryPickChange.java b/java/com/google/gerrit/server/restapi/change/CherryPickChange.java
index 5753874..a3e0cf0 100644
--- a/java/com/google/gerrit/server/restapi/change/CherryPickChange.java
+++ b/java/com/google/gerrit/server/restapi/change/CherryPickChange.java
@@ -334,7 +334,7 @@
                 input.allowEmpty,
                 input.allowConflicts);
       } catch (MergeIdenticalTreeException | MergeConflictException e) {
-        throw new IntegrationConflictException("Cherry pick failed: " + e.getMessage());
+        throw new IntegrationConflictException("Cherry pick failed: " + e.getMessage(), e);
       }
 
       try (BatchUpdate bu = batchUpdateFactory.create(project, identifiedUser, timestamp)) {
diff --git a/java/com/google/gerrit/server/restapi/change/ReviewerRecommender.java b/java/com/google/gerrit/server/restapi/change/ReviewerRecommender.java
index 39df82d..da09f11 100644
--- a/java/com/google/gerrit/server/restapi/change/ReviewerRecommender.java
+++ b/java/com/google/gerrit/server/restapi/change/ReviewerRecommender.java
@@ -182,7 +182,7 @@
     // Sort results
     Stream<Map.Entry<Account.Id, MutableDouble>> sorted =
         reviewerScores.entrySet().stream()
-            .sorted(Collections.reverseOrder(Map.Entry.comparingByValue()));
+            .sorted(Map.Entry.comparingByValue(Collections.reverseOrder()));
     List<Account.Id> sortedSuggestions = sorted.map(Map.Entry::getKey).collect(toList());
     logger.atFine().log("Sorted suggestions: %s", sortedSuggestions);
     return sortedSuggestions;
diff --git a/java/com/google/gerrit/server/restapi/project/ConfigInfoImpl.java b/java/com/google/gerrit/server/restapi/project/ConfigInfoCreator.java
similarity index 77%
rename from java/com/google/gerrit/server/restapi/project/ConfigInfoImpl.java
rename to java/com/google/gerrit/server/restapi/project/ConfigInfoCreator.java
index 783b39b..904a16f 100644
--- a/java/com/google/gerrit/server/restapi/project/ConfigInfoImpl.java
+++ b/java/com/google/gerrit/server/restapi/project/ConfigInfoCreator.java
@@ -21,6 +21,10 @@
 import com.google.gerrit.entities.Project;
 import com.google.gerrit.extensions.api.projects.CommentLinkInfo;
 import com.google.gerrit.extensions.api.projects.ConfigInfo;
+import com.google.gerrit.extensions.api.projects.ConfigInfo.ConfigParameterInfo;
+import com.google.gerrit.extensions.api.projects.ConfigInfo.InheritedBooleanInfo;
+import com.google.gerrit.extensions.api.projects.ConfigInfo.MaxObjectSizeLimitInfo;
+import com.google.gerrit.extensions.api.projects.ConfigInfo.SubmitTypeInfo;
 import com.google.gerrit.extensions.api.projects.ProjectConfigEntryType;
 import com.google.gerrit.extensions.common.ActionInfo;
 import com.google.gerrit.extensions.registration.DynamicMap;
@@ -42,9 +46,12 @@
 import java.util.Map;
 import java.util.TreeMap;
 
-public class ConfigInfoImpl extends ConfigInfo {
+public class ConfigInfoCreator {
+  /** do not instantiate this class. */
+  private ConfigInfoCreator() {}
+
   @SuppressWarnings("deprecation")
-  public ConfigInfoImpl(
+  public static ConfigInfo constructInfo(
       boolean serverEnableSignedPush,
       ProjectState projectState,
       CurrentUser user,
@@ -53,8 +60,9 @@
       AllProjectsName allProjects,
       UiActions uiActions,
       DynamicMap<RestView<ProjectResource>> views) {
+    ConfigInfo configInfo = new ConfigInfo();
     Project p = projectState.getProject();
-    this.description = Strings.emptyToNull(p.getDescription());
+    configInfo.description = Strings.emptyToNull(p.getDescription());
 
     ProjectState parentState = Iterables.getFirst(projectState.parents(), null);
     for (BooleanProjectConfig cfg : BooleanProjectConfig.values()) {
@@ -63,48 +71,51 @@
       if (parentState != null) {
         info.inheritedValue = parentState.is(cfg);
       }
-      BooleanProjectConfigTransformations.set(cfg, this, info);
+      BooleanProjectConfigTransformations.set(cfg, configInfo, info);
     }
 
     if (!serverEnableSignedPush) {
-      this.enableSignedPush = null;
-      this.requireSignedPush = null;
+      configInfo.enableSignedPush = null;
+      configInfo.requireSignedPush = null;
     }
 
-    this.maxObjectSizeLimit = getMaxObjectSizeLimit(projectState, p);
+    configInfo.maxObjectSizeLimit = getMaxObjectSizeLimit(projectState, p);
 
-    this.defaultSubmitType = new SubmitTypeInfo();
-    this.defaultSubmitType.value = projectState.getSubmitType();
-    this.defaultSubmitType.configuredValue =
+    configInfo.defaultSubmitType = new SubmitTypeInfo();
+    configInfo.defaultSubmitType.value = projectState.getSubmitType();
+    configInfo.defaultSubmitType.configuredValue =
         MoreObjects.firstNonNull(
             projectState.getConfig().getProject().getSubmitType(), Project.DEFAULT_SUBMIT_TYPE);
     ProjectState parent =
         projectState.isAllProjects() ? projectState : projectState.parents().get(0);
-    this.defaultSubmitType.inheritedValue = parent.getSubmitType();
+    configInfo.defaultSubmitType.inheritedValue = parent.getSubmitType();
 
-    this.submitType = this.defaultSubmitType.value;
+    configInfo.submitType = configInfo.defaultSubmitType.value;
 
-    this.state =
+    configInfo.state =
         p.getState() != com.google.gerrit.extensions.client.ProjectState.ACTIVE
             ? p.getState()
             : null;
 
-    this.commentlinks = new LinkedHashMap<>();
+    configInfo.commentlinks = new LinkedHashMap<>();
     for (CommentLinkInfo cl : projectState.getCommentLinks()) {
-      this.commentlinks.put(cl.name, cl);
+      configInfo.commentlinks.put(cl.name, cl);
     }
 
-    pluginConfig = getPluginConfig(projectState, pluginConfigEntries, cfgFactory, allProjects);
+    configInfo.pluginConfig =
+        getPluginConfig(projectState, pluginConfigEntries, cfgFactory, allProjects);
 
-    actions = new TreeMap<>();
+    configInfo.actions = new TreeMap<>();
     for (UiAction.Description d : uiActions.from(views, new ProjectResource(projectState, user))) {
-      actions.put(d.getId(), new ActionInfo(d));
+      configInfo.actions.put(d.getId(), new ActionInfo(d));
     }
 
-    this.extensionPanelNames = projectState.getConfig().getExtensionPanelSections();
+    configInfo.extensionPanelNames = projectState.getConfig().getExtensionPanelSections();
+    return configInfo;
   }
 
-  private MaxObjectSizeLimitInfo getMaxObjectSizeLimit(ProjectState projectState, Project p) {
+  private static MaxObjectSizeLimitInfo getMaxObjectSizeLimit(
+      ProjectState projectState, Project p) {
     MaxObjectSizeLimitInfo info = new MaxObjectSizeLimitInfo();
     EffectiveMaxObjectSizeLimit limit = projectState.getEffectiveMaxObjectSizeLimit();
     long value = limit.value;
@@ -114,7 +125,7 @@
     return info;
   }
 
-  private Map<String, Map<String, ConfigParameterInfo>> getPluginConfig(
+  private static Map<String, Map<String, ConfigParameterInfo>> getPluginConfig(
       ProjectState project,
       DynamicMap<ProjectConfigEntry> pluginConfigEntries,
       PluginConfigFactory cfgFactory,
@@ -162,7 +173,7 @@
     return !pluginConfig.isEmpty() ? pluginConfig : null;
   }
 
-  private String getInheritedValue(
+  private static String getInheritedValue(
       ProjectState project, PluginConfigFactory cfgFactory, Extension<ProjectConfigEntry> e) {
     ProjectConfigEntry configEntry = e.getProvider().get();
     ProjectState parent = Iterables.getFirst(project.parents(), null);
diff --git a/java/com/google/gerrit/server/restapi/project/DeleteTags.java b/java/com/google/gerrit/server/restapi/project/DeleteTags.java
index 6e8ec37..7ac3aff 100644
--- a/java/com/google/gerrit/server/restapi/project/DeleteTags.java
+++ b/java/com/google/gerrit/server/restapi/project/DeleteTags.java
@@ -43,6 +43,10 @@
     if (input == null || input.tags == null || input.tags.isEmpty()) {
       throw new BadRequestException("tags must be specified");
     }
+
+    // If input.tags = ["refs/heads/bla"], this will actually delete the 'ref/heads/bla' branch,
+    // rather than refs/tags/refs/heads/bla.
+    // Since this is checked against DELETE permissions for refs/heads/bla, we'll let it go through.
     deleteRef.deleteMultipleRefs(
         project.getProjectState(), ImmutableSet.copyOf(input.tags), R_TAGS);
     return Response.none();
diff --git a/java/com/google/gerrit/server/restapi/project/GetConfig.java b/java/com/google/gerrit/server/restapi/project/GetConfig.java
index ad66587..8ffd5ec 100644
--- a/java/com/google/gerrit/server/restapi/project/GetConfig.java
+++ b/java/com/google/gerrit/server/restapi/project/GetConfig.java
@@ -67,7 +67,7 @@
             .project(resource.getNameKey())
             .test(ProjectPermission.READ_CONFIG);
     return Response.ok(
-        new ConfigInfoImpl(
+        ConfigInfoCreator.constructInfo(
             serverEnableSignedPush,
             resource.getProjectState(),
             resource.getUser(),
diff --git a/java/com/google/gerrit/server/restapi/project/ListChildProjects.java b/java/com/google/gerrit/server/restapi/project/ListChildProjects.java
index 0bd053e..6a0fc97 100644
--- a/java/com/google/gerrit/server/restapi/project/ListChildProjects.java
+++ b/java/com/google/gerrit/server/restapi/project/ListChildProjects.java
@@ -25,7 +25,6 @@
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.permissions.PermissionBackendException;
-import com.google.gerrit.server.permissions.ProjectPermission;
 import com.google.gerrit.server.project.ChildProjects;
 import com.google.gerrit.server.project.ProjectResource;
 import com.google.inject.Inject;
@@ -85,8 +84,6 @@
   private List<ProjectInfo> directChildProjects(Project.NameKey parent) throws RestApiException {
     PermissionBackend.WithUser currentUser = permissionBackend.currentUser();
     return queryProvider.get().withQuery("parent:" + parent.get()).withLimit(limit).apply().stream()
-        .filter(
-            p -> currentUser.project(Project.nameKey(p.name)).testOrFalse(ProjectPermission.ACCESS))
         .collect(toList());
   }
 }
diff --git a/java/com/google/gerrit/server/restapi/project/PutConfig.java b/java/com/google/gerrit/server/restapi/project/PutConfig.java
index 55ea312..afa08cd 100644
--- a/java/com/google/gerrit/server/restapi/project/PutConfig.java
+++ b/java/com/google/gerrit/server/restapi/project/PutConfig.java
@@ -176,7 +176,7 @@
       }
 
       ProjectState state = projectStateFactory.create(projectConfigFactory.read(md).getCacheable());
-      return new ConfigInfoImpl(
+      return ConfigInfoCreator.constructInfo(
           serverEnableSignedPush,
           state,
           user.get(),
diff --git a/javatests/com/google/gerrit/acceptance/rest/project/ListChildProjectsIT.java b/javatests/com/google/gerrit/acceptance/rest/project/ListChildProjectsIT.java
index 7535dea..3c8357b 100644
--- a/javatests/com/google/gerrit/acceptance/rest/project/ListChildProjectsIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/project/ListChildProjectsIT.java
@@ -16,13 +16,21 @@
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.gerrit.acceptance.rest.project.ProjectAssert.assertThatNameList;
+import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allow;
+import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.block;
 import static com.google.gerrit.testing.GerritJUnit.assertThrows;
 
 import com.google.gerrit.acceptance.AbstractDaemonTest;
 import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.acceptance.testsuite.group.GroupOperations;
 import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
+import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
+import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.entities.Permission;
 import com.google.gerrit.entities.Project;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.server.group.SystemGroupBackend;
 import com.google.inject.Inject;
 import org.apache.commons.lang.RandomStringUtils;
 import org.junit.Test;
@@ -30,6 +38,8 @@
 @NoHttpd
 public class ListChildProjectsIT extends AbstractDaemonTest {
   @Inject private ProjectOperations projectOperations;
+  @Inject private GroupOperations groupOperations;
+  @Inject private RequestScopeOperations requestScopeOperations;
 
   @Test
   public void listChildrenOfNonExistingProject_NotFound() throws Exception {
@@ -84,4 +94,29 @@
         .containsExactly(child1_1, child1_1_1, child1_1_1_1, child1_2)
         .inOrder();
   }
+
+  @Test
+  public void listChildrenVisibility() throws Exception {
+    Project.NameKey parent = projectOperations.newProject().createEmptyCommit(true).create();
+    Project.NameKey project =
+        projectOperations.newProject().createEmptyCommit(true).parent(parent).create();
+
+    AccountGroup.UUID privilegedGroupUuid =
+        groupOperations.newGroup().name(name("privilegedGroup")).create();
+    projectOperations
+        .project(project)
+        .forUpdate()
+        .add(allow(Permission.READ).ref("refs/*").group(privilegedGroupUuid))
+        .add(block(Permission.READ).ref("refs/*").group(SystemGroupBackend.REGISTERED_USERS))
+        .update();
+
+    TestAccount privilegedUser =
+        accountCreator.create("privilegedUser", "snowden@nsa.gov", "Ed Snowden", null);
+    groupOperations.group(privilegedGroupUuid).forUpdate().addMember(privilegedUser.id()).update();
+
+    requestScopeOperations.setApiUser(user.id());
+    assertThat(gApi.projects().name(parent.get()).children(false)).isEmpty();
+    requestScopeOperations.setApiUser(privilegedUser.id());
+    assertThat(gApi.projects().name(parent.get()).children(false)).isNotEmpty();
+  }
 }
diff --git a/plugins/replication b/plugins/replication
index 6185455..f83ee3f 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit 6185455e0bbe184b9b7d7fb29d19335c2cdeb000
+Subproject commit f83ee3ff6af7f93529a6518d138893e347936786
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts
index 9574c1d..601ea80 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts
@@ -716,19 +716,10 @@
       }
 
       if (lineNumberEl) {
-        const ANNOTATE_MAX_LINE_LENGTH = 1000;
-        // For performance reason, we skip annotating long lines.
-        if (line.text.length < ANNOTATE_MAX_LINE_LENGTH) {
-          for (const layer of this.layers) {
-            if (typeof layer.annotate === 'function') {
-              layer.annotate(contentText, lineNumberEl, line);
-            }
+        for (const layer of this.layers) {
+          if (typeof layer.annotate === 'function') {
+            layer.annotate(contentText, lineNumberEl, line);
           }
-        } else {
-          const msg =
-            `A line is longer than ${ANNOTATE_MAX_LINE_LENGTH}.` +
-            ' Line annotation was skipped.';
-          console.warn(msg);
         }
       } else {
         console.error('The lineNumberEl is null, skipping layer annotations.');