Merge branch 'stable-2.9'
* stable-2.9: SideBySide2: Show [ and ] shortcut keys in nav arrow tooltips Always auto confirm adding reviewers for set-reviewers SSH command Improve wording of 'parents' field description in CommitInfo Fix 'parents' field name of CommitInfo in REST documentation Implement pagination in project list screen Add option 'S' to projects REST API to support query offset Fix: Failure of acceptance tests. Fix link behaviour inconsistencies in change info panel Remove message box when editing topic of change Update cookbook plugin to latest revision Update Gerrit 2.9 release notes with info about 2.8.x series Update GWT version to 2.6.0 in debug launcher Do not refresh project list if filter did not change Fix inconsistent behavior of diff view when viewing binary files Update cookbook plugin to latest revision Correct Javadoc of RestReadView in extension API Emit ref-updated event when editing project access via web UI Fix ChangeListener auto-registered implementations Fix: The email notification of review comments gets stuck. Fix memory leak of SubIndex.NrtFuture objects Use consistent grammatical tense in command descriptions Make skip bar more user friendly Bump version to 2.8.4 in plugin API and archetypes Helper script to update API version in plugin archetype pom files Serialize GWT dbg and opt compiles Bump GERRIT_VERSION to 2.8.4 Update the mysql documentation concerning charsets By default don't allow admins to create new branches by push Disable commitWithin when running Reindex Emit ref-updated event when editing project access via web UI SideBySide2: Fix syntax highlighting for shell files ChangeScreen2: Respect comment visibility strategy Don't add "Patch File" download link for merge commits Conflicts: gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchMessages.java gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchMessages.properties gerrit-server/src/main/java/com/google/gerrit/server/project/PutConfig.java Change-Id: I3f2cb9a9f98e2c39d98fae47b0407bdf4ab8e4f4
This commit is contained in:
@@ -1979,18 +1979,16 @@ Determines the period at which changes are automatically committed to
|
|||||||
stable store on disk. This is a costly operation and may block
|
stable store on disk. This is a costly operation and may block
|
||||||
additional index writes, so lower with caution.
|
additional index writes, so lower with caution.
|
||||||
+
|
+
|
||||||
If zero or negative, changes are committed after every write. This is
|
If zero, changes are committed after every write. This is very costly
|
||||||
very costly but may be useful if offline reindexing is infeasible, or
|
but may be useful if offline reindexing is infeasible, or for development
|
||||||
for development servers.
|
servers.
|
||||||
+
|
+
|
||||||
Values can be specified using standard time unit abbreviations (`ms`,
|
Values can be specified using standard time unit abbreviations (`ms`, `sec`,
|
||||||
`sec`, `min`, etc.).
|
`min`, etc.).
|
||||||
+
|
+
|
||||||
This setting also applies when running the reindex program. If it is
|
If negative, `commitWithin` is disabled. Changes are flushed to disk when
|
||||||
configured to commit on every write, this will cause reindex to take
|
the in-memory buffer fills, but only committed and guaranteed to be synced
|
||||||
an unnecessarily long time to complete on sites that have a lot of
|
to disk when the process finishes.
|
||||||
changes. It is recommended to temporarily set a higher value while
|
|
||||||
running reindex.
|
|
||||||
|
|
||||||
Defaults to 300000 ms (5 minutes).
|
Defaults to 300000 ms (5 minutes).
|
||||||
|
|
||||||
@@ -2516,6 +2514,16 @@ only the default internal rules will be used.
|
|||||||
+
|
+
|
||||||
Default is true, to execute project specific rules.
|
Default is true, to execute project specific rules.
|
||||||
|
|
||||||
|
[[execution]]
|
||||||
|
=== Section execution
|
||||||
|
|
||||||
|
[[execution.defaultThreadPoolSize]]execution.defaultThreadPoolSize::
|
||||||
|
+
|
||||||
|
The default size of the background execution thread pool in
|
||||||
|
which miscellaneous tasks are handled.
|
||||||
|
+
|
||||||
|
Default is 1.
|
||||||
|
|
||||||
[[sendemail]]
|
[[sendemail]]
|
||||||
=== Section sendemail
|
=== Section sendemail
|
||||||
|
|
||||||
@@ -2526,6 +2534,26 @@ and all other properties of section sendemail are ignored.
|
|||||||
+
|
+
|
||||||
By default, true, allowing notifications to be sent.
|
By default, true, allowing notifications to be sent.
|
||||||
|
|
||||||
|
[[sendemail.connectTimeout]]sendemail.connectTimeout::
|
||||||
|
+
|
||||||
|
The connection timeout of opening a socket connected to a
|
||||||
|
remote SMTP server.
|
||||||
|
+
|
||||||
|
Values can be specified using standard time unit abbreviations
|
||||||
|
('ms', 'sec', 'min', etc.).
|
||||||
|
If no unit is specified, milliseconds is assumed.
|
||||||
|
+
|
||||||
|
Default is 0. A timeout of zero is interpreted as an infinite
|
||||||
|
timeout. The connection will then block until established or
|
||||||
|
an error occurs.
|
||||||
|
|
||||||
|
[[sendemail.threadPoolSize]]sendemail.threadPoolSize::
|
||||||
|
+
|
||||||
|
Maximum size of thread pool in which the review comments
|
||||||
|
notifications are sent out asynchronously.
|
||||||
|
+
|
||||||
|
By default, 1.
|
||||||
|
|
||||||
[[sendemail.from]]sendemail.from::
|
[[sendemail.from]]sendemail.from::
|
||||||
+
|
+
|
||||||
Designates what name and address Gerrit will place in the From
|
Designates what name and address Gerrit will place in the From
|
||||||
|
@@ -2908,10 +2908,10 @@ The `CommitInfo` entity contains information about a commit.
|
|||||||
|==========================
|
|==========================
|
||||||
|Field Name |Description
|
|Field Name |Description
|
||||||
|`commit` |The commit ID.
|
|`commit` |The commit ID.
|
||||||
|`parent` |
|
|`parents` |
|
||||||
The parent commits of this commit as a list of
|
The parent commits of this commit as a list of
|
||||||
link:#commit-info[CommitInfo] entities. In parent
|
link:#commit-info[CommitInfo] entities. In each parent
|
||||||
only `commit` and `subject` fields are populated.
|
only the `commit` and `subject` fields are populated.
|
||||||
|`author` |The author of the commit as a
|
|`author` |The author of the commit as a
|
||||||
link:#git-person-info[GitPersonInfo] entity.
|
link:#git-person-info[GitPersonInfo] entity.
|
||||||
|`committer` |The committer of the commit as a
|
|`committer` |The committer of the commit as a
|
||||||
|
@@ -7,10 +7,15 @@ Gerrit 2.9 is now available:
|
|||||||
link:https://gerrit-releases.storage.googleapis.com/gerrit-2.9.war[
|
link:https://gerrit-releases.storage.googleapis.com/gerrit-2.9.war[
|
||||||
https://gerrit-releases.storage.googleapis.com/gerrit-2.9.war]
|
https://gerrit-releases.storage.googleapis.com/gerrit-2.9.war]
|
||||||
|
|
||||||
|
|
||||||
*WARNING:* Support for Java 1.6 has been discontinued.
|
*WARNING:* Support for Java 1.6 has been discontinued.
|
||||||
As of Gerrit 2.9, Java 1.7 is required.
|
As of Gerrit 2.9, Java 1.7 is required.
|
||||||
|
|
||||||
|
Gerrit 2.9 includes the bug fixes done with
|
||||||
|
link:ReleaseNotes-2.8.1.html[Gerrit 2.8.1],
|
||||||
|
link:ReleaseNotes-2.8.2.html[Gerrit 2.8.2],
|
||||||
|
link:ReleaseNotes-2.8.3.html[Gerrit 2.8.3], and
|
||||||
|
link:ReleaseNotes-2.8.4.html[Gerrit 2.8.4].
|
||||||
|
These bug fixes are *not* listed in these release notes.
|
||||||
|
|
||||||
Schema Change
|
Schema Change
|
||||||
-------------
|
-------------
|
||||||
|
@@ -23,7 +23,7 @@ public interface RestReadView<R extends RestResource> extends RestView<R> {
|
|||||||
/**
|
/**
|
||||||
* Process the view operation by reading from the resource.
|
* Process the view operation by reading from the resource.
|
||||||
*
|
*
|
||||||
* @param resource resource to modify.
|
* @param resource resource to read.
|
||||||
* @return result to return to the client. Use {@link BinaryResult} to avoid
|
* @return result to return to the client. Use {@link BinaryResult} to avoid
|
||||||
* automatic conversion to JSON.
|
* automatic conversion to JSON.
|
||||||
* @throws AuthException the client is not permitted to access this view.
|
* @throws AuthException the client is not permitted to access this view.
|
||||||
|
@@ -27,7 +27,7 @@ gwt_application(
|
|||||||
name = 'ui_opt',
|
name = 'ui_opt',
|
||||||
module_target = MODULE,
|
module_target = MODULE,
|
||||||
compiler_opts = GWT_COMPILER_OPTS,
|
compiler_opts = GWT_COMPILER_OPTS,
|
||||||
deps = APP_DEPS,
|
deps = APP_DEPS + [':ui_dbg'],
|
||||||
)
|
)
|
||||||
|
|
||||||
gwt_application(
|
gwt_application(
|
||||||
|
@@ -601,7 +601,7 @@ public class Dispatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isChangeScreen2() {
|
public static boolean isChangeScreen2() {
|
||||||
if (!Gerrit.getConfig().getNewFeatures()) {
|
if (!Gerrit.getConfig().getNewFeatures()) {
|
||||||
return false;
|
return false;
|
||||||
} else if (changeScreen2) {
|
} else if (changeScreen2) {
|
||||||
@@ -666,7 +666,20 @@ public class Dispatcher {
|
|||||||
panel = 0 <= c ? token.substring(c + 1) : "";
|
panel = 0 <= c ? token.substring(c + 1) : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("unified".equals(panel)) {
|
if ("".equals(panel)) {
|
||||||
|
if (isChangeScreen2()) {
|
||||||
|
return new SideBySide2(baseId, id.getParentKey(), id.get(),
|
||||||
|
side, line);
|
||||||
|
}
|
||||||
|
return new PatchScreen.SideBySide( //
|
||||||
|
id, //
|
||||||
|
patchIndex, //
|
||||||
|
patchSetDetail, //
|
||||||
|
patchTable, //
|
||||||
|
top, //
|
||||||
|
baseId //
|
||||||
|
);
|
||||||
|
} else if ("unified".equals(panel)) {
|
||||||
return new PatchScreen.Unified( //
|
return new PatchScreen.Unified( //
|
||||||
id, //
|
id, //
|
||||||
patchIndex, //
|
patchIndex, //
|
||||||
|
@@ -134,4 +134,7 @@ public interface AdminConstants extends Constants {
|
|||||||
String sectionTypeReference();
|
String sectionTypeReference();
|
||||||
String sectionTypeSection();
|
String sectionTypeSection();
|
||||||
Map<String, String> sectionNames();
|
Map<String, String> sectionNames();
|
||||||
|
|
||||||
|
String pagedProjectListPrev();
|
||||||
|
String pagedProjectListNext();
|
||||||
}
|
}
|
||||||
|
@@ -99,6 +99,8 @@ noGroupSelected = (No group selected)
|
|||||||
errorNoMatchingGroups = No Matching Groups
|
errorNoMatchingGroups = No Matching Groups
|
||||||
errorNoGitRepository = No Git Repository
|
errorNoGitRepository = No Git Repository
|
||||||
|
|
||||||
|
pagedProjectListPrev = ⇦Prev
|
||||||
|
pagedProjectListNext = Next⇨
|
||||||
|
|
||||||
addPermission = Add Permission ...
|
addPermission = Add Permission ...
|
||||||
|
|
||||||
|
@@ -24,11 +24,13 @@ import com.google.gerrit.client.projects.ProjectMap;
|
|||||||
import com.google.gerrit.client.rpc.GerritCallback;
|
import com.google.gerrit.client.rpc.GerritCallback;
|
||||||
import com.google.gerrit.client.ui.FilteredUserInterface;
|
import com.google.gerrit.client.ui.FilteredUserInterface;
|
||||||
import com.google.gerrit.client.ui.HighlightingInlineHyperlink;
|
import com.google.gerrit.client.ui.HighlightingInlineHyperlink;
|
||||||
|
import com.google.gerrit.client.ui.Hyperlink;
|
||||||
import com.google.gerrit.client.ui.IgnoreOutdatedFilterResultsCallbackWrapper;
|
import com.google.gerrit.client.ui.IgnoreOutdatedFilterResultsCallbackWrapper;
|
||||||
import com.google.gerrit.client.ui.ProjectSearchLink;
|
import com.google.gerrit.client.ui.ProjectSearchLink;
|
||||||
import com.google.gerrit.client.ui.ProjectsTable;
|
import com.google.gerrit.client.ui.ProjectsTable;
|
||||||
import com.google.gerrit.client.ui.Screen;
|
import com.google.gerrit.client.ui.Screen;
|
||||||
import com.google.gerrit.common.PageLinks;
|
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.KeyCodes;
|
||||||
import com.google.gwt.event.dom.client.KeyUpEvent;
|
import com.google.gwt.event.dom.client.KeyUpEvent;
|
||||||
import com.google.gwt.event.dom.client.KeyUpHandler;
|
import com.google.gwt.event.dom.client.KeyUpHandler;
|
||||||
@@ -42,11 +44,16 @@ import com.google.gwt.user.client.ui.Label;
|
|||||||
import com.google.gwtexpui.globalkey.client.NpTextBox;
|
import com.google.gwtexpui.globalkey.client.NpTextBox;
|
||||||
|
|
||||||
public class ProjectListScreen extends Screen implements FilteredUserInterface {
|
public class ProjectListScreen extends Screen implements FilteredUserInterface {
|
||||||
|
private Hyperlink prev;
|
||||||
|
private Hyperlink next;
|
||||||
private ProjectsTable projects;
|
private ProjectsTable projects;
|
||||||
private NpTextBox filterTxt;
|
private NpTextBox filterTxt;
|
||||||
private String subname;
|
private String subname = "";
|
||||||
|
private int startPosition;
|
||||||
|
private int pageSize;
|
||||||
|
|
||||||
public ProjectListScreen() {
|
public ProjectListScreen() {
|
||||||
|
configurePageSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProjectListScreen(String params) {
|
public ProjectListScreen(String params) {
|
||||||
@@ -59,6 +66,22 @@ public class ProjectListScreen extends Screen implements FilteredUserInterface {
|
|||||||
if ("filter".equals(kv[0])) {
|
if ("filter".equals(kv[0])) {
|
||||||
subname = URL.decodeQueryString(kv[1]);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,13 +89,17 @@ public class ProjectListScreen extends Screen implements FilteredUserInterface {
|
|||||||
protected void onLoad() {
|
protected void onLoad() {
|
||||||
super.onLoad();
|
super.onLoad();
|
||||||
display();
|
display();
|
||||||
refresh(false);
|
refresh(false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refresh(final boolean open) {
|
private void refresh(final boolean open, final boolean filterModified) {
|
||||||
setToken(subname == null || "".equals(subname) ? ADMIN_PROJECTS
|
if (filterModified){
|
||||||
: ADMIN_PROJECTS + "?filter=" + URL.encodeQueryString(subname));
|
startPosition = 0;
|
||||||
ProjectMap.match(subname,
|
}
|
||||||
|
setToken(getTokenForScreen(subname, startPosition));
|
||||||
|
// Retrieve one more project than page size to determine if there are more
|
||||||
|
// projects to display
|
||||||
|
ProjectMap.match(subname, pageSize + 1, startPosition,
|
||||||
new IgnoreOutdatedFilterResultsCallbackWrapper<ProjectMap>(this,
|
new IgnoreOutdatedFilterResultsCallbackWrapper<ProjectMap>(this,
|
||||||
new GerritCallback<ProjectMap>() {
|
new GerritCallback<ProjectMap>() {
|
||||||
@Override
|
@Override
|
||||||
@@ -81,12 +108,44 @@ public class ProjectListScreen extends Screen implements FilteredUserInterface {
|
|||||||
Gerrit.display(PageLinks.toProject(
|
Gerrit.display(PageLinks.toProject(
|
||||||
result.values().get(0).name_key()));
|
result.values().get(0).name_key()));
|
||||||
} else {
|
} else {
|
||||||
projects.display(result);
|
if (result.size() <= pageSize) {
|
||||||
|
projects.display(result);
|
||||||
|
next.setVisible(false);
|
||||||
|
} else {
|
||||||
|
projects.displaySubset(result, 0, result.size() - 1);
|
||||||
|
setupNavigationLink(next, subname, startPosition + pageSize);
|
||||||
|
}
|
||||||
|
if (startPosition > 0) {
|
||||||
|
setupNavigationLink(prev, subname, startPosition - pageSize);
|
||||||
|
} else {
|
||||||
|
prev.setVisible(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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_PROJECTS;
|
||||||
|
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
|
@Override
|
||||||
public String getCurrentFilter() {
|
public String getCurrentFilter() {
|
||||||
return subname;
|
return subname;
|
||||||
@@ -98,6 +157,12 @@ public class ProjectListScreen extends Screen implements FilteredUserInterface {
|
|||||||
setPageTitle(Util.C.projectListTitle());
|
setPageTitle(Util.C.projectListTitle());
|
||||||
initPageHeader();
|
initPageHeader();
|
||||||
|
|
||||||
|
prev = new Hyperlink(Util.C.pagedProjectListPrev(), true, "");
|
||||||
|
prev.setVisible(false);
|
||||||
|
|
||||||
|
next = new Hyperlink(Util.C.pagedProjectListNext(), true, "");
|
||||||
|
next.setVisible(false);
|
||||||
|
|
||||||
projects = new ProjectsTable() {
|
projects = new ProjectsTable() {
|
||||||
@Override
|
@Override
|
||||||
protected void initColumnHeaders() {
|
protected void initColumnHeaders() {
|
||||||
@@ -167,6 +232,11 @@ public class ProjectListScreen extends Screen implements FilteredUserInterface {
|
|||||||
projects.setSavePointerId(PageLinks.ADMIN_PROJECTS);
|
projects.setSavePointerId(PageLinks.ADMIN_PROJECTS);
|
||||||
|
|
||||||
add(projects);
|
add(projects);
|
||||||
|
final HorizontalPanel buttons = new HorizontalPanel();
|
||||||
|
buttons.setStyleName(Gerrit.RESOURCES.css().changeTablePrevNextLinks());
|
||||||
|
buttons.add(prev);
|
||||||
|
buttons.add(next);
|
||||||
|
add(buttons);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initPageHeader() {
|
private void initPageHeader() {
|
||||||
@@ -180,8 +250,13 @@ public class ProjectListScreen extends Screen implements FilteredUserInterface {
|
|||||||
filterTxt.addKeyUpHandler(new KeyUpHandler() {
|
filterTxt.addKeyUpHandler(new KeyUpHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void onKeyUp(KeyUpEvent event) {
|
public void onKeyUp(KeyUpEvent event) {
|
||||||
subname = filterTxt.getValue();
|
boolean enterPressed =
|
||||||
refresh(event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER);
|
event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER;
|
||||||
|
boolean filterModified = !filterTxt.getValue().equals(subname);
|
||||||
|
if (enterPressed || filterModified) {
|
||||||
|
subname = filterTxt.getValue();
|
||||||
|
refresh(enterPressed, filterModified);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
hp.add(filterTxt);
|
hp.add(filterTxt);
|
||||||
|
@@ -138,7 +138,7 @@ public class ChangeScreen2 extends Screen {
|
|||||||
@UiField Reviewers reviewers;
|
@UiField Reviewers reviewers;
|
||||||
@UiField InlineHyperlink ownerLink;
|
@UiField InlineHyperlink ownerLink;
|
||||||
@UiField Element statusText;
|
@UiField Element statusText;
|
||||||
@UiField Image projectQuery;
|
@UiField Image projectSettings;
|
||||||
@UiField InlineHyperlink projectLink;
|
@UiField InlineHyperlink projectLink;
|
||||||
@UiField InlineHyperlink branchLink;
|
@UiField InlineHyperlink branchLink;
|
||||||
@UiField Element strategy;
|
@UiField Element strategy;
|
||||||
@@ -356,16 +356,16 @@ public class ChangeScreen2 extends Screen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initProjectLinks(final ChangeInfo info) {
|
private void initProjectLinks(final ChangeInfo info) {
|
||||||
projectQuery.addDomHandler(new ClickHandler() {
|
projectSettings.addDomHandler(new ClickHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(ClickEvent event) {
|
public void onClick(ClickEvent event) {
|
||||||
Gerrit.display(
|
Gerrit.display(
|
||||||
PageLinks.toProjectDefaultDashboard(info.project_name_key()));
|
PageLinks.toProject(info.project_name_key()));
|
||||||
}
|
}
|
||||||
}, ClickEvent.getType());
|
}, ClickEvent.getType());
|
||||||
projectLink.setText(info.project());
|
projectLink.setText(info.project());
|
||||||
projectLink.setTargetHistoryToken(
|
projectLink.setTargetHistoryToken(
|
||||||
PageLinks.toProject(info.project_name_key()));
|
PageLinks.toProjectDefaultDashboard(info.project_name_key()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initBranchLink(ChangeInfo info) {
|
private void initBranchLink(ChangeInfo info) {
|
||||||
@@ -376,7 +376,7 @@ public class ChangeScreen2 extends Screen {
|
|||||||
info.project_name_key(),
|
info.project_name_key(),
|
||||||
info.status(),
|
info.status(),
|
||||||
info.branch(),
|
info.branch(),
|
||||||
info.topic())));
|
null)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initEditMessageAction(ChangeInfo info, String revision) {
|
private void initEditMessageAction(ChangeInfo info, String revision) {
|
||||||
|
@@ -161,7 +161,7 @@ limitations under the License.
|
|||||||
padding: 0 5px 0 0;
|
padding: 0 5px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.queryProject {
|
.projectSettings {
|
||||||
float: right;
|
float: right;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
@@ -383,14 +383,14 @@ limitations under the License.
|
|||||||
<tr>
|
<tr>
|
||||||
<th><ui:msg>Project</ui:msg></th>
|
<th><ui:msg>Project</ui:msg></th>
|
||||||
<td><x:InlineHyperlink ui:field='projectLink'
|
<td><x:InlineHyperlink ui:field='projectLink'
|
||||||
title='Go to project'>
|
title='Search for changes on this project'>
|
||||||
<ui:attribute name='title'/>
|
<ui:attribute name='title'/>
|
||||||
</x:InlineHyperlink>
|
</x:InlineHyperlink>
|
||||||
<g:Image
|
<g:Image
|
||||||
ui:field='projectQuery'
|
ui:field='projectSettings'
|
||||||
resource='{ico.queryIcon}'
|
resource='{ico.gear}'
|
||||||
styleName='{style.queryProject}'
|
styleName='{style.projectSettings}'
|
||||||
title='Search for changes on this project'>
|
title='Go to project'>
|
||||||
<ui:attribute name='title'/>
|
<ui:attribute name='title'/>
|
||||||
</g:Image>
|
</g:Image>
|
||||||
</td>
|
</td>
|
||||||
|
@@ -111,7 +111,9 @@ class DownloadBox extends VerticalPanel {
|
|||||||
insertCommand(commandName, copyLabel);
|
insertCommand(commandName, copyLabel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
insertPatch();
|
if (change.revision(revision).commit().parents().length() == 1) {
|
||||||
|
insertPatch();
|
||||||
|
}
|
||||||
insertArchive();
|
insertArchive();
|
||||||
insertCommand(null, scheme);
|
insertCommand(null, scheme);
|
||||||
}
|
}
|
||||||
|
@@ -18,6 +18,8 @@ import com.google.gerrit.client.Gerrit;
|
|||||||
import com.google.gerrit.client.changes.ChangeApi;
|
import com.google.gerrit.client.changes.ChangeApi;
|
||||||
import com.google.gerrit.client.changes.ChangeInfo;
|
import com.google.gerrit.client.changes.ChangeInfo;
|
||||||
import com.google.gerrit.client.rpc.GerritCallback;
|
import com.google.gerrit.client.rpc.GerritCallback;
|
||||||
|
import com.google.gerrit.client.ui.BranchLink;
|
||||||
|
import com.google.gerrit.client.ui.InlineHyperlink;
|
||||||
import com.google.gerrit.common.PageLinks;
|
import com.google.gerrit.common.PageLinks;
|
||||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||||
import com.google.gwt.core.client.GWT;
|
import com.google.gwt.core.client.GWT;
|
||||||
@@ -31,10 +33,8 @@ import com.google.gwt.uibinder.client.UiField;
|
|||||||
import com.google.gwt.uibinder.client.UiHandler;
|
import com.google.gwt.uibinder.client.UiHandler;
|
||||||
import com.google.gwt.user.client.ui.Button;
|
import com.google.gwt.user.client.ui.Button;
|
||||||
import com.google.gwt.user.client.ui.Composite;
|
import com.google.gwt.user.client.ui.Composite;
|
||||||
import com.google.gwt.user.client.ui.FlowPanel;
|
|
||||||
import com.google.gwt.user.client.ui.HTMLPanel;
|
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||||
import com.google.gwt.user.client.ui.Image;
|
import com.google.gwt.user.client.ui.Image;
|
||||||
import com.google.gwt.user.client.ui.InlineLabel;
|
|
||||||
import com.google.gwt.user.client.ui.UIObject;
|
import com.google.gwt.user.client.ui.UIObject;
|
||||||
import com.google.gwtexpui.globalkey.client.NpTextBox;
|
import com.google.gwtexpui.globalkey.client.NpTextBox;
|
||||||
|
|
||||||
@@ -46,8 +46,8 @@ class Topic extends Composite {
|
|||||||
private PatchSet.Id psId;
|
private PatchSet.Id psId;
|
||||||
private boolean canEdit;
|
private boolean canEdit;
|
||||||
|
|
||||||
@UiField FlowPanel show;
|
@UiField Element show;
|
||||||
@UiField InlineLabel text;
|
@UiField InlineHyperlink text;
|
||||||
@UiField Image editIcon;
|
@UiField Image editIcon;
|
||||||
|
|
||||||
@UiField Element form;
|
@UiField Element form;
|
||||||
@@ -57,7 +57,7 @@ class Topic extends Composite {
|
|||||||
|
|
||||||
Topic() {
|
Topic() {
|
||||||
initWidget(uiBinder.createAndBindUi(this));
|
initWidget(uiBinder.createAndBindUi(this));
|
||||||
show.addDomHandler(
|
editIcon.addDomHandler(
|
||||||
new ClickHandler() {
|
new ClickHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(ClickEvent event) {
|
public void onClick(ClickEvent event) {
|
||||||
@@ -76,20 +76,30 @@ class Topic extends Composite {
|
|||||||
info.legacy_id(),
|
info.legacy_id(),
|
||||||
info.revisions().get(revision)._number());
|
info.revisions().get(revision)._number());
|
||||||
|
|
||||||
text.setText(info.topic());
|
initTopicLink(info);
|
||||||
editIcon.setVisible(canEdit);
|
editIcon.setVisible(canEdit);
|
||||||
if (!canEdit) {
|
if (!canEdit) {
|
||||||
show.setTitle(null);
|
show.setTitle(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void initTopicLink(ChangeInfo info) {
|
||||||
|
text.setText(info.topic());
|
||||||
|
text.setTargetHistoryToken(
|
||||||
|
PageLinks.toChangeQuery(
|
||||||
|
BranchLink.query(
|
||||||
|
info.project_name_key(),
|
||||||
|
info.status(),
|
||||||
|
info.branch(),
|
||||||
|
info.topic())));
|
||||||
|
}
|
||||||
|
|
||||||
boolean canEdit() {
|
boolean canEdit() {
|
||||||
return canEdit;
|
return canEdit;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onEdit() {
|
void onEdit() {
|
||||||
if (canEdit) {
|
if (canEdit) {
|
||||||
show.setVisible(false);
|
|
||||||
UIObject.setVisible(form, true);
|
UIObject.setVisible(form, true);
|
||||||
|
|
||||||
input.setText(text.getText());
|
input.setText(text.getText());
|
||||||
@@ -100,7 +110,6 @@ class Topic extends Composite {
|
|||||||
@UiHandler("cancel")
|
@UiHandler("cancel")
|
||||||
void onCancel(ClickEvent e) {
|
void onCancel(ClickEvent e) {
|
||||||
input.setFocus(false);
|
input.setFocus(false);
|
||||||
show.setVisible(true);
|
|
||||||
UIObject.setVisible(form, false);
|
UIObject.setVisible(form, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -17,7 +17,8 @@ limitations under the License.
|
|||||||
<ui:UiBinder
|
<ui:UiBinder
|
||||||
xmlns:ui='urn:ui:com.google.gwt.uibinder'
|
xmlns:ui='urn:ui:com.google.gwt.uibinder'
|
||||||
xmlns:c='urn:import:com.google.gwtexpui.globalkey.client'
|
xmlns:c='urn:import:com.google.gwtexpui.globalkey.client'
|
||||||
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
|
xmlns:g='urn:import:com.google.gwt.user.client.ui'
|
||||||
|
xmlns:x='urn:import:com.google.gerrit.client.ui'>
|
||||||
<ui:with field='ico' type='com.google.gerrit.client.GerritResources'/>
|
<ui:with field='ico' type='com.google.gerrit.client.GerritResources'/>
|
||||||
<ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
|
<ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
|
||||||
<ui:style>
|
<ui:style>
|
||||||
@@ -25,15 +26,14 @@ limitations under the License.
|
|||||||
.edit, .cancel { float: right; }
|
.edit, .cancel { float: right; }
|
||||||
</ui:style>
|
</ui:style>
|
||||||
<g:HTMLPanel>
|
<g:HTMLPanel>
|
||||||
<g:FlowPanel ui:field='show'
|
<div ui:field='show' styleName='{style.show}'>
|
||||||
styleName='{style.show}'
|
<x:InlineHyperlink ui:field='text'
|
||||||
title='Click to edit topic (Shortcut: t)'>
|
title='Search for changes on this topic'/>
|
||||||
<ui:attribute name='title'/>
|
|
||||||
<g:InlineLabel ui:field='text'/>
|
|
||||||
<g:Image ui:field='editIcon'
|
<g:Image ui:field='editIcon'
|
||||||
resource='{ico.edit}'
|
resource='{ico.edit}'
|
||||||
styleName='{style.edit}'/>
|
styleName='{style.edit}'
|
||||||
</g:FlowPanel>
|
title='Click to edit topic (Shortcut: t)'/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div ui:field='form' style='display: none' aria-hidden='true'>
|
<div ui:field='form' style='display: none' aria-hidden='true'>
|
||||||
<div>
|
<div>
|
||||||
|
@@ -22,6 +22,7 @@ import com.google.gerrit.client.ui.ListenableAccountDiffPreference;
|
|||||||
import com.google.gerrit.client.ui.NavigationTable;
|
import com.google.gerrit.client.ui.NavigationTable;
|
||||||
import com.google.gerrit.client.ui.PatchLink;
|
import com.google.gerrit.client.ui.PatchLink;
|
||||||
import com.google.gerrit.common.data.PatchSetDetail;
|
import com.google.gerrit.common.data.PatchSetDetail;
|
||||||
|
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DiffView;
|
||||||
import com.google.gerrit.reviewdb.client.Patch;
|
import com.google.gerrit.reviewdb.client.Patch;
|
||||||
import com.google.gerrit.reviewdb.client.Patch.ChangeType;
|
import com.google.gerrit.reviewdb.client.Patch.ChangeType;
|
||||||
import com.google.gerrit.reviewdb.client.Patch.Key;
|
import com.google.gerrit.reviewdb.client.Patch.Key;
|
||||||
@@ -238,21 +239,23 @@ public class PatchTable extends Composite {
|
|||||||
/**
|
/**
|
||||||
* @return a link to the the given patch.
|
* @return a link to the the given patch.
|
||||||
* @param index The patch to link to
|
* @param index The patch to link to
|
||||||
* @param patchType The type of patch display
|
* @param screenType The screen type of patch display
|
||||||
* @param before A string to display at the beginning of the href text
|
* @param before A string to display at the beginning of the href text
|
||||||
* @param after A string to display at the end of the href text
|
* @param after A string to display at the end of the href text
|
||||||
*/
|
*/
|
||||||
public PatchLink createLink(int index, PatchScreen.Type patchType,
|
public PatchLink createLink(int index, PatchScreen.Type screenType,
|
||||||
SafeHtml before, SafeHtml after) {
|
SafeHtml before, SafeHtml after) {
|
||||||
Patch patch = patchList.get(index);
|
Patch patch = patchList.get(index);
|
||||||
|
|
||||||
Key thisKey = patch.getKey();
|
Key thisKey = patch.getKey();
|
||||||
PatchLink link;
|
PatchLink link;
|
||||||
if (patchType == PatchScreen.Type.SIDE_BY_SIDE) {
|
|
||||||
link = new PatchLink.SideBySide("", base, thisKey, index, detail, this);
|
if (isUnifiedPatchLink(patch, screenType)) {
|
||||||
} else {
|
|
||||||
link = new PatchLink.Unified("", base, thisKey, index, detail, this);
|
link = new PatchLink.Unified("", base, thisKey, index, detail, this);
|
||||||
|
} else {
|
||||||
|
link = new PatchLink.SideBySide("", base, thisKey, index, detail, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
SafeHtmlBuilder text = new SafeHtmlBuilder();
|
SafeHtmlBuilder text = new SafeHtmlBuilder();
|
||||||
text.append(before);
|
text.append(before);
|
||||||
text.append(getFileNameOnly(patch));
|
text.append(getFileNameOnly(patch));
|
||||||
@@ -261,6 +264,16 @@ public class PatchTable extends Composite {
|
|||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isUnifiedPatchLink(final Patch patch,
|
||||||
|
final PatchScreen.Type screenType) {
|
||||||
|
if (Dispatcher.isChangeScreen2()) {
|
||||||
|
return (patch.getPatchType().equals(PatchType.BINARY)
|
||||||
|
|| Gerrit.getUserAccount().getGeneralPreferences().getDiffView()
|
||||||
|
.equals(DiffView.UNIFIED_DIFF));
|
||||||
|
}
|
||||||
|
return screenType == PatchScreen.Type.UNIFIED;
|
||||||
|
}
|
||||||
|
|
||||||
private static String getFileNameOnly(Patch patch) {
|
private static String getFileNameOnly(Patch patch) {
|
||||||
// Note: use '/' here and not File.pathSeparator since git paths
|
// Note: use '/' here and not File.pathSeparator since git paths
|
||||||
// are always separated by /
|
// are always separated by /
|
||||||
|
@@ -116,7 +116,8 @@ class SkipBar extends Composite {
|
|||||||
upArrow.setHTML(PatchUtil.M.expandBefore(NUM_ROWS_TO_EXPAND));
|
upArrow.setHTML(PatchUtil.M.expandBefore(NUM_ROWS_TO_EXPAND));
|
||||||
downArrow.setHTML(PatchUtil.M.expandAfter(NUM_ROWS_TO_EXPAND));
|
downArrow.setHTML(PatchUtil.M.expandAfter(NUM_ROWS_TO_EXPAND));
|
||||||
}
|
}
|
||||||
skipNum.setText(Integer.toString(skipped));
|
skipNum.setText(PatchUtil.M.patchSkipRegion(Integer
|
||||||
|
.toString(skipped)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void link(SkipBar barA, SkipBar barB) {
|
static void link(SkipBar barA, SkipBar barB) {
|
||||||
|
@@ -44,9 +44,7 @@ limitations under the License.
|
|||||||
<div class='{style.text}'>
|
<div class='{style.text}'>
|
||||||
<ui:msg>
|
<ui:msg>
|
||||||
<g:Anchor ui:field='upArrow' addStyleNames='{style.arrow} {style.anchor}' />
|
<g:Anchor ui:field='upArrow' addStyleNames='{style.arrow} {style.anchor}' />
|
||||||
<span><ui:msg>... skipped </ui:msg></span>
|
|
||||||
<g:Anchor ui:field='skipNum' addStyleNames='{style.anchor}' />
|
<g:Anchor ui:field='skipNum' addStyleNames='{style.anchor}' />
|
||||||
<span><ui:msg> common lines ...</ui:msg></span>
|
|
||||||
<g:Anchor ui:field='downArrow' addStyleNames=' {style.arrow} {style.anchor}' />
|
<g:Anchor ui:field='downArrow' addStyleNames=' {style.arrow} {style.anchor}' />
|
||||||
</ui:msg>
|
</ui:msg>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -22,5 +22,6 @@ public interface PatchMessages extends Messages {
|
|||||||
String expandBefore(int cnt);
|
String expandBefore(int cnt);
|
||||||
String expandAfter(int cnt);
|
String expandAfter(int cnt);
|
||||||
String draftSaved(Date when);
|
String draftSaved(Date when);
|
||||||
|
String patchSkipRegion(String lineNumber);
|
||||||
String fileNameWithShortcutKey(String file, String key);
|
String fileNameWithShortcutKey(String file, String key);
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
expandBefore = +{0}⇧
|
expandBefore = +{0}⇧
|
||||||
expandAfter = +{0}⇩
|
expandAfter = +{0}⇩
|
||||||
draftSaved = Draft saved at {0,time,short}
|
draftSaved = Draft saved at {0,time,short}
|
||||||
|
patchSkipRegion = ... skipped {0} common lines ...
|
||||||
fileNameWithShortcutKey = {0} (Shortcut: {1})
|
fileNameWithShortcutKey = {0} (Shortcut: {1})
|
||||||
|
@@ -1,2 +1,3 @@
|
|||||||
expandBefore = +{0}⇧
|
expandBefore = +{0}⇧
|
||||||
expandAfter = +{0}⇩
|
expandAfter = +{0}⇩
|
||||||
|
patchSkipRegion = ... skipped {0} common lines ...
|
||||||
|
@@ -53,16 +53,24 @@ public class ProjectMap extends NativeMap<ProjectInfo> {
|
|||||||
.get(NativeMap.copyKeysIntoChildren(cb));
|
.get(NativeMap.copyKeysIntoChildren(cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void match(String match, AsyncCallback<ProjectMap> cb) {
|
public static void match(String match, int limit, int start, AsyncCallback<ProjectMap> cb) {
|
||||||
if (match == null || "".equals(match)) {
|
RestApi call = new RestApi("/projects/");
|
||||||
all(cb);
|
if (match != null) {
|
||||||
} else {
|
call.addParameter("m", match);
|
||||||
new RestApi("/projects/")
|
|
||||||
.addParameter("m", match)
|
|
||||||
.addParameterRaw("type", "ALL")
|
|
||||||
.addParameterTrue("d") // description
|
|
||||||
.get(NativeMap.copyKeysIntoChildren(cb));
|
|
||||||
}
|
}
|
||||||
|
if (limit > 0) {
|
||||||
|
call.addParameter("n", limit);
|
||||||
|
}
|
||||||
|
if (start > 0) {
|
||||||
|
call.addParameter("S", start);
|
||||||
|
}
|
||||||
|
call.addParameterRaw("type", "ALL");
|
||||||
|
call.addParameterTrue("d"); // description
|
||||||
|
call.get(NativeMap.copyKeysIntoChildren(cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void match(String match, AsyncCallback<ProjectMap> cb) {
|
||||||
|
match(match, 0, 0, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ProjectMap() {
|
protected ProjectMap() {
|
||||||
|
@@ -61,6 +61,10 @@ public class ProjectsTable extends NavigationTable<ProjectInfo> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void display(ProjectMap projects) {
|
public void display(ProjectMap projects) {
|
||||||
|
displaySubset(projects, 0, projects.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void displaySubset(ProjectMap projects, int fromIndex, int toIndex) {
|
||||||
while (1 < table.getRowCount())
|
while (1 < table.getRowCount())
|
||||||
table.removeRow(table.getRowCount() - 1);
|
table.removeRow(table.getRowCount() - 1);
|
||||||
|
|
||||||
@@ -71,7 +75,7 @@ public class ProjectsTable extends NavigationTable<ProjectInfo> {
|
|||||||
return a.name().compareTo(b.name());
|
return a.name().compareTo(b.name());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
for(ProjectInfo p : list)
|
for(ProjectInfo p : list.subList(fromIndex, toIndex))
|
||||||
insert(table.getRowCount(), p);
|
insert(table.getRowCount(), p);
|
||||||
|
|
||||||
finishDisplay();
|
finishDisplay();
|
||||||
|
@@ -14,10 +14,14 @@
|
|||||||
|
|
||||||
package com.google.gerrit.httpd.rpc.project;
|
package com.google.gerrit.httpd.rpc.project;
|
||||||
|
|
||||||
|
import com.google.gerrit.common.ChangeHooks;
|
||||||
import com.google.gerrit.common.Nullable;
|
import com.google.gerrit.common.Nullable;
|
||||||
import com.google.gerrit.common.data.AccessSection;
|
import com.google.gerrit.common.data.AccessSection;
|
||||||
import com.google.gerrit.common.data.ProjectAccess;
|
import com.google.gerrit.common.data.ProjectAccess;
|
||||||
|
import com.google.gerrit.reviewdb.client.Branch;
|
||||||
import com.google.gerrit.reviewdb.client.Project;
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
|
import com.google.gerrit.reviewdb.client.RefNames;
|
||||||
|
import com.google.gerrit.server.IdentifiedUser;
|
||||||
import com.google.gerrit.server.account.GroupBackend;
|
import com.google.gerrit.server.account.GroupBackend;
|
||||||
import com.google.gerrit.server.config.AllProjectsNameProvider;
|
import com.google.gerrit.server.config.AllProjectsNameProvider;
|
||||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||||
@@ -32,6 +36,7 @@ import com.google.inject.assistedinject.Assisted;
|
|||||||
|
|
||||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -46,6 +51,8 @@ class ChangeProjectAccess extends ProjectAccessHandler<ProjectAccess> {
|
|||||||
@Nullable @Assisted String message);
|
@Nullable @Assisted String message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final ChangeHooks hooks;
|
||||||
|
private final IdentifiedUser user;
|
||||||
private final ProjectAccessFactory.Factory projectAccessFactory;
|
private final ProjectAccessFactory.Factory projectAccessFactory;
|
||||||
private final ProjectCache projectCache;
|
private final ProjectCache projectCache;
|
||||||
|
|
||||||
@@ -56,7 +63,7 @@ class ChangeProjectAccess extends ProjectAccessHandler<ProjectAccess> {
|
|||||||
MetaDataUpdate.User metaDataUpdateFactory,
|
MetaDataUpdate.User metaDataUpdateFactory,
|
||||||
AllProjectsNameProvider allProjects,
|
AllProjectsNameProvider allProjects,
|
||||||
Provider<SetParent> setParent,
|
Provider<SetParent> setParent,
|
||||||
|
ChangeHooks hooks, IdentifiedUser user,
|
||||||
@Assisted("projectName") Project.NameKey projectName,
|
@Assisted("projectName") Project.NameKey projectName,
|
||||||
@Nullable @Assisted ObjectId base,
|
@Nullable @Assisted ObjectId base,
|
||||||
@Assisted List<AccessSection> sectionList,
|
@Assisted List<AccessSection> sectionList,
|
||||||
@@ -67,13 +74,20 @@ class ChangeProjectAccess extends ProjectAccessHandler<ProjectAccess> {
|
|||||||
parentProjectName, message, true);
|
parentProjectName, message, true);
|
||||||
this.projectAccessFactory = projectAccessFactory;
|
this.projectAccessFactory = projectAccessFactory;
|
||||||
this.projectCache = projectCache;
|
this.projectCache = projectCache;
|
||||||
|
this.hooks = hooks;
|
||||||
|
this.user = user;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ProjectAccess updateProjectConfig(ProjectConfig config,
|
protected ProjectAccess updateProjectConfig(ProjectConfig config,
|
||||||
MetaDataUpdate md, boolean parentProjectUpdate) throws IOException,
|
MetaDataUpdate md, boolean parentProjectUpdate) throws IOException,
|
||||||
NoSuchProjectException, ConfigInvalidException {
|
NoSuchProjectException, ConfigInvalidException {
|
||||||
config.commit(md);
|
RevCommit commit = config.commit(md);
|
||||||
|
|
||||||
|
hooks.doRefUpdatedHook(
|
||||||
|
new Branch.NameKey(config.getProject().getNameKey(), RefNames.REFS_CONFIG),
|
||||||
|
base, commit.getId(), user.getAccount());
|
||||||
|
|
||||||
projectCache.evict(config.getProject());
|
projectCache.evict(config.getProject());
|
||||||
return projectAccessFactory.create(projectName).call();
|
return projectAccessFactory.create(projectName).call();
|
||||||
}
|
}
|
||||||
|
@@ -160,7 +160,7 @@ public class LuceneChangeIndex implements ChangeIndex {
|
|||||||
|
|
||||||
static class GerritIndexWriterConfig {
|
static class GerritIndexWriterConfig {
|
||||||
private final IndexWriterConfig luceneConfig;
|
private final IndexWriterConfig luceneConfig;
|
||||||
private final long commitWithinMs;
|
private long commitWithinMs;
|
||||||
|
|
||||||
private GerritIndexWriterConfig(Version version, Config cfg, String name) {
|
private GerritIndexWriterConfig(Version version, Config cfg, String name) {
|
||||||
luceneConfig = new IndexWriterConfig(version,
|
luceneConfig = new IndexWriterConfig(version,
|
||||||
@@ -173,9 +173,13 @@ public class LuceneChangeIndex implements ChangeIndex {
|
|||||||
luceneConfig.setMaxBufferedDocs(cfg.getInt(
|
luceneConfig.setMaxBufferedDocs(cfg.getInt(
|
||||||
"index", name, "maxBufferedDocs",
|
"index", name, "maxBufferedDocs",
|
||||||
IndexWriterConfig.DEFAULT_MAX_BUFFERED_DOCS));
|
IndexWriterConfig.DEFAULT_MAX_BUFFERED_DOCS));
|
||||||
commitWithinMs = ConfigUtil.getTimeUnit(
|
try {
|
||||||
cfg, "index", name, "commitWithin",
|
commitWithinMs =
|
||||||
MILLISECONDS.convert(5, MINUTES), MILLISECONDS);
|
ConfigUtil.getTimeUnit(cfg, "index", name, "commitWithin",
|
||||||
|
MILLISECONDS.convert(5, MINUTES), MILLISECONDS);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
commitWithinMs = cfg.getLong("index", name, "commitWithin", 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IndexWriterConfig getLuceneConfig() {
|
IndexWriterConfig getLuceneConfig() {
|
||||||
|
@@ -16,13 +16,14 @@ package com.google.gerrit.lucene;
|
|||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
|
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Sets;
|
||||||
import com.google.common.util.concurrent.AbstractFuture;
|
import com.google.common.util.concurrent.AbstractFuture;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
import com.google.gerrit.lucene.LuceneChangeIndex.GerritIndexWriterConfig;
|
import com.google.gerrit.lucene.LuceneChangeIndex.GerritIndexWriterConfig;
|
||||||
|
|
||||||
import org.apache.lucene.document.Document;
|
import org.apache.lucene.document.Document;
|
||||||
|
import org.apache.lucene.index.IndexWriter;
|
||||||
import org.apache.lucene.index.Term;
|
import org.apache.lucene.index.Term;
|
||||||
import org.apache.lucene.index.TrackingIndexWriter;
|
import org.apache.lucene.index.TrackingIndexWriter;
|
||||||
import org.apache.lucene.search.ControlledRealTimeReopenThread;
|
import org.apache.lucene.search.ControlledRealTimeReopenThread;
|
||||||
@@ -38,14 +39,12 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
/** Piece of the change index that is implemented as a separate Lucene index. */
|
/** Piece of the change index that is implemented as a separate Lucene index. */
|
||||||
class SubIndex {
|
class SubIndex {
|
||||||
@@ -55,8 +54,7 @@ class SubIndex {
|
|||||||
private final TrackingIndexWriter writer;
|
private final TrackingIndexWriter writer;
|
||||||
private final SearcherManager searcherManager;
|
private final SearcherManager searcherManager;
|
||||||
private final ControlledRealTimeReopenThread<IndexSearcher> reopenThread;
|
private final ControlledRealTimeReopenThread<IndexSearcher> reopenThread;
|
||||||
private final ConcurrentMap<RefreshListener, Boolean> refreshListeners;
|
private final Set<NrtFuture> notDoneNrtFutures;
|
||||||
private final ScheduledExecutorService commitExecutor;
|
|
||||||
|
|
||||||
SubIndex(File file, GerritIndexWriterConfig writerConfig) throws IOException {
|
SubIndex(File file, GerritIndexWriterConfig writerConfig) throws IOException {
|
||||||
this(FSDirectory.open(file), file.getName(), writerConfig);
|
this(FSDirectory.open(file), file.getName(), writerConfig);
|
||||||
@@ -65,49 +63,50 @@ class SubIndex {
|
|||||||
SubIndex(Directory dir, final String dirName,
|
SubIndex(Directory dir, final String dirName,
|
||||||
GerritIndexWriterConfig writerConfig) throws IOException {
|
GerritIndexWriterConfig writerConfig) throws IOException {
|
||||||
this.dir = dir;
|
this.dir = dir;
|
||||||
|
IndexWriter delegateWriter;
|
||||||
final AutoCommitWriter delegateWriter;
|
|
||||||
long commitPeriod = writerConfig.getCommitWithinMs();
|
long commitPeriod = writerConfig.getCommitWithinMs();
|
||||||
if (commitPeriod <= 0) {
|
|
||||||
commitExecutor = null;
|
if (commitPeriod < 0) {
|
||||||
|
delegateWriter = new IndexWriter(dir, writerConfig.getLuceneConfig());
|
||||||
|
} else if (commitPeriod == 0) {
|
||||||
delegateWriter =
|
delegateWriter =
|
||||||
new AutoCommitWriter(dir, writerConfig.getLuceneConfig(), true);
|
new AutoCommitWriter(dir, writerConfig.getLuceneConfig(), true);
|
||||||
} else {
|
} else {
|
||||||
commitExecutor = new ScheduledThreadPoolExecutor(1,
|
final AutoCommitWriter autoCommitWriter =
|
||||||
new ThreadFactoryBuilder()
|
|
||||||
.setNameFormat("Commit-%d " + dirName)
|
|
||||||
.setDaemon(true)
|
|
||||||
.build());
|
|
||||||
delegateWriter =
|
|
||||||
new AutoCommitWriter(dir, writerConfig.getLuceneConfig(), false);
|
new AutoCommitWriter(dir, writerConfig.getLuceneConfig(), false);
|
||||||
commitExecutor.scheduleAtFixedRate(new Runnable() {
|
delegateWriter = autoCommitWriter;
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
if (delegateWriter.hasUncommittedChanges()) {
|
|
||||||
delegateWriter.manualFlush();
|
|
||||||
delegateWriter.commit();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("Error committing Lucene index " + dirName, e);
|
|
||||||
} catch (OutOfMemoryError e) {
|
|
||||||
log.error("Error committing Lucene index " + dirName, e);
|
|
||||||
try {
|
|
||||||
delegateWriter.close();
|
|
||||||
} catch (IOException e2) {
|
|
||||||
log.error("SEVERE: Error closing Lucene index "
|
|
||||||
+ dirName + " after OOM; index may be corrupted.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, commitPeriod, commitPeriod, MILLISECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder()
|
||||||
|
.setNameFormat("Commit-%d " + dirName)
|
||||||
|
.setDaemon(true)
|
||||||
|
.build())
|
||||||
|
.scheduleAtFixedRate(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
if (autoCommitWriter.hasUncommittedChanges()) {
|
||||||
|
autoCommitWriter.manualFlush();
|
||||||
|
autoCommitWriter.commit();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Error committing Lucene index " + dirName, e);
|
||||||
|
} catch (OutOfMemoryError e) {
|
||||||
|
log.error("Error committing Lucene index " + dirName, e);
|
||||||
|
try {
|
||||||
|
autoCommitWriter.close();
|
||||||
|
} catch (IOException e2) {
|
||||||
|
log.error("SEVERE: Error closing Lucene index " + dirName
|
||||||
|
+ " after OOM; index may be corrupted.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, commitPeriod, commitPeriod, MILLISECONDS);
|
||||||
|
}
|
||||||
writer = new TrackingIndexWriter(delegateWriter);
|
writer = new TrackingIndexWriter(delegateWriter);
|
||||||
searcherManager = new SearcherManager(
|
searcherManager = new SearcherManager(
|
||||||
writer.getIndexWriter(), true, new SearcherFactory());
|
writer.getIndexWriter(), true, new SearcherFactory());
|
||||||
|
|
||||||
refreshListeners = Maps.newConcurrentMap();
|
notDoneNrtFutures = Sets.newConcurrentHashSet();
|
||||||
searcherManager.addListener(new RefreshListener() {
|
searcherManager.addListener(new RefreshListener() {
|
||||||
@Override
|
@Override
|
||||||
public void beforeRefresh() throws IOException {
|
public void beforeRefresh() throws IOException {
|
||||||
@@ -115,8 +114,8 @@ class SubIndex {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterRefresh(boolean didRefresh) throws IOException {
|
public void afterRefresh(boolean didRefresh) throws IOException {
|
||||||
for (RefreshListener l : refreshListeners.keySet()) {
|
for (NrtFuture f : notDoneNrtFutures) {
|
||||||
l.afterRefresh(didRefresh);
|
f.removeIfDone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -176,10 +175,8 @@ class SubIndex {
|
|||||||
searcherManager.release(searcher);
|
searcherManager.release(searcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class NrtFuture extends AbstractFuture<Void>
|
private final class NrtFuture extends AbstractFuture<Void> {
|
||||||
implements RefreshListener {
|
|
||||||
private final long gen;
|
private final long gen;
|
||||||
private final AtomicBoolean hasListeners = new AtomicBoolean();
|
|
||||||
|
|
||||||
NrtFuture(long gen) {
|
NrtFuture(long gen) {
|
||||||
this.gen = gen;
|
this.gen = gen;
|
||||||
@@ -198,9 +195,12 @@ class SubIndex {
|
|||||||
public Void get(long timeout, TimeUnit unit) throws InterruptedException,
|
public Void get(long timeout, TimeUnit unit) throws InterruptedException,
|
||||||
TimeoutException, ExecutionException {
|
TimeoutException, ExecutionException {
|
||||||
if (!isDone()) {
|
if (!isDone()) {
|
||||||
reopenThread.waitForGeneration(gen,
|
if (reopenThread.waitForGeneration(gen,
|
||||||
(int) MILLISECONDS.convert(timeout, unit));
|
(int) MILLISECONDS.convert(timeout, unit))) {
|
||||||
set(null);
|
set(null);
|
||||||
|
} else {
|
||||||
|
throw new TimeoutException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return super.get(timeout, unit);
|
return super.get(timeout, unit);
|
||||||
}
|
}
|
||||||
@@ -209,7 +209,7 @@ class SubIndex {
|
|||||||
public boolean isDone() {
|
public boolean isDone() {
|
||||||
if (super.isDone()) {
|
if (super.isDone()) {
|
||||||
return true;
|
return true;
|
||||||
} else if (isSearcherCurrent()) {
|
} else if (isGenAvailableNowForCurrentSearcher()) {
|
||||||
set(null);
|
set(null);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -218,33 +218,31 @@ class SubIndex {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addListener(Runnable listener, Executor executor) {
|
public void addListener(Runnable listener, Executor executor) {
|
||||||
if (hasListeners.compareAndSet(false, true) && !isDone()) {
|
if (!isDone()) {
|
||||||
searcherManager.addListener(this);
|
notDoneNrtFutures.add(this);
|
||||||
}
|
}
|
||||||
super.addListener(listener, executor);
|
super.addListener(listener, executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||||
if (hasListeners.get()) {
|
boolean result = super.cancel(mayInterruptIfRunning);
|
||||||
refreshListeners.put(this, true);
|
if (result) {
|
||||||
|
notDoneNrtFutures.remove(this);
|
||||||
}
|
}
|
||||||
return super.cancel(mayInterruptIfRunning);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
void removeIfDone() {
|
||||||
public void beforeRefresh() throws IOException {
|
if (isGenAvailableNowForCurrentSearcher()) {
|
||||||
}
|
notDoneNrtFutures.remove(this);
|
||||||
|
if (!isCancelled()) {
|
||||||
@Override
|
set(null);
|
||||||
public void afterRefresh(boolean didRefresh) throws IOException {
|
}
|
||||||
if (isSearcherCurrent()) {
|
|
||||||
refreshListeners.remove(this);
|
|
||||||
set(null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSearcherCurrent() {
|
private boolean isGenAvailableNowForCurrentSearcher() {
|
||||||
try {
|
try {
|
||||||
return reopenThread.waitForGeneration(gen, 0);
|
return reopenThread.waitForGeneration(gen, 0);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
@@ -63,6 +63,7 @@ import com.google.gerrit.server.index.ChangeIndex;
|
|||||||
import com.google.gerrit.server.index.ChangeSchemas;
|
import com.google.gerrit.server.index.ChangeSchemas;
|
||||||
import com.google.gerrit.server.index.IndexCollection;
|
import com.google.gerrit.server.index.IndexCollection;
|
||||||
import com.google.gerrit.server.index.IndexModule;
|
import com.google.gerrit.server.index.IndexModule;
|
||||||
|
import com.google.gerrit.server.index.IndexModule.IndexType;
|
||||||
import com.google.gerrit.server.mail.ReplacePatchSetSender;
|
import com.google.gerrit.server.mail.ReplacePatchSetSender;
|
||||||
import com.google.gerrit.server.notedb.NoteDbModule;
|
import com.google.gerrit.server.notedb.NoteDbModule;
|
||||||
import com.google.gerrit.server.patch.PatchListCacheImpl;
|
import com.google.gerrit.server.patch.PatchListCacheImpl;
|
||||||
@@ -133,6 +134,7 @@ public class Reindex extends SiteProgram {
|
|||||||
mustHaveValidSite();
|
mustHaveValidSite();
|
||||||
dbInjector = createDbInjector(MULTI_USER);
|
dbInjector = createDbInjector(MULTI_USER);
|
||||||
limitThreads();
|
limitThreads();
|
||||||
|
disableLuceneAutomaticCommit();
|
||||||
if (version == null) {
|
if (version == null) {
|
||||||
version = ChangeSchemas.getLatest().getVersion();
|
version = ChangeSchemas.getLatest().getVersion();
|
||||||
}
|
}
|
||||||
@@ -233,6 +235,15 @@ public class Reindex extends SiteProgram {
|
|||||||
return dbInjector.createChildInjector(modules);
|
return dbInjector.createChildInjector(modules);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void disableLuceneAutomaticCommit() {
|
||||||
|
Config cfg =
|
||||||
|
dbInjector.getInstance(Key.get(Config.class, GerritServerConfig.class));
|
||||||
|
if (IndexModule.getIndexType(dbInjector) == IndexType.LUCENE) {
|
||||||
|
cfg.setLong("index", "changes_open", "commitWithin", -1);
|
||||||
|
cfg.setLong("index", "changes_closed", "commitWithin", -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class ReviewDbModule extends LifecycleModule {
|
private class ReviewDbModule extends LifecycleModule {
|
||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
|
@@ -23,7 +23,8 @@ import com.google.gerrit.reviewdb.client.PatchLineComment;
|
|||||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||||
import com.google.gerrit.server.CurrentUser;
|
import com.google.gerrit.server.CurrentUser;
|
||||||
import com.google.gerrit.server.git.WorkQueue;
|
import com.google.gerrit.server.git.EmailReviewCommentsExecutor;
|
||||||
|
import com.google.gerrit.server.git.WorkQueue.Executor;
|
||||||
import com.google.gerrit.server.mail.CommentSender;
|
import com.google.gerrit.server.mail.CommentSender;
|
||||||
import com.google.gerrit.server.patch.PatchSetInfoFactory;
|
import com.google.gerrit.server.patch.PatchSetInfoFactory;
|
||||||
import com.google.gerrit.server.util.RequestContext;
|
import com.google.gerrit.server.util.RequestContext;
|
||||||
@@ -55,7 +56,7 @@ class EmailReviewComments implements Runnable, RequestContext {
|
|||||||
List<PatchLineComment> comments);
|
List<PatchLineComment> comments);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final WorkQueue workQueue;
|
private final Executor sendEmailsExecutor;
|
||||||
private final PatchSetInfoFactory patchSetInfoFactory;
|
private final PatchSetInfoFactory patchSetInfoFactory;
|
||||||
private final CommentSender.Factory commentSenderFactory;
|
private final CommentSender.Factory commentSenderFactory;
|
||||||
private final SchemaFactory<ReviewDb> schemaFactory;
|
private final SchemaFactory<ReviewDb> schemaFactory;
|
||||||
@@ -71,7 +72,7 @@ class EmailReviewComments implements Runnable, RequestContext {
|
|||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
EmailReviewComments (
|
EmailReviewComments (
|
||||||
WorkQueue workQueue,
|
@EmailReviewCommentsExecutor final Executor executor,
|
||||||
PatchSetInfoFactory patchSetInfoFactory,
|
PatchSetInfoFactory patchSetInfoFactory,
|
||||||
CommentSender.Factory commentSenderFactory,
|
CommentSender.Factory commentSenderFactory,
|
||||||
SchemaFactory<ReviewDb> schemaFactory,
|
SchemaFactory<ReviewDb> schemaFactory,
|
||||||
@@ -82,7 +83,7 @@ class EmailReviewComments implements Runnable, RequestContext {
|
|||||||
@Assisted Account.Id authorId,
|
@Assisted Account.Id authorId,
|
||||||
@Assisted ChangeMessage message,
|
@Assisted ChangeMessage message,
|
||||||
@Assisted List<PatchLineComment> comments) {
|
@Assisted List<PatchLineComment> comments) {
|
||||||
this.workQueue = workQueue;
|
this.sendEmailsExecutor = executor;
|
||||||
this.patchSetInfoFactory = patchSetInfoFactory;
|
this.patchSetInfoFactory = patchSetInfoFactory;
|
||||||
this.commentSenderFactory = commentSenderFactory;
|
this.commentSenderFactory = commentSenderFactory;
|
||||||
this.schemaFactory = schemaFactory;
|
this.schemaFactory = schemaFactory;
|
||||||
@@ -96,7 +97,7 @@ class EmailReviewComments implements Runnable, RequestContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void sendAsync() {
|
void sendAsync() {
|
||||||
workQueue.getDefaultQueue().submit(this);
|
sendEmailsExecutor.submit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -207,6 +207,10 @@ public class ConfigUtil {
|
|||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (s.startsWith("-")/* negative */) {
|
||||||
|
throw notTimeUnit(section, subsection, setting, valueString);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return getTimeUnit(s, defaultValue, wantUnit);
|
return getTimeUnit(s, defaultValue, wantUnit);
|
||||||
} catch (IllegalArgumentException notTime) {
|
} catch (IllegalArgumentException notTime) {
|
||||||
|
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (C) 2014 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package com.google.gerrit.server.git;
|
||||||
|
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
import com.google.inject.BindingAnnotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marker on the global {@link WorkQueue.Executor} used by
|
||||||
|
* {@link EmailReviewComments}.
|
||||||
|
*/
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@BindingAnnotation
|
||||||
|
public @interface EmailReviewCommentsExecutor {
|
||||||
|
}
|
@@ -45,6 +45,15 @@ public class ReceiveCommitsExecutorModule extends AbstractModule {
|
|||||||
return queues.createQueue(poolSize, "ReceiveCommits");
|
return queues.createQueue(poolSize, "ReceiveCommits");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
@EmailReviewCommentsExecutor
|
||||||
|
public WorkQueue.Executor createEmailReviewCommentsExecutor(
|
||||||
|
@GerritServerConfig Config config, WorkQueue queues) {
|
||||||
|
int poolSize = config.getInt("sendemail", null, "threadPoolSize", 1);
|
||||||
|
return queues.createQueue(poolSize, "EmailReviewComments");
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
@ChangeUpdateExecutor
|
@ChangeUpdateExecutor
|
||||||
|
@@ -18,10 +18,12 @@ import com.google.common.collect.Lists;
|
|||||||
import com.google.gerrit.extensions.events.LifecycleListener;
|
import com.google.gerrit.extensions.events.LifecycleListener;
|
||||||
import com.google.gerrit.lifecycle.LifecycleModule;
|
import com.google.gerrit.lifecycle.LifecycleModule;
|
||||||
import com.google.gerrit.reviewdb.client.Project.NameKey;
|
import com.google.gerrit.reviewdb.client.Project.NameKey;
|
||||||
|
import com.google.gerrit.server.config.GerritServerConfig;
|
||||||
import com.google.gerrit.server.util.IdGenerator;
|
import com.google.gerrit.server.util.IdGenerator;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.lib.Config;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -83,19 +85,21 @@ public class WorkQueue {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private Executor defaultQueue;
|
private Executor defaultQueue;
|
||||||
|
private int defaultQueueSize;
|
||||||
private final IdGenerator idGenerator;
|
private final IdGenerator idGenerator;
|
||||||
private final CopyOnWriteArrayList<Executor> queues;
|
private final CopyOnWriteArrayList<Executor> queues;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
WorkQueue(final IdGenerator idGenerator) {
|
WorkQueue(final IdGenerator idGenerator, @GerritServerConfig final Config cfg) {
|
||||||
this.idGenerator = idGenerator;
|
this.idGenerator = idGenerator;
|
||||||
this.queues = new CopyOnWriteArrayList<Executor>();
|
this.queues = new CopyOnWriteArrayList<Executor>();
|
||||||
|
defaultQueueSize = cfg.getInt("execution", "defaultThreadPoolSize", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the default work queue, for miscellaneous tasks. */
|
/** Get the default work queue, for miscellaneous tasks. */
|
||||||
public synchronized Executor getDefaultQueue() {
|
public synchronized Executor getDefaultQueue() {
|
||||||
if (defaultQueue == null) {
|
if (defaultQueue == null) {
|
||||||
defaultQueue = createQueue(1, "WorkQueue");
|
defaultQueue = createQueue(defaultQueueSize, "WorkQueue");
|
||||||
}
|
}
|
||||||
return defaultQueue;
|
return defaultQueue;
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
package com.google.gerrit.server.mail;
|
package com.google.gerrit.server.mail;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Ints;
|
||||||
import com.google.gerrit.common.Version;
|
import com.google.gerrit.common.Version;
|
||||||
import com.google.gerrit.common.errors.EmailException;
|
import com.google.gerrit.common.errors.EmailException;
|
||||||
import com.google.gerrit.server.config.ConfigUtil;
|
import com.google.gerrit.server.config.ConfigUtil;
|
||||||
@@ -39,10 +40,14 @@ import java.util.HashSet;
|
|||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/** Sends email via a nearby SMTP server. */
|
/** Sends email via a nearby SMTP server. */
|
||||||
@Singleton
|
@Singleton
|
||||||
public class SmtpEmailSender implements EmailSender {
|
public class SmtpEmailSender implements EmailSender {
|
||||||
|
/** The socket's connect timeout (0 = infinite timeout) */
|
||||||
|
private static final int DEFAULT_CONNECT_TIMEOUT = 0;
|
||||||
|
|
||||||
public static class Module extends AbstractModule {
|
public static class Module extends AbstractModule {
|
||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
@@ -55,6 +60,7 @@ public class SmtpEmailSender implements EmailSender {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final boolean enabled;
|
private final boolean enabled;
|
||||||
|
private final int connectTimeout;
|
||||||
|
|
||||||
private String smtpHost;
|
private String smtpHost;
|
||||||
private int smtpPort;
|
private int smtpPort;
|
||||||
@@ -69,6 +75,10 @@ public class SmtpEmailSender implements EmailSender {
|
|||||||
@Inject
|
@Inject
|
||||||
SmtpEmailSender(@GerritServerConfig final Config cfg) {
|
SmtpEmailSender(@GerritServerConfig final Config cfg) {
|
||||||
enabled = cfg.getBoolean("sendemail", null, "enable", true);
|
enabled = cfg.getBoolean("sendemail", null, "enable", true);
|
||||||
|
connectTimeout =
|
||||||
|
Ints.checkedCast(ConfigUtil.getTimeUnit(cfg, "sendemail", null,
|
||||||
|
"connectTimeout", DEFAULT_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS));
|
||||||
|
|
||||||
|
|
||||||
smtpHost = cfg.getString("sendemail", null, "smtpserver");
|
smtpHost = cfg.getString("sendemail", null, "smtpserver");
|
||||||
if (smtpHost == null) {
|
if (smtpHost == null) {
|
||||||
@@ -240,6 +250,7 @@ public class SmtpEmailSender implements EmailSender {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
client.setConnectTimeout(connectTimeout);
|
||||||
client.connect(smtpHost, smtpPort);
|
client.connect(smtpHost, smtpPort);
|
||||||
if (!SMTPReply.isPositiveCompletion(client.getReplyCode())) {
|
if (!SMTPReply.isPositiveCompletion(client.getReplyCode())) {
|
||||||
throw new EmailException("SMTP server rejected connection");
|
throw new EmailException("SMTP server rejected connection");
|
||||||
|
@@ -16,7 +16,9 @@ package com.google.gerrit.server.project;
|
|||||||
|
|
||||||
import com.google.common.base.CharMatcher;
|
import com.google.common.base.CharMatcher;
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
|
import com.google.common.base.Objects;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
|
import com.google.gerrit.common.ChangeHooks;
|
||||||
import com.google.gerrit.extensions.api.projects.ProjectInput.ConfigValue;
|
import com.google.gerrit.extensions.api.projects.ProjectInput.ConfigValue;
|
||||||
import com.google.gerrit.extensions.common.InheritableBoolean;
|
import com.google.gerrit.extensions.common.InheritableBoolean;
|
||||||
import com.google.gerrit.extensions.common.SubmitType;
|
import com.google.gerrit.extensions.common.SubmitType;
|
||||||
@@ -26,12 +28,15 @@ import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
|||||||
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
||||||
import com.google.gerrit.extensions.restapi.RestModifyView;
|
import com.google.gerrit.extensions.restapi.RestModifyView;
|
||||||
import com.google.gerrit.extensions.restapi.RestView;
|
import com.google.gerrit.extensions.restapi.RestView;
|
||||||
|
import com.google.gerrit.reviewdb.client.Branch;
|
||||||
import com.google.gerrit.reviewdb.client.Project;
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
|
import com.google.gerrit.reviewdb.client.RefNames;
|
||||||
import com.google.gerrit.server.CurrentUser;
|
import com.google.gerrit.server.CurrentUser;
|
||||||
import com.google.gerrit.server.config.AllProjectsNameProvider;
|
import com.google.gerrit.server.config.AllProjectsNameProvider;
|
||||||
import com.google.gerrit.server.config.PluginConfig;
|
import com.google.gerrit.server.config.PluginConfig;
|
||||||
import com.google.gerrit.server.config.PluginConfigFactory;
|
import com.google.gerrit.server.config.PluginConfigFactory;
|
||||||
import com.google.gerrit.server.config.ProjectConfigEntry;
|
import com.google.gerrit.server.config.ProjectConfigEntry;
|
||||||
|
import com.google.gerrit.server.IdentifiedUser;
|
||||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||||
import com.google.gerrit.server.git.ProjectConfig;
|
import com.google.gerrit.server.git.ProjectConfig;
|
||||||
@@ -42,6 +47,7 @@ import com.google.inject.Provider;
|
|||||||
|
|
||||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||||
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -75,6 +81,7 @@ public class PutConfig implements RestModifyView<ProjectResource, Input> {
|
|||||||
private final AllProjectsNameProvider allProjects;
|
private final AllProjectsNameProvider allProjects;
|
||||||
private final DynamicMap<RestView<ProjectResource>> views;
|
private final DynamicMap<RestView<ProjectResource>> views;
|
||||||
private final Provider<CurrentUser> currentUser;
|
private final Provider<CurrentUser> currentUser;
|
||||||
|
private final ChangeHooks hooks;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
PutConfig(MetaDataUpdate.User metaDataUpdateFactory,
|
PutConfig(MetaDataUpdate.User metaDataUpdateFactory,
|
||||||
@@ -86,6 +93,7 @@ public class PutConfig implements RestModifyView<ProjectResource, Input> {
|
|||||||
PluginConfigFactory cfgFactory,
|
PluginConfigFactory cfgFactory,
|
||||||
AllProjectsNameProvider allProjects,
|
AllProjectsNameProvider allProjects,
|
||||||
DynamicMap<RestView<ProjectResource>> views,
|
DynamicMap<RestView<ProjectResource>> views,
|
||||||
|
ChangeHooks hooks,
|
||||||
Provider<CurrentUser> currentUser) {
|
Provider<CurrentUser> currentUser) {
|
||||||
this.metaDataUpdateFactory = metaDataUpdateFactory;
|
this.metaDataUpdateFactory = metaDataUpdateFactory;
|
||||||
this.projectCache = projectCache;
|
this.projectCache = projectCache;
|
||||||
@@ -96,6 +104,7 @@ public class PutConfig implements RestModifyView<ProjectResource, Input> {
|
|||||||
this.cfgFactory = cfgFactory;
|
this.cfgFactory = cfgFactory;
|
||||||
this.allProjects = allProjects;
|
this.allProjects = allProjects;
|
||||||
this.views = views;
|
this.views = views;
|
||||||
|
this.hooks = hooks;
|
||||||
this.currentUser = currentUser;
|
this.currentUser = currentUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +167,15 @@ public class PutConfig implements RestModifyView<ProjectResource, Input> {
|
|||||||
|
|
||||||
md.setMessage("Modified project settings\n");
|
md.setMessage("Modified project settings\n");
|
||||||
try {
|
try {
|
||||||
projectConfig.commit(md);
|
ObjectId baseRev = projectConfig.getRevision();
|
||||||
|
ObjectId commitRev = projectConfig.commit(md);
|
||||||
|
// Only fire hook if project was actually changed.
|
||||||
|
if (!Objects.equal(baseRev, commitRev)) {
|
||||||
|
IdentifiedUser user = (IdentifiedUser) currentUser.get();
|
||||||
|
hooks.doRefUpdatedHook(
|
||||||
|
new Branch.NameKey(projectName, RefNames.REFS_CONFIG),
|
||||||
|
baseRev, commitRev, user.getAccount());
|
||||||
|
};
|
||||||
projectCache.evict(projectConfig.getProject());
|
projectCache.evict(projectConfig.getProject());
|
||||||
gitMgr.setProjectDescription(projectName, p.getDescription());
|
gitMgr.setProjectDescription(projectName, p.getDescription());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@@ -16,13 +16,16 @@ package com.google.gerrit.server.project;
|
|||||||
|
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
|
import com.google.gerrit.common.ChangeHooks;
|
||||||
import com.google.gerrit.extensions.restapi.AuthException;
|
import com.google.gerrit.extensions.restapi.AuthException;
|
||||||
import com.google.gerrit.extensions.restapi.DefaultInput;
|
import com.google.gerrit.extensions.restapi.DefaultInput;
|
||||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||||
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
||||||
import com.google.gerrit.extensions.restapi.Response;
|
import com.google.gerrit.extensions.restapi.Response;
|
||||||
import com.google.gerrit.extensions.restapi.RestModifyView;
|
import com.google.gerrit.extensions.restapi.RestModifyView;
|
||||||
|
import com.google.gerrit.reviewdb.client.Branch;
|
||||||
import com.google.gerrit.reviewdb.client.Project;
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
|
import com.google.gerrit.reviewdb.client.RefNames;
|
||||||
import com.google.gerrit.server.IdentifiedUser;
|
import com.google.gerrit.server.IdentifiedUser;
|
||||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||||
@@ -32,6 +35,7 @@ import com.google.inject.Inject;
|
|||||||
|
|
||||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||||
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@@ -45,13 +49,16 @@ class PutDescription implements RestModifyView<ProjectResource, Input> {
|
|||||||
private final ProjectCache cache;
|
private final ProjectCache cache;
|
||||||
private final MetaDataUpdate.Server updateFactory;
|
private final MetaDataUpdate.Server updateFactory;
|
||||||
private final GitRepositoryManager gitMgr;
|
private final GitRepositoryManager gitMgr;
|
||||||
|
private final ChangeHooks hooks;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
PutDescription(ProjectCache cache,
|
PutDescription(ProjectCache cache,
|
||||||
MetaDataUpdate.Server updateFactory,
|
MetaDataUpdate.Server updateFactory,
|
||||||
|
ChangeHooks hooks,
|
||||||
GitRepositoryManager gitMgr) {
|
GitRepositoryManager gitMgr) {
|
||||||
this.cache = cache;
|
this.cache = cache;
|
||||||
this.updateFactory = updateFactory;
|
this.updateFactory = updateFactory;
|
||||||
|
this.hooks = hooks;
|
||||||
this.gitMgr = gitMgr;
|
this.gitMgr = gitMgr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +91,14 @@ class PutDescription implements RestModifyView<ProjectResource, Input> {
|
|||||||
}
|
}
|
||||||
md.setAuthor(user);
|
md.setAuthor(user);
|
||||||
md.setMessage(msg);
|
md.setMessage(msg);
|
||||||
config.commit(md);
|
ObjectId baseRev = config.getRevision();
|
||||||
|
ObjectId commitRev = config.commit(md);
|
||||||
|
// Only fire hook if project was actually changed.
|
||||||
|
if (!Objects.equal(baseRev, commitRev)) {
|
||||||
|
hooks.doRefUpdatedHook(
|
||||||
|
new Branch.NameKey(resource.getNameKey(), RefNames.REFS_CONFIG),
|
||||||
|
baseRev, commitRev, user.getAccount());
|
||||||
|
}
|
||||||
cache.evict(ctl.getProject());
|
cache.evict(ctl.getProject());
|
||||||
gitMgr.setProjectDescription(
|
gitMgr.setProjectDescription(
|
||||||
resource.getNameKey(),
|
resource.getNameKey(),
|
||||||
|
@@ -241,18 +241,21 @@ public class RefControl {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
boolean owner;
|
boolean owner;
|
||||||
|
boolean admin;
|
||||||
switch (getCurrentUser().getAccessPath()) {
|
switch (getCurrentUser().getAccessPath()) {
|
||||||
case REST_API:
|
case REST_API:
|
||||||
case JSON_RPC:
|
case JSON_RPC:
|
||||||
owner = isOwner();
|
owner = isOwner();
|
||||||
|
admin = getCurrentUser().getCapabilities().canAdministrateServer();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
owner = false;
|
owner = false;
|
||||||
|
admin = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object instanceof RevCommit) {
|
if (object instanceof RevCommit) {
|
||||||
return getCurrentUser().getCapabilities().canAdministrateServer()
|
return admin
|
||||||
|| (owner && !isBlocked(Permission.CREATE))
|
|| (owner && !isBlocked(Permission.CREATE))
|
||||||
|| (canPerform(Permission.CREATE) && (!existsOnServer && canUpdate() || projectControl
|
|| (canPerform(Permission.CREATE) && (!existsOnServer && canUpdate() || projectControl
|
||||||
.canReadCommit(rw, (RevCommit) object)));
|
.canReadCommit(rw, (RevCommit) object)));
|
||||||
|
@@ -41,8 +41,10 @@ import com.google.gerrit.server.config.GerritServerConfig;
|
|||||||
import com.google.gerrit.server.config.SitePath;
|
import com.google.gerrit.server.config.SitePath;
|
||||||
import com.google.gerrit.server.config.TrackingFooters;
|
import com.google.gerrit.server.config.TrackingFooters;
|
||||||
import com.google.gerrit.server.config.TrackingFootersProvider;
|
import com.google.gerrit.server.config.TrackingFootersProvider;
|
||||||
|
import com.google.gerrit.server.git.EmailReviewCommentsExecutor;
|
||||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||||
import com.google.gerrit.server.git.PerThreadRequestScope;
|
import com.google.gerrit.server.git.PerThreadRequestScope;
|
||||||
|
import com.google.gerrit.server.git.WorkQueue;
|
||||||
import com.google.gerrit.server.index.ChangeSchemas;
|
import com.google.gerrit.server.index.ChangeSchemas;
|
||||||
import com.google.gerrit.server.index.IndexModule.IndexType;
|
import com.google.gerrit.server.index.IndexModule.IndexType;
|
||||||
import com.google.gerrit.server.mail.SignedTokenEmailTokenVerifier;
|
import com.google.gerrit.server.mail.SignedTokenEmailTokenVerifier;
|
||||||
@@ -178,6 +180,15 @@ public class InMemoryModule extends FactoryModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
@EmailReviewCommentsExecutor
|
||||||
|
public WorkQueue.Executor createEmailReviewCommentsExecutor(
|
||||||
|
@GerritServerConfig Config config, WorkQueue queues) {
|
||||||
|
int poolSize = config.getInt("sendemail", null, "threadPoolSize", 1);
|
||||||
|
return queues.createQueue(poolSize, "EmailReviewComments");
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
InMemoryDatabase getInMemoryDatabase(@Current SchemaVersion schemaVersion,
|
InMemoryDatabase getInMemoryDatabase(@Current SchemaVersion schemaVersion,
|
||||||
|
@@ -41,7 +41,7 @@ import javax.inject.Inject;
|
|||||||
/**
|
/**
|
||||||
* Implements a command that allows the user to see the members of a group.
|
* Implements a command that allows the user to see the members of a group.
|
||||||
*/
|
*/
|
||||||
@CommandMetaData(name = "ls-members", description = "Lists the members of a given group",
|
@CommandMetaData(name = "ls-members", description = "List the members of a given group",
|
||||||
runsAt = MASTER_OR_SLAVE)
|
runsAt = MASTER_OR_SLAVE)
|
||||||
public class ListMembersCommand extends BaseCommand {
|
public class ListMembersCommand extends BaseCommand {
|
||||||
@Inject
|
@Inject
|
||||||
|
@@ -43,7 +43,7 @@ import java.io.IOException;
|
|||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@CommandMetaData(name = "set-members", description = "Modifies members of specific group or number of groups")
|
@CommandMetaData(name = "set-members", description = "Modify members of specific group or number of groups")
|
||||||
public class SetMembersCommand extends SshCommand {
|
public class SetMembersCommand extends SshCommand {
|
||||||
|
|
||||||
@Option(name = "--add", aliases = {"-a"}, metaVar = "USER", usage = "users that should be added as group member")
|
@Option(name = "--add", aliases = {"-a"}, metaVar = "USER", usage = "users that should be added as group member")
|
||||||
|
@@ -143,6 +143,7 @@ public class SetReviewersCommand extends SshCommand {
|
|||||||
for (String reviewer : toAdd) {
|
for (String reviewer : toAdd) {
|
||||||
AddReviewerInput input = new AddReviewerInput();
|
AddReviewerInput input = new AddReviewerInput();
|
||||||
input.reviewer = reviewer;
|
input.reviewer = reviewer;
|
||||||
|
input.confirmed = true;
|
||||||
String error;
|
String error;
|
||||||
try {
|
try {
|
||||||
error = post.apply(changeRsrc, input).error;
|
error = post.apply(changeRsrc, input).error;
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
|
<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
|
||||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||||
<listEntry value="/gerrit/buck-out/gen/lib/gwt/dev/gwt-dev-2.5.1.jar"/>
|
<listEntry value="/gerrit/buck-out/gen/lib/gwt/dev/gwt-dev-2.6.0.jar"/>
|
||||||
</listAttribute>
|
</listAttribute>
|
||||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||||
<listEntry value="1"/>
|
<listEntry value="1"/>
|
||||||
|
49
tools/version.py
Executable file
49
tools/version.py
Executable file
@@ -0,0 +1,49 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright (C) 2014 The Android Open Source Project
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
from optparse import OptionParser
|
||||||
|
import os.path
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
parser = OptionParser()
|
||||||
|
opts, args = parser.parse_args()
|
||||||
|
|
||||||
|
if not len(args):
|
||||||
|
parser.error('not enough arguments')
|
||||||
|
elif len(args) > 1:
|
||||||
|
parser.error('too many arguments')
|
||||||
|
|
||||||
|
new_version = args[0]
|
||||||
|
pattern = re.compile(r'(\s*)<version>[-.\w]+</version>')
|
||||||
|
|
||||||
|
for project in ['gerrit-plugin-archetype', 'gerrit-plugin-gwt-archetype',
|
||||||
|
'gerrit-plugin-gwtui', 'gerrit-plugin-js-archetype']:
|
||||||
|
pom = os.path.join(project, 'pom.xml')
|
||||||
|
try:
|
||||||
|
outxml = ""
|
||||||
|
found = False
|
||||||
|
for line in open(pom, "r"):
|
||||||
|
m = pattern.match(line)
|
||||||
|
if m and not found:
|
||||||
|
outxml += "%s<version>%s</version>\n" % (m.group(1), new_version)
|
||||||
|
found = True
|
||||||
|
else:
|
||||||
|
outxml += line
|
||||||
|
with open(pom, "w") as outfile:
|
||||||
|
outfile.write(outxml)
|
||||||
|
except IOError as err:
|
||||||
|
print('error updating %s: %s' % (pom, err), file=sys.stderr)
|
Reference in New Issue
Block a user