Merge "CreateLabel/SetLabel: Reject duplicate values"
diff --git a/Jenkinsfile b/Jenkinsfile
index 0193df3..f21c7897 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -185,9 +185,17 @@
 
 def collectBuilds() {
     def builds = [:]
-    builds["Gerrit-codestyle"] = prepareBuildsForMode("Gerrit-codestyle")
-    Builds.modes.each {
-        builds["Gerrit-verification(${it})"] = prepareBuildsForMode("Gerrit-verifier-bazel", it)
+    if (env.GERRIT_CHANGE_NUMBER == "") {
+       builds["java8"] = { -> build "Gerrit-bazel-${env.BRANCH_NAME}" }
+
+       if (env.BRANCH_NAME == "master") {
+          builds["java11"] = { -> build "Gerrit-bazel-java11-${env.BRANCH_NAME}" }
+       }
+    } else {
+        builds["Gerrit-codestyle"] = prepareBuildsForMode("Gerrit-codestyle")
+        Builds.modes.each {
+            builds["Gerrit-verification(${it})"] = prepareBuildsForMode("Gerrit-verifier-bazel", it)
+        }
     }
     return builds
 }
@@ -274,44 +282,48 @@
 
 node ('master') {
 
-    stage('Preparing'){
-        gerritReview labels: ['Verified': 0, 'Code-Style': 0]
+    if (env.GERRIT_CHANGE_NUMBER != "") {
+        stage('Preparing'){
+            gerritReview labels: ['Verified': 0, 'Code-Style': 0]
 
-        getChangeMetaData()
-        collectBuildModes()
+            getChangeMetaData()
+            collectBuildModes()
+        }
     }
 
     parallel(collectBuilds())
 
-    stage('Retry Flaky Builds'){
-        def flakyBuildsModes = findFlakyBuilds()
-        if (flakyBuildsModes.size() > 0){
-            parallel flakyBuildsModes.collectEntries {
-                ["Gerrit-verification(${it})" :
-                    prepareBuildsForMode("Gerrit-verifier-bazel", it, 3)]
+    if (env.GERRIT_CHANGE_NUMBER != "") {
+        stage('Retry Flaky Builds'){
+            def flakyBuildsModes = findFlakyBuilds()
+            if (flakyBuildsModes.size() > 0){
+                parallel flakyBuildsModes.collectEntries {
+                    ["Gerrit-verification(${it})" :
+                        prepareBuildsForMode("Gerrit-verifier-bazel", it, 3)]
+                }
             }
         }
-    }
 
-    stage('Report to Gerrit'){
-        resCodeStyle = getLabelValue(1, Builds.codeStyle.result)
-        gerritReview(
-            labels: ['Code-Style': resCodeStyle],
-            message: createCodeStyleMsgBody(Builds.codeStyle, resCodeStyle))
-        postCheck(new GerritCheck("codestyle", Change.number, Change.sha1, Builds.codeStyle))
+        stage('Report to Gerrit'){
+            resCodeStyle = getLabelValue(1, Builds.codeStyle.result)
+            gerritReview(
+                labels: ['Code-Style': resCodeStyle],
+                message: createCodeStyleMsgBody(Builds.codeStyle, resCodeStyle))
+            postCheck(new GerritCheck("codestyle", Change.number, Change.sha1, Builds.codeStyle))
 
-        def verificationResults = Builds.verification.collect { k, v -> v }
-        def resVerify = verificationResults.inject(1) {
-            acc, build -> getLabelValue(acc, build.result)
+            def verificationResults = Builds.verification.collect { k, v -> v }
+            def resVerify = verificationResults.inject(1) {
+                acc, build -> getLabelValue(acc, build.result)
+            }
+            gerritReview(
+                labels: ['Verified': resVerify],
+                message: createVerifyMsgBody(Builds.verification))
+
+            Builds.verification.each { type, build -> postCheck(
+                new GerritCheck(type, Change.number, Change.sha1, build)
+            )}
+
+            setResult(resVerify, resCodeStyle)
         }
-        gerritReview(
-            labels: ['Verified': resVerify],
-            message: createVerifyMsgBody(Builds.verification))
-
-        Builds.verification.each { type, build -> postCheck(
-            new GerritCheck(type, Change.number, Change.sha1, build)
-        )}
-
-        setResult(resVerify, resCodeStyle)
     }
 }
diff --git a/java/com/google/gerrit/server/CreateGroupPermissionSyncer.java b/java/com/google/gerrit/server/CreateGroupPermissionSyncer.java
index 996257c..5e7919f 100644
--- a/java/com/google/gerrit/server/CreateGroupPermissionSyncer.java
+++ b/java/com/google/gerrit/server/CreateGroupPermissionSyncer.java
@@ -115,11 +115,12 @@
                 .collect(toList()));
         config.replace(createGroupAccessSection);
       } else {
-        Permission createGroupPermission = new Permission(Permission.CREATE);
-        createGroupAccessSection.addPermission(createGroupPermission);
-        createGroupsGlobal.forEach(createGroupPermission::add);
         // The create permission is managed by Gerrit at this point only so there is no concern of
         // overwriting user-defined permissions here.
+        Permission createGroupPermission = new Permission(Permission.CREATE);
+        createGroupAccessSection.remove(createGroupPermission);
+        createGroupAccessSection.addPermission(createGroupPermission);
+        createGroupsGlobal.forEach(createGroupPermission::add);
         config.replace(createGroupAccessSection);
       }
 
diff --git a/java/com/google/gerrit/server/git/TracingHook.java b/java/com/google/gerrit/server/git/TracingHook.java
index 63d8bc6..56eded0 100644
--- a/java/com/google/gerrit/server/git/TracingHook.java
+++ b/java/com/google/gerrit/server/git/TracingHook.java
@@ -14,8 +14,6 @@
 
 package com.google.gerrit.server.git;
 
-import static com.google.common.base.Preconditions.checkState;
-
 import com.google.gerrit.server.logging.TraceContext;
 import java.util.List;
 import java.util.Optional;
@@ -59,7 +57,10 @@
    * @param serverOptionList list of provided server options
    */
   private void maybeStartTrace(List<String> serverOptionList) {
-    checkState(traceContext == null, "Trace was already started.");
+    if (traceContext != null) {
+      // Trace was already started
+      return;
+    }
 
     Optional<String> traceOption = parseTraceOption(serverOptionList);
     traceContext =
diff --git a/javatests/com/google/gerrit/acceptance/rest/project/AccessIT.java b/javatests/com/google/gerrit/acceptance/rest/project/AccessIT.java
index 91a10ca..3e9b1f6 100644
--- a/javatests/com/google/gerrit/acceptance/rest/project/AccessIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/project/AccessIT.java
@@ -604,7 +604,7 @@
   }
 
   @Test
-  public void syncCreateGroupPermission() throws Exception {
+  public void syncCreateGroupPermission_addAndRemoveCreateGroupCapability() throws Exception {
     // Grant CREATE_GROUP to Registered Users
     ProjectAccessInput accessInput = newProjectAccessInput();
     AccessSectionInfo accessSection = newAccessSectionInfo();
@@ -642,6 +642,44 @@
   }
 
   @Test
+  public void syncCreateGroupPermission_addCreateGroupCapabilityToMultipleGroups()
+      throws Exception {
+    PermissionRuleInfo pri = new PermissionRuleInfo(PermissionRuleInfo.Action.ALLOW, false);
+
+    // Grant CREATE_GROUP to Registered Users
+    ProjectAccessInput accessInput = newProjectAccessInput();
+    AccessSectionInfo accessSection = newAccessSectionInfo();
+    PermissionInfo createGroup = newPermissionInfo();
+    createGroup.rules.put(SystemGroupBackend.REGISTERED_USERS.get(), pri);
+    accessSection.permissions.put(GlobalCapability.CREATE_GROUP, createGroup);
+    accessInput.add.put(AccessSection.GLOBAL_CAPABILITIES, accessSection);
+    gApi.projects().name(allProjects.get()).access(accessInput);
+
+    // Grant CREATE_GROUP to Administrators
+    accessInput = newProjectAccessInput();
+    accessSection = newAccessSectionInfo();
+    createGroup = newPermissionInfo();
+    createGroup.rules.put(adminGroupUuid().get(), pri);
+    accessSection.permissions.put(GlobalCapability.CREATE_GROUP, createGroup);
+    accessInput.add.put(AccessSection.GLOBAL_CAPABILITIES, accessSection);
+    gApi.projects().name(allProjects.get()).access(accessInput);
+
+    // Assert that the permissions were synced from All-Projects (global) to All-Users (ref)
+    Map<String, AccessSectionInfo> local = gApi.projects().name("All-Users").access().local;
+    assertThat(local).isNotNull();
+    assertThat(local).containsKey(RefNames.REFS_GROUPS + "*");
+    Map<String, PermissionInfo> permissions = local.get(RefNames.REFS_GROUPS + "*").permissions;
+    assertThat(permissions).hasSize(2);
+    // READ is the default permission and should be preserved by the syncer
+    assertThat(permissions.keySet()).containsExactly(Permission.READ, Permission.CREATE);
+    Map<String, PermissionRuleInfo> rules = permissions.get(Permission.CREATE).rules;
+    assertThat(rules.keySet())
+        .containsExactly(SystemGroupBackend.REGISTERED_USERS.get(), adminGroupUuid().get());
+    assertThat(rules.get(SystemGroupBackend.REGISTERED_USERS.get())).isEqualTo(pri);
+    assertThat(rules.get(adminGroupUuid().get())).isEqualTo(pri);
+  }
+
+  @Test
   public void addAccessSectionForInvalidRef() throws Exception {
     ProjectAccessInput accessInput = newProjectAccessInput();
     AccessSectionInfo accessSectionInfo = createDefaultAccessSectionInfo();