Merge "Add REST API to toggle starred change state" into stable-2.8
diff --git a/Documentation/access-control.txt b/Documentation/access-control.txt
index db806cc..189316c 100644
--- a/Documentation/access-control.txt
+++ b/Documentation/access-control.txt
@@ -822,6 +822,10 @@
can always edit the topic name (even without having the `Edit Topic Name`
access right assigned).
+Whether the topic can be edited on closed changes can be controlled
+by the 'Force Edit' flag. If this flag is not set the topic can only be
+edited on open changes.
+
Examples of typical roles in a project
--------------------------------------
diff --git a/Documentation/config-hooks.txt b/Documentation/config-hooks.txt
index e232c0c..5875837 100644
--- a/Documentation/config-hooks.txt
+++ b/Documentation/config-hooks.txt
@@ -126,7 +126,7 @@
Called whenever a change's topic is changed from the Web UI or via the REST API.
====
- topic-changed --change <change id> --changer <changer> --old-topic <old topic> --new-topic <new topic>
+ topic-changed --change <change id> --project <project name> --branch <branch> --changer <changer> --old-topic <old topic> --new-topic <new topic>
====
cla-signed
diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt
index d0e361a..717547b 100644
--- a/Documentation/dev-plugins.txt
+++ b/Documentation/dev-plugins.txt
@@ -650,16 +650,17 @@
UI Extension
------------
-Plugins can contribute their own UI actions on core Gerrit pages.
-This is useful for workflow customization or exposing plugin functionality
-through the UI in addition to SSH commands and the REST API.
+Plugins can contribute UI actions on core Gerrit pages. This is useful
+for workflow customization or exposing plugin functionality through the
+UI in addition to SSH commands and the REST API.
-For instance a plugin to integrate Jira with Gerrit changes may contribute its
-own "File bug" button to allow filing a bug from the change page or plugins to
-integrate continuous integration systems may contribute a "Schedule" button to
-allow a CI build to be scheduled manually from the patch set panel.
+For instance a plugin to integrate Jira with Gerrit changes may
+contribute a "File bug" button to allow filing a bug from the change
+page or plugins to integrate continuous integration systems may
+contribute a "Schedule" button to allow a CI build to be scheduled
+manually from the patch set panel.
-Two different places on core Gerrit pages are currently supported:
+Two different places on core Gerrit pages are supported:
* Change screen
* Project info screen
@@ -768,7 +769,8 @@
}
----
-The module above must be declared in pom.xml for Maven driven plugins:
+The module above must be declared in the `pom.xml` for Maven driven
+plugins:
[source,xml]
----
@@ -777,7 +779,7 @@
</manifestEntries>
----
-or in the BUCK configuration file for Buck driven plugins:
+or in the `BUCK` configuration file for Buck driven plugins:
[source,python]
----
@@ -832,7 +834,8 @@
}
----
-The HTTP module above must be declared in pom.xml for Maven driven plugins:
+The HTTP module above must be declared in the `pom.xml` for Maven
+driven plugins:
[source,xml]
----
@@ -841,7 +844,7 @@
</manifestEntries>
----
-or in the BUCK configuration file for Buck driven plugins
+or in the `BUCK` configuration file for Buck driven plugins
[source,python]
----
@@ -858,7 +861,7 @@
The following prerequisities must be met, to satisfy the capability check:
* user is authenticated
-* user is a member of the Administrators group, or
+* user is a member of a group which has the `Administrate Server` capability, or
* user is a member of a group which has the required capability
The `apply` method is called when the button is clicked. If `UiAction` is
@@ -878,7 +881,7 @@
====
A special case is to bind an endpoint without a view name. This is
-particularly useful for DELETE requests:
+particularly useful for `DELETE` requests:
[source,java]
----
diff --git a/Documentation/index.txt b/Documentation/index.txt
index 9b8acc4..58dae6e 100644
--- a/Documentation/index.txt
+++ b/Documentation/index.txt
@@ -60,7 +60,7 @@
... How to read stats from the JVM
.. High availability
.. Replication
-.. Plugins
+.. link:https://gerrit-review.googlesource.com/#/admin/projects/?filter=plugins%252F[Plugins]
.. link:dev-design.html[System Design]
.. link:config-contact.html[User Contact Information]
.. link:config-reverseproxy.html[Reverse Proxy]
diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt
index 4f25aa8..5bd5e0c 100644
--- a/Documentation/rest-api-config.txt
+++ b/Documentation/rest-api-config.txt
@@ -181,7 +181,7 @@
~~~~~~~~~~~~~~
The `CapabilityInfo` entity contains information about a capability.
-[options="header",width="50%",cols="1,5"]
+[options="header",width="50%",cols="1,6"]
|=================================
|Field Name |Description
|`kind` |`gerritcodereview#capability`
@@ -195,7 +195,7 @@
The `TopMenuEntryInfo` entity contains information about a top menu
entry.
-[options="header",width="50%",cols="1,5"]
+[options="header",width="50%",cols="1,6"]
|=================================
|Field Name |Description
|`name` |Name of the top menu entry.
@@ -208,13 +208,14 @@
The `TopMenuItemInfo` entity contains information about a menu item in
a top menu entry.
-[options="header",width="50%",cols="1,5"]
-|=================================
-|Field Name |Description
-|`url` |The URL of the menu item link.
-|`name` |The name of the menu item.
-|`target` |Target attribute of the menu item link.
-|=================================
+[options="header",width="50%",cols="1,^1,5"]
+|========================
+|Field Name ||Description
+|`url` ||The URL of the menu item link.
+|`name` ||The name of the menu item.
+|`target` ||Target attribute of the menu item link.
+|`id` |optional|The `id` attribute of the menu item link.
+|========================
GERRIT
------
diff --git a/gerrit-acceptance-tests/BUCK b/gerrit-acceptance-tests/BUCK
index 6b6a18e..cb946d6 100644
--- a/gerrit-acceptance-tests/BUCK
+++ b/gerrit-acceptance-tests/BUCK
@@ -7,6 +7,7 @@
'//gerrit-common:server',
'//gerrit-extension-api:api',
'//gerrit-launcher:launcher',
+ '//gerrit-lucene:lucene',
'//gerrit-httpd:httpd',
'//gerrit-pgm:init-base',
'//gerrit-pgm:pgm',
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/TopMenu.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/TopMenu.java
index 7389519fc..e5a1f7e 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/TopMenu.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/webui/TopMenu.java
@@ -38,15 +38,21 @@
public final String url;
public final String name;
public final String target;
+ public final String id;
public MenuItem(String name, String url) {
this(name, url, "_blank");
}
public MenuItem(String name, String url, String target) {
+ this(name, url, target, null);
+ }
+
+ public MenuItem(String name, String url, String target, String id) {
this.url = url;
this.name = name;
this.target = target;
+ this.id = id;
}
}
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommand.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommand.java
index ba4f626..032db65 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommand.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyCommand.java
@@ -24,6 +24,7 @@
public static final int M_CTRL = 1 << 16;
public static final int M_ALT = 2 << 16;
public static final int M_META = 4 << 16;
+ public static final int M_SHIFT = 8 << 16;
public static boolean same(final KeyCommand a, final KeyCommand b) {
return a.getClass() == b.getClass() && a.helpText.equals(b.helpText);
@@ -58,6 +59,9 @@
if ((keyMask & M_META) == M_META) {
modifier(b, KeyConstants.I.keyMeta());
}
+ if ((keyMask & M_SHIFT) == M_SHIFT) {
+ modifier(b, KeyConstants.I.keyShift());
+ }
final char c = (char) (keyMask & 0xffff);
switch (c) {
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.java
index 56fb85c..b4cb41e 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.java
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.java
@@ -32,6 +32,7 @@
String keyCtrl();
String keyAlt();
String keyMeta();
+ String keyShift();
String keyEnter();
String keyEsc();
}
diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.properties b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.properties
index e21daf5..2e12b07 100644
--- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.properties
+++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/globalkey/client/KeyConstants.properties
@@ -10,5 +10,6 @@
keyCtrl = Ctrl
keyAlt = Alt
keyMeta = Meta
+keyShift = Shift
keyEnter = Enter
keyEsc = Esc
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
index e73670f..568a15c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
@@ -978,6 +978,9 @@
private static void addExtensionLink(final LinkMenuBar m, final TopMenuItem item) {
final Anchor atag = anchor(item.getName(), item.getUrl());
atag.setTarget(item.getTarget());
+ if (item.getId() != null) {
+ atag.getElement().setAttribute("id", item.getId());
+ }
m.add(atag);
}
}
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 0a01adc..e0c0cd4 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
@@ -69,7 +69,6 @@
import com.google.gwtexpui.globalkey.client.ShowHelpCommand;
import net.codemirror.lib.CodeMirror;
-import net.codemirror.lib.CodeMirror.EventHandler;
import net.codemirror.lib.CodeMirror.GutterClickHandler;
import net.codemirror.lib.CodeMirror.LineClassWhere;
import net.codemirror.lib.CodeMirror.LineHandle;
@@ -111,7 +110,6 @@
private CodeMirror cmA;
private CodeMirror cmB;
- private CodeMirror lastFocused;
private ScrollSynchronizer scrollingGlue;
private HandlerRegistration resizeHandler;
private JsArray<CommentInfo> publishedBase;
@@ -279,17 +277,9 @@
cm.on("focus", new Runnable() {
@Override
public void run() {
- lastFocused = cm;
updateActiveLine(cm).run();
}
});
- cm.on("contextmenu", new EventHandler() {
- @Override
- public void handle(CodeMirror instance, NativeEvent event) {
- CodeMirror.setObjectProperty(event, "codemirrorIgnore", true);
- lastFocused.focus();
- }
- });
cm.addKeyMap(KeyMap.create()
.on("'a'", upToChange(true))
.on("'u'", upToChange(false))
@@ -316,12 +306,30 @@
(header.hasNext() ? header.next : header.up).go();
}
})
- .on("Shift-Alt-/", new Runnable() {
+ .on("Shift-/", new Runnable() {
@Override
public void run() {
new ShowHelpCommand().onKeyPress(null);
}
})
+ .on("Ctrl-F", new Runnable() {
+ @Override
+ public void run() {
+ CodeMirror.handleVimKey(cm, "/");
+ }
+ })
+ .on("Space", new Runnable() {
+ @Override
+ public void run() {
+ CodeMirror.handleVimKey(cm, "<PageDown>");
+ }
+ })
+ .on("Ctrl-A", new Runnable() {
+ @Override
+ public void run() {
+ cm.execCommand("selectAll");
+ }
+ })
.on("N", maybeNextVimSearch(cm))
.on("P", diffChunkNav(cm, true))
.on("Shift-O", openClosePublished(cm))
@@ -336,9 +344,13 @@
keysNavigation.add(new UpToChangeCommand2(revision, 0, 'u'));
keysNavigation.add(new NoOpKeyCommand(0, 'j', PatchUtil.C.lineNext()));
keysNavigation.add(new NoOpKeyCommand(0, 'k', PatchUtil.C.linePrev()));
+ keysNavigation.add(new NoOpKeyCommand(0, 'n', PatchUtil.C.chunkNext2()));
+ keysNavigation.add(new NoOpKeyCommand(0, 'p', PatchUtil.C.chunkPrev2()));
keysAction = new KeyCommandSet(Gerrit.C.sectionActions());
keysAction.add(new NoOpKeyCommand(0, 'o', PatchUtil.C.expandComment()));
+ keysAction.add(new NoOpKeyCommand(
+ KeyCommand.M_SHIFT, 'o', PatchUtil.C.expandAllCommentsOnCurrentLine()));
keysAction.add(new KeyCommand(0, 'r', PatchUtil.C.toggleReviewed()) {
@Override
public void onKeyPress(KeyPressEvent event) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/extensions/TopMenuItem.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/extensions/TopMenuItem.java
index 7906fd0..22bb981 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/extensions/TopMenuItem.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/extensions/TopMenuItem.java
@@ -20,6 +20,7 @@
public final native String getName() /*-{ return this.name; }-*/;
public final native String getUrl() /*-{ return this.url; }-*/;
public final native String getTarget() /*-{ return this.target; }-*/;
+ public final native String getId() /*-{ return this.id; }-*/;
protected TopMenuItem() {
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java
index c6793d6..908801b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java
@@ -45,10 +45,13 @@
String lineNext();
String chunkPrev();
String chunkNext();
+ String chunkPrev2();
+ String chunkNext2();
String commentPrev();
String commentNext();
String fileList();
String expandComment();
+ String expandAllCommentsOnCurrentLine();
String toggleReviewed();
String markAsReviewedAndGoToNext();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties
index 5259a4c..a1b6192 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties
@@ -27,10 +27,13 @@
lineNext = Next line
chunkPrev = Previous diff chunk or comment
chunkNext = Next diff chunk or comment
+chunkPrev2 = Previous diff chunk
+chunkNext2 = Next diff chunk or search result
commentPrev = Previous comment
commentNext = Next comment
fileList = Browse files in patch set
expandComment = Expand or collapse comment
+expandAllCommentsOnCurrentLine = Expand or collapse all comments on current line
toggleReviewed = Toggle the reviewed flag
markAsReviewedAndGoToNext = Mark patch as reviewed and go to next unreviewed patch
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java b/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java
index 96daa49..c5a047c 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java
@@ -277,11 +277,6 @@
return this.display.scrollbarV;
}-*/;
- public static final native void setObjectProperty(JavaScriptObject obj,
- String name, boolean value) /*-{
- obj[name] = value;
- }-*/;
-
public static final native KeyMap cloneKeyMap(String name) /*-{
var i = $wnd.CodeMirror.keyMap[name];
var o = {};
@@ -291,6 +286,10 @@
return o;
}-*/;
+ public final native void execCommand(String cmd) /*-{
+ this.execCommand(cmd);
+ }-*/;
+
public static final native void addKeyMap(String name, KeyMap km) /*-{
$wnd.CodeMirror.keyMap[name] = km;
}-*/;
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/lib/Loader.java b/gerrit-gwtui/src/main/java/net/codemirror/lib/Loader.java
index 46e7a71..d2954ba 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/lib/Loader.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/lib/Loader.java
@@ -90,7 +90,8 @@
private static void initVimKeys() {
// TODO: Better custom keybindings, remove temporary navigation hacks.
KeyMap km = CodeMirror.cloneKeyMap("vim");
- for (String s : new String[] {"A", "C", "O", "R", "U", "Ctrl-C"}) {
+ for (String s : new String[] {
+ "A", "C", "O", "R", "U", "Ctrl-C", "Ctrl-O"}) {
km.remove(s);
}
CodeMirror.addKeyMap("vim_ro", km);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
index 53abc4c..b2972d9 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
@@ -81,6 +81,8 @@
private static final long serialVersionUID = 1L;
private static final Logger log
= LoggerFactory.getLogger(HttpPluginServlet.class);
+ private static final String PLUGINS_PREFIX = "/plugins/";
+ private static final String AUTHORIZED_PREFIX = "/a" + PLUGINS_PREFIX;
private final MimeUtilFileTypeRegistry mimeUtil;
private final Provider<String> webUrl;
@@ -91,6 +93,7 @@
private List<Plugin> pending = Lists.newArrayList();
private String base;
+ private String authorizedBase;
private final ConcurrentMap<String, PluginHolder> plugins
= Maps.newConcurrentMap();
@@ -129,7 +132,8 @@
super.init(config);
String path = config.getServletContext().getContextPath();
- base = Strings.nullToEmpty(path) + "/plugins/";
+ base = Strings.nullToEmpty(path) + PLUGINS_PREFIX;
+ authorizedBase = Strings.nullToEmpty(path) + AUTHORIZED_PREFIX;
for (Plugin plugin : pending) {
install(plugin);
}
@@ -213,7 +217,8 @@
return;
}
- WrappedRequest wr = new WrappedRequest(req, base + name);
+ WrappedRequest wr = new WrappedRequest(req,
+ (isAuthorizedCall(req) ? authorizedBase : base) + name);
FilterChain chain = new FilterChain() {
@Override
public void doFilter(ServletRequest req, ServletResponse res)
@@ -228,6 +233,11 @@
}
}
+ private boolean isAuthorizedCall(HttpServletRequest req) {
+ return !Strings.isNullOrEmpty(req.getServletPath())
+ && req.getServletPath().startsWith(AUTHORIZED_PREFIX);
+ }
+
private static boolean isApiCall(HttpServletRequest req, List<String> parts) {
String method = req.getMethod();
int cnt = parts.size();
diff --git a/gerrit-plugin-gwtui/pom.xml b/gerrit-plugin-gwtui/pom.xml
new file mode 100644
index 0000000..3c9e2ca
--- /dev/null
+++ b/gerrit-plugin-gwtui/pom.xml
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2012 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>com.google.gerrit</groupId>
+ <artifactId>gerrit-plugin-gwtui</artifactId>
+ <version>2.8-SNAPSHOT</version>
+ <name>Gerrit Code Review - Plugin GWT UI</name>
+
+ <description>
+ API for UI plugins to build with GWT and integrate with Gerrit
+ </description>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.google.gwt</groupId>
+ <artifactId>gwt-user</artifactId>
+ <version>2.5.1</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.gwt</groupId>
+ <artifactId>gwt-dev</artifactId>
+ <version>2.5.1</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.eclipse.m2e</groupId>
+ <artifactId>lifecycle-mapping</artifactId>
+ <version>1.0.0</version>
+ <configuration>
+ <lifecycleMappingMetadata>
+ <pluginExecutions>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>gwt-maven-plugin</artifactId>
+ <versionRange>[2.5.0,)</versionRange>
+ <goals>
+ <goal>resources</goal>
+ <goal>compile</goal>
+ <goal>i18n</goal>
+ <goal>generateAsync</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <execute />
+ </action>
+ </pluginExecution>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-war-plugin</artifactId>
+ <versionRange>[2.1.1,)</versionRange>
+ <goals>
+ <goal>exploded</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <execute />
+ </action>
+ </pluginExecution>
+ </pluginExecutions>
+ </lifecycleMappingMetadata>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>gwt-maven-plugin</artifactId>
+ <configuration>
+ <module>com.google.gerrit.Plugin</module>
+ <disableClassMetadata>true</disableClassMetadata>
+ <disableCastChecking>true</disableCastChecking>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>resources</goal>
+ <goal>compile</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>unpack-sources</id>
+ <phase>package</phase>
+ <configuration>
+ <tasks>
+ <unzip src="${project.build.directory}/${project.artifactId}-${project.version}-sources.jar" dest="${project.build.directory}/unpack_sources" />
+ </tasks>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <sourcepath>${project.build.directory}/unpack_sources</sourcepath>
+ <encoding>ISO-8859-1</encoding>
+ <quiet>true</quiet>
+ <detectOfflineLinks>false</detectOfflineLinks>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ <phase>package</phase>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+ </build>
+</project>
+
diff --git a/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java b/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java
index 96a7b7e..1798f5a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java
@@ -582,6 +582,8 @@
final List<String> args = new ArrayList<String>();
addArg(args, "--change", event.change.id);
+ addArg(args, "--project", event.change.project);
+ addArg(args, "--branch", event.change.branch);
addArg(args, "--changer", getDisplayName(account));
addArg(args, "--old-topic", oldTopic);
addArg(args, "--new-topic", event.change.topic);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Files.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Files.java
index ec8234f..98e2ee9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Files.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Files.java
@@ -37,7 +37,6 @@
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.patch.PatchList;
import com.google.gerrit.server.patch.PatchListCache;
-import com.google.gerrit.server.patch.PatchListEntry;
import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
@@ -45,9 +44,9 @@
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
import org.kohsuke.args4j.Option;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -219,23 +218,49 @@
List<String> pathList = Lists.newArrayListWithCapacity(sz);
RevWalk rw = new RevWalk(reader);
- RevTree o = rw.parseCommit(oldList.getNewId()).getTree();
- RevTree c = rw.parseCommit(curList.getNewId()).getTree();
- for (PatchListEntry p : curList.getPatches()) {
- String path = p.getNewName();
- if (!Patch.COMMIT_MSG.equals(path) && paths.contains(path)) {
- TreeWalk tw = TreeWalk.forPath(reader, path, o, c);
- if (tw != null
- && tw.getRawMode(0) != 0
- && tw.getRawMode(1) != 0
- && tw.idEqual(0, 1)) {
- inserts.add(new AccountPatchReview(
- new Patch.Key(
- resource.getPatchSet().getId(),
- path),
- userId));
- pathList.add(path);
- }
+ TreeWalk tw = new TreeWalk(reader);
+ tw.setFilter(PathFilterGroup.createFromStrings(paths));
+ tw.setRecursive(true);
+ int o = tw.addTree(rw.parseCommit(oldList.getNewId()).getTree());
+ int c = tw.addTree(rw.parseCommit(curList.getNewId()).getTree());
+
+ int op = -1;
+ if (oldList.getOldId() != null) {
+ op = tw.addTree(rw.parseCommit(oldList.getOldId()).getTree());
+ }
+
+ int cp = -1;
+ if (curList.getOldId() != null) {
+ cp = tw.addTree(rw.parseCommit(curList.getOldId()).getTree());
+ }
+
+ while (tw.next()) {
+ String path = tw.getPathString();
+ if (tw.getRawMode(o) != 0 && tw.getRawMode(c) != 0
+ && tw.idEqual(o, c)
+ && paths.contains(path)) {
+ // File exists in previously reviewed oldList and in curList.
+ // File content is identical.
+ inserts.add(new AccountPatchReview(
+ new Patch.Key(
+ resource.getPatchSet().getId(),
+ path),
+ userId));
+ pathList.add(path);
+ } else if (op >= 0 && cp >= 0
+ && tw.getRawMode(o) == 0 && tw.getRawMode(c) == 0
+ && tw.getRawMode(op) != 0 && tw.getRawMode(cp) != 0
+ && tw.idEqual(op, cp)
+ && paths.contains(path)) {
+ // File was deleted in previously reviewed oldList and curList.
+ // File exists in ancestor of oldList and curList.
+ // File content is identical in ancestors.
+ inserts.add(new AccountPatchReview(
+ new Patch.Key(
+ resource.getPatchSet().getId(),
+ path),
+ userId));
+ pathList.add(path);
}
}
db.get().accountPatchReviews().insert(inserts);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_74.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_74.java
index f884c73..4a2c477 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_74.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_74.java
@@ -45,7 +45,7 @@
// Grab all the groups since we don't have the cache available
HashMap<AccountGroup.Id, AccountGroup.UUID> allGroups =
new HashMap<AccountGroup.Id, AccountGroup.UUID>();
- for( AccountGroup ag : db.accountGroups().all() ) {
+ for (AccountGroup ag : db.accountGroups().all()) {
allGroups.put(ag.getId(), ag.getGroupUUID());
}
@@ -58,54 +58,58 @@
// Iterate over all entries in account_group_includes
Statement oldGroupIncludesStmt = conn.createStatement();
- ResultSet oldGroupIncludes = oldGroupIncludesStmt.
- executeQuery("SELECT * FROM account_group_includes");
- while (oldGroupIncludes.next()) {
- AccountGroup.Id oldGroupId =
- new AccountGroup.Id(oldGroupIncludes.getInt("group_id"));
- AccountGroup.Id oldIncludeId =
- new AccountGroup.Id(oldGroupIncludes.getInt("include_id"));
- AccountGroup.UUID uuidFromIncludeId = allGroups.get(oldIncludeId);
+ try {
+ ResultSet oldGroupIncludes = oldGroupIncludesStmt.
+ executeQuery("SELECT * FROM account_group_includes");
+ while (oldGroupIncludes.next()) {
+ AccountGroup.Id oldGroupId =
+ new AccountGroup.Id(oldGroupIncludes.getInt("group_id"));
+ AccountGroup.Id oldIncludeId =
+ new AccountGroup.Id(oldGroupIncludes.getInt("include_id"));
+ AccountGroup.UUID uuidFromIncludeId = allGroups.get(oldIncludeId);
- // If we've got an include, but the group no longer exists, don't bother converting
- if (uuidFromIncludeId == null) {
- ui.message("Skipping group_id = \"" + oldIncludeId.get() +
- "\", not a current group");
- continue;
- }
-
- // Create the new include entry
- AccountGroupById destIncludeEntry = new AccountGroupById(
- new AccountGroupById.Key(oldGroupId, uuidFromIncludeId));
-
- // Iterate over all the audits (for this group)
- PreparedStatement oldAuditsQuery = conn.prepareStatement(
- "SELECT * FROM account_group_includes_audit WHERE group_id=? AND include_id=?");
- oldAuditsQuery.setInt(1, oldGroupId.get());
- oldAuditsQuery.setInt(2, oldIncludeId.get());
- ResultSet oldGroupIncludeAudits = oldAuditsQuery.executeQuery();
- while (oldGroupIncludeAudits.next()) {
- Account.Id addedBy = new Account.Id(oldGroupIncludeAudits.getInt("added_by"));
- int removedBy = oldGroupIncludeAudits.getInt("removed_by");
-
- // Create the new audit entry
- AccountGroupByIdAud destAuditEntry =
- new AccountGroupByIdAud(destIncludeEntry, addedBy,
- oldGroupIncludeAudits.getTimestamp("added_on"));
-
- // If this was a "removed on" entry, note that
- if (removedBy > 0) {
- destAuditEntry.removed(new Account.Id(removedBy),
- oldGroupIncludeAudits.getTimestamp("removed_on"));
+ // If we've got an include, but the group no longer exists, don't bother converting
+ if (uuidFromIncludeId == null) {
+ ui.message("Skipping group_id = \"" + oldIncludeId.get() +
+ "\", not a current group");
+ continue;
}
- newIncludeAudits.add(destAuditEntry);
+
+ // Create the new include entry
+ AccountGroupById destIncludeEntry = new AccountGroupById(
+ new AccountGroupById.Key(oldGroupId, uuidFromIncludeId));
+
+ // Iterate over all the audits (for this group)
+ PreparedStatement oldAuditsQueryStmt = conn.prepareStatement(
+ "SELECT * FROM account_group_includes_audit WHERE group_id=? AND include_id=?");
+ try {
+ oldAuditsQueryStmt.setInt(1, oldGroupId.get());
+ oldAuditsQueryStmt.setInt(2, oldIncludeId.get());
+ ResultSet oldGroupIncludeAudits = oldAuditsQueryStmt.executeQuery();
+ while (oldGroupIncludeAudits.next()) {
+ Account.Id addedBy = new Account.Id(oldGroupIncludeAudits.getInt("added_by"));
+ int removedBy = oldGroupIncludeAudits.getInt("removed_by");
+
+ // Create the new audit entry
+ AccountGroupByIdAud destAuditEntry =
+ new AccountGroupByIdAud(destIncludeEntry, addedBy,
+ oldGroupIncludeAudits.getTimestamp("added_on"));
+
+ // If this was a "removed on" entry, note that
+ if (removedBy > 0) {
+ destAuditEntry.removed(new Account.Id(removedBy),
+ oldGroupIncludeAudits.getTimestamp("removed_on"));
+ }
+ newIncludeAudits.add(destAuditEntry);
+ }
+ newIncludes.add(destIncludeEntry);
+ } finally {
+ oldAuditsQueryStmt.close();
+ }
}
- newIncludes.add(destIncludeEntry);
- oldAuditsQuery.close();
- oldGroupIncludeAudits.close();
+ } finally {
+ oldGroupIncludesStmt.close();
}
- oldGroupIncludes.close();
- oldGroupIncludesStmt.close();
// Now insert all of the new entries to the database
db.accountGroupById().insert(newIncludes);