Merge "Copy reviewed flags to new patch sets for identical files"
diff --git a/.gitmodules b/.gitmodules
index e45868b..2ac959c 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -10,6 +10,6 @@
path = plugins/commit-message-length-validator
url = https://gerrit.googlesource.com/plugins/commit-message-length-validator
-[submodule "plugins/helloworld"]
- path = plugins/helloworld
- url = https://gerrit.googlesource.com/plugins/helloworld
+[submodule "plugins/cookbook-plugin"]
+ path = plugins/cookbook-plugin
+ url = https://gerrit.googlesource.com/plugins/cookbook-plugin
diff --git a/BUCK b/BUCK
index e454d37..b1a0c75 100644
--- a/BUCK
+++ b/BUCK
@@ -61,7 +61,7 @@
java_library(
name = 'plugin-lib',
- deps = PLUGIN_API,
+ deps = PLUGIN_API + ['//lib:servlet-api-3_0'],
export_deps = True,
visibility = ['PUBLIC'],
)
diff --git a/Documentation/access-control.txt b/Documentation/access-control.txt
index 504f125..9c964e0 100644
--- a/Documentation/access-control.txt
+++ b/Documentation/access-control.txt
@@ -1297,14 +1297,6 @@
all projects.
-[[capability_startReplication]]
-Start Replication
-~~~~~~~~~~~~~~~~~
-
-Allow access to execute `replication start` command, if the
-replication plugin is installed on the server.
-
-
[[capability_streamEvents]]
Stream Events
~~~~~~~~~~~~~
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 8e85b6d..3360cdf 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -1975,8 +1975,8 @@
from the user's account object matched under `ldap.accountBase`.
Attributes such as `${dn}` or `${uidNumber}` may be useful.
+
-Default is `(memberUid=${username})` for RFC 2307,
-and unset (disabled) for Active Directory.
+Default is `(|(memberUid=${username})(gidNumber=${gidNumber}))` for
+RFC 2307, and unset (disabled) for Active Directory.
[[ldap.groupName]]ldap.groupName::
+
diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt
index 051f9c2..b0a0e5f 100644
--- a/Documentation/dev-plugins.txt
+++ b/Documentation/dev-plugins.txt
@@ -310,6 +310,87 @@
$ ssh -p 29418 review.example.com helloworld print
----
+[[capabilities]]
+Plugin Owned Capabilities
+-------------------------
+
+Plugins may provide their own capabilities and restrict usage of SSH
+commands to the users who are granted those capabilities.
+
+Plugins define the capabilities by overriding the `CapabilityDefinition`
+abstract class:
+
+====
+ public class PrintHelloCapability extends CapabilityDefinition {
+ @Override
+ public String getDescription() {
+ return "Print Hello";
+ }
+ }
+====
+
+If no Guice modules are declared in the manifest, UI commands may
+use auto-registration by providing an `@Export` annotation:
+
+====
+ @Export("printHello")
+ public class PrintHelloCapability extends CapabilityDefinition {
+ ...
+====
+
+Otherwise the capability must be bound in a plugin module:
+
+====
+ public class HelloWorldModule extends AbstractModule {
+ @Override
+ protected void configure() {
+ bind(CapabilityDefinition.class)
+ .annotatedWith(Exports.named("printHello"))
+ .to(PrintHelloCapability.class);
+ }
+ }
+====
+
+With a plugin-owned capability defined in this way, it is possible to restrict
+usage of an SSH command or UiAction to members of the group that were granted
+this capability in the usual way, using the `RequiresCapability` annotation:
+
+====
+ @RequiresCapability("printHello")
+ @CommandMetaData(name="print", description="Print greeting in different languages")
+ public final class PrintHelloWorldCommand extends SshCommand {
+ ...
+====
+
+Or with UiAction:
+
+====
+ @RequiresCapability("printHello")
+ public class SayHelloAction extends UiAction<RevisionResource>
+ implements RestModifyView<RevisionResource, SayHelloAction.Input> {
+ ...
+====
+
+Capability scope was introduced to differentiate between plugin-owned
+capabilities and core capabilities. Per default the scope of
+@RequiresCapability annotation is `CapabilityScope.CONTEXT`, that means:
++
+* when `@RequiresCapability` is used within a plugin the scope of the
+capability is assumed to be that plugin.
++
+* If `@RequiresCapability` is used within the core Gerrit Code Review server
+(and thus is outside of a plugin) the scope is the core server and will use
+the `GlobalCapability` known to Gerrit Code Review server.
+
+If a plugin needs to use a core capability name (e.g. "administrateServer")
+this can be specified by setting `scope = CapabilityScope.CORE`:
+
+====
+ @RequiresCapability(value = "administrateServer", scope =
+ CapabilityScope.CORE)
+ ...
+====
+
[[http]]
HTTP Servlets
-------------
diff --git a/Documentation/rest-api-accounts.txt b/Documentation/rest-api-accounts.txt
index 2cff3eb..7dbdf94 100644
--- a/Documentation/rest-api-accounts.txt
+++ b/Documentation/rest-api-accounts.txt
@@ -658,8 +658,7 @@
"flushCaches": true,
"viewConnections": true,
"viewQueue": true,
- "runGC": true,
- "startReplication": true
+ "runGC": true
}
----
@@ -1059,9 +1058,6 @@
|`runGC` |not set if `false`|Whether the user has the
link:access-control.html#capability_runGC[Run Garbage Collection]
capability.
-|`startReplication` |not set if `false`|Whether the user has the
-link:access-control.html#capability_startReplication[Start Replication]
-capability.
|=================================
[[diff-preferences-info]]
diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt
index 6af6897..f566704 100644
--- a/Documentation/rest-api-config.txt
+++ b/Documentation/rest-api-config.txt
@@ -112,11 +112,6 @@
"id": "runGC",
"name": "Run Garbage Collection"
},
- "startReplication": {
- "kind": "gerritcodereview#capability",
- "id": "startReplication",
- "name": "Start Replication"
- },
"streamEvents": {
"kind": "gerritcodereview#capability",
"id": "streamEvents",
diff --git a/ReleaseNotes/ReleaseNotes-2.6.2.txt b/ReleaseNotes/ReleaseNotes-2.6.2.txt
index cf963c2..2b78cb4 100644
--- a/ReleaseNotes/ReleaseNotes-2.6.2.txt
+++ b/ReleaseNotes/ReleaseNotes-2.6.2.txt
@@ -38,6 +38,12 @@
* Allow label values to be configured with no text.
+* link:https://code.google.com/p/gerrit/issues/detail?id=1966[Issue 1966]:
+Fix Gerrit plugins under Tomcat by avoiding Guice static filter.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2054[Issue 2054]:
+Expand capabilities of `ldap.groupMemberPattern`.
+
No other changes since 2.6.1.
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java
index 6c6cd26..a9ce827 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java
@@ -100,6 +100,7 @@
cfg.setString("httpd", null, "listenUrl", url);
cfg.setString("sshd", null, "listenAddress", format(sshd));
cfg.setString("cache", null, "directory", null);
+ cfg.setBoolean("sendemail", null, "enable", false);
cfg.setInt("cache", "projects", "checkFrequency", 0);
cfg.setInt("plugins", null, "checkFrequency", 0);
cfg.save();
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/GlobalCapability.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/GlobalCapability.java
index e18aee2..1fd98b6 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/GlobalCapability.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/GlobalCapability.java
@@ -76,9 +76,6 @@
/** Can run the Git garbage collection. */
public static final String RUN_GC = "runGC";
- /** Forcefully restart replication to any configured destination. */
- public static final String START_REPLICATION = "startReplication";
-
/** Can perform streaming of Gerrit events. */
public static final String STREAM_EVENTS = "streamEvents";
@@ -108,7 +105,6 @@
NAMES_ALL.add(QUERY_LIMIT);
NAMES_ALL.add(RUN_AS);
NAMES_ALL.add(RUN_GC);
- NAMES_ALL.add(START_REPLICATION);
NAMES_ALL.add(STREAM_EVENTS);
NAMES_ALL.add(VIEW_CACHES);
NAMES_ALL.add(VIEW_CONNECTIONS);
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/CapabilityScope.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/CapabilityScope.java
new file mode 100644
index 0000000..ede8b8c
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/CapabilityScope.java
@@ -0,0 +1,36 @@
+// Copyright (C) 2013 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.extensions.annotations;
+
+/** Declared scope of a capability named by {@link RequiresCapability}. */
+public enum CapabilityScope {
+ /**
+ * Scope is assumed based on the context.
+ *
+ * When {@code @RequiresCapability} is used within a plugin the scope of the
+ * capability is assumed to be that plugin.
+ *
+ * If {@code @RequiresCapability} is used within the core Gerrit Code Review
+ * server (and thus is outside of a plugin) the scope is the core server and
+ * will use {@link com.google.gerrit.common.data.GlobalCapability}.
+ */
+ CONTEXT,
+
+ /** Scope is only the plugin. */
+ PLUGIN,
+
+ /** Scope is the core server. */
+ CORE;
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/RequiresCapability.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/RequiresCapability.java
index 382f4ea..b8e07d1 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/RequiresCapability.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/annotations/RequiresCapability.java
@@ -27,5 +27,9 @@
@Target({ElementType.TYPE})
@Retention(RUNTIME)
public @interface RequiresCapability {
+ /** Name of the capability required to invoke this action. */
String value();
+
+ /** Scope of the named capability. */
+ CapabilityScope scope() default CapabilityScope.CONTEXT;
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/config/CapabilityDefinition.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/config/CapabilityDefinition.java
new file mode 100644
index 0000000..aafb583
--- /dev/null
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/config/CapabilityDefinition.java
@@ -0,0 +1,24 @@
+// Copyright (C) 2013 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.extensions.config;
+
+import com.google.gerrit.extensions.annotations.ExtensionPoint;
+
+/** Specifies a capability declared by a plugin. */
+@ExtensionPoint
+public abstract class CapabilityDefinition {
+ /** @return description of the capability. */
+ public abstract String getDescription();
+}
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/SafeHtml.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/SafeHtml.java
index 41e4abc..f752780 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/SafeHtml.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/SafeHtml.java
@@ -15,10 +15,10 @@
package com.google.gwtexpui.safehtml.client;
import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.Element;
import com.google.gwt.regexp.shared.MatchResult;
import com.google.gwt.regexp.shared.RegExp;
import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HTMLTable;
import com.google.gwt.user.client.ui.HasHTML;
@@ -86,13 +86,13 @@
}
/** @return the existing inner HTML of any element. */
- public static SafeHtml get(final Element e) {
- return new SafeHtmlString(DOM.getInnerHTML(e));
+ public static SafeHtml get(Element e) {
+ return new SafeHtmlString(e.getInnerHTML());
}
/** Set the inner HTML of any element. */
- public static Element set(final Element e, final SafeHtml str) {
- DOM.setInnerHTML(e, str.asString());
+ public static Element setInnerHTML(Element e, SafeHtml str) {
+ e.setInnerHTML(str.asString());
return e;
}
@@ -109,8 +109,10 @@
}
/** Parse an HTML block and return the first (typically root) element. */
- public static Element parse(final SafeHtml str) {
- return DOM.getFirstChild(set(DOM.createDiv(), str));
+ public static com.google.gwt.user.client.Element parse(SafeHtml html) {
+ com.google.gwt.user.client.Element e = DOM.createDiv();
+ setInnerHTML(e, html);
+ return DOM.getFirstChild(e);
}
/** Convert bare http:// and https:// URLs into <a href> tags. */
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.ui.xml
index c2b98b0..2a356b0 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.ui.xml
@@ -213,7 +213,7 @@
<div class='{style.headerButtons}'>
<g:Button ui:field='reply'
styleName=''
- title='Reply and score (Shortcut: r)'>
+ title='Reply and score (Shortcut: a)'>
<ui:attribute name='title'/>
<div><ui:msg>Reply…</ui:msg></div>
</g:Button>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
index 1bcab1a..ba71357 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
@@ -71,6 +71,7 @@
String commentColumn();
String deltaColumn1();
String deltaColumn2();
+ String commonPrefix();
String inserted();
String deleted();
}
@@ -227,7 +228,7 @@
keysNavigation.add(new OpenKeyCommand(0, KeyCodes.KEY_ENTER,
Util.C.patchTableOpenDiff()));
- keysNavigation.add(new KeyCommand(0, 'r', PatchUtil.C.toggleReviewed()) {
+ keysAction.add(new KeyCommand(0, 'r', PatchUtil.C.toggleReviewed()) {
@Override
public void onKeyPress(KeyPressEvent event) {
int row = getCurrentRow();
@@ -323,6 +324,7 @@
private int row;
private double start;
private ProgressBar meter;
+ private String lastPath = "";
private int inserted;
private int deleted;
@@ -448,14 +450,42 @@
.setStyleName(R.css().pathColumn())
.openAnchor()
.setAttribute("href", "#" + url(info))
- .setAttribute("onclick", OPEN + "(event," + info._row() + ")")
- .append(Patch.COMMIT_MSG.equals(info.path())
- ? Util.C.commitMessage()
- : info.path())
- .closeAnchor()
+ .setAttribute("onclick", OPEN + "(event," + info._row() + ")");
+
+ String path = info.path();
+ if (Patch.COMMIT_MSG.equals(path)) {
+ sb.append(Util.C.commitMessage());
+ } else {
+ int commonPrefixLen = commonPrefix(path);
+ if (commonPrefixLen > 0) {
+ sb.openSpan().setStyleName(R.css().commonPrefix())
+ .append(path.substring(0, commonPrefixLen))
+ .closeSpan();
+ }
+ sb.append(path.substring(commonPrefixLen));
+ lastPath = path;
+ }
+
+ sb.closeAnchor()
.closeTd();
}
+ private int commonPrefix(String path) {
+ for (int n = path.length(); n > 0;) {
+ int s = path.lastIndexOf('/', n);
+ if (s < 0) {
+ return 0;
+ }
+
+ String p = path.substring(0, s + 1);
+ if (lastPath.startsWith(p)) {
+ return s + 1;
+ }
+ n = s - 1;
+ }
+ return 0;
+ }
+
private void columnComments(SafeHtmlBuilder sb, FileInfo info) {
JsArray<CommentInfo> cList = get(info.path(), comments);
JsArray<CommentInfo> dList = get(info.path(), drafts);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/file_table.css b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/file_table.css
index 25724dc..943f9f1 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/file_table.css
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/file_table.css
@@ -23,6 +23,12 @@
white-space: nowrap;
min-width: 600px;
}
+.pathColumn a {
+ color: #000;
+}
+.commonPrefix {
+ color: #888;
+}
.draftColumn,
.newColumn,
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeDescriptionBlock.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeDescriptionBlock.java
index e5c8dcf..6b13ba0a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeDescriptionBlock.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeDescriptionBlock.java
@@ -16,8 +16,8 @@
import com.google.gerrit.client.ui.CommentLinkProcessor;
import com.google.gerrit.common.data.AccountInfoCache;
+import com.google.gerrit.common.data.ChangeDetail;
import com.google.gerrit.common.data.SubmitTypeRecord;
-import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSetInfo;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HorizontalPanel;
@@ -37,12 +37,12 @@
initWidget(hp);
}
- public void display(Change chg, Boolean starred, Boolean canEditCommitMessage,
+ public void display(ChangeDetail changeDetail, Boolean starred, Boolean canEditCommitMessage,
PatchSetInfo info, AccountInfoCache acc,
SubmitTypeRecord submitTypeRecord,
CommentLinkProcessor commentLinkProcessor) {
- infoBlock.display(chg, acc, submitTypeRecord);
- messageBlock.display(chg.currentPatchSetId(), starred,
+ infoBlock.display(changeDetail, acc, submitTypeRecord);
+ messageBlock.display(changeDetail.getChange().currentPatchSetId(), starred,
canEditCommitMessage, info.getMessage(), commentLinkProcessor);
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfoBlock.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfoBlock.java
index b942824..b4ae2f3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfoBlock.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfoBlock.java
@@ -95,8 +95,9 @@
table.getCellFormatter().addStyleName(row, 0, Gerrit.RESOURCES.css().header());
}
- public void display(final Change chg, final AccountInfoCache acc,
- SubmitTypeRecord submitTypeRecord) {
+ public void display(final ChangeDetail changeDetail,
+ final AccountInfoCache acc, SubmitTypeRecord submitTypeRecord) {
+ final Change chg = changeDetail.getChange();
final Branch.NameKey dst = chg.getDest();
CopyableLabel changeIdLabel =
@@ -114,7 +115,7 @@
table.setWidget(R_BRANCH, 1, new BranchLink(dst.getShortName(), chg
.getProject(), chg.getStatus(), dst.get(), null));
- table.setWidget(R_TOPIC, 1, topic(chg));
+ table.setWidget(R_TOPIC, 1, topic(changeDetail));
table.setText(R_UPLOADED, 1, mediumFormat(chg.getCreatedOn()));
table.setText(R_UPDATED, 1, mediumFormat(chg.getLastUpdatedOn()));
table.setText(R_STATUS, 1, Util.toLongString(chg.getStatus()));
@@ -146,7 +147,8 @@
}
}
- public Widget topic(final Change chg) {
+ public Widget topic(final ChangeDetail changeDetail) {
+ final Change chg = changeDetail.getChange();
final Branch.NameKey dst = chg.getDest();
FlowPanel fp = new FlowPanel();
@@ -154,9 +156,6 @@
fp.add(new BranchLink(chg.getTopic(), chg.getProject(), chg.getStatus(),
dst.get(), chg.getTopic()));
- ChangeDetailCache detailCache = ChangeCache.get(chg.getId()).getChangeDetailCache();
- ChangeDetail changeDetail = detailCache.get();
-
if (changeDetail.canEditTopicName()) {
final Image edit = new Image(Gerrit.RESOURCES.edit());
edit.addStyleName(Gerrit.RESOURCES.css().link());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeScreen.java
index 0a53b6d..0ec34a9 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeScreen.java
@@ -322,7 +322,7 @@
dependencies.setAccountInfoCache(detail.getAccounts());
- descriptionBlock.display(detail.getChange(),
+ descriptionBlock.display(detail,
detail.isStarred(),
detail.canEditCommitMessage(),
detail.getCurrentPatchSetDetail().getInfo(),
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentInfo.java
index 5f6a9c5..34c0638 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentInfo.java
@@ -15,6 +15,7 @@
package com.google.gerrit.client.changes;
import com.google.gerrit.client.account.AccountInfo;
+import com.google.gerrit.client.diff.CommentRange;
import com.google.gerrit.common.changes.Side;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwtjsonrpc.client.impl.ser.JavaSqlTimestamp_JsonSerializer;
@@ -22,10 +23,11 @@
import java.sql.Timestamp;
public class CommentInfo extends JavaScriptObject {
- public static CommentInfo createLine(String path, Side side, int line,
- String in_reply_to, String message) {
+ public static CommentInfo createRange(String path, Side side, int line,
+ String in_reply_to, String message, CommentRange range) {
CommentInfo info = createFile(path, side, in_reply_to, message);
- info.setLine(line);
+ info.setRange(range);
+ info.setLine(range == null ? line : range.end_line());
return info;
}
@@ -82,6 +84,10 @@
public final native boolean has_line() /*-{ return this.hasOwnProperty('line'); }-*/;
+ public final native CommentRange range() /*-{ return this.range; }-*/;
+
+ public final native void setRange(CommentRange range) /*-{ this.range = range; }-*/;
+
protected CommentInfo() {
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentInput.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentInput.java
index 592e087..c96a67f 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentInput.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentInput.java
@@ -14,6 +14,7 @@
package com.google.gerrit.client.changes;
+import com.google.gerrit.client.diff.CommentRange;
import com.google.gerrit.common.changes.Side;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwtjsonrpc.client.impl.ser.JavaSqlTimestamp_JsonSerializer;
@@ -29,6 +30,7 @@
if (original.has_line()) {
input.setLine(original.line());
}
+ input.setRange(original.range());
input.setInReplyTo(original.in_reply_to());
input.setMessage(original.message());
return input;
@@ -71,6 +73,10 @@
public final native boolean has_line() /*-{ return this.hasOwnProperty('line'); }-*/;
+ public final native CommentRange range() /*-{ return this.range; }-*/;
+
+ public final native void setRange(CommentRange range) /*-{ this.range = range; }-*/;
+
protected CommentInput() {
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PublishCommentScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PublishCommentScreen.java
index 608a2c7..58a7042 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PublishCommentScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PublishCommentScreen.java
@@ -31,6 +31,7 @@
import com.google.gerrit.client.ui.PatchLink;
import com.google.gerrit.client.ui.SmallHeading;
import com.google.gerrit.common.PageLinks;
+import com.google.gerrit.common.data.ChangeDetail;
import com.google.gerrit.common.data.PatchSetPublishDetail;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Patch;
@@ -317,9 +318,12 @@
}
private void display(final PatchSetPublishDetail r) {
+ ChangeDetail changeDetail = new ChangeDetail();
+ changeDetail.setChange(r.getChange());
+
setPageTitle(Util.M.publishComments(r.getChange().getKey().abbreviate(),
patchSetId.get()));
- descBlock.display(r.getChange(), null, false, r.getPatchSetInfo(), r.getAccounts(),
+ descBlock.display(changeDetail, null, false, r.getPatchSetInfo(), r.getAccounts(),
r.getSubmitTypeRecord(), commentLinkProcessor);
if (r.getChange().getStatus().isOpen()) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentBoxUi.css b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentBoxUi.css
index 7895c9b9..36f57b9 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentBoxUi.css
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentBoxUi.css
@@ -32,12 +32,13 @@
.summary {
color: #777;
position: absolute;
- top: 2px;
+ top: 1px;
left: 120px;
width: 408px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
+ padding-bottom: 0.1em;
}
.date {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentRange.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentRange.java
new file mode 100644
index 0000000..f6fb1ba
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentRange.java
@@ -0,0 +1,40 @@
+// Copyright (C) 2013 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.client.diff;
+
+import com.google.gwt.core.client.JavaScriptObject;
+
+public class CommentRange extends JavaScriptObject {
+ public static CommentRange create(int sl, int sc, int el, int ec) {
+ CommentRange r = createObject().cast();
+ r.set(sl, sc, el, ec);
+ return r;
+ }
+
+ public final native int start_line() /*-{ return this.start_line; }-*/;
+ public final native int start_character() /*-{ return this.start_character; }-*/;
+ public final native int end_line() /*-{ return this.end_line; }-*/;
+ public final native int end_character() /*-{ return this.end_character; }-*/;
+
+ private final native void set(int sl, int sc, int el, int ec) /*-{
+ this.start_line = sl;
+ this.start_character = sc;
+ this.end_line = el;
+ this.end_character = ec;
+ }-*/;
+
+ protected CommentRange() {
+ }
+}
\ No newline at end of file
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.ui.xml
index c9fe8b0..aa8b0df 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.ui.xml
@@ -60,11 +60,11 @@
.b .diff .CodeMirror-linenumber {
background-color: #9f9;
}
- .padding, .fileCommentCell {
+ .padding, .fileComment {
background-color: #eee;
}
- .fileCommentCell {
- overflow-x: auto;
+ .fileComment {
+ line-height: 1;
}
.a .CodeMirror-vscrollbar {
display: none !important;
@@ -105,19 +105,19 @@
<tr>
<td>
<table class='{style.table}'>
- <tr ui:field='patchsetNavRow'>
- <td ui:field='patchsetNavCellA' class='{style.padding}'>
+ <tr ui:field='patchsetNavRow' class='{style.padding}'>
+ <td ui:field='patchsetNavCellA'>
<d:PatchSelectBox2 ui:field='patchSelectBoxA' />
</td>
- <td ui:field='patchsetNavCellB' class='{style.padding}'>
+ <td ui:field='patchsetNavCellB'>
<d:PatchSelectBox2 ui:field='patchSelectBoxB' />
</td>
</tr>
- <tr ui:field='fileCommentRow'>
- <td ui:field='fileCommentCellA' class='{style.padding}'>
+ <tr ui:field='fileCommentRow' class='{style.fileComment}'>
+ <td ui:field='fileCommentCellA'>
<d:FileCommentPanel ui:field='fileCommentPanelA' />
</td>
- <td ui:field='fileCommentCellB' class='{style.padding}'>
+ <td ui:field='fileCommentCellB'>
<d:FileCommentPanel ui:field='fileCommentPanelB' />
</td>
</tr>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DraftBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DraftBox.java
index 3e28898..9e6cd57 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DraftBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DraftBox.java
@@ -44,6 +44,7 @@
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.UIObject;
+import com.google.gwt.user.client.ui.Widget;
import com.google.gwtexpui.globalkey.client.NpTextArea;
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
@@ -65,6 +66,7 @@
private PublishedBox replyToBox;
private Timer expandTimer;
+ @UiField Widget header;
@UiField Element summary;
@UiField Element date;
@@ -99,7 +101,7 @@
};
set(info);
- addDomHandler(new ClickHandler() {
+ header.addDomHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
if (!isEdit()) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DraftBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DraftBox.ui.xml
index f3e4997..52ef0ff 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DraftBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DraftBox.ui.xml
@@ -26,6 +26,7 @@
text-align: center;
color: #fff;
background-color: #aaa;
+ -webkit-border-radius: 2px;
}
.editArea { max-width: 637px; }
button.button div {
@@ -42,11 +43,11 @@
<g:HTMLPanel styleName='{res.style.commentBox}'>
<div class='{res.style.contents}'>
- <div class='{res.style.header}'>
+ <g:HTMLPanel ui:field='header' styleName='{res.style.header}'>
<div class='{style.draft}'>Draft</div>
<div ui:field='summary' class='{res.style.summary}'/>
<div ui:field='date' class='{res.style.date}'/>
- </div>
+ </g:HTMLPanel>
<div ui:field='p_view' aria-hidden='true' style='display: NONE'>
<g:HTML ui:field='message' styleName=''/>
<div style='position: relative'>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/NavLinks2.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java
similarity index 63%
rename from gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/NavLinks2.java
rename to gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java
index d795319..4573d0d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/NavLinks2.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.java
@@ -16,10 +16,13 @@
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.changes.ChangeApi;
+import com.google.gerrit.client.changes.ReviewInfo;
import com.google.gerrit.client.changes.Util;
import com.google.gerrit.client.patches.PatchUtil;
+import com.google.gerrit.client.rpc.CallbackGroup;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.NativeMap;
+import com.google.gerrit.client.rpc.RestApi;
import com.google.gerrit.client.ui.InlineHyperlink;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.reviewdb.client.Change;
@@ -27,9 +30,14 @@
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JsArray;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.Style.Visibility;
import com.google.gwt.event.dom.client.KeyPressEvent;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.uibinder.client.UiHandler;
+import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwtexpui.globalkey.client.KeyCommand;
@@ -38,28 +46,47 @@
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
import com.google.gwtorm.client.KeyUtil;
-class NavLinks2 extends Composite {
- interface Binder extends UiBinder<HTMLPanel, NavLinks2> {}
+class Header extends Composite {
+ interface Binder extends UiBinder<HTMLPanel, Header> {}
private static final Binder uiBinder = GWT.create(Binder.class);
- @UiField InlineHyperlink prevLink;
- @UiField InlineHyperlink nextLink;
- @UiField InlineHyperlink upLink;
+ @UiField CheckBox reviewed;
+ @UiField Element filePath;
+
+ @UiField InlineHyperlink prev;
+ @UiField InlineHyperlink up;
+ @UiField InlineHyperlink next;
private final KeyCommandSet keys;
private final PatchSet.Id patchSetId;
private final String path;
- NavLinks2(KeyCommandSet keys, PatchSet.Id patchSetId, String path) {
+ Header(KeyCommandSet keys, PatchSet.Id patchSetId, String path) {
initWidget(uiBinder.createAndBindUi(this));
this.keys = keys;
this.patchSetId = patchSetId;
this.path = path;
- upLink.setTargetHistoryToken(PageLinks.toChange2(
+
+ SafeHtml.setInnerHTML(filePath, formatPath(path));
+ up.setTargetHistoryToken(PageLinks.toChange2(
patchSetId.getParentKey(),
String.valueOf(patchSetId.get())));
}
+ private static SafeHtml formatPath(String path) {
+ SafeHtmlBuilder b = new SafeHtmlBuilder();
+ if (Patch.COMMIT_MSG.equals(path)) {
+ return b.append(Util.C.commitMessage());
+ }
+
+ int s = path.lastIndexOf('/') + 1;
+ b.append(path.substring(0, s));
+ b.openElement("b");
+ b.append(path.substring(s));
+ b.closeElement("b");
+ return b;
+ }
+
@Override
protected void onLoad() {
ChangeApi.revision(patchSetId).view("files").get(
@@ -75,14 +102,35 @@
index = i;
}
}
- setupNav('[', PatchUtil.C.previousFileHelp(),
+ setupNav(prev, '[', PatchUtil.C.previousFileHelp(),
index == 0 ? null : files.get(index - 1));
- setupNav(']', PatchUtil.C.nextFileHelp(),
+ setupNav(next, ']', PatchUtil.C.nextFileHelp(),
index == files.length() - 1 ? null : files.get(index + 1));
}
});
}
+ void setReviewed(boolean r) {
+ reviewed.setValue(r, true);
+ }
+
+ boolean isReviewed() {
+ return reviewed.getValue();
+ }
+
+ @UiHandler("reviewed")
+ void onValueChange(ValueChangeEvent<Boolean> event) {
+ RestApi api = ChangeApi.revision(patchSetId)
+ .view("files")
+ .id(path)
+ .view("reviewed");
+ if (event.getValue()) {
+ api.put(CallbackGroup.<ReviewInfo>emptyCallback());
+ } else {
+ api.delete(CallbackGroup.<ReviewInfo>emptyCallback());
+ }
+ }
+
private String url(FileInfo info) {
Change.Id c = patchSetId.getParentKey();
StringBuilder p = new StringBuilder();
@@ -92,21 +140,11 @@
return p.toString();
}
- private void setupNav(int key, String help, FileInfo info) {
+ private void setupNav(InlineHyperlink link, int key, String help, FileInfo info) {
if (info != null) {
final String url = url(info);
- String fileName = getFileNameOnly(info.path());
- if (key == '[') {
- prevLink.setTargetHistoryToken(url);
- prevLink.setHTML(new SafeHtmlBuilder()
- .append(SafeHtml.asis(Util.C.prevPatchLinkIcon()))
- .append(fileName));
- } else {
- nextLink.setTargetHistoryToken(url);
- nextLink.setHTML(new SafeHtmlBuilder()
- .append(fileName)
- .append(SafeHtml.asis(Util.C.nextPatchLinkIcon())));
- }
+ link.setTargetHistoryToken(url);
+ link.setTitle(getFileName(info.path()));
keys.add(new KeyCommand(0, key, help) {
@Override
public void onKeyPress(KeyPressEvent event) {
@@ -114,11 +152,12 @@
}
});
} else {
+ link.getElement().getStyle().setVisibility(Visibility.HIDDEN);
keys.add(new UpToChangeCommand2(patchSetId, 0, key));
}
}
- private static String getFileNameOnly(String path) {
+ private static String getFileName(String path) {
String fileName = Patch.COMMIT_MSG.equals(path)
? Util.C.commitMessage()
: path;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.ui.xml
new file mode 100644
index 0000000..a23cbfb
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/Header.ui.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2013 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.
+-->
+<ui:UiBinder
+ xmlns:ui='urn:ui:com.google.gwt.uibinder'
+ xmlns:g='urn:import:com.google.gwt.user.client.ui'
+ xmlns:x='urn:import:com.google.gerrit.client.ui'>
+ <ui:style>
+ .header {
+ position: relative;
+ }
+ .reviewed input {
+ margin: 0;
+ padding: 0;
+ vertical-align: bottom;
+ }
+ .path {
+ }
+ .navigation {
+ position: absolute;
+ top: 0;
+ right: 15px;
+ }
+ </ui:style>
+ <g:HTMLPanel styleName='{style.header}'>
+ <g:CheckBox ui:field='reviewed'
+ styleName='{style.reviewed}'
+ title='Mark file as reviewed (Shortcut: r)'>
+ <ui:attribute name='title'/>
+ </g:CheckBox>
+ <span ui:field='filePath' class='{style.path}'/>
+
+ <div class='{style.navigation}'>
+ <x:InlineHyperlink ui:field='prev'>⇦</x:InlineHyperlink>
+ <x:InlineHyperlink ui:field='up' title='Up to change (Shortcut: u)'>
+ <ui:attribute name='title'/>
+ ⇧
+ </x:InlineHyperlink>
+ <x:InlineHyperlink ui:field='next'>⇨</x:InlineHyperlink>
+ </div>
+ </g:HTMLPanel>
+</ui:UiBinder>
\ No newline at end of file
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/NavLinks2.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/NavLinks2.ui.xml
deleted file mode 100644
index f825979..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/NavLinks2.ui.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-Copyright (C) 2013 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.
--->
-<ui:UiBinder
- xmlns:ui='urn:ui:com.google.gwt.uibinder'
- xmlns:g='urn:import:com.google.gwt.user.client.ui'
- xmlns:ge='urn:import:com.google.gerrit.client.ui'>
- <ui:style>
- .table {
- table-layout: fixed;
- width: 100%;
- }
- .prev {
- text-align: left;
- }
- .up {
- text-align: center;
- }
- .next {
- text-align: right;
- }
- </ui:style>
- <g:HTMLPanel>
- <table ui:field='table' class='{style.table}'>
- <tr>
- <td class='{style.prev}'>
- <ge:InlineHyperlink ui:field='prevLink'/>
- </td>
- <td class='{style.up}'>
- <ge:InlineHyperlink ui:field='upLink'>
- <ui:msg>⇧Up to change</ui:msg>
- </ge:InlineHyperlink>
- </td>
- <td class='{style.next}'>
- <ge:InlineHyperlink ui:field='nextLink'/>
- </td>
- </tr>
- </table>
- </g:HTMLPanel>
-</ui:UiBinder>
\ No newline at end of file
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PublishedBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PublishedBox.java
index 2f923c8..6298296 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PublishedBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PublishedBox.java
@@ -36,6 +36,7 @@
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.UIObject;
+import com.google.gwt.user.client.ui.Widget;
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
/** An HtmlPanel for displaying a published comment */
@@ -53,6 +54,7 @@
private DraftBox replyBox;
@UiField Style style;
+ @UiField Widget header;
@UiField Element name;
@UiField Element summary;
@UiField Element date;
@@ -81,7 +83,7 @@
}
initWidget(uiBinder.createAndBindUi(this));
- addDomHandler(new ClickHandler() {
+ header.addDomHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
setOpen(!isOpen());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PublishedBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PublishedBox.ui.xml
index 50d67f0..f3beda1 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PublishedBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/PublishedBox.ui.xml
@@ -48,11 +48,11 @@
addStyleNames='{style.closed}'>
<c:AvatarImage ui:field='avatar' styleName='{style.avatar}'/>
<div class='{res.style.contents}'>
- <div class='{res.style.header}'>
+ <g:HTMLPanel ui:field='header' styleName='{res.style.header}'>
<div ui:field='name' class='{style.name}'/>
<div ui:field='summary' class='{res.style.summary}'/>
<div ui:field='date' class='{res.style.date}'/>
- </div>
+ </g:HTMLPanel>
<div ui:field='message' aria-hidden='true' style='display: NONE'/>
<div ui:field='buttons' aria-hidden='true' style='display: NONE'>
<g:Button ui:field='reply' styleName=''
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/ReviewedPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/ReviewedPanel.java
deleted file mode 100644
index 60120bf..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/ReviewedPanel.java
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright (C) 2013 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.client.diff;
-
-import com.google.gerrit.client.changes.ChangeApi;
-import com.google.gerrit.client.changes.ReviewInfo;
-import com.google.gerrit.client.changes.Util;
-import com.google.gerrit.client.patches.PatchUtil;
-import com.google.gerrit.client.rpc.CallbackGroup;
-import com.google.gerrit.client.rpc.RestApi;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.dom.client.Element;
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.logical.shared.ValueChangeEvent;
-import com.google.gwt.uibinder.client.UiBinder;
-import com.google.gwt.uibinder.client.UiField;
-import com.google.gwt.uibinder.client.UiHandler;
-import com.google.gwt.user.client.ui.Anchor;
-import com.google.gwt.user.client.ui.CheckBox;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.HTMLPanel;
-
-class ReviewedPanel extends Composite {
- interface Binder extends UiBinder<HTMLPanel, ReviewedPanel> {}
- private static UiBinder<HTMLPanel, ReviewedPanel> uiBinder =
- GWT.create(Binder.class);
-
- @UiField
- Element fileName;
-
- @UiField
- CheckBox checkBox;
-
- @UiField
- Anchor nextLink;
-
- private PatchSet.Id patchId;
- private String fileId;
-
- ReviewedPanel(PatchSet.Id id, String path) {
- initWidget(uiBinder.createAndBindUi(this));
- patchId = id;
- fileId = path;
- fileName.setInnerText(path);
- nextLink.setHTML(PatchUtil.C.next() + Util.C.nextPatchLinkIcon());
- }
-
- void setReviewed(boolean reviewed) {
- checkBox.setValue(reviewed, true);
- }
-
- boolean isReviewed() {
- return checkBox.getValue();
- }
-
- @UiHandler("checkBox")
- void onValueChange(ValueChangeEvent<Boolean> event) {
- RestApi api = ChangeApi.revision(patchId)
- .view("files")
- .id(fileId)
- .view("reviewed");
- if (event.getValue()) {
- api.put(CallbackGroup.<ReviewInfo>emptyCallback());
- } else {
- api.delete(CallbackGroup.<ReviewInfo>emptyCallback());
- }
- }
-
- // TODO: Implement this to go to the next file in the patchset.
- void onNext(ClickEvent e) {
- setReviewed(true);
- }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/ReviewedPanel.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/ReviewedPanel.ui.xml
deleted file mode 100644
index f2b6725..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/ReviewedPanel.ui.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
-<!--
-Copyright (C) 2013 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.
--->
-<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
- xmlns:g='urn:import:com.google.gwt.user.client.ui'
- xmlns:d='urn:import:com.google.gerrit.client.diff'>
- <ui:style>
- .reviewedPanel, .table {
- width: 100%;
- }
- .fileName {
- font-size: larger;
- font-weight: bold;
- }
- .reviewed {
- width: 20%;
- text-align: right;
- }
- </ui:style>
- <g:HTMLPanel styleName='{style.reviewedPanel}'>
- <table class='{style.table}'>
- <tr>
- <td ui:field='fileName' class='{style.fileName}' />
- <td class='{style.reviewed}'>
- <g:CheckBox ui:field='checkBox'><ui:msg>Reviewed & </ui:msg></g:CheckBox>
- <g:Anchor ui:field='nextLink' href='javascript:;'/>
- </td>
- </tr>
- </table>
- </g:HTMLPanel>
-</ui:UiBinder>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.java
index c953df8..3ad82f8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.java
@@ -56,7 +56,7 @@
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwt.user.client.ui.HTMLPanel;
+import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwtexpui.globalkey.client.GlobalKey;
import com.google.gwtexpui.globalkey.client.KeyCommand;
import com.google.gwtexpui.globalkey.client.KeyCommandSet;
@@ -85,17 +85,14 @@
import java.util.Map;
public class SideBySide2 extends Screen {
- interface Binder extends UiBinder<HTMLPanel, SideBySide2> {}
+ interface Binder extends UiBinder<FlowPanel, SideBySide2> {}
private static Binder uiBinder = GWT.create(Binder.class);
private static final JsArrayString EMPTY =
JavaScriptObject.createArray().cast();
@UiField(provided = true)
- ReviewedPanel reviewed;
-
- @UiField(provided = true)
- NavLinks2 navLinks;
+ Header header;
@UiField(provided = true)
DiffTable diffTable;
@@ -139,9 +136,8 @@
this.handlers = new ArrayList<HandlerRegistration>(6);
// TODO: Re-implement necessary GlobalKey bindings.
addDomHandler(GlobalKey.STOP_PROPAGATION, KeyPressEvent.getType());
- reviewed = new ReviewedPanel(revision, path);
keysNavigation = new KeyCommandSet(Gerrit.C.sectionNavigation());
- add(navLinks = new NavLinks2(keysNavigation, revision, path));
+ add(header = new Header(keysNavigation, revision, path));
add(diffTable = new DiffTable(this, path));
add(uiBinder.createAndBindUi(this));
}
@@ -466,11 +462,12 @@
}
private DraftBox addNewDraft(CodeMirror cm, int line) {
- return addDraftBox(CommentInfo.createLine(
+ return addDraftBox(CommentInfo.createRange(
path,
getSideFromCm(cm),
line + 1,
null,
+ null,
null));
}
@@ -478,8 +475,8 @@
if (!replyTo.has_line()) {
return CommentInfo.createFile(path, replyTo.side(), replyTo.id(), null);
} else {
- return CommentInfo.createLine(path, replyTo.side(), replyTo.line(),
- replyTo.id(), null);
+ return CommentInfo.createRange(path, replyTo.side(), replyTo.line(),
+ replyTo.id(), null, null);
}
}
@@ -972,7 +969,7 @@
private Runnable toggleReviewed() {
return new Runnable() {
public void run() {
- reviewed.setReviewed(!reviewed.isReviewed());
+ header.setReviewed(!header.isReviewed());
}
};
}
@@ -1057,8 +1054,10 @@
if (cmA == null) {
return;
}
- int h = Gerrit.getHeaderFooterHeight() + reviewed.getOffsetHeight() +
- navLinks.getOffsetHeight() + diffTable.getHeaderHeight() + 10; // Estimate
+ int h = Gerrit.getHeaderFooterHeight()
+ + header.getOffsetHeight()
+ + diffTable.getHeaderHeight()
+ + 10; // Estimate
cmA.setHeight(Window.getClientHeight() - h);
cmA.refresh();
cmB.setHeight(Window.getClientHeight() - h);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.ui.xml
index 8719ecd..1bc707a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.ui.xml
@@ -17,9 +17,8 @@
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:d='urn:import:com.google.gerrit.client.diff'>
- <g:HTMLPanel>
- <d:ReviewedPanel ui:field='reviewed'/>
- <d:NavLinks2 ui:field='navLinks'/>
+ <g:FlowPanel>
+ <d:Header ui:field='header'/>
<d:DiffTable ui:field='diffTable'/>
- </g:HTMLPanel>
+ </g:FlowPanel>
</ui:UiBinder>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CherryPickDialog.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CherryPickDialog.java
index 9a10c23..d862965 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CherryPickDialog.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CherryPickDialog.java
@@ -14,6 +14,7 @@
package com.google.gerrit.client.ui;
+import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.changes.Util;
import com.google.gerrit.client.projects.BranchInfo;
import com.google.gerrit.client.projects.ProjectApi;
@@ -21,6 +22,8 @@
import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gwt.core.client.JsArray;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FocusWidget;
import com.google.gwt.user.client.ui.SuggestBox;
import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
@@ -59,9 +62,15 @@
}
});
- newBranch.setWidth("70ex");
+ newBranch.setWidth("100%");
+ DOM.setStyleAttribute(newBranch.getElement(), "box-sizing", "border-box");
message.setCharacterWidth(70);
- panel.insert(newBranch, 0);
+
+ final FlowPanel mwrap = new FlowPanel();
+ mwrap.setStyleName(Gerrit.RESOURCES.css().commentedActionMessage());
+ mwrap.add(newBranch);
+
+ panel.insert(mwrap, 0);
panel.insert(new SmallHeading(Util.C.headingCherryPickBranch()), 0);
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CommentedActionDialog.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CommentedActionDialog.java
index 263703e..1095b66 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CommentedActionDialog.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CommentedActionDialog.java
@@ -67,7 +67,7 @@
});
cancelButton = new Button(Util.C.commentedActionButtonCancel());
- DOM.setStyleAttribute(cancelButton.getElement(), "marginLeft", "300px");
+ DOM.setStyleAttribute(cancelButton.getElement(), "float", "right");
cancelButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(final ClickEvent event) {
@@ -82,6 +82,7 @@
buttonPanel = new FlowPanel();
buttonPanel.add(sendButton);
buttonPanel.add(cancelButton);
+ DOM.setStyleAttribute(buttonPanel.getElement(), "margin-top", "4px");
panel = new FlowPanel();
panel.add(new SmallHeading(heading));
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTableImpl.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTableImpl.java
index c72969e..2c7451a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTableImpl.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTableImpl.java
@@ -21,7 +21,7 @@
public class FancyFlexTableImpl {
public void resetHtml(final MyFlexTable myTable, final SafeHtml body) {
- SafeHtml.set(getBodyElement(myTable), body);
+ SafeHtml.setInnerHTML(getBodyElement(myTable), body);
}
protected static native Element getBodyElement(HTMLTable myTable)
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/RestApiServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
index f2fee0b..a4ba520 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
@@ -23,8 +23,8 @@
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import static javax.servlet.http.HttpServletResponse.SC_METHOD_NOT_ALLOWED;
-import static javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED;
import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
+import static javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import static javax.servlet.http.HttpServletResponse.SC_PRECONDITION_FAILED;
@@ -46,6 +46,7 @@
import com.google.common.net.HttpHeaders;
import com.google.gerrit.audit.AuditService;
import com.google.gerrit.audit.HttpAuditEvent;
+import com.google.gerrit.extensions.annotations.CapabilityScope;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AcceptsCreate;
@@ -199,17 +200,17 @@
List<IdString> path = splitPath(req);
RestCollection<RestResource, RestResource> rc = members.get();
- checkAccessAnnotations(rc.getClass());
+ checkAccessAnnotations(null, rc.getClass());
RestResource rsrc = TopLevelResource.INSTANCE;
- RestView<RestResource> view = null;
+ ViewData viewData = new ViewData(null, null);
if (path.isEmpty()) {
if ("GET".equals(req.getMethod())) {
- view = rc.list();
+ viewData = new ViewData(null, rc.list());
} else if (rc instanceof AcceptsPost && "POST".equals(req.getMethod())) {
@SuppressWarnings("unchecked")
AcceptsPost<RestResource> ac = (AcceptsPost<RestResource>) rc;
- view = ac.post(rsrc);
+ viewData = new ViewData(null, ac.post(rsrc));
} else {
throw new MethodNotAllowedException();
}
@@ -227,30 +228,30 @@
|| "PUT".equals(req.getMethod()))) {
@SuppressWarnings("unchecked")
AcceptsCreate<RestResource> ac = (AcceptsCreate<RestResource>) rc;
- view = ac.create(rsrc, id);
+ viewData = new ViewData(null, ac.create(rsrc, id));
status = SC_CREATED;
} else {
throw e;
}
}
- if (view == null) {
- view = view(rc, req.getMethod(), path);
+ if (viewData.view == null) {
+ viewData = view(rc, req.getMethod(), path);
}
}
- checkAccessAnnotations(view.getClass());
+ checkAccessAnnotations(viewData);
- while (view instanceof RestCollection<?,?>) {
+ while (viewData.view instanceof RestCollection<?,?>) {
@SuppressWarnings("unchecked")
RestCollection<RestResource, RestResource> c =
- (RestCollection<RestResource, RestResource>) view;
+ (RestCollection<RestResource, RestResource>) viewData.view;
if (path.isEmpty()) {
if ("GET".equals(req.getMethod())) {
- view = c.list();
+ viewData = new ViewData(null, c.list());
} else if (c instanceof AcceptsPost && "POST".equals(req.getMethod())) {
@SuppressWarnings("unchecked")
AcceptsPost<RestResource> ac = (AcceptsPost<RestResource>) c;
- view = ac.post(rsrc);
+ viewData = new ViewData(null, ac.post(rsrc));
} else {
throw new MethodNotAllowedException();
}
@@ -260,7 +261,7 @@
try {
rsrc = c.parse(rsrc, id);
checkPreconditions(req, rsrc);
- view = null;
+ viewData = new ViewData(null, null);
} catch (ResourceNotFoundException e) {
if (c instanceof AcceptsCreate
&& path.isEmpty()
@@ -268,17 +269,17 @@
|| "PUT".equals(req.getMethod()))) {
@SuppressWarnings("unchecked")
AcceptsCreate<RestResource> ac = (AcceptsCreate<RestResource>) c;
- view = ac.create(rsrc, id);
+ viewData = new ViewData(null, ac.create(rsrc, id));
status = SC_CREATED;
} else {
throw e;
}
}
- if (view == null) {
- view = view(c, req.getMethod(), path);
+ if (viewData.view == null) {
+ viewData = view(c, req.getMethod(), path);
}
}
- checkAccessAnnotations(view.getClass());
+ checkAccessAnnotations(viewData);
}
if (notModified(req, rsrc)) {
@@ -288,19 +289,19 @@
Multimap<String, String> config = LinkedHashMultimap.create();
ParameterParser.splitQueryString(req.getQueryString(), config, params);
- if (!globals.paramParser.get().parse(view, params, req, res)) {
+ if (!globals.paramParser.get().parse(viewData.view, params, req, res)) {
return;
}
- if (view instanceof RestModifyView<?, ?>) {
+ if (viewData.view instanceof RestModifyView<?, ?>) {
@SuppressWarnings("unchecked")
RestModifyView<RestResource, Object> m =
- (RestModifyView<RestResource, Object>) view;
+ (RestModifyView<RestResource, Object>) viewData.view;
inputRequestBody = parseRequest(req, inputType(m));
result = m.apply(rsrc, inputRequestBody);
- } else if (view instanceof RestReadView<?>) {
- result = ((RestReadView<RestResource>) view).apply(rsrc);
+ } else if (viewData.view instanceof RestReadView<?>) {
+ result = ((RestReadView<RestResource>) viewData.view).apply(rsrc);
} else {
throw new ResourceNotFoundException();
}
@@ -766,7 +767,7 @@
return gz.setContentType(src.getContentType());
}
- private RestView<RestResource> view(
+ private ViewData view(
RestCollection<RestResource, RestResource> rc,
String method, List<IdString> path) throws ResourceNotFoundException,
MethodNotAllowedException, AmbiguousViewException {
@@ -786,7 +787,7 @@
RestView<RestResource> view =
views.get(p.get(0), method + "." + p.get(1));
if (view != null) {
- return view;
+ return new ViewData(p.get(0), view);
}
throw new ResourceNotFoundException(projection);
}
@@ -794,7 +795,7 @@
String name = method + "." + p.get(0);
RestView<RestResource> core = views.get("gerrit", name);
if (core != null) {
- return core;
+ return new ViewData(null, core);
}
Map<String, RestView<RestResource>> r = Maps.newTreeMap();
@@ -806,7 +807,9 @@
}
if (r.size() == 1) {
- return Iterables.getFirst(r.values(), null);
+ Map.Entry<String, RestView<RestResource>> entry =
+ Iterables.getOnlyElement(r.entrySet());
+ return new ViewData(entry.getKey(), entry.getValue());
} else if (r.isEmpty()) {
throw new ResourceNotFoundException(projection);
} else {
@@ -862,16 +865,35 @@
return !("GET".equals(method) || "HEAD".equals(method));
}
- private void checkAccessAnnotations(Class<? extends Object> clazz)
+ private void checkAccessAnnotations(ViewData viewData) throws AuthException {
+ checkAccessAnnotations(viewData.pluginName, viewData.view.getClass());
+ }
+
+ private void checkAccessAnnotations(String pluginName, Class<?> clazz)
throws AuthException {
RequiresCapability rc = clazz.getAnnotation(RequiresCapability.class);
if (rc != null) {
CurrentUser user = globals.currentUser.get();
CapabilityControl ctl = user.getCapabilities();
- if (!ctl.canPerform(rc.value()) && !ctl.canAdministrateServer()) {
+ String capability = rc.value();
+
+ if (pluginName != null && !"gerrit".equals(pluginName)
+ && (rc.scope() == CapabilityScope.PLUGIN
+ || rc.scope() == CapabilityScope.CONTEXT)) {
+ capability = String.format("%s-%s", pluginName, rc.value());
+ } else if (rc.scope() == CapabilityScope.PLUGIN) {
+ log.error(String.format(
+ "Class %s uses @%s(scope=%s), but is not within a plugin",
+ clazz.getName(),
+ RequiresCapability.class.getSimpleName(),
+ CapabilityScope.PLUGIN.name()));
+ throw new AuthException("cannot check capability");
+ }
+
+ if (!ctl.canPerform(capability) && !ctl.canAdministrateServer()) {
throw new AuthException(String.format(
"Capability %s is required to access this resource",
- rc.value()));
+ capability));
}
}
}
@@ -988,4 +1010,14 @@
super(message);
}
}
+
+ private static class ViewData {
+ String pluginName;
+ RestView<RestResource> view;
+
+ ViewData(String pluginName, RestView<RestResource> view) {
+ this.pluginName = pluginName;
+ this.view = view;
+ }
+ }
}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/SaveDraft.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/SaveDraft.java
index 18ab5ff5..66b5ec1 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/SaveDraft.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/SaveDraft.java
@@ -84,12 +84,18 @@
throw new IllegalStateException("Parent comment must be on same side");
}
}
+ if (comment.getRange() != null
+ && comment.getLine() != comment.getRange().getEndLine()) {
+ throw new IllegalStateException(
+ "Range endLine must be on the same line as the comment");
+ }
final PatchLineComment nc =
new PatchLineComment(new PatchLineComment.Key(patchKey, ChangeUtil
.messageUUID(db)), comment.getLine(), me, comment.getParentUuid());
nc.setSide(comment.getSide());
nc.setMessage(comment.getMessage());
+ nc.setRange(comment.getRange());
db.patchComments().insert(Collections.singleton(nc));
db.commit();
return nc;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/CommentRange.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/CommentRange.java
new file mode 100644
index 0000000..b0f3879
--- /dev/null
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/CommentRange.java
@@ -0,0 +1,90 @@
+// Copyright (C) 2013 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.reviewdb.client;
+
+import com.google.gwtorm.client.Column;
+
+public class CommentRange {
+
+ @Column(id = 1)
+ protected int startLine;
+
+ @Column(id = 2)
+ protected int startCharacter;
+
+ @Column(id = 3)
+ protected int endLine;
+
+ @Column(id = 4)
+ protected int endCharacter;
+
+ protected CommentRange() {
+ }
+
+ public CommentRange(int sl, int sc, int el, int ec) {
+ startLine = sl;
+ startCharacter = sc;
+ endLine = el;
+ endCharacter = ec;
+ }
+
+ public int getStartLine() {
+ return startLine;
+ }
+
+ public int getStartCharacter() {
+ return startCharacter;
+ }
+
+ public int getEndLine() {
+ return endLine;
+ }
+
+ public int getEndCharacter() {
+ return endCharacter;
+ }
+
+ public void setStartLine(int sl) {
+ startLine = sl;
+ }
+
+ public void setStartCharacter(int sc) {
+ startCharacter = sc;
+ }
+
+ public void setEndLine(int el) {
+ endLine = el;
+ }
+
+ public void setEndCharacter(int ec) {
+ endCharacter = ec;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof CommentRange) {
+ CommentRange other = (CommentRange) obj;
+ return startLine == other.startLine && startCharacter == other.startCharacter &&
+ endLine == other.endLine && endCharacter == other.endCharacter;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "Range[startLine=" + startLine + ", startCharacter=" + startCharacter
+ + ", endLine=" + endLine + ", endCharacter=" + endCharacter + "]";
+ }
+}
\ No newline at end of file
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchLineComment.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchLineComment.java
index af35e52f..0119c3e 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchLineComment.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchLineComment.java
@@ -117,6 +117,9 @@
@Column(id = 8, length = 40, notNull = false)
protected String parentUuid;
+ @Column(id = 9, notNull = false)
+ protected CommentRange range;
+
protected PatchLineComment() {
}
@@ -189,4 +192,12 @@
public void setParentUuid(String inReplyTo) {
parentUuid = inReplyTo;
}
+
+ public void setRange(CommentRange r) {
+ range = r;
+ }
+
+ public CommentRange getRange() {
+ return range;
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityControl.java
index 01e8002..cafc540 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityControl.java
@@ -139,12 +139,6 @@
return canPerform(GlobalCapability.ACCESS_DATABASE);
}
- /** @return true if the user can force replication to any configured destination. */
- public boolean canStartReplication() {
- return canPerform(GlobalCapability.START_REPLICATION)
- || canAdministrateServer();
- }
-
/** @return true if the user can stream Gerrit events. */
public boolean canStreamEvents() {
return canPerform(GlobalCapability.STREAM_EVENTS)
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetCapabilities.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetCapabilities.java
index 54f1980..615d09e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetCapabilities.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetCapabilities.java
@@ -23,7 +23,6 @@
import static com.google.gerrit.common.data.GlobalCapability.KILL_TASK;
import static com.google.gerrit.common.data.GlobalCapability.PRIORITY;
import static com.google.gerrit.common.data.GlobalCapability.RUN_GC;
-import static com.google.gerrit.common.data.GlobalCapability.START_REPLICATION;
import static com.google.gerrit.common.data.GlobalCapability.STREAM_EVENTS;
import static com.google.gerrit.common.data.GlobalCapability.VIEW_CACHES;
import static com.google.gerrit.common.data.GlobalCapability.VIEW_CONNECTIONS;
@@ -34,6 +33,8 @@
import com.google.common.collect.Sets;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.common.data.PermissionRange;
+import com.google.gerrit.extensions.config.CapabilityDefinition;
+import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.BinaryResult;
@@ -68,10 +69,13 @@
private Set<String> query;
private final Provider<CurrentUser> self;
+ private final DynamicMap<CapabilityDefinition> pluginCapabilities;
@Inject
- GetCapabilities(Provider<CurrentUser> self) {
+ GetCapabilities(Provider<CurrentUser> self,
+ DynamicMap<CapabilityDefinition> pluginCapabilities) {
this.self = self;
+ this.pluginCapabilities = pluginCapabilities;
}
@Override
@@ -93,6 +97,14 @@
}
}
}
+ for (String pluginName : pluginCapabilities.plugins()) {
+ for (String capability : pluginCapabilities.byPlugin(pluginName).keySet()) {
+ String name = String.format("%s-%s", pluginName, capability);
+ if (want(name) && cc.canPerform(name)) {
+ have.put(name, true);
+ }
+ }
+ }
have.put(CREATE_ACCOUNT, cc.canCreateAccount());
have.put(CREATE_GROUP, cc.canCreateGroup());
@@ -104,7 +116,6 @@
have.put(VIEW_CONNECTIONS, cc.canViewConnections());
have.put(VIEW_QUEUE, cc.canViewQueue());
have.put(RUN_GC, cc.canRunGC());
- have.put(START_REPLICATION, cc.canStartReplication());
have.put(STREAM_EVENTS, cc.canStreamEvents());
have.put(ACCESS_DATABASE, cc.canAccessDatabase());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/Helper.java b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/Helper.java
index 0151dde..7d0ad24 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/Helper.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/Helper.java
@@ -197,13 +197,11 @@
if (!schema.groupMemberQueryList.isEmpty()) {
final HashMap<String, String> params = new HashMap<String, String>();
- if (schema.groupNeedsAccount) {
- if (account == null) {
- account = findAccount(schema, ctx, username);
- }
- for (String name : schema.groupMemberQueryList.get(0).getParameters()) {
- params.put(name, account.get(name));
- }
+ if (account == null) {
+ account = findAccount(schema, ctx, username);
+ }
+ for (String name : schema.groupMemberQueryList.get(0).getParameters()) {
+ params.put(name, account.get(name));
}
params.put(LdapRealm.USERNAME, username);
@@ -286,7 +284,6 @@
final String accountMemberField;
final List<LdapQuery> accountQueryList;
- boolean groupNeedsAccount;
final List<String> groupBases;
final SearchScope groupScope;
final ParameterizedString groupPattern;
@@ -321,10 +318,7 @@
}
for (final String name : groupMemberQuery.getParameters()) {
- if (!LdapRealm.USERNAME.equals(name)) {
- groupNeedsAccount = true;
- accountAtts.add(name);
- }
+ accountAtts.add(name);
}
groupMemberQueryList.add(groupMemberQuery);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapType.java b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapType.java
index db5baeb..3c1b0d2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapType.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapType.java
@@ -57,7 +57,7 @@
@Override
String groupMemberPattern() {
- return "(memberUid=${username})";
+ return "(|(memberUid=${username})(gidNumber=${gidNumber}))";
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/CommentInfo.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/CommentInfo.java
index c0942b2..fe372f3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/CommentInfo.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/CommentInfo.java
@@ -18,6 +18,7 @@
import com.google.gerrit.common.changes.Side;
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.reviewdb.client.CommentRange;
import com.google.gerrit.server.account.AccountInfo;
import java.sql.Timestamp;
@@ -33,6 +34,7 @@
String message;
Timestamp updated;
AccountInfo author;
+ CommentRange range;
CommentInfo(PatchLineComment c, AccountInfo.Loader accountLoader) {
id = Url.encode(c.getKey().get());
@@ -46,6 +48,7 @@
inReplyTo = Url.encode(c.getParentUuid());
message = Strings.emptyToNull(c.getMessage());
updated = c.getWrittenOn();
+ range = c.getRange();
if (accountLoader != null) {
author = accountLoader.get(c.getAuthor());
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateDraft.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateDraft.java
index 9ef1cfe..1b7bbe7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateDraft.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/CreateDraft.java
@@ -24,7 +24,6 @@
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.reviewdb.client.PatchLineComment;
-import com.google.gerrit.reviewdb.client.PatchLineComment.Status;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.change.PutDraft.Input;
@@ -51,18 +50,22 @@
throw new BadRequestException("message must be non-empty");
} else if (in.line != null && in.line <= 0) {
throw new BadRequestException("line must be > 0");
+ } else if (in.line != null && in.range != null && in.line != in.range.getEndLine()) {
+ throw new BadRequestException("range endLine must be on the same line as the comment");
}
+ int line = in.line != null
+ ? in.line
+ : in.range != null ? in.range.getEndLine() : 0;
+
PatchLineComment c = new PatchLineComment(
new PatchLineComment.Key(
new Patch.Key(rsrc.getPatchSet().getId(), in.path),
ChangeUtil.messageUUID(db.get())),
- in.line != null ? in.line : 0,
- rsrc.getAccountId(),
- Url.decode(in.inReplyTo));
- c.setStatus(Status.DRAFT);
+ line, rsrc.getAccountId(), Url.decode(in.inReplyTo));
c.setSide(in.side == Side.PARENT ? (short) 0 : (short) 1);
c.setMessage(in.message.trim());
+ c.setRange(in.range);
db.get().patchComments().insert(Collections.singleton(c));
return Response.created(new CommentInfo(c, null));
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java
index d929a89..5e2c797 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java
@@ -151,6 +151,11 @@
return this;
}
+ public PatchSet.Id getPatchSetId() {
+ init();
+ return patchSet.getId();
+ }
+
public PatchSetInserter setMessage(String message) throws OrmException {
changeMessage = new ChangeMessage(new ChangeMessage.Key(change.getId(),
ChangeUtil.messageUUID(db)), user.getAccountId(), patchSet.getId());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java
index b9ca124..91c6abe 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PostReview.java
@@ -38,6 +38,7 @@
import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.reviewdb.client.PatchLineComment;
import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.CommentRange;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.IdentifiedUser;
@@ -116,6 +117,7 @@
int line;
String inReplyTo;
String message;
+ CommentRange range;
}
static class Output {
@@ -365,6 +367,7 @@
e.setWrittenOn(timestamp);
e.setSide(c.side == Side.PARENT ? (short) 0 : (short) 1);
e.setMessage(c.message);
+ e.setRange(c.range);
(create ? ins : upd).add(e);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PutDraft.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PutDraft.java
index c6fc4fc..005d493 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/PutDraft.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PutDraft.java
@@ -23,6 +23,7 @@
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.reviewdb.client.CommentRange;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.change.PutDraft.Input;
import com.google.gwtorm.server.OrmException;
@@ -41,6 +42,7 @@
Integer line;
String inReplyTo;
Timestamp updated; // Accepted but ignored.
+ CommentRange range;
@DefaultInput
String message;
@@ -67,6 +69,8 @@
throw new BadRequestException("id must match URL");
} else if (in.line != null && in.line < 0) {
throw new BadRequestException("line must be >= 0");
+ } else if (in.line != null && in.range != null && in.line != in.range.getEndLine()) {
+ throw new BadRequestException("range endLine must be on the same line as the comment");
}
if (in.path != null
@@ -92,13 +96,14 @@
if (in.side != null) {
e.setSide(in.side == Side.PARENT ? (short) 0 : (short) 1);
}
- if (in.line != null) {
- e.setLine(in.line);
- }
if (in.inReplyTo != null) {
e.setParentUuid(Url.decode(in.inReplyTo));
}
e.setMessage(in.message.trim());
+ if (in.range != null || in.line != null) {
+ e.setRange(in.range);
+ e.setLine(in.range != null ? in.range.getEndLine() : in.line);
+ }
e.updated();
return e;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java
index 40deb0c..dceecbe 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java
@@ -293,7 +293,7 @@
final ChangeControl changeControl =
changeControlFactory.validateFor(change.getId(), uploader);
- PatchSetInserter patchSetinserter = patchSetInserterFactory
+ PatchSetInserter patchSetInserter = patchSetInserterFactory
.create(git, revWalk, changeControl.getRefControl(), uploader, change, rebasedCommit)
.setCopyLabels(true)
.setValidatePolicy(validate)
@@ -301,13 +301,15 @@
.setSendMail(sendMail)
.setRunHooks(runHooks);
+ final PatchSet.Id newPatchSetId = patchSetInserter.getPatchSetId();
final ChangeMessage cmsg =
new ChangeMessage(new ChangeMessage.Key(change.getId(),
ChangeUtil.messageUUID(db)), uploader.getAccountId(), patchSetId);
- cmsg.setMessage("Patch Set " + change.currentPatchSetId().get()
+
+ cmsg.setMessage("Patch Set " + newPatchSetId.get()
+ ": Patch Set " + patchSetId.get() + " was rebased");
- Change newChange = patchSetinserter
+ Change newChange = patchSetInserter
.setMessage(cmsg)
.insert();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/CapabilityConstants.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/CapabilityConstants.java
index c0a014c..2e54f3e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/CapabilityConstants.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/CapabilityConstants.java
@@ -34,7 +34,6 @@
public String queryLimit;
public String runAs;
public String runGC;
- public String startReplication;
public String streamEvents;
public String viewCaches;
public String viewConnections;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
index 581b067..66ee72b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -19,6 +19,7 @@
import com.google.common.cache.Cache;
import com.google.gerrit.audit.AuditModule;
import com.google.gerrit.common.ChangeListener;
+import com.google.gerrit.extensions.config.CapabilityDefinition;
import com.google.gerrit.extensions.events.GitReferenceUpdatedListener;
import com.google.gerrit.extensions.events.NewProjectCreatedListener;
import com.google.gerrit.extensions.registration.DynamicItem;
@@ -249,6 +250,7 @@
bind(GitReferenceUpdated.class);
DynamicMap.mapOf(binder(), new TypeLiteral<Cache<?, ?>>() {});
DynamicSet.setOf(binder(), CacheRemovalListener.class);
+ DynamicMap.mapOf(binder(), CapabilityDefinition.class);
DynamicSet.setOf(binder(), GitReferenceUpdatedListener.class);
DynamicSet.setOf(binder(), NewProjectCreatedListener.class);
DynamicSet.bind(binder(), GitReferenceUpdatedListener.class).to(ChangeCache.class);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java
index 8b517a3..641a48f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java
@@ -16,6 +16,8 @@
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.account.GroupBackend;
+import com.google.gerrit.server.util.ServerRequestContext;
+import com.google.gerrit.server.util.ThreadLocalRequestContext;
import com.google.inject.Inject;
import org.eclipse.jgit.lib.Config;
@@ -25,8 +27,10 @@
public class GitReceivePackGroupsProvider extends GroupSetProvider {
@Inject
public GitReceivePackGroupsProvider(GroupBackend gb,
- @GerritServerConfig Config config) {
- super(gb, config, "receive", null, "allowGroup");
+ @GerritServerConfig Config config,
+ ThreadLocalRequestContext threadContext,
+ ServerRequestContext serverCtx) {
+ super(gb, config, threadContext, serverCtx, "receive", null, "allowGroup");
// If no group was set, default to "registered users"
//
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java
index c519902..edae46b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java
@@ -16,6 +16,8 @@
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.account.GroupBackend;
+import com.google.gerrit.server.util.ServerRequestContext;
+import com.google.gerrit.server.util.ThreadLocalRequestContext;
import com.google.inject.Inject;
import org.eclipse.jgit.lib.Config;
@@ -26,8 +28,10 @@
public class GitUploadPackGroupsProvider extends GroupSetProvider {
@Inject
public GitUploadPackGroupsProvider(GroupBackend gb,
- @GerritServerConfig Config config) {
- super(gb, config, "upload", null, "allowGroup");
+ @GerritServerConfig Config config,
+ ThreadLocalRequestContext threadContext,
+ ServerRequestContext serverCtx) {
+ super(gb, config, threadContext, serverCtx, "upload", null, "allowGroup");
// If no group was set, default to "registered users" and "anonymous"
//
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java
index 5fa243b..5c3ec39 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java
@@ -19,6 +19,9 @@
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.account.GroupBackends;
+import com.google.gerrit.server.util.RequestContext;
+import com.google.gerrit.server.util.ServerRequestContext;
+import com.google.gerrit.server.util.ThreadLocalRequestContext;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -37,19 +40,26 @@
@Inject
protected GroupSetProvider(GroupBackend groupBackend,
- @GerritServerConfig Config config, String section,
+ @GerritServerConfig Config config,
+ ThreadLocalRequestContext threadContext,
+ ServerRequestContext serverCtx, String section,
String subsection, String name) {
- String[] groupNames = config.getStringList(section, subsection, name);
- ImmutableSet.Builder<AccountGroup.UUID> builder = ImmutableSet.builder();
- for (String n : groupNames) {
- GroupReference g = GroupBackends.findBestSuggestion(groupBackend, n);
- if (g == null) {
- log.warn("Group \"{0}\" not in database, skipping.", n);
- } else {
- builder.add(g.getUUID());
+ RequestContext ctx = threadContext.setContext(serverCtx);
+ try {
+ String[] groupNames = config.getStringList(section, subsection, name);
+ ImmutableSet.Builder<AccountGroup.UUID> builder = ImmutableSet.builder();
+ for (String n : groupNames) {
+ GroupReference g = GroupBackends.findBestSuggestion(groupBackend, n);
+ if (g == null) {
+ log.warn("Group \"{}\" not in database, skipping.", n);
+ } else {
+ builder.add(g.getUUID());
+ }
}
+ groupIds = builder.build();
+ } finally {
+ threadContext.setContext(ctx);
}
- groupIds = builder.build();
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ListCapabilities.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ListCapabilities.java
index d92dfa7..8062087 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/ListCapabilities.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ListCapabilities.java
@@ -16,21 +16,39 @@
import com.google.common.collect.Maps;
import com.google.gerrit.common.data.GlobalCapability;
+import com.google.gerrit.extensions.config.CapabilityDefinition;
+import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
import java.util.Map;
/** List capabilities visible to the calling user. */
public class ListCapabilities implements RestReadView<ConfigResource> {
+ private final DynamicMap<CapabilityDefinition> pluginCapabilities;
+
+ @Inject
+ public ListCapabilities(DynamicMap<CapabilityDefinition> pluginCapabilities) {
+ this.pluginCapabilities = pluginCapabilities;
+ }
+
@Override
public Map<String, CapabilityInfo> apply(ConfigResource resource)
throws AuthException, BadRequestException, ResourceConflictException,
IllegalArgumentException, SecurityException, IllegalAccessException,
NoSuchFieldException {
Map<String, CapabilityInfo> output = Maps.newTreeMap();
+ collectCoreCapabilities(output);
+ collectPluginCapabilities(output);
+ return output;
+ }
+
+ private void collectCoreCapabilities(Map<String, CapabilityInfo> output)
+ throws IllegalAccessException, NoSuchFieldException {
Class<? extends CapabilityConstants> bundleClass =
CapabilityConstants.get().getClass();
CapabilityConstants c = CapabilityConstants.get();
@@ -38,7 +56,18 @@
String name = (String) bundleClass.getField(id).get(c);
output.put(id, new CapabilityInfo(id, name));
}
- return output;
+ }
+
+ private void collectPluginCapabilities(Map<String, CapabilityInfo> output) {
+ for (String pluginName : pluginCapabilities.plugins()) {
+ for (Map.Entry<String, Provider<CapabilityDefinition>> entry :
+ pluginCapabilities.byPlugin(pluginName).entrySet()) {
+ String id = String.format("%s-%s", pluginName, entry.getKey());
+ output.put(id, new CapabilityInfo(
+ id,
+ entry.getValue().get().getDescription()));
+ }
+ }
}
public static class CapabilityInfo {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroupsProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroupsProvider.java
index 6622b0f..0189de3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroupsProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroupsProvider.java
@@ -15,6 +15,8 @@
package com.google.gerrit.server.config;
import com.google.gerrit.server.account.GroupBackend;
+import com.google.gerrit.server.util.ServerRequestContext;
+import com.google.gerrit.server.util.ThreadLocalRequestContext;
import com.google.inject.Inject;
import org.eclipse.jgit.lib.Config;
@@ -33,7 +35,9 @@
public class ProjectOwnerGroupsProvider extends GroupSetProvider {
@Inject
public ProjectOwnerGroupsProvider(GroupBackend gb,
- @GerritServerConfig final Config config) {
- super(gb, config, "repository", "*", "ownerGroup");
+ @GerritServerConfig final Config config,
+ ThreadLocalRequestContext context,
+ ServerRequestContext serverCtx) {
+ super(gb, config, context, serverCtx, "repository", "*", "ownerGroup");
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
index 5144dcb..a803ddd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
@@ -533,15 +533,13 @@
AccessSection capability = null;
for (String varName : rc.getNames(CAPABILITY)) {
- if (GlobalCapability.isCapability(varName)) {
- if (capability == null) {
- capability = new AccessSection(AccessSection.GLOBAL_CAPABILITIES);
- accessSections.put(AccessSection.GLOBAL_CAPABILITIES, capability);
- }
- Permission perm = capability.getPermission(varName, true);
- loadPermissionRules(rc, CAPABILITY, null, varName, groupsByName, perm,
- GlobalCapability.hasRange(varName));
+ if (capability == null) {
+ capability = new AccessSection(AccessSection.GLOBAL_CAPABILITIES);
+ accessSections.put(AccessSection.GLOBAL_CAPABILITIES, capability);
}
+ Permission perm = capability.getPermission(varName, true);
+ loadPermissionRules(rc, CAPABILITY, null, varName, groupsByName, perm,
+ GlobalCapability.hasRange(varName));
}
}
@@ -879,8 +877,7 @@
rc.setStringList(CAPABILITY, null, permission.getName(), rules);
}
for (String varName : rc.getNames(CAPABILITY)) {
- if (GlobalCapability.isCapability(varName)
- && !have.contains(varName.toLowerCase())) {
+ if (!have.contains(varName.toLowerCase())) {
rc.unset(CAPABILITY, null, varName);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
index bb11e62..64210a0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
@@ -26,6 +26,7 @@
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.ArrayList;
+import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
@@ -248,6 +249,7 @@
private final Executor executor;
private final int taskId;
private final AtomicBoolean running;
+ private final Date startTime;
Task(Runnable runnable, RunnableScheduledFuture<V> task, Executor executor,
int taskId) {
@@ -256,6 +258,7 @@
this.executor = executor;
this.taskId = taskId;
this.running = new AtomicBoolean();
+ this.startTime = new Date();
}
public int getTaskId() {
@@ -281,6 +284,10 @@
return State.OTHER;
}
+ public Date getStartTime() {
+ return startTime;
+ }
+
public boolean cancel(boolean mayInterruptIfRunning) {
if (task.cancel(mayInterruptIfRunning)) {
// Tiny abuse of running: if the task needs to know it was
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeBatchIndexer.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeBatchIndexer.java
index 5bf1cbd..e997c57 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeBatchIndexer.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeBatchIndexer.java
@@ -276,7 +276,7 @@
}
for (ObjectId id : byId.keySet()) {
- getPathsAndIndex(walk.parseCommit(id));
+ getPathsAndIndex(id);
}
} finally {
walk.release();
@@ -284,10 +284,11 @@
return null;
}
- private void getPathsAndIndex(RevCommit bCommit) throws Exception {
- RevTree bTree = bCommit.getTree();
- List<ChangeData> cds = Lists.newArrayList(byId.get(bCommit));
+ private void getPathsAndIndex(ObjectId b) throws Exception {
+ List<ChangeData> cds = Lists.newArrayList(byId.get(b));
try {
+ RevCommit bCommit = walk.parseCommit(b);
+ RevTree bTree = bCommit.getTree();
RevTree aTree = aFor(bCommit, walk);
DiffFormatter df = new DiffFormatter(DisabledOutputStream.INSTANCE);
try {
@@ -315,7 +316,7 @@
df.release();
}
} catch (Exception e) {
- fail("Failed to index commit " + bCommit.name(), false, e);
+ fail("Failed to index commit " + b.name(), false, e);
for (ChangeData cd : cds) {
fail("Failed to index change " + cd.getId(), true, null);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java
index 716a22b..4439755 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java
@@ -28,6 +28,8 @@
import com.google.inject.assistedinject.Assisted;
import org.eclipse.jgit.lib.Repository;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Collections;
@@ -37,6 +39,9 @@
/** Send comments, after the author of them hit used Publish Comments in the UI. */
public class CommentSender extends ReplyToChangeSender {
+ private static final Logger log = LoggerFactory
+ .getLogger(CommentSender.class);
+
public static interface Factory {
public CommentSender create(NotifyHandling notify, Change change);
}
@@ -97,8 +102,7 @@
}
public String getInlineComments(int lines) {
- StringBuilder cmts = new StringBuilder();
-
+ StringBuilder cmts = new StringBuilder();
final Repository repo = getRepository();
try {
PatchList patchList = null;
@@ -114,55 +118,34 @@
PatchFile currentFileData = null;
for (final PatchLineComment c : inlineComments) {
final Patch.Key pk = c.getKey().getParentKey();
- final int lineNbr = c.getLine();
- final short side = c.getSide();
if (!pk.equals(currentFileKey)) {
cmts.append("....................................................\n");
if (Patch.COMMIT_MSG.equals(pk.get())) {
cmts.append("Commit Message\n");
} else {
- cmts.append("File ");
- cmts.append(pk.get());
- cmts.append("\n");
+ cmts.append("File ").append(pk.get()).append('\n');
}
currentFileKey = pk;
if (patchList != null) {
try {
currentFileData =
- new PatchFile(repo, patchList, pk.getFileName());
+ new PatchFile(repo, patchList, pk.get());
} catch (IOException e) {
- // Don't quote the line if we can't load it.
+ log.warn(String.format(
+ "Cannot load %s from %s in %s",
+ pk.getFileName(),
+ patchList.getNewId().name(),
+ projectState.getProject().getName()), e);
+ currentFileData = null;
}
- } else {
- currentFileData = null;
}
}
if (currentFileData != null) {
- int maxLines;
- try {
- maxLines = currentFileData.getLineCount(side);
- } catch (Throwable e) {
- maxLines = lineNbr;
- }
-
- final int startLine = Math.max(1, lineNbr - lines + 1);
- final int stopLine = Math.min(maxLines, lineNbr + lines);
-
- for (int line = startLine; line <= lineNbr; ++line) {
- appendFileLine(cmts, currentFileData, side, line);
- }
-
- cmts.append(c.getMessage().trim());
- cmts.append("\n");
-
- for (int line = lineNbr + 1; line < stopLine; ++line) {
- appendFileLine(cmts, currentFileData, side, line);
- }
+ appendComment(cmts, lines, currentFileData, c);
}
-
cmts.append("\n\n");
}
} finally {
@@ -173,6 +156,30 @@
return cmts.toString();
}
+ private void appendComment(StringBuilder out, int contextLines,
+ PatchFile currentFileData, PatchLineComment comment) {
+ int lineNbr = comment.getLine();
+ short side = comment.getSide();
+ int maxLines;
+ try {
+ maxLines = currentFileData.getLineCount(side);
+ } catch (Throwable e) {
+ maxLines = lineNbr;
+ }
+
+ final int startLine = Math.max(1, lineNbr - contextLines + 1);
+ final int stopLine = Math.min(maxLines, lineNbr + contextLines);
+
+ for (int line = startLine; line <= lineNbr; ++line) {
+ appendFileLine(out, currentFileData, side, line);
+ }
+ out.append(comment.getMessage().trim()).append('\n');
+
+ for (int line = lineNbr + 1; line < stopLine; ++line) {
+ appendFileLine(out, currentFileData, side, line);
+ }
+ }
+
private void appendFileLine(StringBuilder cmts, PatchFile fileData, short side, int line) {
cmts.append("Line " + line);
try {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java
index ac59f65..fba13cc 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java
@@ -32,7 +32,7 @@
/** A version of the database schema. */
public abstract class SchemaVersion {
/** The current schema version. */
- public static final Class<Schema_79> C = Schema_79.class;
+ public static final Class<Schema_81> C = Schema_81.class;
public static class Module extends AbstractModule {
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_80.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_80.java
new file mode 100644
index 0000000..2cf8d2a
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_80.java
@@ -0,0 +1,26 @@
+// Copyright (C) 2013 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.schema;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+public class Schema_80 extends SchemaVersion {
+
+ @Inject
+ Schema_80(Provider<Schema_79> prior) {
+ super(prior);
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_81.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_81.java
new file mode 100644
index 0000000..bc3b390
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_81.java
@@ -0,0 +1,159 @@
+// Copyright (C) 2013 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.schema;
+
+import com.google.gerrit.common.data.AccessSection;
+import com.google.gerrit.common.data.Permission;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.GerritPersonIdent;
+import com.google.gerrit.server.config.AllProjectsName;
+import com.google.gerrit.server.config.SitePaths;
+import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.MetaDataUpdate;
+import com.google.gerrit.server.git.ProjectConfig;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Repository;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.sql.SQLException;
+
+public class Schema_81 extends SchemaVersion {
+
+ private final File pluginsDir;
+ private final GitRepositoryManager mgr;
+ private final AllProjectsName allProjects;
+ private final PersonIdent serverUser;
+
+ @Inject
+ Schema_81(Provider<Schema_80> prior, SitePaths sitePaths,
+ AllProjectsName allProjects, GitRepositoryManager mgr,
+ @GerritPersonIdent PersonIdent serverUser) {
+ super(prior);
+ this.pluginsDir = sitePaths.plugins_dir;
+ this.mgr = mgr;
+ this.allProjects = allProjects;
+ this.serverUser = serverUser;
+ }
+
+ @Override
+ protected void migrateData(ReviewDb db, UpdateUI ui) throws OrmException,
+ SQLException {
+ try {
+ migrateStartReplicationCapability(db, scanForReplicationPlugin());
+ } catch (RepositoryNotFoundException e) {
+ throw new OrmException(e);
+ } catch (SQLException e) {
+ throw new OrmException(e);
+ } catch (IOException e) {
+ throw new OrmException(e);
+ } catch (ConfigInvalidException e) {
+ throw new OrmException(e);
+ }
+ }
+
+ private File[] scanForReplicationPlugin() {
+ File[] matches = null;
+ if (pluginsDir != null && pluginsDir.exists()) {
+ matches = pluginsDir.listFiles(new FileFilter() {
+ @Override
+ public boolean accept(File pathname) {
+ String n = pathname.getName();
+ return (n.endsWith(".jar") || n.endsWith(".jar.disabled"))
+ && pathname.isFile() && n.indexOf("replication") >= 0;
+ }
+ });
+ }
+ return matches;
+ }
+
+ private void migrateStartReplicationCapability(ReviewDb db, File[] matches)
+ throws SQLException, RepositoryNotFoundException, IOException,
+ ConfigInvalidException {
+ Description d = new Description();
+ if (matches == null || matches.length == 0) {
+ d.what = Description.Action.REMOVE;
+ } else {
+ d.what = Description.Action.RENAME;
+ d.prefix = nameOf(matches[0]);
+ }
+ migrateStartReplicationCapability(db, d);
+ }
+
+ private void migrateStartReplicationCapability(ReviewDb db, Description d)
+ throws SQLException, RepositoryNotFoundException, IOException,
+ ConfigInvalidException {
+ Repository git = mgr.openRepository(allProjects);
+ try {
+ MetaDataUpdate md =
+ new MetaDataUpdate(GitReferenceUpdated.DISABLED, allProjects, git);
+ md.getCommitBuilder().setAuthor(serverUser);
+ md.getCommitBuilder().setCommitter(serverUser);
+ ProjectConfig config = ProjectConfig.read(md);
+ AccessSection capabilities =
+ config.getAccessSection(AccessSection.GLOBAL_CAPABILITIES);
+ Permission startReplication =
+ capabilities.getPermission("startReplication");
+ if (startReplication == null) {
+ return;
+ }
+ String msg = null;
+ switch (d.what) {
+ case REMOVE:
+ capabilities.remove(startReplication);
+ msg = "Remove startReplication capability, plugin not installed\n";
+ break;
+ case RENAME:
+ capabilities.remove(startReplication);
+ Permission pluginStartReplication =
+ capabilities.getPermission(
+ String.format("%s-startReplication", d.prefix), true);
+ pluginStartReplication.setRules(startReplication.getRules());
+ msg = "Rename startReplication capability to match updated plugin\n";
+ break;
+ }
+ config.replace(capabilities);
+ md.setMessage(msg);
+ config.commit(md);
+ } finally {
+ git.close();
+ }
+ }
+
+ private static String nameOf(File jar) {
+ String name = jar.getName();
+ if (name.endsWith(".disabled")) {
+ name = name.substring(0, name.lastIndexOf('.'));
+ }
+ int ext = name.lastIndexOf('.');
+ return 0 < ext ? name.substring(0, ext) : name;
+ }
+
+ private static class Description {
+ private enum Action {
+ REMOVE, RENAME
+ }
+ Action what;
+ String prefix;
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/ServerRequestContext.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/ServerRequestContext.java
new file mode 100644
index 0000000..6730e30
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/ServerRequestContext.java
@@ -0,0 +1,48 @@
+// Copyright (C) 2013 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.util;
+
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.InternalUser;
+import com.google.inject.Provider;
+import com.google.inject.ProvisionException;
+import com.google.inject.Inject;
+
+/** RequestContext with an InternalUser making the internals visible. */
+public class ServerRequestContext implements RequestContext {
+ private final InternalUser user;
+
+ @Inject
+ ServerRequestContext(InternalUser.Factory userFactory) {
+ this.user = userFactory.create();
+ }
+
+ @Override
+ public CurrentUser getCurrentUser() {
+ return user;
+ }
+
+ @Override
+ public Provider<ReviewDb> getReviewDbProvider() {
+ return new Provider<ReviewDb>() {
+ @Override
+ public ReviewDb get() {
+ throw new ProvisionException(
+ "Automatic ReviewDb only available in request scope");
+ }
+ };
+ }
+}
diff --git a/gerrit-server/src/main/java/gerrit/PRED_get_legacy_label_types_1.java b/gerrit-server/src/main/java/gerrit/PRED_get_legacy_label_types_1.java
index 7d14ac2..4b89544 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_get_legacy_label_types_1.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_get_legacy_label_types_1.java
@@ -15,6 +15,7 @@
package gerrit;
import com.google.gerrit.common.data.LabelType;
+import com.google.gerrit.common.data.LabelValue;
import com.google.gerrit.rules.PrologEnvironment;
import com.google.gerrit.rules.StoredValues;
import com.google.gerrit.server.project.ProjectState;
@@ -43,6 +44,8 @@
* </ul>
*/
class PRED_get_legacy_label_types_1 extends Predicate.P1 {
+ private static final SymbolTerm NONE = SymbolTerm.intern("none");
+
PRED_get_legacy_label_types_1(Term a1, Operation n) {
arg1 = a1;
cont = n;
@@ -75,10 +78,12 @@
"label_type", 4);
static Term export(LabelType type) {
+ LabelValue min = type.getMin();
+ LabelValue max = type.getMax();
return new StructureTerm(symLabelType,
SymbolTerm.intern(type.getName()),
SymbolTerm.intern(type.getFunctionName()),
- new IntegerTerm(type.getMin().getValue()),
- new IntegerTerm(type.getMax().getValue()));
+ min != null ? new IntegerTerm(min.getValue()) : NONE,
+ max != null ? new IntegerTerm(max.getValue()) : NONE);
}
}
diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/config/CapabilityConstants.properties b/gerrit-server/src/main/resources/com/google/gerrit/server/config/CapabilityConstants.properties
index d19fd22..a1b966f7 100644
--- a/gerrit-server/src/main/resources/com/google/gerrit/server/config/CapabilityConstants.properties
+++ b/gerrit-server/src/main/resources/com/google/gerrit/server/config/CapabilityConstants.properties
@@ -10,7 +10,6 @@
queryLimit = Query Limit
runAs = Run As
runGC = Run Garbage Collection
-startReplication = Start Replication
streamEvents = Stream Events
viewCaches = View Caches
viewConnections = View Connections
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/change/CommentsTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/change/CommentsTest.java
index 6a9a93f..f1d986d 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/change/CommentsTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/change/CommentsTest.java
@@ -34,6 +34,7 @@
import com.google.gerrit.reviewdb.client.PatchLineComment;
import com.google.gerrit.reviewdb.client.PatchLineComment.Status;
import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.CommentRange;
import com.google.gerrit.reviewdb.server.PatchLineCommentAccess;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.account.AccountInfo;
@@ -111,13 +112,13 @@
long timeBase = System.currentTimeMillis();
plc1 = newPatchLineComment(psId1, "Comment1", null,
"FileOne.txt", Side.REVISION, 1, account1, timeBase,
- "First Comment");
+ "First Comment", new CommentRange(1, 2, 3, 4));
plc2 = newPatchLineComment(psId1, "Comment2", "Comment1",
"FileOne.txt", Side.REVISION, 1, account2, timeBase + 1000,
- "Reply to First Comment");
+ "Reply to First Comment", new CommentRange(1, 2, 3, 4));
plc3 = newPatchLineComment(psId1, "Comment3", "Comment1",
"FileOne.txt", Side.PARENT, 1, account1, timeBase + 2000,
- "First Parent Comment");
+ "First Parent Comment", new CommentRange(1, 2, 3, 4));
expect(plca.publishedByPatchSet(psId1))
.andAnswer(results(plc1, plc2, plc3)).anyTimes();
@@ -206,16 +207,18 @@
assertEquals(plc.getSide() == 0 ? Side.PARENT : Side.REVISION,
Objects.firstNonNull(ci.side, Side.REVISION));
assertEquals(plc.getWrittenOn(), ci.updated);
+ assertEquals(plc.getRange(), ci.range);
}
private static PatchLineComment newPatchLineComment(PatchSet.Id psId,
String uuid, String inReplyToUuid, String filename, Side side, int line,
- Account.Id authorId, long millis, String message) {
+ Account.Id authorId, long millis, String message, CommentRange range) {
Patch.Key p = new Patch.Key(psId, filename);
PatchLineComment.Key id = new PatchLineComment.Key(p, uuid);
PatchLineComment plc =
new PatchLineComment(id, line, authorId, inReplyToUuid);
plc.setMessage(message);
+ plc.setRange(range);
plc.setSide(side == Side.PARENT ? (short) 0 : (short) 1);
plc.setStatus(Status.PUBLISHED);
plc.setWrittenOn(new Timestamp(millis));
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/config/ListCapabilitiesTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/config/ListCapabilitiesTest.java
index f97ca55..992502f 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/config/ListCapabilitiesTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/config/ListCapabilitiesTest.java
@@ -19,21 +19,55 @@
import static org.junit.Assert.assertTrue;
import com.google.gerrit.common.data.GlobalCapability;
+import com.google.gerrit.extensions.annotations.Exports;
+import com.google.gerrit.extensions.config.CapabilityDefinition;
+import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.server.config.ListCapabilities.CapabilityInfo;
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import org.junit.Before;
import org.junit.Test;
import java.util.Map;
public class ListCapabilitiesTest {
+ private Injector injector;
+
+ @Before
+ public void setUp() throws Exception {
+ AbstractModule mod = new AbstractModule() {
+ @Override
+ protected void configure() {
+ DynamicMap.mapOf(binder(), CapabilityDefinition.class);
+ bind(CapabilityDefinition.class)
+ .annotatedWith(Exports.named("printHello"))
+ .toInstance(new CapabilityDefinition() {
+ @Override
+ public String getDescription() {
+ return "Print Hello";
+ }
+ });
+ }
+ };
+ injector = Guice.createInjector(mod);
+ }
+
@Test
public void testList() throws Exception {
Map<String, CapabilityInfo> m =
- new ListCapabilities().apply(new ConfigResource());
+ injector.getInstance(ListCapabilities.class)
+ .apply(new ConfigResource());
for (String id : GlobalCapability.getAllNames()) {
assertTrue("contains " + id, m.containsKey(id));
assertEquals(id, m.get(id).id);
assertNotNull(id + " has name", m.get(id).name);
}
+
+ String pluginCapability = "gerrit-printHello";
+ assertTrue("contains " + pluginCapability, m.containsKey(pluginCapability));
+ assertEquals(pluginCapability, m.get(pluginCapability).id);
+ assertEquals("Print Hello", m.get(pluginCapability).name);
}
}
diff --git a/gerrit-sshd/BUCK b/gerrit-sshd/BUCK
index 93a3ef7..7a8610d 100644
--- a/gerrit-sshd/BUCK
+++ b/gerrit-sshd/BUCK
@@ -16,6 +16,7 @@
'//lib:guava',
'//lib:gwtorm',
'//lib:jsch',
+ '//lib:jsr305',
'//lib/commons:codec',
'//lib/guice:guice',
'//lib/guice:guice-assistedinject',
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
index 98b740c..0cf48d8 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
@@ -15,6 +15,7 @@
package com.google.gerrit.sshd;
import com.google.common.util.concurrent.Atomics;
+import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.Project.NameKey;
import com.google.gerrit.server.CurrentUser;
@@ -53,6 +54,8 @@
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
+import javax.annotation.Nullable;
+
public abstract class BaseCommand implements Command {
private static final Logger log = LoggerFactory.getLogger(BaseCommand.class);
public static final String ENC = "UTF-8";
@@ -90,6 +93,11 @@
@Inject
private Provider<SshScope.Context> contextProvider;
+ /** Commands declared by a plugin can be scoped by the plugin name. */
+ @Inject(optional = true)
+ @PluginName
+ private String pluginName;
+
/** The task, as scheduled on a worker thread. */
private final AtomicReference<Future<?>> task;
@@ -119,6 +127,11 @@
this.exit = callback;
}
+ @Nullable
+ String getPluginName() {
+ return pluginName;
+ }
+
String getName() {
return commandName;
}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandMetaData.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandMetaData.java
index cfcee6a..42c0fd7 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandMetaData.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandMetaData.java
@@ -27,5 +27,9 @@
@Retention(RUNTIME)
public @interface CommandMetaData {
String name();
+ String description() default "";
+
+ /** @deprecated use description intead. */
+ @Deprecated
String descr() default "";
}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandModule.java
index e7e8a44..c64f9d8 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandModule.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandModule.java
@@ -14,6 +14,8 @@
package com.google.gerrit.sshd;
+import com.google.common.base.Objects;
+import com.google.common.base.Strings;
import com.google.inject.AbstractModule;
import com.google.inject.binder.LinkedBindingBuilder;
@@ -74,7 +76,7 @@
if (meta == null) {
throw new IllegalStateException("no CommandMetaData annotation found");
}
- bind(Commands.key(parent, meta.name(), meta.descr())).to(clazz);
+ bind(Commands.key(parent, meta.name(), description(meta))).to(clazz);
}
/**
@@ -93,7 +95,14 @@
if (meta == null) {
throw new IllegalStateException("no CommandMetaData annotation found");
}
- bind(Commands.key(parent, name, meta.descr())).to(clazz);
+ bind(Commands.key(parent, name, description(meta))).to(clazz);
+ }
+
+ @SuppressWarnings("deprecation")
+ private static String description(CommandMetaData meta) {
+ return Objects.firstNonNull(
+ Strings.emptyToNull(meta.description()),
+ meta.descr());
}
/**
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DispatchCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DispatchCommand.java
index 455b732..0fa5d25 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DispatchCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DispatchCommand.java
@@ -17,6 +17,7 @@
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Atomics;
+import com.google.gerrit.extensions.annotations.CapabilityScope;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.CapabilityControl;
@@ -28,6 +29,8 @@
import org.apache.sshd.server.Command;
import org.apache.sshd.server.Environment;
import org.kohsuke.args4j.Argument;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.StringWriter;
@@ -40,6 +43,9 @@
* Command that dispatches to a subcommand from its command table.
*/
final class DispatchCommand extends BaseCommand {
+ private static final Logger log = LoggerFactory
+ .getLogger(DispatchCommand.class);
+
interface Factory {
DispatchCommand create(Map<String, CommandProvider> map);
}
@@ -113,15 +119,36 @@
}
}
- private void checkRequiresCapability(Command cmd) throws UnloggedFailure {
+ private void checkRequiresCapability(Command cmd)
+ throws UnloggedFailure {
RequiresCapability rc = cmd.getClass().getAnnotation(RequiresCapability.class);
if (rc != null) {
CurrentUser user = currentUser.get();
CapabilityControl ctl = user.getCapabilities();
- if (!ctl.canPerform(rc.value()) && !ctl.canAdministrateServer()) {
+ String capability = rc.value();
+
+ if (cmd instanceof BaseCommand) {
+ String pluginName = ((BaseCommand) cmd).getPluginName();
+ if (pluginName != null && !"gerrit".equals(pluginName)
+ && (rc.scope() == CapabilityScope.PLUGIN
+ || rc.scope() == CapabilityScope.CONTEXT)) {
+ capability = String.format("%s-%s", pluginName, rc.value());
+ } else if (rc.scope() == CapabilityScope.PLUGIN) {
+ log.error(String.format(
+ "Class %s uses @%s(scope=%s), but is not within a plugin",
+ cmd.getClass().getName(),
+ RequiresCapability.class.getSimpleName(),
+ CapabilityScope.PLUGIN.name()));
+ throw new UnloggedFailure(
+ BaseCommand.STATUS_NOT_ADMIN,
+ "fatal: cannot check capability");
+ }
+ }
+
+ if (!ctl.canPerform(capability) && !ctl.canAdministrateServer()) {
String msg = String.format(
"fatal: %s does not have \"%s\" capability.",
- user.getUserName(), rc.value());
+ user.getUserName(), capability);
throw new UnloggedFailure(BaseCommand.STATUS_NOT_ADMIN, msg);
}
}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminQueryShell.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminQueryShell.java
index 15229dc..0ff3a01 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminQueryShell.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminQueryShell.java
@@ -28,7 +28,7 @@
/** Opens a query processor. */
@AdminHighPriorityCommand
@RequiresCapability(GlobalCapability.ACCESS_DATABASE)
-@CommandMetaData(name = "gsql", descr = "Administrative interface to active database")
+@CommandMetaData(name = "gsql", description = "Administrative interface to active database")
final class AdminQueryShell extends SshCommand {
@Inject
private QueryShell.Factory factory;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java
index e83963a..c68dc26 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java
@@ -50,7 +50,7 @@
import java.util.Set;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
-@CommandMetaData(name = "set-project-parent", descr = "Change the project permissions are inherited from")
+@CommandMetaData(name = "set-project-parent", description = "Change the project permissions are inherited from")
final class AdminSetParent extends SshCommand {
private static final Logger log = LoggerFactory.getLogger(AdminSetParent.class);
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/BanCommitCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/BanCommitCommand.java
index 0268bc0..dc22a29 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/BanCommitCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/BanCommitCommand.java
@@ -33,7 +33,7 @@
import java.util.ArrayList;
import java.util.List;
-@CommandMetaData(name = "ban-commit", descr = "Ban a commit from a project's repository")
+@CommandMetaData(name = "ban-commit", description = "Ban a commit from a project's repository")
public class BanCommitCommand extends SshCommand {
@Option(name = "--reason", aliases = {"-r"}, metaVar = "REASON", usage = "reason for banning the commit")
private String reason;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateAccountCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateAccountCommand.java
index 6c4b41c..aef1560 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateAccountCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateAccountCommand.java
@@ -39,7 +39,7 @@
/** Create a new user account. **/
@RequiresCapability(GlobalCapability.CREATE_ACCOUNT)
-@CommandMetaData(name = "create-account", descr = "Create a new batch/role account")
+@CommandMetaData(name = "create-account", description = "Create a new batch/role account")
final class CreateAccountCommand extends SshCommand {
@Option(name = "--group", aliases = {"-g"}, metaVar = "GROUP", usage = "groups to add account to")
private List<AccountGroup.Id> groups = new ArrayList<AccountGroup.Id>();
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java
index 660460a..c652641 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java
@@ -38,7 +38,7 @@
* Optionally, puts an initial set of user in the newly created group.
*/
@RequiresCapability(GlobalCapability.CREATE_GROUP)
-@CommandMetaData(name = "create-group", descr = "Create a new account group")
+@CommandMetaData(name = "create-group", description = "Create a new account group")
final class CreateGroupCommand extends SshCommand {
@Option(name = "--owner", aliases = {"-o"}, metaVar = "GROUP", usage = "owning group, if not specified the group will be self-owning")
private AccountGroup.Id ownerGroupId;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProjectCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProjectCommand.java
index 89bb973..24d7689 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProjectCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProjectCommand.java
@@ -36,7 +36,7 @@
/** Create a new project. **/
@RequiresCapability(GlobalCapability.CREATE_PROJECT)
-@CommandMetaData(name = "create-project", descr = "Create a new project and associated Git repository")
+@CommandMetaData(name = "create-project", description = "Create a new project and associated Git repository")
final class CreateProjectCommand extends SshCommand {
@Option(name = "--name", aliases = {"-n"}, metaVar = "NAME", usage = "name of project to be created (deprecated option)")
void setProjectNameFromOption(String name) {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/FlushCaches.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/FlushCaches.java
index 4b78cfc..6c07dddb 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/FlushCaches.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/FlushCaches.java
@@ -31,7 +31,7 @@
/** Causes the caches to purge all entries and reload. */
@RequiresCapability(GlobalCapability.FLUSH_CACHES)
-@CommandMetaData(name = "flush-caches", descr = "Flush some/all server caches from memory")
+@CommandMetaData(name = "flush-caches", description = "Flush some/all server caches from memory")
final class FlushCaches extends CacheCommand {
private static final String WEB_SESSIONS = "web_sessions";
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/GarbageCollectionCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/GarbageCollectionCommand.java
index c561153..346bea7 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/GarbageCollectionCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/GarbageCollectionCommand.java
@@ -37,7 +37,7 @@
/** Runs the Git garbage collection. */
@RequiresCapability(GlobalCapability.RUN_GC)
-@CommandMetaData(name = "gc", descr = "Run Git garbage collection")
+@CommandMetaData(name = "gc", description = "Run Git garbage collection")
public class GarbageCollectionCommand extends BaseCommand {
@Option(name = "--all", usage = "runs the Git garbage collection for all projects")
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListGroupsCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListGroupsCommand.java
index e5b4203..aadb1d9 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListGroupsCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListGroupsCommand.java
@@ -37,7 +37,7 @@
import java.io.PrintWriter;
-@CommandMetaData(name = "ls-groups", descr = "List groups visible to the caller")
+@CommandMetaData(name = "ls-groups", description = "List groups visible to the caller")
public class ListGroupsCommand extends BaseCommand {
@Inject
private MyListGroups impl;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListMembersCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListMembersCommand.java
index c5bda3c..b7dd380 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListMembersCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListMembersCommand.java
@@ -39,7 +39,7 @@
/**
* Implements a command that allows the user to see the members of a group.
*/
-@CommandMetaData(name = "ls-members", descr = "Lists the members of a given group")
+@CommandMetaData(name = "ls-members", description = "Lists the members of a given group")
public class ListMembersCommand extends BaseCommand {
@Inject
ListMembersCommandImpl impl;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListProjectsCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListProjectsCommand.java
index ab70395..8bcae4b 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListProjectsCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListProjectsCommand.java
@@ -23,7 +23,7 @@
import java.util.List;
-@CommandMetaData(name = "ls-projects", descr = "List projects visible to the caller")
+@CommandMetaData(name = "ls-projects", description = "List projects visible to the caller")
final class ListProjectsCommand extends BaseCommand {
@Inject
private ListProjects impl;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/LsUserRefs.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/LsUserRefs.java
index 58abf95..1806749 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/LsUserRefs.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/LsUserRefs.java
@@ -40,7 +40,7 @@
import java.util.Map;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
-@CommandMetaData(name = "ls-user-refs", descr = "List refs visible to a specific user")
+@CommandMetaData(name = "ls-user-refs", description = "List refs visible to a specific user")
public class LsUserRefs extends SshCommand {
@Inject
private AccountResolver accountResolver;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginEnableCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginEnableCommand.java
index 709e337..47c2d68 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginEnableCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginEnableCommand.java
@@ -28,7 +28,7 @@
import java.util.List;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
-@CommandMetaData(name = "enable", descr = "Enable plugins")
+@CommandMetaData(name = "enable", description = "Enable plugins")
final class PluginEnableCommand extends SshCommand {
@Argument(index = 0, metaVar = "NAME", required = true, usage = "plugin(s) to enable")
List<String> names;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginInstallCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginInstallCommand.java
index fc036fe..70d09ee 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginInstallCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginInstallCommand.java
@@ -35,7 +35,7 @@
import java.net.URL;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
-@CommandMetaData(name = "install", descr = "Install/Add a plugin")
+@CommandMetaData(name = "install", description = "Install/Add a plugin")
final class PluginInstallCommand extends SshCommand {
@Option(name = "--name", aliases = {"-n"}, usage = "install under name")
private String name;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginLsCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginLsCommand.java
index ab6c978..7e44641 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginLsCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginLsCommand.java
@@ -26,7 +26,7 @@
import java.io.IOException;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
-@CommandMetaData(name = "ls", descr = "List the installed plugins")
+@CommandMetaData(name = "ls", description = "List the installed plugins")
final class PluginLsCommand extends BaseCommand {
@Inject
private ListPlugins impl;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginReloadCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginReloadCommand.java
index 85ade03..3ed1011 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginReloadCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginReloadCommand.java
@@ -28,7 +28,7 @@
import java.util.List;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
-@CommandMetaData(name = "reload", descr = "Reload/Restart plugins")
+@CommandMetaData(name = "reload", description = "Reload/Restart plugins")
final class PluginReloadCommand extends SshCommand {
@Argument(index = 0, metaVar = "NAME", usage = "plugins to reload/restart")
private List<String> names;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginRemoveCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginRemoveCommand.java
index 96adb8fe..0ae11af 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginRemoveCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginRemoveCommand.java
@@ -27,7 +27,7 @@
import java.util.List;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
-@CommandMetaData(name = "remove", descr = "Disable plugins")
+@CommandMetaData(name = "remove", description = "Disable plugins")
final class PluginRemoveCommand extends SshCommand {
@Argument(index = 0, metaVar = "NAME", required = true, usage = "plugin to remove")
List<String> names;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Query.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Query.java
index 2d17876..185bb67 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Query.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Query.java
@@ -24,7 +24,7 @@
import java.util.List;
-@CommandMetaData(name = "query", descr = "Query the change database")
+@CommandMetaData(name = "query", description = "Query the change database")
class Query extends SshCommand {
@Inject
private QueryProcessor processor;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java
index f9d5ac1..b3aad6f 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java
@@ -42,7 +42,7 @@
import java.util.Set;
/** Receives change upload over SSH using the Git receive-pack protocol. */
-@CommandMetaData(name = "receive-pack", descr = "Standard Git server side command for client side git push")
+@CommandMetaData(name = "receive-pack", description = "Standard Git server side command for client side git push")
final class Receive extends AbstractGitCommand {
private static final Logger log = LoggerFactory.getLogger(Receive.class);
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/RenameGroupCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/RenameGroupCommand.java
index f3c1bb3..38535a4 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/RenameGroupCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/RenameGroupCommand.java
@@ -25,7 +25,7 @@
import org.kohsuke.args4j.Argument;
-@CommandMetaData(name = "rename-group", descr = "Rename an account group")
+@CommandMetaData(name = "rename-group", description = "Rename an account group")
public class RenameGroupCommand extends SshCommand {
@Argument(index = 0, required = true, metaVar = "GROUP", usage = "name of the group to be renamed")
private String groupName;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java
index b48320f..714a6ad 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java
@@ -63,7 +63,7 @@
import java.util.Map;
import java.util.Set;
-@CommandMetaData(name = "review", descr = "Verify, approve and/or submit one or more patch sets")
+@CommandMetaData(name = "review", description = "Verify, approve and/or submit one or more patch sets")
public class ReviewCommand extends SshCommand {
private static final Logger log =
LoggerFactory.getLogger(ReviewCommand.class);
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetAccountCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetAccountCommand.java
index d515aab..5736bb6 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetAccountCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetAccountCommand.java
@@ -55,7 +55,7 @@
import java.util.List;
/** Set a user's account settings. **/
-@CommandMetaData(name = "set-account", descr = "Change an account's settings")
+@CommandMetaData(name = "set-account", description = "Change an account's settings")
final class SetAccountCommand extends BaseCommand {
@Argument(index = 0, required = true, metaVar = "USER", usage = "full name, email-address, ssh username or account id")
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetMembersCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetMembersCommand.java
index cd2710f..48c37b8 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetMembersCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetMembersCommand.java
@@ -43,7 +43,7 @@
import java.io.UnsupportedEncodingException;
import java.util.List;
-@CommandMetaData(name = "set-members", descr = "Modifies members of specific group or number of groups")
+@CommandMetaData(name = "set-members", description = "Modifies members of specific group or number of groups")
public class SetMembersCommand extends SshCommand {
@Option(name = "--add", aliases = {"-a"}, metaVar = "USER", usage = "users that should be added as group member")
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetProjectCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetProjectCommand.java
index d512fd5..b45fb3a 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetProjectCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetProjectCommand.java
@@ -38,7 +38,7 @@
import java.io.IOException;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
-@CommandMetaData(name = "set-project", descr = "Change a project's settings")
+@CommandMetaData(name = "set-project", description = "Change a project's settings")
final class SetProjectCommand extends SshCommand {
private static final Logger log = LoggerFactory
.getLogger(SetProjectCommand.class);
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetReviewersCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetReviewersCommand.java
index 8e9bcac..6dc79ff 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetReviewersCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetReviewersCommand.java
@@ -45,7 +45,7 @@
import java.util.List;
import java.util.Set;
-@CommandMetaData(name = "set-reviewers", descr = "Add or remove reviewers on a change")
+@CommandMetaData(name = "set-reviewers", description = "Add or remove reviewers on a change")
public class SetReviewersCommand extends SshCommand {
private static final Logger log =
LoggerFactory.getLogger(SetReviewersCommand.class);
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java
index ae5dc56..7929ef6 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java
@@ -52,7 +52,7 @@
/** Show the current cache states. */
@RequiresCapability(GlobalCapability.VIEW_CACHES)
-@CommandMetaData(name = "show-caches", descr = "Display current cache statistics")
+@CommandMetaData(name = "show-caches", description = "Display current cache statistics")
final class ShowCaches extends CacheCommand {
private static volatile long serverStarted;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowConnections.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowConnections.java
index f5abf4b..7b308c1 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowConnections.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowConnections.java
@@ -44,7 +44,7 @@
/** Show the current SSH connections. */
@RequiresCapability(GlobalCapability.VIEW_CONNECTIONS)
-@CommandMetaData(name = "show-connections", descr = "Display active client SSH connections")
+@CommandMetaData(name = "show-connections", description = "Display active client SSH connections")
final class ShowConnections extends SshCommand {
@Option(name = "--numeric", aliases = {"-n"}, usage = "don't resolve names")
private boolean numeric;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowQueue.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowQueue.java
index 88973fc..a1b062c 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowQueue.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowQueue.java
@@ -40,7 +40,7 @@
/** Display the current work queue. */
@AdminHighPriorityCommand
-@CommandMetaData(name = "show-queue", descr = "Display the background work queues, including replication")
+@CommandMetaData(name = "show-queue", description = "Display the background work queues, including replication")
final class ShowQueue extends SshCommand {
@Option(name = "--wide", aliases = {"-w"}, usage = "display without line width truncation")
private boolean wide;
@@ -94,10 +94,10 @@
}
});
- taskNameWidth = wide ? Integer.MAX_VALUE : columns - 8 - 12 - 8 - 4;
+ taskNameWidth = wide ? Integer.MAX_VALUE : columns - 8 - 12 - 12 - 4 - 4;
- stdout.print(String.format("%-8s %-12s %-8s %s\n", //
- "Task", "State", "", "Command"));
+ stdout.print(String.format("%-8s %-12s %-12s %-4s %s\n", //
+ "Task", "State", "StartTime", "", "Command"));
stdout.print("----------------------------------------------"
+ "--------------------------------\n");
@@ -149,10 +149,12 @@
}
}
+ String startTime = startTime(task.getStartTime());
+
// Shows information about tasks depending on the user rights
if (viewAll || (!hasCustomizedPrint && regularUserCanSee)) {
- stdout.print(String.format("%8s %-12s %-8s %s\n", //
- id(task.getTaskId()), start, "", format(task)));
+ stdout.print(String.format("%8s %-12s %-12s %-4s %s\n", //
+ id(task.getTaskId()), start, startTime, "", format(task)));
} else if (regularUserCanSee) {
if (remoteName == null) {
remoteName = projectName.get();
@@ -160,8 +162,8 @@
remoteName = remoteName + "/" + projectName;
}
- stdout.print(String.format("%8s %-12s %-8s %s\n", //
- id(task.getTaskId()), start, "", remoteName));
+ stdout.print(String.format("%8s %-12s %-4s %s\n", //
+ id(task.getTaskId()), start, startTime, "", remoteName));
}
}
stdout.print("----------------------------------------------"
@@ -180,7 +182,15 @@
private static String time(final long now, final long delay) {
final Date when = new Date(now + delay);
- if (delay < 24 * 60 * 60 * 1000L) {
+ return format(when, delay);
+ }
+
+ private static String startTime(final Date when) {
+ return format(when, System.currentTimeMillis() - when.getTime());
+ }
+
+ private static String format(final Date when, final long timeFromNow) {
+ if (timeFromNow < 24 * 60 * 60 * 1000L) {
return new SimpleDateFormat("HH:mm:ss.SSS").format(when);
}
return new SimpleDateFormat("MMM-dd HH:mm").format(when);
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/StreamEvents.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/StreamEvents.java
index 99d4baa..fd4a9ec 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/StreamEvents.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/StreamEvents.java
@@ -36,7 +36,7 @@
import java.util.concurrent.LinkedBlockingQueue;
@RequiresCapability(GlobalCapability.STREAM_EVENTS)
-@CommandMetaData(name = "stream-events", descr = "Monitor events occurring in real time")
+@CommandMetaData(name = "stream-events", description = "Monitor events occurring in real time")
final class StreamEvents extends BaseCommand {
/** Maximum number of events that may be queued up for each connection. */
private static final int MAX_EVENTS = 128;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/TestSubmitRuleCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/TestSubmitRuleCommand.java
index 6335160..b957a7a 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/TestSubmitRuleCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/TestSubmitRuleCommand.java
@@ -23,7 +23,7 @@
import com.google.inject.Provider;
/** Command that allows testing of prolog submit-rules in a live instance. */
-@CommandMetaData(name = "rule", descr = "Test prolog submit rules")
+@CommandMetaData(name = "rule", description = "Test prolog submit rules")
final class TestSubmitRuleCommand extends BaseTestPrologCommand {
@Inject
private Provider<TestSubmitRule> view;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/TestSubmitTypeCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/TestSubmitTypeCommand.java
index 326ff46..2e7f0df 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/TestSubmitTypeCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/TestSubmitTypeCommand.java
@@ -23,7 +23,7 @@
import com.google.inject.Inject;
import com.google.inject.Provider;
-@CommandMetaData(name = "type", descr = "Test prolog submit type")
+@CommandMetaData(name = "type", description = "Test prolog submit type")
final class TestSubmitTypeCommand extends BaseTestPrologCommand {
@Inject
private Provider<TestSubmitType> view;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/VersionCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/VersionCommand.java
index 2066cc2..19888c8 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/VersionCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/VersionCommand.java
@@ -18,7 +18,7 @@
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
-@CommandMetaData(name = "version", descr = "Display gerrit version")
+@CommandMetaData(name = "version", description = "Display gerrit version")
final class VersionCommand extends SshCommand {
@Override
diff --git a/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java b/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
index e53a6fc..dd41f52 100644
--- a/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
+++ b/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
@@ -63,6 +63,7 @@
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.name.Names;
+import com.google.inject.servlet.GuiceFilter;
import com.google.inject.servlet.GuiceServletContextListener;
import com.google.inject.spi.Message;
@@ -71,16 +72,24 @@
import org.slf4j.LoggerFactory;
import java.io.File;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.sql.DataSource;
/** Configures the web application environment for Gerrit Code Review. */
-public class WebAppInitializer extends GuiceServletContextListener {
+public class WebAppInitializer extends GuiceServletContextListener
+ implements Filter {
private static final Logger log =
LoggerFactory.getLogger(WebAppInitializer.class);
@@ -91,6 +100,13 @@
private Injector webInjector;
private Injector sshInjector;
private LifecycleManager manager;
+ private GuiceFilter filter;
+
+ @Override
+ public void doFilter(ServletRequest req, ServletResponse res,
+ FilterChain chain) throws IOException, ServletException {
+ filter.doFilter(req, res, chain);
+ }
private synchronized void init() {
if (manager == null) {
@@ -143,6 +159,7 @@
.setHttpServletRequest(
webInjector.getProvider(HttpServletRequest.class));
+ filter = webInjector.getInstance(GuiceFilter.class);
manager = new LifecycleManager();
manager.add(dbInjector);
manager.add(cfgInjector);
@@ -303,18 +320,17 @@
}
@Override
- public void contextInitialized(final ServletContextEvent event) {
- super.contextInitialized(event);
+ public void init(FilterConfig cfg) throws ServletException {
+ contextInitialized(new ServletContextEvent(cfg.getServletContext()));
init();
manager.start();
}
@Override
- public void contextDestroyed(final ServletContextEvent event) {
+ public void destroy() {
if (manager != null) {
manager.stop();
manager = null;
}
- super.contextDestroyed(event);
}
}
diff --git a/gerrit-war/src/main/webapp/WEB-INF/web.xml b/gerrit-war/src/main/webapp/WEB-INF/web.xml
index 205341c..386eb07 100644
--- a/gerrit-war/src/main/webapp/WEB-INF/web.xml
+++ b/gerrit-war/src/main/webapp/WEB-INF/web.xml
@@ -8,14 +8,10 @@
<filter>
<filter-name>guiceFilter</filter-name>
- <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
+ <filter-class>com.google.gerrit.httpd.WebAppInitializer</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
-
- <listener>
- <listener-class>com.google.gerrit.httpd.WebAppInitializer</listener-class>
- </listener>
</web-app>
diff --git a/lib/BUCK b/lib/BUCK
index 18d13cd..44193e7 100644
--- a/lib/BUCK
+++ b/lib/BUCK
@@ -22,9 +22,9 @@
maven_jar(
name = 'gwtorm',
- id = 'gwtorm:gwtorm:1.6',
- bin_sha1 = '61bcb92f438524260429149910b5261d48812419',
- src_sha1 = '2624f9d6a750a8aa8f9a5d4b5062b70cd12d1ae7',
+ id = 'gwtorm:gwtorm:1.7',
+ bin_sha1 = 'ee3b316a023f1422dd4b6654a3d51d0e5690809c',
+ src_sha1 = 'a145bde4cc87a4ff4cec283880e2a03be32cc868',
license = 'Apache2.0',
repository = GERRIT,
)
diff --git a/plugins/cookbook-plugin b/plugins/cookbook-plugin
new file mode 160000
index 0000000..0da2b05
--- /dev/null
+++ b/plugins/cookbook-plugin
@@ -0,0 +1 @@
+Subproject commit 0da2b05c13948dba6a92346538a844a20ee353cc
diff --git a/plugins/helloworld b/plugins/helloworld
deleted file mode 160000
index 6e3c3c8..0000000
--- a/plugins/helloworld
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 6e3c3c8a54e9e0e2c5b2fb9205bbbe3112ea55bb
diff --git a/plugins/replication b/plugins/replication
index fefda22..7ec017f 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit fefda225f42c7d5995f791034704eb4989915972
+Subproject commit 7ec017fbac3f34fffc7af175d0dec181d18c33f2
diff --git a/plugins/reviewnotes b/plugins/reviewnotes
index 36d87e5..1fac69b 160000
--- a/plugins/reviewnotes
+++ b/plugins/reviewnotes
@@ -1 +1 @@
-Subproject commit 36d87e549a4294c1697d68a0160383153b8f7891
+Subproject commit 1fac69b085cf67706a3a124df366d55e1976cd21