Merge "When message have overflow Y content clip it."
diff --git a/java/com/google/gerrit/server/project/ProjectConfig.java b/java/com/google/gerrit/server/project/ProjectConfig.java
index d01954c..7eb5f57 100644
--- a/java/com/google/gerrit/server/project/ProjectConfig.java
+++ b/java/com/google/gerrit/server/project/ProjectConfig.java
@@ -1191,6 +1191,7 @@
   }
 
   private void saveAccountsSection(Config rc, Set<AccountGroup.UUID> keepGroups) {
+    unsetSection(rc, ACCOUNTS);
     if (accountsSection != null) {
       rc.setStringList(
           ACCOUNTS,
@@ -1201,6 +1202,7 @@
   }
 
   private void saveCommentLinkSections(Config rc) {
+    unsetSection(rc, COMMENTLINK);
     if (commentLinkSections != null) {
       for (CommentLinkInfoImpl cm : commentLinkSections.values()) {
         rc.setString(COMMENTLINK, cm.name, KEY_MATCH, cm.match);
@@ -1218,6 +1220,7 @@
   }
 
   private void saveContributorAgreements(Config rc, Set<AccountGroup.UUID> keepGroups) {
+    unsetSection(rc, CONTRIBUTOR_AGREEMENT);
     for (ContributorAgreement ca : sort(contributorAgreements.values())) {
       set(rc, CONTRIBUTOR_AGREEMENT, ca.getName(), KEY_DESCRIPTION, ca.getDescription());
       set(rc, CONTRIBUTOR_AGREEMENT, ca.getName(), KEY_AGREEMENT_URL, ca.getAgreementUrl());
@@ -1251,6 +1254,7 @@
   }
 
   private void saveNotifySections(Config rc, Set<AccountGroup.UUID> keepGroups) {
+    unsetSection(rc, NOTIFY);
     for (NotifyConfig nc : sort(notifySections.values())) {
       nc.getGroups().stream()
           .map(GroupReference::getUUID)
@@ -1305,6 +1309,7 @@
   }
 
   private void saveAccessSections(Config rc, Set<AccountGroup.UUID> keepGroups) {
+    unsetSection(rc, CAPABILITY);
     AccessSection capability = accessSections.get(AccessSection.GLOBAL_CAPABILITIES);
     if (capability != null) {
       Set<String> have = new HashSet<>();
@@ -1387,9 +1392,7 @@
     List<String> existing = new ArrayList<>(rc.getSubsections(LABEL));
     if (!new ArrayList<>(labelSections.keySet()).equals(existing)) {
       // Order of sections changed, remove and rewrite them all.
-      for (String name : existing) {
-        rc.unsetSection(LABEL, name);
-      }
+      unsetSection(rc, LABEL);
     }
 
     Set<String> toUnset = new HashSet<>(existing);
@@ -1485,11 +1488,7 @@
   }
 
   private void savePluginSections(Config rc, Set<AccountGroup.UUID> keepGroups) {
-    List<String> existing = new ArrayList<>(rc.getSubsections(PLUGIN));
-    for (String name : existing) {
-      rc.unsetSection(PLUGIN, name);
-    }
-
+    unsetSection(rc, PLUGIN);
     for (Map.Entry<String, Config> e : pluginConfigs.entrySet()) {
       String plugin = e.getKey();
       Config pluginConfig = e.getValue();
@@ -1530,6 +1529,13 @@
     }
   }
 
+  private void unsetSection(Config rc, String sectionName) {
+    for (String subSectionName : rc.getSubsections(sectionName)) {
+      rc.unsetSection(sectionName, subSectionName);
+    }
+    rc.unsetSection(sectionName, null);
+  }
+
   private <E extends Enum<?>> E getEnum(
       Config rc, String section, String subsection, String name, E defaultValue) {
     try {
diff --git a/javatests/com/google/gerrit/server/project/ProjectConfigTest.java b/javatests/com/google/gerrit/server/project/ProjectConfigTest.java
index 07cfe2f..0b401df 100644
--- a/javatests/com/google/gerrit/server/project/ProjectConfigTest.java
+++ b/javatests/com/google/gerrit/server/project/ProjectConfigTest.java
@@ -318,17 +318,17 @@
                 + "\tsubmit = group Staff\n"
                 + "  upload = group Developers\n"
                 + "  read = group Developers\n"
-                + "[accounts]\n"
-                + "  sameGroupVisibility = group Staff\n"
-                + "[contributor-agreement \"Individual\"]\n"
-                + "  description = A new description\n"
-                + "  accepted = group Staff\n"
-                + "  agreementUrl = http://www.example.com/agree\n"
-                + "\texcludeProjects = ^/theirproject\n"
                 + "[label \"CustomLabel\"]\n"
                 + LABEL_SCORES_CONFIG
                 + "\tfunction = MaxWithBlock\n" // label gets this function when it is created
-                + "\tdefaultValue = 0\n"); //  label gets this value when it is created
+                + "\tdefaultValue = 0\n" //  label gets this value when it is created
+                + "[accounts]\n"
+                + "\tsameGroupVisibility = group Staff\n"
+                + "[contributor-agreement \"Individual\"]\n"
+                + "\tdescription = A new description\n"
+                + "\tagreementUrl = http://www.example.com/agree\n"
+                + "\taccepted = group Staff\n"
+                + "\texcludeProjects = ^/theirproject\n");
   }
 
   @Test
@@ -454,27 +454,6 @@
   }
 
   @Test
-  public void pluginSectionIsUnsetIfAllPluginConfigsAreEmpty() throws Exception {
-    RevCommit rev =
-        tr.commit()
-            .add(
-                "project.config",
-                "[commentlink \"bugzilla\"]\n"
-                    + "  match = \"(bugs#?)(d+)\"\n"
-                    + "[plugin \"somePlugin\"]\n"
-                    + "  key = value\n")
-            .create();
-    update(rev);
-
-    ProjectConfig cfg = read(rev);
-    PluginConfig pluginCfg = cfg.getPluginConfig("somePlugin");
-    pluginCfg.unset("key");
-    rev = commit(cfg);
-    assertThat(text(rev, "project.config"))
-        .isEqualTo("[commentlink \"bugzilla\"]\n  match = \"(bugs#?)(d+)\"\n");
-  }
-
-  @Test
   public void readPluginConfigGroupReference() throws Exception {
     RevCommit rev =
         tr.commit()
@@ -661,6 +640,118 @@
         .isEqualTo(InheritableBoolean.INHERIT);
   }
 
+  @Test
+  public void accountsSectionIsUnsetIfNoSameGroupVisibilityIsSet() throws Exception {
+    RevCommit rev =
+        tr.commit()
+            .add(
+                "project.config",
+                "[commentlink \"bugzilla\"]\n"
+                    + "\tmatch = \"(bug\\\\s+#?)(\\\\d+)\"\n"
+                    + "\tlink = http://bugs.example.com/show_bug.cgi?id=$2\n"
+                    + "[accounts]\n"
+                    + "  sameGroupVisibility = group Staff\n")
+            .create();
+    update(rev);
+
+    ProjectConfig cfg = read(rev);
+    cfg.getAccountsSection().setSameGroupVisibility(ImmutableList.of());
+    rev = commit(cfg);
+    assertThat(text(rev, "project.config"))
+        .isEqualTo(
+            "[commentlink \"bugzilla\"]\n\tmatch = \"(bug\\\\s+#?)(\\\\d+)\"\n\tlink = http://bugs.example.com/show_bug.cgi?id=$2\n");
+  }
+
+  @Test
+  public void contributorSectionIsUnsetIfNoContributorAgreementIsSet() throws Exception {
+    RevCommit rev =
+        tr.commit()
+            .add(
+                "project.config",
+                "[commentlink \"bugzilla\"]\n"
+                    + "\tmatch = \"(bug\\\\s+#?)(\\\\d+)\"\n"
+                    + "\tlink = http://bugs.example.com/show_bug.cgi?id=$2\n"
+                    + "[contributor-agreement \"Individual\"]\n"
+                    + "  accepted = group Developers\n"
+                    + "  accepted = group Staff\n")
+            .create();
+    update(rev);
+
+    ProjectConfig cfg = read(rev);
+    ContributorAgreement section = cfg.getContributorAgreement("Individual");
+    section.setAccepted(ImmutableList.of());
+    rev = commit(cfg);
+    assertThat(text(rev, "project.config"))
+        .isEqualTo(
+            "[commentlink \"bugzilla\"]\n\tmatch = \"(bug\\\\s+#?)(\\\\d+)\"\n\tlink = http://bugs.example.com/show_bug.cgi?id=$2\n");
+  }
+
+  @Test
+  public void notifySectionIsUnsetIfNoNotificationsAreSet() throws Exception {
+    RevCommit rev =
+        tr.commit()
+            .add(
+                "project.config",
+                "[commentlink \"bugzilla\"]\n"
+                    + "\tmatch = \"(bug\\\\s+#?)(\\\\d+)\"\n"
+                    + "\tlink = http://bugs.example.com/show_bug.cgi?id=$2\n"
+                    + "[notify \"name\"]\n"
+                    + "  email = example@example.com\n")
+            .create();
+    update(rev);
+
+    ProjectConfig cfg = read(rev);
+    cfg.getNotifyConfigs().clear();
+    rev = commit(cfg);
+    assertThat(text(rev, "project.config"))
+        .isEqualTo(
+            "[commentlink \"bugzilla\"]\n\tmatch = \"(bug\\\\s+#?)(\\\\d+)\"\n\tlink = http://bugs.example.com/show_bug.cgi?id=$2\n");
+  }
+
+  @Test
+  public void commentLinkSectionIsUnsetIfNoCommentLinksAreSet() throws Exception {
+    RevCommit rev =
+        tr.commit()
+            .add(
+                "project.config",
+                "[commentlink \"bugzilla\"]\n"
+                    + "\tmatch = \"(bug\\\\s+#?)(\\\\d+)\"\n"
+                    + "\tlink = http://bugs.example.com/show_bug.cgi?id=$2\n"
+                    + "[notify \"name\"]\n"
+                    + "  email = example@example.com\n")
+            .create();
+    update(rev);
+
+    ProjectConfig cfg = read(rev);
+    cfg.getCommentLinkSections().clear();
+    rev = commit(cfg);
+    assertThat(text(rev, "project.config"))
+        .isEqualTo("[notify \"name\"]\n\temail = example@example.com\n");
+  }
+
+  @Test
+  public void pluginSectionIsUnsetIfAllPluginConfigsAreEmpty() throws Exception {
+    RevCommit rev =
+        tr.commit()
+            .add(
+                "project.config",
+                "[commentlink \"bugzilla\"]\n"
+                    + "\tmatch = \"(bug\\\\s+#?)(\\\\d+)\"\n"
+                    + "\tlink = http://bugs.example.com/show_bug.cgi?id=$2\n"
+                    + "[plugin \"somePlugin\"]\n"
+                    + "  key = value\n")
+            .create();
+    update(rev);
+
+    ProjectConfig cfg = read(rev);
+    PluginConfig pluginCfg = cfg.getPluginConfig("somePlugin");
+    pluginCfg.unset("key");
+    rev = commit(cfg);
+    assertThat(text(rev, "project.config"))
+        .isEqualTo(
+            "[commentlink \"bugzilla\"]\n\tmatch = \"(bug\\\\s+#?)(\\\\d+)\"\n\tlink = http://bugs.example.com/show_bug.cgi?id=$2\n");
+  }
+
   private Path writeDefaultAllProjectsConfig(String... lines) throws IOException {
     Path dir = sitePaths.etc_dir.resolve(ALL_PROJECTS.get());
     Files.createDirectories(dir);
diff --git a/plugins/replication b/plugins/replication
index a5a5e0c..90253f8 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit a5a5e0cd13f1ff2614d77e9bf1bacbbc1d61b696
+Subproject commit 90253f88e42653a0c3af632beae507847f71adec
diff --git a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.html b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.html
index 2f2c7ba..7f71c89 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.html
+++ b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.html
@@ -40,8 +40,14 @@
       :host([show-avatar]) .container {
         padding-left: 0;
       }
+      gr-button.remove:hover,
+      gr-button.remove:focus {
+        --gr-button: {
+          color: #333;
+        }
+      }
       gr-button.remove {
-        --gr-remove-button-style: {
+        --gr-button: {
           border: 0;
           color: var(--deemphasized-text-color);
           font-size: 1.7rem;
@@ -53,19 +59,6 @@
           text-decoration: none;
         }
       }
-
-      gr-button.remove:hover,
-      gr-button.remove:focus {
-        --gr-button: {
-          @apply --gr-remove-button-style
-          color: #333;
-        }
-      }
-      gr-button.remove {
-        --gr-button: {
-          @apply --gr-remove-button-style
-        }
-      }
       :host:focus {
         border-color: transparent;
         box-shadow: none;
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.html b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.html
index 46877d7..b74e48c 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.html
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.html
@@ -76,31 +76,14 @@
         on-focus="_onInputFocus"
         on-blur="_onInputBlur"
         autocomplete="off">
-
-      <template is="dom-if" if="[[_isPolymer2()]]">
-        <!-- Content uses vertical-align:baseline. If iron-icon is placed
-          directly in the slot and is not visible,  vertical-align doesn't
-          work, because display:none convert it from inline-block element to
-          block element. To fix this problem, iron-icon is wrapped in div
-          which never changes display type.
-          The problem doesn't exist in Polymer1 because DOM is different.
-          Applying the same fix to Polymer1 breaks vertical-align.
-        -->
-        <div slot="prefix">
-          <iron-icon
-            icon="gr-icons:search"
-            class$="searchIcon [[_computeShowSearchIconClass(showSearchIcon)]]">
-          </iron-icon>
-        </div>
-      </template>
-      <template is="dom-if" if="[[!_isPolymer2()]]">
-        <iron-icon
-          prefix
+      <!-- slot is for future use (2.x) while prefix attribute is for 1.x
+        (current) -->
+      <iron-icon
           icon="gr-icons:search"
+          slot="prefix"
+          prefix
           class$="searchIcon [[_computeShowSearchIconClass(showSearchIcon)]]">
-        </iron-icon>
-      </template>
-
+      </iron-icon>
     </paper-input>
     <gr-autocomplete-dropdown
         vertical-align="top"
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
index af31473..34f1ff9 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.js
@@ -425,9 +425,5 @@
     _computeShowSearchIconClass(showSearchIcon) {
       return showSearchIcon ? 'showSearchIcon' : '';
     },
-
-    _isPolymer2() {
-      return window.POLYMER2;
-    },
   });
 })();
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
index cff35b4..217321f 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete_test.html
@@ -320,15 +320,12 @@
       });
     });
 
-    test('search icon shows with showSearchIcon property', done => {
-      flush(() => {
-        assert.equal(getComputedStyle(element.$$('iron-icon')).display,
-            'none');
-        element.showSearchIcon = true;
-        assert.notEqual(getComputedStyle(element.$$('iron-icon')).display,
-            'none');
-        done();
-      });
+    test('search icon shows with showSearchIcon property', () => {
+      assert.equal(getComputedStyle(element.$$('iron-icon')).display,
+          'none');
+      element.showSearchIcon = true;
+      assert.notEqual(getComputedStyle(element.$$('iron-icon')).display,
+          'none');
     });
 
     test('vertical offset overridden by param if it exists', () => {
diff --git a/polygerrit-ui/app/elements/shared/gr-button/gr-button.html b/polygerrit-ui/app/elements/shared/gr-button/gr-button.html
index 340297f..754c3c0 100644
--- a/polygerrit-ui/app/elements/shared/gr-button/gr-button.html
+++ b/polygerrit-ui/app/elements/shared/gr-button/gr-button.html
@@ -39,37 +39,6 @@
         text-transform: none;
       }
       paper-button {
-        /* The next lines contains a copy of paper-button style.
-          Without a copy, the @apply works incorrectly with Polymer 2.
-          @apply is deprecated and is not recommended to use. It is expected
-          that @apply will be replaced with the ::part CSS pseudo-element.
-          After replacecment copied lines can be removed.
-        */
-        @apply --layout-inline;
-        @apply --layout-center-center;
-        position: relative;
-        box-sizing: border-box;
-        min-width: 5.14em;
-        margin: 0 0.29em;
-        background: transparent;
-        -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-        -webkit-tap-highlight-color: transparent;
-        font: inherit;
-        text-transform: uppercase;
-        outline-width: 0;
-        border-radius: 3px;
-        -moz-user-select: none;
-        -ms-user-select: none;
-        -webkit-user-select: none;
-        user-select: none;
-        cursor: pointer;
-        z-index: 0;
-        padding: 0.7em 0.57em;
-
-        @apply --paper-font-common-base;
-        @apply --paper-button;
-        /* End of copy*/
-
         /* paper-button sets this to anti-aliased, which appears different than
           bold font elsewhere on macOS. */
         -webkit-font-smoothing: initial;
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.html b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.html
index 939d582..f6332f4 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.html
+++ b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.html
@@ -37,8 +37,14 @@
         display: inline-flex;
         padding: 0 .5em;
       }
+      gr-button.remove:hover,
+      gr-button.remove:focus {
+        --gr-button: {
+          color: #333;
+        }
+      }
       gr-button.remove {
-        --gr-remove-button-style: {
+        --gr-button: {
           border: 0;
           color: var(--deemphasized-text-color);
           font-size: 1.7rem;
@@ -50,19 +56,6 @@
           text-decoration: none;
         }
       }
-
-      gr-button.remove:hover,
-      gr-button.remove:focus {
-        --gr-button: {
-          @apply --gr-remove-button-style
-          color: #333;
-        }
-      }
-      gr-button.remove {
-        --gr-button: {
-          @apply --gr-remove-button-style
-        }
-      }
       .transparentBackground,
       gr-button.transparentBackground {
         background-color: transparent;
diff --git a/polygerrit-ui/app/styles/gr-voting-styles.html b/polygerrit-ui/app/styles/gr-voting-styles.html
index eec79be..3b1ee64 100644
--- a/polygerrit-ui/app/styles/gr-voting-styles.html
+++ b/polygerrit-ui/app/styles/gr-voting-styles.html
@@ -23,7 +23,6 @@
           border: 1px solid rgba(0,0,0,.12);
           border-radius: 1em;
           box-shadow: none;
-          box-sizing: border-box;
           min-width: 3em;
         }
       }