Merge changes from topic 'bundle-diff-fixes'

* changes:
  ChangeBundle: Ignore ReviewDb current PSID if invalid
  ChangeBundle: Be more lenient about reviewers
  ChangeBundle: Handle change subjects extracted with a buggy JGit
  ChangeBundle: Fix ChangeMessage comparison for extra patch sets
  ChangeBundle: Handle leading whitespace in ReviewDb topics
  ChangeBundle: Fix NPE when change has no current patch set
diff --git a/Documentation/access-control.txt b/Documentation/access-control.txt
index 0123724..771e323 100644
--- a/Documentation/access-control.txt
+++ b/Documentation/access-control.txt
@@ -204,8 +204,8 @@
 Permissions can be set on a single reference name to match one
 branch (e.g. `refs/heads/master`), or on a reference namespace
 (e.g. `+refs/heads/*+`) to match any branch starting with that
-prefix. So a permission with `+refs/heads/*+` will match
-`refs/heads/master` and `refs/heads/experimental`, etc.
+prefix. So a permission with `+refs/heads/*+` will match all of
+`refs/heads/master`, `refs/heads/experimental`, `refs/heads/release/1.0` etc.
 
 Reference names can also be described with a regular expression
 by prefixing the reference name with `^`.  For example
diff --git a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/RestSession.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/RestSession.java
index 4c8ba42..9c59e10 100644
--- a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/RestSession.java
+++ b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/RestSession.java
@@ -54,6 +54,10 @@
     return execute(get);
   }
 
+  public RestResponse head(String endPoint) throws IOException {
+    return execute(Request.Head(url + "/a" + endPoint));
+  }
+
   public RestResponse put(String endPoint) throws IOException {
     return put(endPoint, null);
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AccountGroupSuggestOracle.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AccountGroupSuggestOracle.java
index aa76128..a96624a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AccountGroupSuggestOracle.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AccountGroupSuggestOracle.java
@@ -35,7 +35,9 @@
   @Override
   public void _onRequestSuggestions(final Request req, final Callback callback) {
     GroupMap.suggestAccountGroupForProject(
-        projectName.get(), req.getQuery(), req.getLimit(),
+        projectName == null ? null : projectName.get(),
+        req.getQuery(),
+        req.getLimit(),
         new GerritCallback<GroupMap>() {
           @Override
           public void onSuccess(GroupMap result) {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Change.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Change.java
index 20f9b82..1864c56 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Change.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Change.java
@@ -280,6 +280,9 @@
   /** ID number of the first patch set in a change. */
   public static final int INITIAL_PATCH_SET_ID = 1;
 
+  /** Change-Id pattern. */
+  public static final String CHANGE_ID_PATTERN = "^[iI][0-9a-f]{4,}.*$";
+
   /**
    * Current state within the basic workflow of the change.
    *
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/validators/CommitValidators.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/validators/CommitValidators.java
index 5e84fd3..74411ad 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/validators/CommitValidators.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/validators/CommitValidators.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.server.git.validators;
 
+import static com.google.gerrit.reviewdb.client.Change.CHANGE_ID_PATTERN;
 import static com.google.gerrit.reviewdb.client.RefNames.REFS_CHANGES;
 import static com.google.gerrit.reviewdb.client.RefNames.REFS_CONFIG;
 import static org.eclipse.jgit.lib.Constants.R_HEADS;
@@ -61,6 +62,7 @@
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.regex.Pattern;
 
 public class CommitValidators {
   private static final Logger log = LoggerFactory
@@ -182,6 +184,27 @@
   }
 
   public static class ChangeIdValidator implements CommitValidationListener {
+    private static final int SHA1_LENGTH = 7;
+    private static final String CHANGE_ID_PREFIX =
+        FooterConstants.CHANGE_ID.getName() + ":";
+    private static final String MISSING_CHANGE_ID_MSG =
+        "[%s] missing "
+        + FooterConstants.CHANGE_ID.getName()
+        + " in commit message footer";
+    private static final String MISSING_SUBJECT_MSG =
+        "[%s] missing subject; "
+        + FooterConstants.CHANGE_ID.getName()
+        + " must be in commit message footer";
+    private static final String MULTIPLE_CHANGE_ID_MSG =
+        "[%s] multiple "
+        + FooterConstants.CHANGE_ID.getName()
+        + " lines in commit message footer";
+    private static final String INVALID_CHANGE_ID_MSG =
+        "[%s] invalid "
+        + FooterConstants.CHANGE_ID.getName() +
+        " line format in commit message footer";
+    private static final Pattern CHANGE_ID = Pattern.compile(CHANGE_ID_PATTERN);
+
     private final ProjectControl projectControl;
     private final String canonicalWebUrl;
     private final String installCommitMsgHookCommand;
@@ -200,63 +223,62 @@
     @Override
     public List<CommitValidationMessage> onCommitReceived(
         CommitReceivedEvent receiveEvent) throws CommitValidationException {
-      final List<String> idList = receiveEvent.commit.getFooterLines(
-          FooterConstants.CHANGE_ID);
-
+      RevCommit commit = receiveEvent.commit;
       List<CommitValidationMessage> messages = new LinkedList<>();
+      List<String> idList = commit.getFooterLines(FooterConstants.CHANGE_ID);
+      String sha1 = commit.abbreviate(SHA1_LENGTH).name();
 
       if (idList.isEmpty()) {
         if (projectControl.getProjectState().isRequireChangeID()) {
-          String shortMsg = receiveEvent.commit.getShortMessage();
-          String changeIdPrefix = FooterConstants.CHANGE_ID.getName() + ":";
-          if (shortMsg.startsWith(changeIdPrefix)
-              && shortMsg.substring(changeIdPrefix.length()).trim()
-                  .matches("^I[0-9a-f]{8,}.*$")) {
-            throw new CommitValidationException(
-                "missing subject; Change-Id must be in commit message footer");
-          } else {
-            String errMsg = "missing Change-Id in commit message footer";
-            messages.add(getMissingChangeIdErrorMsg(
-                errMsg, receiveEvent.commit));
-            throw new CommitValidationException(errMsg, messages);
+          String shortMsg = commit.getShortMessage();
+          if (shortMsg.startsWith(CHANGE_ID_PREFIX)
+              && CHANGE_ID.matcher(shortMsg.substring(
+                  CHANGE_ID_PREFIX.length()).trim()).matches()) {
+            String errMsg = String.format(MISSING_SUBJECT_MSG, sha1);
+            throw new CommitValidationException(errMsg);
           }
-        }
-      } else if (idList.size() > 1) {
-        throw new CommitValidationException(
-            "multiple Change-Id lines in commit message footer", messages);
-      } else {
-        final String v = idList.get(idList.size() - 1).trim();
-        if (!v.matches("^I[0-9a-f]{8,}.*$")) {
-          final String errMsg =
-              "missing or invalid Change-Id line format in commit message footer";
-          messages.add(
-              getMissingChangeIdErrorMsg(errMsg, receiveEvent.commit));
+          String errMsg = String.format(MISSING_CHANGE_ID_MSG, sha1);
+          messages.add(getMissingChangeIdErrorMsg(errMsg, commit));
           throw new CommitValidationException(errMsg, messages);
         }
+      } else if (idList.size() > 1) {
+        String errMsg = String.format(
+            MULTIPLE_CHANGE_ID_MSG, sha1);
+        throw new CommitValidationException(errMsg, messages);
+      }
+      String v = idList.get(idList.size() - 1).trim();
+      if (!CHANGE_ID.matcher(v).matches()) {
+        String errMsg = String.format(INVALID_CHANGE_ID_MSG, sha1);
+        messages.add(
+          getMissingChangeIdErrorMsg(errMsg, receiveEvent.commit));
+        throw new CommitValidationException(errMsg, messages);
       }
       return Collections.emptyList();
     }
 
     private CommitValidationMessage getMissingChangeIdErrorMsg(
         final String errMsg, final RevCommit c) {
-      final String changeId = "Change-Id:";
       StringBuilder sb = new StringBuilder();
       sb.append("ERROR: ").append(errMsg);
 
-      if (c.getFullMessage().indexOf(changeId) >= 0) {
+      if (c.getFullMessage().indexOf(CHANGE_ID_PREFIX) >= 0) {
         String[] lines = c.getFullMessage().trim().split("\n");
         String lastLine = lines.length > 0 ? lines[lines.length - 1] : "";
 
-        if (lastLine.indexOf(changeId) == -1) {
+        if (lastLine.indexOf(CHANGE_ID_PREFIX) == -1) {
           sb.append('\n');
           sb.append('\n');
-          sb.append("Hint: A potential Change-Id was found, but it was not in the ");
+          sb.append("Hint: A potential ");
+          sb.append(FooterConstants.CHANGE_ID.getName());
+          sb.append("Change-Id was found, but it was not in the ");
           sb.append("footer (last paragraph) of the commit message.");
         }
       }
       sb.append('\n');
       sb.append('\n');
-      sb.append("Hint: To automatically insert Change-Id, install the hook:\n");
+      sb.append("Hint: To automatically insert ");
+      sb.append(FooterConstants.CHANGE_ID.getName());
+      sb.append(", install the hook:\n");
       sb.append(getCommitMessageHookInstallationHint());
       sb.append('\n');
       sb.append("And then amend the commit:\n");
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
index d92c2b2..590be32 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.server.query.change;
 
+import static com.google.gerrit.reviewdb.client.Change.CHANGE_ID_PATTERN;
 import static com.google.gerrit.server.query.change.ChangeData.asChanges;
 
 import com.google.common.annotations.VisibleForTesting;
@@ -94,8 +95,7 @@
   }
 
   private static final Pattern PAT_LEGACY_ID = Pattern.compile("^[1-9][0-9]*$");
-  private static final Pattern PAT_CHANGE_ID =
-      Pattern.compile("^[iI][0-9a-f]{4,}.*$");
+  private static final Pattern PAT_CHANGE_ID = Pattern.compile(CHANGE_ID_PATTERN);
   private static final Pattern DEF_CHANGE = Pattern.compile(
       "^(?:[1-9][0-9]*|(?:[^~]+~[^~]+~)?[iI][0-9a-f]{4,}.*)$");
 
diff --git a/plugins/replication b/plugins/replication
index 43af15b..b3ab82d 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit 43af15baab9b2312677000c47313026f34352abb
+Subproject commit b3ab82de95bedd46a60152e2ecffdab1f762e00d
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
index 78d4123..25eacc2 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
@@ -279,7 +279,7 @@
           comments="[[_comments]]"
           drafts="[[_diffDrafts]]"
           revisions="[[_change.revisions]]"
-          projectConfig="[[projectConfig]]"
+          projectConfig="[[_projectConfig]]"
           selected-index="{{viewState.selectedFileIndex}}"></gr-file-list>
       <gr-messages-list id="messageList"
           change-num="[[_changeNum]]"
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
index 17aa0c4..85cf380 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
@@ -69,6 +69,7 @@
         value: true,
       },
       _prefs: Object,
+      _projectConfig: Object,
       _userPrefs: Object,
       _diffMode: {
         type: String,
diff --git a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.html b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.html
index b55a1c3..ae514ba 100644
--- a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.html
@@ -43,6 +43,36 @@
             _account_id: 123
           }),
           '/accounts/123/avatar?s=16');
+      assert.equal(element._buildAvatarURL(
+          {
+            _account_id: 123,
+            avatars: [
+              {
+                url: 'https://cdn.example.com/s12-p/photo.jpg',
+                height: 12
+              },
+              {
+                url: 'https://cdn.example.com/s16-p/photo.jpg',
+                height: 16
+              },
+              {
+                url: 'https://cdn.example.com/s100-p/photo.jpg',
+                height: 100
+              },
+            ],
+          }),
+          'https://cdn.example.com/s16-p/photo.jpg');
+      assert.equal(element._buildAvatarURL(
+          {
+            _account_id: 123,
+            avatars: [
+              {
+                url: 'https://cdn.example.com/s95-p/photo.jpg',
+                height: 95
+              },
+            ],
+          }),
+          '/accounts/123/avatar?s=16');
     });
 
     test('dom for existing account', function() {
diff --git a/tools/eclipse/project.py b/tools/eclipse/project.py
index 4b35f7c..46f5680 100755
--- a/tools/eclipse/project.py
+++ b/tools/eclipse/project.py
@@ -42,6 +42,8 @@
                 help='do not attach sources')
 opts.add_option('--plugins', help='create eclipse projects for plugins',
                 action='store_true')
+opts.add_option('--name', help='name of the generated project',
+                action='store', default='gerrit', dest='project_name')
 args, _ = opts.parse_args()
 
 def _query_classpath(targets):
@@ -223,7 +225,7 @@
     except CalledProcessError as err:
       exit(1)
 
-  gen_project()
+  gen_project(args.project_name)
   gen_classpath()
   gen_factorypath()