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 = ⇦Prev
pagedProjectListNext = Next⇨
+pagedGroupListPrev = ⇦Prev
+pagedGroupListNext = Next⇨
+
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