Merge "Allow service users to access REST API if auth.gitBasicAuth = true" into stable-2.9
diff --git a/Documentation/access-control.txt b/Documentation/access-control.txt
index 79b44f7..4099ed4 100644
--- a/Documentation/access-control.txt
+++ b/Documentation/access-control.txt
@@ -6,6 +6,7 @@
 users.
 
 
+[[system_groups]]
 == System Groups
 
 Gerrit comes with following system groups:
@@ -375,6 +376,7 @@
 These are references with added functionality to them compared to a regular
 git push operation.
 
+[[refs_for]]
 ==== refs/for/<branch ref>
 
 Most prominent is the `refs/for/<branch ref>` reference which is the reference
@@ -818,6 +820,7 @@
 edited on open changes.
 
 
+[[example_roles]]
 == Examples of typical roles in a project
 
 Below follows a set of typical roles on a server and which access
diff --git a/Documentation/cmd-create-project.txt b/Documentation/cmd-create-project.txt
index b66f18a..b665f9c 100644
--- a/Documentation/cmd-create-project.txt
+++ b/Documentation/cmd-create-project.txt
@@ -113,7 +113,7 @@
 link:config-gerrit.html#repository.name.defaultSubmitType[
 repository.<name>.defaultSubmitType] is set to a different value.
 For more details see link:project-setup.html#submit_type[
-Change Submit Actions].
+Submit Types].
 
 --use-content-merge::
 	If enabled, Gerrit will try to perform a 3-way merge of text
diff --git a/Documentation/cmd-set-project.txt b/Documentation/cmd-set-project.txt
index c568e9c..adfc364 100644
--- a/Documentation/cmd-set-project.txt
+++ b/Documentation/cmd-set-project.txt
@@ -57,7 +57,7 @@
 
 +
 For more details see
-link:project-setup.html#submit_type[Change Submit Actions].
+link:project-setup.html#submit_type[Submit Types].
 
 --content-merge::
     If enabled, Gerrit will try to perform a 3-way merge of text
diff --git a/Documentation/index.txt b/Documentation/index.txt
index 131e81d..33f1e95 100644
--- a/Documentation/index.txt
+++ b/Documentation/index.txt
@@ -4,6 +4,7 @@
 . Getting started
 .. link:intro-quick.html[A Quick Introduction to Gerrit]
 .. link:intro-change-screen.html[A Quick Introduction to the New Change Screen]
+.. link:intro-project-owner.html[Project Owner Guide]
 .. link:http://source.android.com/submit-patches/workflow[Default Android Workflow] (external)
 . Web
 .. Registering a new Gerrit account
diff --git a/Documentation/intro-project-owner.txt b/Documentation/intro-project-owner.txt
new file mode 100644
index 0000000..63d8d6c
--- /dev/null
+++ b/Documentation/intro-project-owner.txt
@@ -0,0 +1,227 @@
+= Project Owner Guide
+
+This is a Gerrit guide that is dedicated to project owners. It
+explains the many possibilities that Gerrit provides to customize the
+workflows for a project.
+
+[[project-owner]]
+== What is a project owner?
+
+Being project owner means that you own a project in Gerrit.
+Technically this is expressed by having the
+link:access-control.html#category_owner[Owner] access right on
+`refs/*` on that project. As project owner you have the permission to
+edit the access control list and the project settings of the project.
+It also means that you should get familiar with these settings so that
+you can adapt them to the needs of your project.
+
+Being project owner means being responsible for the administration of
+a project. This requires having a deeper knowledge of Gerrit than the
+average user. Normally per team there should be 2 to 3 persons, who
+have a certain level of Git/Gerrit knowledge, assigned as project
+owners. It normally doesn't make sense that everyone in a team is
+project owner. For normal team members it is sufficient to be committer
+or contributor.
+
+[[access-rights]]
+== Access Rights
+
+As a project owner you can edit the access control list of your
+project. This allows you to grant permissions on the project to
+different groups.
+
+Gerrit comes with a rich set of permissions which allow a very
+fine-grained control over who can do what on a project. Access
+control is one of the most powerful Gerrit features but it is also a
+rather complex topic. This guide will only highlight the most
+important aspects of access control, but the link:access-control.html[
+Access Control] chapter explains all the details.
+
+[[edit-access-rights]]
+=== Editing Access Rights
+
+To see the access rights of your project
+
+- go to the Gerrit WebUI
+- click on the `Projects` > `List` menu entry
+- find your project in the project list and click on it
+- click on the `Access` menu entry
+
+By clicking on the `Edit` button the access rights become editable and
+you may save any changes by clicking on the `Save Changes` button.
+Optionally you can provide a `Commit Message` to explain the reasons
+for changing the access rights.
+
+The access rights are stored in the project's Git repository in a
+special branch called `refs/meta/config`. On this branch there is a
+`project.config` file which contains the access rights. More
+information about this storage format can be found in the
+link:config-project-config.html[Project Configuration File Format]
+chapter. What is important to know is that by looking at the history
+of the `project.config` file on the `refs/meta/config` branch you can
+always see how the access rights were changed and by whom. If a good
+commit message is provided you can also see from the history why the
+access rights were modified.
+
+If a Git browser such as GitWeb is configured for the Gerrit server you
+can find a link to the history of the `project.config` file in the
+WebUI. Otherwise you may inspect the history locally. If you have
+cloned the repository you can do this by executing the following
+commands:
+
+====
+  $ git fetch origin refs/meta/config:config
+  $ git checkout config
+  $ git log project.config
+====
+
+Non project owners may still edit the access rights and propose the
+modifications to the project owners by clicking on the `Save for
+Review` button. This creates a new change with the access rights
+modifications that can be approved by a project owner. The project
+owners are automatically added as reviewer on this change so that they
+get informed about it by email.
+
+[[inheritance]]
+=== Inheritance
+
+Normally when a new project is created in Gerrit it already has some
+access rights which are inherited from the parent projects.
+Projects in Gerrit are organized hierarchically as a tree with the
+`All-Projects' project as root from which all projects inherit. Each
+project can have only a single parent project, multi-inheritance is
+not supported.
+
+Looking at the access rights of your project in the Gerrit WebUI, you
+only see the access rights which are defined on that project. To see
+the inherited access rights you must follow the link to the parent
+project under `Rights Inherit From`.
+
+Inherited access rights can be overwritten unless they are defined as
+link:access-control.html#block[BLOCK rule]. BLOCK rules are used to
+limit the possibilities of the project owners on the inheriting
+projects. With this, global policies can be enforced on all projects.
+Please note that Gerrit doesn't prevent you from assigning access
+rights that contradict an inherited BLOCK rule, but these access rights
+will simply have no effect.
+
+If you are responsible for several projects which require the same
+permissions, it makes sense to have a common parent for them and to
+maintain the access rights on that common parent. Changing the parent
+of a project is only allowed for Gerrit administrators. This means you
+need to contact the administrator of your Gerrit server if you want to
+reparent your project. One way to do this is to change the parent
+project in the WebUI, save the modifications for review and get the
+change approved and merged by a Gerrit administrator.
+
+[[refs]]
+=== References
+
+Access rights in Gerrit are assigned on references (aka refs). Refs in
+Git exist in different namespaces, e.g. all branches normally exist
+under `refs/heads/` and all tags under `refs/tags/`. In addition there
+are a number of link:access-control.html#references_special[special refs]
+and link:access-control.html#references_magic[magic refs].
+
+Access rights can be assigned on a concrete ref, e.g.
+`refs/heads/master` but also on ref patterns and regular expressions
+for ref names.
+
+A ref pattern ends with `/*` and describes a complete ref name
+namespace, e.g. access rights assigned on `refs/heads/*` apply to all
+branches.
+
+Regular expressions must start with `^`, e.g. access rights assigned
+on `^refs/heads/rel-.*` would apply to all `rel-*` branches.
+
+[[groups]]
+=== Groups
+
+Access rights are granted to groups. It is useful to know that Gerrit
+maintains its own groups internally but also supports different external
+group backends.
+
+The Gerrit internal groups can be seen in the Gerrit WebUI by clicking
+on the `Groups` > `List` menu entry. By clicking on a group you can
+edit the group members (`Members` tab) and the group options
+(`General` tab).
+
+Gerrit internal groups contain users as members, but can also include
+other groups, even external groups.
+
+Every group is owned by an owner group. Only members of the owner
+group can administrate the owned group (assign members, edit the group
+options). A group can own itself; in this case members of the group
+can, for example, add further members to the group. When you create new
+groups for your project to assign access rights to committer or other
+roles, make sure that they are owned by the project owner group.
+
+An important setting on a group is the option
+`Make group visible to all registered users.`, which defines whether
+non-members can see who is member of the group.
+
+New internal Gerrit groups can be created under `Groups` >
+`Create New Group`. This menu is only available if you have the global
+capability link:access-control.html#capability_createGroup[Create Group]
+assigned.
+
+Gerrit also has a set of special
+link:access-control.html#system_groups[system groups] that you might
+find useful.
+
+External groups need to be prefixed when assigning access rights to
+them, e.g. link:access-control.html#ldap_groups[LDAP group names] need
+to be prefixed with `ldap/`.
+
+If the link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/singleusergroup[
+singleusergroup] plugin is installed you can also directly assign
+access rights to users, by prefixing the username with `user/` or the
+user's account ID by `userid/`.
+
+[[common-access-rights]]
+=== Common Access Rights
+
+Different roles in a project, such as developer (committer) or
+contributor, need different access rights. Examples for which access
+rights are typically assigned for which role are described in the
+link:access-control.html#example_roles[Access Control] chapter.
+
+[[code-review]]
+=== Code Review
+
+Gerrit's main functionality is code review, however using code review
+is optional and you may decide to only use Gerrit as a Git server with
+access control. Whether you allow only pushes for review or also
+direct pushes depends on the project's access rights.
+
+To push a commit for review it must be pushed to
+link:access-control.html#refs_for[refs/for/<branch-name>]. This means
+the link:access-control.html#category_push_review[Push] access right
+must be assigned on `refs/for/<branch-name>`.
+
+To allow direct pushes and bypass code review, the
+link:access-control.html#category_push_direct[Push] access right is
+required on `refs/heads/<branch-name>`.
+
+By pushing for review you are not only enabling the review workflow,
+but you can also get automatic verifications from a build server
+before changes are merged. In addition you can benefit from Gerrit's
+merge strategies that can automatically merge/rebase commits on server
+side if necessary. You can control the merge strategy by configuring
+the link:project-setup.html#submit_type[submit type] on the project.
+If you bypass code review you always need to merge/rebase manually if
+the tip of the destination branch has moved. Please keep this in mind
+if you choose to not work with code review because you think it's
+easier to avoid the additional complexity of the review workflow; it
+might actually not be easier.
+
+You may also enable link:user-upload.html#auto_merge[auto-merge on
+push] to benefit from the automatic merge/rebase on server side while
+pushing directly into the repository.
+
+GERRIT
+------
+Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/js-api.txt b/Documentation/js-api.txt
index d41eab5..396edf6 100644
--- a/Documentation/js-api.txt
+++ b/Documentation/js-api.txt
@@ -872,6 +872,10 @@
 === Gerrit.refresh()
 Redisplays the current web UI view, refreshing all information.
 
+[[Gerrit_refreshMenuBar]]
+=== Gerrit.refreshMenuBar()
+Refreshes Gerrit's menu bar.
+
 [[Gerrit_url]]
 === Gerrit.url()
 Returns the URL of the Gerrit Code Review server. If invoked with
diff --git a/Documentation/project-setup.txt b/Documentation/project-setup.txt
index 98ac504..82bc1ea 100644
--- a/Documentation/project-setup.txt
+++ b/Documentation/project-setup.txt
@@ -45,7 +45,7 @@
 ====
 
 [[submit_type]]
-== Change Submit Action
+== Submit Type
 
 The method Gerrit uses to submit a change to a project can be
 modified by any project owner through the project console, `Projects` >
diff --git a/Documentation/rest-api-groups.txt b/Documentation/rest-api-groups.txt
index 3ba30c3..26f8f94 100644
--- a/Documentation/rest-api-groups.txt
+++ b/Documentation/rest-api-groups.txt
@@ -161,6 +161,24 @@
   }
 ----
 
+[[group-limit]]
+==== Group Limit
+The `/groups/` URL also accepts a limit integer in the `n` parameter.
+This limits the results to show `n` groups.
+
+Query the first 25 groups in group list.
+----
+  GET /groups/?n=25 HTTP/1.0
+----
+
+The `/groups/` URL also accepts a start integer in the `S` parameter.
+The results will skip `S` groups from group list.
+
+Query 25 groups starting from index 50.
+----
+  GET /groups/?n=25&S=50 HTTP/1.0
+----
+
 [[get-group]]
 === Get Group
 --
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
index 9e87b48..a92b736 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
@@ -137,4 +137,7 @@
 
   String pagedProjectListPrev();
   String pagedProjectListNext();
+
+  String pagedGroupListPrev();
+  String pagedGroupListNext();
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
index 04baf49..ef35e00 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
@@ -102,6 +102,9 @@
 pagedProjectListPrev = &#x21e6;Prev
 pagedProjectListNext = Next&#x21e8;
 
+pagedGroupListPrev = &#x21e6;Prev
+pagedGroupListNext = Next&#x21e8;
+
 addPermission = Add Permission ...
 
 # Permission Names
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupListScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupListScreen.java
index bed6b4a..6579f83 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupListScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupListScreen.java
@@ -21,8 +21,10 @@
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.ui.AccountScreen;
 import com.google.gerrit.client.ui.FilteredUserInterface;
+import com.google.gerrit.client.ui.Hyperlink;
 import com.google.gerrit.client.ui.IgnoreOutdatedFilterResultsCallbackWrapper;
 import com.google.gerrit.common.PageLinks;
+import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
 import com.google.gwt.event.dom.client.KeyCodes;
 import com.google.gwt.event.dom.client.KeyUpEvent;
 import com.google.gwt.event.dom.client.KeyUpHandler;
@@ -32,11 +34,16 @@
 import com.google.gwtexpui.globalkey.client.NpTextBox;
 
 public class GroupListScreen extends AccountScreen implements FilteredUserInterface {
+  private Hyperlink prev;
+  private Hyperlink next;
   private GroupTable groups;
   private NpTextBox filterTxt;
-  private String subname;
+  private String subname = "";
+  private int startPosition;
+  private int pageSize;
 
   public GroupListScreen() {
+    configurePageSize();
   }
 
   public GroupListScreen(String params) {
@@ -49,6 +56,22 @@
       if ("filter".equals(kv[0])) {
         subname = URL.decodeQueryString(kv[1]);
       }
+
+      if ("skip".equals(kv[0]) && URL.decodeQueryString(kv[1]).matches("^[\\d]+")) {
+        startPosition = Integer.parseInt(URL.decodeQueryString(kv[1]));
+      }
+    }
+    configurePageSize();
+  }
+
+  private void configurePageSize() {
+    if (Gerrit.isSignedIn()) {
+      final AccountGeneralPreferences p =
+          Gerrit.getUserAccount().getGeneralPreferences();
+      final short m = p.getMaximumPageSize();
+      pageSize = 0 < m ? m : AccountGeneralPreferences.DEFAULT_PAGESIZE;
+    } else {
+      pageSize = AccountGeneralPreferences.DEFAULT_PAGESIZE;
     }
   }
 
@@ -56,13 +79,17 @@
   protected void onLoad() {
     super.onLoad();
     display();
-    refresh(false);
+    refresh(false, false);
   }
 
-  private void refresh(final boolean open) {
-    setToken(subname == null || "".equals(subname) ? ADMIN_GROUPS
-        : ADMIN_GROUPS + "?filter=" + URL.encodeQueryString(subname));
-    GroupMap.match(subname,
+  private void refresh(final boolean open, final boolean filterModified) {
+    if (filterModified){
+      startPosition = 0;
+    }
+    setToken(getTokenForScreen(subname, startPosition));
+    // Retrieve one more group than page size to determine if there are more
+    // groups to display
+    GroupMap.match(subname, pageSize + 1, startPosition,
         new IgnoreOutdatedFilterResultsCallbackWrapper<GroupMap>(this,
             new GerritCallback<GroupMap>() {
               @Override
@@ -71,13 +98,45 @@
                   Gerrit.display(PageLinks.toGroup(
                       result.values().get(0).getGroupUUID()));
                 } else {
-                  groups.display(result, subname);
+                  if (result.size() <= pageSize) {
+                    groups.display(result, subname);
+                    next.setVisible(false);
+                  } else {
+                    groups.displaySubset(result, 0, result.size() - 1, subname);
+                    setupNavigationLink(next, subname, startPosition + pageSize);
+                  }
+                  if (startPosition > 0) {
+                    setupNavigationLink(prev, subname, startPosition - pageSize);
+                  } else {
+                    prev.setVisible(false);
+                  }
                   groups.finishDisplay();
                 }
               }
             }));
   }
 
+  private void setupNavigationLink(Hyperlink link, String filter, int skip) {
+    link.setTargetHistoryToken(getTokenForScreen(filter, skip));
+    link.setVisible(true);
+  }
+
+  private String getTokenForScreen(String filter, int skip) {
+    String token = ADMIN_GROUPS;
+    if (filter != null && !filter.isEmpty()) {
+      token += "?filter=" + URL.encodeQueryString(filter);
+    }
+    if (skip > 0) {
+      if (token.contains("?filter=")) {
+        token += ",";
+      } else {
+        token += "?";
+      }
+      token += "skip=" + skip;
+    }
+    return token;
+  }
+
   @Override
   public String getCurrentFilter() {
     return subname;
@@ -89,8 +148,20 @@
     setPageTitle(Util.C.groupListTitle());
     initPageHeader();
 
+    prev = new Hyperlink(Util.C.pagedGroupListPrev(), true, "");
+    prev.setVisible(false);
+
+    next = new Hyperlink(Util.C.pagedGroupListNext(), true, "");
+    next.setVisible(false);
+
     groups = new GroupTable(PageLinks.ADMIN_GROUPS);
     add(groups);
+
+    final HorizontalPanel buttons = new HorizontalPanel();
+    buttons.setStyleName(Gerrit.RESOURCES.css().changeTablePrevNextLinks());
+    buttons.add(prev);
+    buttons.add(next);
+    add(buttons);
   }
 
   private void initPageHeader() {
@@ -104,8 +175,13 @@
     filterTxt.addKeyUpHandler(new KeyUpHandler() {
       @Override
       public void onKeyUp(KeyUpEvent event) {
-        subname = filterTxt.getValue();
-        refresh(event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER);
+        boolean enterPressed =
+            event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER;
+        boolean filterModified = !filterTxt.getValue().equals(subname);
+        if (enterPressed || filterModified) {
+          subname = filterTxt.getValue();
+          refresh(enterPressed, filterModified);
+        }
       }
     });
     hp.add(filterTxt);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java
index de84081..1b420b4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java
@@ -95,6 +95,14 @@
   }
 
   public void display(List<GroupInfo> list, String toHighlight) {
+    displaySubset(list, toHighlight, 0, list.size());
+  }
+
+  public void displaySubset(GroupMap groups, int fromIndex, int toIndex, String toHighlight) {
+    displaySubset(Natives.asList(groups.values()), toHighlight, fromIndex, toIndex);
+  }
+
+  public void displaySubset(List<GroupInfo> list, String toHighlight, int fromIndex, int toIndex) {
     while (1 < table.getRowCount())
       table.removeRow(table.getRowCount() - 1);
 
@@ -104,7 +112,7 @@
         return a.name().compareTo(b.name());
       }
     });
-    for(GroupInfo group : list) {
+    for(GroupInfo group : list.subList(fromIndex, toIndex)) {
       final int row = table.getRowCount();
       table.insertRow(row);
       applyDataRowStyle(row);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
index b3f0f65..2b50cac 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
@@ -184,6 +184,13 @@
   private void initProjectOptions() {
     grid.addHeader(new SmallHeading(Util.C.headingProjectOptions()));
 
+    state = new ListBox();
+    for (final Project.State stateValue : Project.State.values()) {
+      state.addItem(Util.toLongString(stateValue), stateValue.name());
+    }
+    saveEnabler.listenTo(state);
+    grid.add(Util.C.headingProjectState(), state);
+
     submitType = new ListBox();
     for (final Project.SubmitType type : Project.SubmitType.values()) {
       submitType.addItem(Util.toLongString(type), type.name());
@@ -197,13 +204,6 @@
     saveEnabler.listenTo(submitType);
     grid.add(Util.C.headingProjectSubmitType(), submitType);
 
-    state = new ListBox();
-    for (final Project.State stateValue : Project.State.values()) {
-      state.addItem(Util.toLongString(stateValue), stateValue.name());
-    }
-    saveEnabler.listenTo(state);
-    grid.add(Util.C.headingProjectState(), state);
-
     contentMerge = newInheritedBooleanBox();
     saveEnabler.listenTo(contentMerge);
     grid.add(Util.C.useContentMerge(), contentMerge);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ActionContext.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ActionContext.java
index fb6cfc4..453a3f2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ActionContext.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ActionContext.java
@@ -37,6 +37,7 @@
     Gerrit.ActionContext.prototype = {
       go: Gerrit.go,
       refresh: Gerrit.refresh,
+      refreshMenuBar: Gerrit.refreshMenuBar,
       showError: Gerrit.showError,
 
       br: function(){return doc.createElement('br')},
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ApiGlue.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ApiGlue.java
index 4fa467a..976dc0c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ApiGlue.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/ApiGlue.java
@@ -62,6 +62,7 @@
 
       go: @com.google.gerrit.client.api.ApiGlue::go(Ljava/lang/String;),
       refresh: @com.google.gerrit.client.api.ApiGlue::refresh(),
+      refreshMenuBar: @com.google.gerrit.client.api.ApiGlue::refreshMenuBar(),
       showError: @com.google.gerrit.client.api.ApiGlue::showError(Ljava/lang/String;),
 
       on: function (e,f){(this.events[e] || (this.events[e]=[])).push(f)},
@@ -189,6 +190,10 @@
     Gerrit.display(History.getToken());
   }
 
+  private static final void refreshMenuBar() {
+    Gerrit.refreshMenuBar();
+  }
+
   private static final void showError(String message) {
     new ErrorDialog(message).center();
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/Plugin.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/Plugin.java
index 00c674f..7ef022a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/Plugin.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/api/Plugin.java
@@ -52,6 +52,7 @@
       getPluginName: function(){return this.name},
       go: @com.google.gerrit.client.api.ApiGlue::go(Ljava/lang/String;),
       refresh: @com.google.gerrit.client.api.ApiGlue::refresh(),
+      refreshMenuBar: @com.google.gerrit.client.api.ApiGlue::refreshMenuBar(),
       showError: @com.google.gerrit.client.api.ApiGlue::showError(Ljava/lang/String;),
       on: function(e,f){G.on(e,f)},
       onAction: function(t,n,c){G._onAction(this.name,t,n,c)},
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupMap.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupMap.java
index 6ba00ae..f28fb86 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupMap.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/groups/GroupMap.java
@@ -24,12 +24,18 @@
     groups().get(NativeMap.copyKeysIntoChildren(callback));
   }
 
-  public static void match(String match, AsyncCallback<GroupMap> cb) {
-    if (match == null || "".equals(match)) {
-      all(cb);
-    } else {
-      groups().addParameter("m", match).get(NativeMap.copyKeysIntoChildren(cb));
+  public static void match(String match, int limit, int start, AsyncCallback<GroupMap> cb) {
+    RestApi call = groups();
+    if (match != null) {
+      call.addParameter("m", match);
     }
+    if (limit > 0) {
+      call.addParameter("n", limit);
+    }
+    if (start > 0) {
+      call.addParameter("S", start);
+    }
+    call.get(NativeMap.copyKeysIntoChildren(cb));
   }
 
   public static void myOwned(AsyncCallback<GroupMap> cb) {
diff --git a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/Plugin.java b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/Plugin.java
index 41c03a2..046488d 100644
--- a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/Plugin.java
+++ b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/Plugin.java
@@ -50,6 +50,10 @@
   public final native void refresh()
   /*-{ return this.refresh() }-*/;
 
+  /** Refresh Gerrit's menu bar. */
+  public final native void refreshMenuBar()
+  /*-{ return this.refreshMenuBar() }-*/;
+
   /** Show message in Gerrit's ErrorDialog. */
   public final native void showError(String message)
   /*-{ return this.showError(message) }-*/;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java
index f585f16..c2ac123 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java
@@ -188,7 +188,8 @@
           "Merge patch set %d into %s",
           resource.getPatchSet().getPatchSetId(),
           resource.getChange().getDest().getShortName()))
-      .setVisible(resource.getChange().getStatus().isOpen()
+      .setVisible(!resource.getPatchSet().isDraft()
+          && resource.getChange().getStatus().isOpen()
           && resource.getPatchSet().getId().equals(current)
           && resource.getControl().canSubmit());
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
index b43967a..457c827 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
@@ -574,7 +574,7 @@
       if (c.getResult() == OK) {
         switch (c.getType()) {
           case CREATE:
-            if (isHead(c)) {
+            if (isHead(c) || isConfig(c)) {
               autoCloseChanges(c);
             }
             break;
@@ -584,13 +584,13 @@
                 c.getRefName(),
                 c.getOldId(),
                 c.getNewId());
-            if (isHead(c)) {
+            if (isHead(c) || isConfig(c)) {
               autoCloseChanges(c);
             }
             break;
 
           case UPDATE_NONFASTFORWARD:
-            if (isHead(c)) {
+            if (isHead(c) || isConfig(c)) {
               autoCloseChanges(c);
             }
             break;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java
index 170c346..f6b7187 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java
@@ -87,6 +87,12 @@
     groupsToInspect.add(id);
   }
 
+  @Option(name = "--limit", aliases = {"-n"}, metaVar = "CNT", usage = "maximum number of groups to list")
+  private int limit;
+
+  @Option(name = "-S", metaVar = "CNT", usage = "number of groups to skip")
+  private int start;
+
   @Option(name = "-m", metaVar = "MATCH", usage = "match group substring")
   private String matchSubstring;
 
@@ -168,7 +174,15 @@
           groupList = filterGroups(groupCache.all());
         }
         groupInfos = Lists.newArrayListWithCapacity(groupList.size());
+        int found = 0;
+        int foundIndex = 0;
         for (AccountGroup group : groupList) {
+          if (foundIndex++ < start) {
+            continue;
+          }
+          if (limit > 0 && ++found > limit) {
+            break;
+          }
           groupInfos.add(json.addOptions(options).format(
               GroupDescriptions.forAccountGroup(group)));
         }
@@ -180,11 +194,19 @@
   private List<GroupInfo> getGroupsOwnedBy(IdentifiedUser user)
       throws OrmException {
     List<GroupInfo> groups = Lists.newArrayList();
+    int found = 0;
+    int foundIndex = 0;
     for (AccountGroup g : filterGroups(groupCache.all())) {
       GroupControl ctl = groupControlFactory.controlFor(g);
       try {
         if (genericGroupControlFactory.controlFor(user, g.getGroupUUID())
             .isOwner()) {
+          if (foundIndex++ < start) {
+            continue;
+          }
+          if (limit > 0 && ++found > limit) {
+            break;
+          }
           groups.add(json.addOptions(options).format(ctl.getGroup()));
         }
       } catch (NoSuchGroupException e) {
diff --git a/plugins/BUCK b/plugins/BUCK
index 16c65da..480cd4c 100644
--- a/plugins/BUCK
+++ b/plugins/BUCK
@@ -4,6 +4,7 @@
   'download-commands',
   'replication',
   'reviewnotes',
+  'singleusergroup'
 ]
 
 # buck audit parses and resolves all deps even if not reachable