diff --git a/Documentation/.gitignore b/Documentation/.gitignore new file mode 100644 index 0000000000..8a3da24187 --- /dev/null +++ b/Documentation/.gitignore @@ -0,0 +1,2 @@ +*.html +/.published diff --git a/Documentation/Makefile b/Documentation/Makefile new file mode 100644 index 0000000000..59de209ab3 --- /dev/null +++ b/Documentation/Makefile @@ -0,0 +1,95 @@ +# Copyright (C) 2009 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. + +ASCIIDOC ?= asciidoc +ASCIIDOC_EXTRA ?= +ASCIIDOC_VER ?= 8.6.3 +SVN ?= svn +PUB_ROOT ?= https://gerrit-documentation.googlecode.com/svn/Documentation + +all: html + +clean: + rm -f *.html + rm -rf $(LOCAL_ROOT) + +ASCIIDOC_EXE := $(shell which $(ASCIIDOC)) +ifeq ($(wildcard $(ASCIIDOC_EXE)),) + $(error $(ASCIIDOC) must be available) +else + ASCIIDOC_OK := $(shell expr `asciidoc --version | cut -f2 -d' '` \>= $(ASCIIDOC_VER)) + ifeq ($(ASCIIDOC_OK),0) + $(error $(ASCIIDOC) version $(ASCIIDOC_VER) or higher is required) + endif +endif + +ifeq ($(origin VERSION), undefined) + VERSION := $(shell ./GEN-DOC-VERSION 2>/dev/null) +endif + +DOC_HTML := $(patsubst %.txt,%.html,$(wildcard *.txt)) +LOCAL_ROOT := .published +COMMIT := $(shell git describe HEAD | sed s/^v//) +PUB_DIR := $(PUB_ROOT)/$(VERSION) +PRIOR = PRIOR + +ifeq ($(VERSION),) + REVISION = $(COMMIT) +else + ifeq ($(VERSION),$(COMMIT)) + REVISION := $(VERSION) + else + REVISION := $(VERSION) (from v$(COMMIT)) + endif +endif + +html: $(DOC_HTML) + +update: html +ifeq ($(VERSION),) + ./GEN-DOC-VERSION +endif + @-rm -rf $(LOCAL_ROOT) + @echo "Checking out current $(VERSION)" + @if ! $(SVN) checkout $(PUB_DIR) $(LOCAL_ROOT) 2>/dev/null ; then \ + echo "Copying $(PRIOR) to $(VERSION) ..." && \ + $(SVN) cp -m "Create $(VERSION) documentation" $(PUB_ROOT)/$(PRIOR) $(PUB_DIR) && \ + $(SVN) checkout $(PUB_DIR) $(LOCAL_ROOT) ; \ + fi + @rm -f $(LOCAL_ROOT)/*.html + @cp *.html $(LOCAL_ROOT) + @cd $(LOCAL_ROOT) && \ + r=`$(SVN) status | perl -ne 'print if s/^! *//' ` && \ + if [ -n "$$r" ]; then $(SVN) rm $$r; fi && \ + a=`$(SVN) status | perl -ne 'print if s/^\? *//' ` && \ + if [ -n "$$a" ]; then \ + $(SVN) add $$a && \ + $(SVN) propset svn:mime-type text/html $$a ; \ + fi && \ + echo "Committing $(VERSION) at v$(COMMIT)" && \ + $(SVN) commit -m "Updated $(VERSION) documentation to v$(COMMIT)" + @-rm -rf $(LOCAL_ROOT) + +$(DOC_HTML): %.html : %.txt + @echo "FORMAT $@" + @rm -f $@+ $@ + @$(ASCIIDOC) -a toc \ + -a data-uri \ + -a 'revision=$(REVISION)' \ + -a 'newline=\n' \ + -b xhtml11 \ + -f asciidoc.conf \ + $(ASCIIDOC_EXTRA) \ + -o $@+ $< + @mv $@+ $@ diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf new file mode 100644 index 0000000000..2fe6213207 --- /dev/null +++ b/Documentation/asciidoc.conf @@ -0,0 +1,29 @@ +[attributes] +asterisk=* +plus=+ +caret=^ +startsb=[ +endsb=] +tilde=~ + +[specialsections] +GERRIT=gerrituplink + +[gerrituplink] +
+ +[macros] +(?u)^(?Pget)::(?P\S*?)$=# + +[get-blockmacro] + + GET {target} HTTP/1.0 + diff --git a/ReleaseNotes/ReleaseNotes-2.9.txt b/ReleaseNotes/ReleaseNotes-2.9.txt index e7bf4f51c2..2a249adbd1 100644 --- a/ReleaseNotes/ReleaseNotes-2.9.txt +++ b/ReleaseNotes/ReleaseNotes-2.9.txt @@ -40,7 +40,8 @@ Release Highlights ------------------ -* The new change screen is now the default change screen. +* link:http://code.google.com/p/gerrit/issues/detail?id=2065[Issue 2065]: +The new change screen is now the default change screen. + The link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/user-review-ui.html[ @@ -90,12 +91,17 @@ the change history. + The support for the old comment visibility strategy is discontinued. -* Inline comments are shown in the change history. +* link:http://code.google.com/p/gerrit/issues/detail?id=93[Issue 93]: +Inline comments are shown in the change history. -* A reply icon is shown on each change message. +* link:http://code.google.com/p/gerrit/issues/detail?id=592[Issue 592]: +A reply icon is shown on each change message. * Quoting is possible when replying to a comment. +* link:http://code.google.com/p/gerrit/issues/detail?id=2313[Issue 2313]: +Show whether a related change is merged or old. + * New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/user-review-ui.html#related-changes[ Related Changes] tabs: ** `Cherry-Picks` @@ -112,7 +118,8 @@ form: "current patch set/number of patch sets". * Support `[`, `/` and `]` keys to navigate between files in a cycle. -* Show a tooltip on reviewers indicating on which labels they can vote. +* link:http://code.google.com/p/gerrit/issues/detail?id=2078[Issue 2078]: +Show a tooltip on reviewers indicating on which labels they can vote. * The `Submit` button is enabled even if the change is not mergeable. + @@ -124,6 +131,32 @@ single merge commit and submit the changes in reverse order. * If a merge commit is viewed this is highlighted by an icon. In this case the parent commits are also shown. +* link:http://code.google.com/p/gerrit/issues/detail?id=2191[Issue 2191]: +New copy-to-clipboard button for commit ID. + + +New Side-by-Side Diff Screen +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* link:http://code.google.com/p/gerrit/issues/detail?id=348[Issue 348]: +The lines of a patch file are linkable. ++ +These links can be used to directly link to certain inline comments. + +* link:http://code.google.com/p/gerrit/issues/detail?id=2395[Issue 2395]: +The line length preference is used to draw a margin line at that many +columns of text. ++ +This allows a user to configure their preferred width (e.g. 80 columns +or 100 columns) and see the margin, making it easier to identify lines +that run over that width. + +* link:http://code.google.com/p/gerrit/issues/detail?id=2530[Issue 2530]: +All diff preferences are honored. + +* link:http://code.google.com/p/gerrit/issues/detail?id=148[Issue 148]: +The full file path is shown. + Change List / Dashboards ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -151,9 +184,11 @@ Project Screens * The general project screen provides a copyable clone command that automatically installs the `commit-msg` hook. -* Project owners can change `HEAD` from the project branches screen. +* link:http://code.google.com/p/gerrit/issues/detail?id=562[Issue 562]: +Project owners can change `HEAD` from the project branches screen. -* Administrators can change the parent project from the project access +* link:http://code.google.com/p/gerrit/issues/detail?id=1298[Issue 1298]: +Administrators can change the parent project from the project access screen; other users can save changes to the parent project for review and get the change approved by an administrator. @@ -189,7 +224,8 @@ link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/cmd-r review] command allowing to control when email notifications should be sent. -* New `--branch` option on the +* link:http://code.google.com/p/gerrit/issues/detail?id=1752[Issue 1752]: +New `--branch` option on the link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/cmd-review.html[ review] command. @@ -201,7 +237,8 @@ reviewers added on the change. * New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/cmd-apropos.html[ apropos] command to search the Gerrit documentation. -* New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/cmd-create-branch.html[ +* link:http://code.google.com/p/gerrit/issues/detail?id=1156[Issue 1156]: +New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/cmd-create-branch.html[ create-branch] command. REST API @@ -232,7 +269,8 @@ global capability for viewing all accounts]. * New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/access-control.html#capability_viewPlugins[ global capability for viewing the list of installed plugins]. -* New `Change Owner` group that allows to assign label permissions to the change owner. +* link:http://code.google.com/p/gerrit/issues/detail?id=1993[Issue 1993]: +New `Change Owner` group that allows to assign label permissions to the change owner. * Support link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/access-control.html#category_submit_on_behalf_of[ on behalf of for submit]. @@ -268,12 +306,14 @@ is:mergeable] search operator Finds changes that have no merge conflicts and can be merged into the destination branch. -* New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/user-search.html#parentproject[ +* link:http://code.google.com/p/gerrit/issues/detail?id=2163[Issue 2163]: +New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/user-search.html#parentproject[ parentproject] search operator + Finds changes in the specified project or in one of its child projects. -* New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/user-search.html#conflicts[ +* link:http://code.google.com/p/gerrit/issues/detail?id=2162[Issue 2162]: +New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/user-search.html#conflicts[ conflicts] search operator + Finds changes that conflict with the specified change. @@ -330,7 +370,8 @@ Configuration * New init step for installing the `Verified` label. -* link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/config-gerrit.html#repository.name.defaultSubmitType[ +* link:http://code.google.com/p/gerrit/issues/detail?id=2257[Issue 2257]: +link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/config-gerrit.html#repository.name.defaultSubmitType[ Default submit type] for newly created projects can be configured. * `sshd_log` and `httpd_log` can use log4j configuration. @@ -341,6 +382,9 @@ Draft workflow can be disabled]. * link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.9/config-project-config.html#receive.checkReceivedObjects[ Project configuration for checking of received objects]. +* link:http://code.google.com/p/gerrit/issues/detail?id=2318[Issue 2318]: +Allow the text of the "Report Bug" link to be configured. + Misc ~~~~ @@ -348,7 +392,8 @@ Misc * The removal of reviewers and their votes is recorded as a change message. -* The change URL is returned on push if the change is updated. +* link:http://code.google.com/p/gerrit/issues/detail?id=2229[Issue 2229]: +The change URL is returned on push if the change is updated. * The topic is included into merge commit messages if all merged changes have the same topic. @@ -427,6 +472,60 @@ Bug Fixes --------- +Access Rights +~~~~~~~~~~~~~ + + +* Fix possibility to overcome BLOCK permissions. + + +Web UI +~~~~~~ + + +* link:http://code.google.com/p/gerrit/issues/detail?id=2652[Issue 2652]: +Copy label approvals when cherry-picking change to same branch. + +* link:http://code.google.com/p/gerrit/issues/detail?id=2178[Issue 2178]: +Fix background of reply box on new change screen getting transparent. + +* link:http://code.google.com/p/gerrit/issues/detail?id=2362[Issue 2362]: +Show quick approve button only for current patch set. + +* link:http://code.google.com/p/gerrit/issues/detail?id=2405[Issue 2405]: +Update `Patch Sets` drop-down panel when draft patch set is deleted. + +* link:http://code.google.com/p/gerrit/issues/detail?id=2397[Issue 2397]: +Fix linkifying of topics that are set to a URL. + +* link:http://code.google.com/p/gerrit/issues/detail?id=2151[Issue 2151]: +Fix overflowing of long lines in commit message block. + +* link:http://code.google.com/p/gerrit/issues/detail?id=2401[Issue 2401]: +Fix truncated long lines in new side-by-side diff screen. + +* link:http://code.google.com/p/gerrit/issues/detail?id=2225[Issue 2225]: +Display larger icons for Prev / Next and Up to Change links on new +side-by-side diff screen. + +* link:http://code.google.com/p/gerrit/issues/detail?id=2340[Issue 2340]: +Fix selection in new side-by-side diff screen. + +* link:http://code.google.com/p/gerrit/issues/detail?id=2417[Issue 2417]: +Respect base diff revision for files REST call. + +* link:http://code.google.com/p/gerrit/issues/detail?id=2654[Issue 2654]: +Require the user to confirm setting the username. ++ +Once the username has been set, it cannot be edited. This can cause +problems for users who accidentally set the wrong username. A +confirmation dialog now warns the user that setting the username is +permanent and the username is only set when the user confirms. + +* link:https://code.google.com/p/gerrit/issues/detail?id=2635[Issue 2635]: +Fix copying from copyable label in Safari. + + Secondary Index ~~~~~~~~~~~~~~~ @@ -441,15 +540,68 @@ This produced bizarre results for queries like "message:1234". Instead, use Lucene's QueryBuilder with an analyzer to convert a full-text search word/phrase into a phrase query. +* link:http://code.google.com/p/gerrit/issues/detail?id=2281[Issue 2281]: +Reindex change after updating commit message. + + +REST +~~~~ + + +* link:http://code.google.com/p/gerrit/issues/detail?id=2568[Issue 2568]: +Update description file during `PUT /projects/{name}/config`. + + +SSH +~~~ + + +* link:http://code.google.com/p/gerrit/issues/detail?id=2516[Issue 2516]: +Fix parsing of label name on `review` command. + +* link:http://code.google.com/p/gerrit/issues/detail?id=2440[Issue 2440]: +Clarify for review command when `--verified` can be used + + +Plugins +~~~~~~~ + + +* link:http://code.google.com/p/gerrit/issues/detail?id=2551[Issue 2551]: +Handle absolute URLs in the top level menu. + +* link:http://code.google.com/p/gerrit/issues/detail?id=2391[Issue 2391]: +Respect servlet context path in URL for top menu items. + + +Other +~~~~~ + + +* link:http://code.google.com/p/gerrit/issues/detail?id=2382[Issue 2382]: +Clean left over data migration after removal of TrackingIds table + Upgrades -------- * Update JGit to 3.4.0.201405051725-m7 ++ +This upgrade fixes the MissingObjectExceptions in Gerrit that are +described in link:http://code.google.com/p/gerrit/issues/detail?id=2025[ +issue 2025]. + * Update gwtjsonrpc to 1.5 * Update gwtorm to 1.8 * Update guava to 16.0 + * Update H2 to 1.3.174 ++ +This version includes a fix for an LOB deadlock between reading and +updating LOB columns. This could lead to a deadlock between web and SSH +clients as described in +link:http://code.google.com/p/gerrit/issues/detail?id=2365[issue 2365]. + * Update Jetty to 9.1.0.v20131115 * Update Servlet API to 3.1 * Update Lucene to 4.6.0 diff --git a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/CopyableLabel.java b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/CopyableLabel.java index 1a8c275a10..a0392f82ba 100644 --- a/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/CopyableLabel.java +++ b/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/clippy/client/CopyableLabel.java @@ -22,6 +22,8 @@ import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.KeyPressEvent; import com.google.gwt.event.dom.client.KeyPressHandler; +import com.google.gwt.event.dom.client.KeyUpEvent; +import com.google.gwt.event.dom.client.KeyUpHandler; import com.google.gwt.http.client.URL; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DOM; @@ -189,9 +191,14 @@ public class CopyableLabel extends Composite implements HasText { switch (event.getCharCode()) { case 'c': case 'x': - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - hideTextBox(); + textBox.addKeyUpHandler(new KeyUpHandler() { + @Override + public void onKeyUp(final KeyUpEvent event) { + Scheduler.get().scheduleDeferred(new Command() { + public void execute() { + hideTextBox(); + } + }); } }); break; diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/ContextMapper.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/ContextMapper.java new file mode 100644 index 0000000000..47ef52026c --- /dev/null +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/ContextMapper.java @@ -0,0 +1,74 @@ +// Copyright (C) 2014 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License.package com.google.gerrit.httpd.plugins; + +package com.google.gerrit.httpd.plugins; + +import com.google.common.base.Strings; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + +class ContextMapper { + private static final String PLUGINS_PREFIX = "/plugins/"; + private static final String AUTHORIZED_PREFIX = "/a" + PLUGINS_PREFIX; + private final String base; + private final String authorizedBase; + + public ContextMapper(String contextPath) { + base = Strings.nullToEmpty(contextPath) + PLUGINS_PREFIX; + authorizedBase = Strings.nullToEmpty(contextPath) + AUTHORIZED_PREFIX; + } + + private static boolean isAuthorizedCall(HttpServletRequest req) { + return !Strings.isNullOrEmpty(req.getServletPath()) + && req.getServletPath().startsWith(AUTHORIZED_PREFIX); + } + + HttpServletRequest create(HttpServletRequest req, String name) { + String contextPath = (isAuthorizedCall(req) ? authorizedBase : base) + name; + + return new WrappedRequest(req, contextPath); + } + + public String getFullPath(String name) { + return base + name; + } + + private class WrappedRequest extends HttpServletRequestWrapper { + private final String contextPath; + private final String pathInfo; + + private WrappedRequest(HttpServletRequest req, String contextPath) { + super(req); + this.contextPath = contextPath; + this.pathInfo = getRequestURI().substring(contextPath.length()); + } + + @Override + public String getServletPath() { + return ""; + } + + @Override + public String getContextPath() { + return contextPath; + } + + @Override + public String getPathInfo() { + return pathInfo; + } + } + +} 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 8f66b0558f..4dc6f1eb5c 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 @@ -73,7 +73,6 @@ import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; @Singleton @@ -83,8 +82,6 @@ class HttpPluginServlet extends HttpServlet 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 webUrl; @@ -94,8 +91,7 @@ class HttpPluginServlet extends HttpServlet private final RestApiServlet managerApi; private List pending = Lists.newArrayList(); - private String base; - private String authorizedBase; + private ContextMapper wrapper; private final ConcurrentMap plugins = Maps.newConcurrentMap(); @@ -134,9 +130,7 @@ class HttpPluginServlet extends HttpServlet public synchronized void init(ServletConfig config) throws ServletException { super.init(config); - String path = config.getServletContext().getContextPath(); - base = Strings.nullToEmpty(path) + PLUGINS_PREFIX; - authorizedBase = Strings.nullToEmpty(path) + AUTHORIZED_PREFIX; + wrapper = new ContextMapper(config.getServletContext().getContextPath()); for (Plugin plugin : pending) { install(plugin); } @@ -182,7 +176,8 @@ class HttpPluginServlet extends HttpServlet } try { - ServletContext ctx = PluginServletContext.create(plugin, base + name); + ServletContext ctx = + PluginServletContext.create(plugin, wrapper.getFullPath(name)); filter.init(new WrappedFilterConfig(ctx)); } catch (ServletException e) { log.warn(String.format("Plugin %s failed to initialize HTTP", name), e); @@ -220,8 +215,7 @@ class HttpPluginServlet extends HttpServlet return; } - WrappedRequest wr = new WrappedRequest(req, - (isAuthorizedCall(req) ? authorizedBase : base) + name); + HttpServletRequest wr = wrapper.create(req, name); FilterChain chain = new FilterChain() { @Override public void doFilter(ServletRequest req, ServletResponse res) @@ -236,11 +230,6 @@ class HttpPluginServlet extends HttpServlet } } - private boolean isAuthorizedCall(HttpServletRequest req) { - return !Strings.isNullOrEmpty(req.getServletPath()) - && req.getServletPath().startsWith(AUTHORIZED_PREFIX); - } - private static boolean isApiCall(HttpServletRequest req, List parts) { String method = req.getMethod(); int cnt = parts.size(); @@ -258,14 +247,13 @@ class HttpPluginServlet extends HttpServlet return; } - String uri = req.getRequestURI(); - String ctx = req.getContextPath(); - if (uri.length() <= ctx.length()) { + String pathInfo = req.getPathInfo(); + if (pathInfo.length() < 1) { Resource.NOT_FOUND.send(req, res); return; } - String file = uri.substring(ctx.length() + 1); + String file = pathInfo.substring(1); ResourceKey key = new ResourceKey(holder.plugin, file); Resource rsc = resourceCache.getIfPresent(key); if (rsc != null) { @@ -273,6 +261,7 @@ class HttpPluginServlet extends HttpServlet return; } + String uri = req.getRequestURI(); if ("".equals(file)) { res.sendRedirect(uri + holder.docPrefix + "index.html"); return; @@ -675,32 +664,4 @@ class HttpPluginServlet extends HttpServlet } } } - - private static class WrappedRequest extends HttpServletRequestWrapper { - private final String contextPath; - - WrappedRequest(HttpServletRequest req, String contextPath) { - super(req); - this.contextPath = contextPath; - } - - @Override - public String getContextPath() { - return contextPath; - } - - @Override - public String getServletPath() { - return getRequestURI().substring(contextPath.length()); - } - - @Override - public String getRequestURI() { - String uri = super.getRequestURI(); - if (uri.startsWith("/a/")) { - uri = uri.substring(2); - } - return uri; - } - } } diff --git a/gerrit-httpd/src/test/java/com/google/gerrit/httpd/plugins/ContextMapperTest.java b/gerrit-httpd/src/test/java/com/google/gerrit/httpd/plugins/ContextMapperTest.java new file mode 100644 index 0000000000..e032823cf1 --- /dev/null +++ b/gerrit-httpd/src/test/java/com/google/gerrit/httpd/plugins/ContextMapperTest.java @@ -0,0 +1,79 @@ +// Copyright (C) 2014 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License.package com.google.gerrit.httpd.plugins; + +package com.google.gerrit.httpd.plugins; + +import static org.easymock.EasyMock.createNiceMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import javax.servlet.http.HttpServletRequest; + +public class ContextMapperTest { + + private static final String CONTEXT = "/context"; + private static final String PLUGIN_NAME = "my-plugin"; + private static final String RESOURCE = "my-resource"; + + @Test + public void testUnauthorized() throws Exception { + ContextMapper classUnderTest = new ContextMapper(CONTEXT); + + HttpServletRequest originalRequest = + createMockRequest("/plugins/", PLUGIN_NAME + "/" + RESOURCE); + + HttpServletRequest result = + classUnderTest.create(originalRequest, PLUGIN_NAME); + + assertEquals(CONTEXT + "/plugins/" + PLUGIN_NAME, result.getContextPath()); + assertEquals("", result.getServletPath()); + assertEquals("/" + RESOURCE, result.getPathInfo()); + assertEquals(CONTEXT + "/plugins/" + PLUGIN_NAME + "/" + RESOURCE, + result.getRequestURI()); + } + + @Test + public void testAuthorized() throws Exception { + ContextMapper classUnderTest = new ContextMapper(CONTEXT); + + HttpServletRequest originalRequest = + createMockRequest("/a/plugins/", PLUGIN_NAME + "/" + RESOURCE); + + HttpServletRequest result = + classUnderTest.create(originalRequest, PLUGIN_NAME); + + assertEquals(CONTEXT + "/a/plugins/" + PLUGIN_NAME, + result.getContextPath()); + assertEquals("", result.getServletPath()); + assertEquals("/" + RESOURCE, result.getPathInfo()); + assertEquals(CONTEXT + "/a/plugins/" + PLUGIN_NAME + "/" + RESOURCE, + result.getRequestURI()); + } + + private static HttpServletRequest createMockRequest(String servletPath, + String pathInfo) { + HttpServletRequest req = createNiceMock(HttpServletRequest.class); + expect(req.getContextPath()).andStubReturn(CONTEXT); + expect(req.getServletPath()).andStubReturn(servletPath); + expect(req.getPathInfo()).andStubReturn(pathInfo); + String uri = CONTEXT + servletPath + pathInfo; + expect(req.getRequestURI()).andStubReturn(uri); + replay(req); + + return req; + } +} diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Reindex.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Reindex.java index 6d93dcd8a1..62896eacff 100644 --- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Reindex.java +++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Reindex.java @@ -155,7 +155,7 @@ public class Reindex extends SiteProgram { result = indexAll(); index.markReady(true); } catch (Exception e) { - throw die(e.getMessage()); + throw die(e.getMessage(), e); } sysManager.stop(); dbManager.stop(); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/PermissionCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/PermissionCollection.java index f3ad45f52a..63d2b35fa3 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/project/PermissionCollection.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/PermissionCollection.java @@ -109,8 +109,7 @@ public class PermissionCollection { List sections = Lists.newArrayList(sectionToProject.keySet()); sorter.sort(ref, sections); - Set seen = new HashSet<>(); - Set seenBlockingRules = new HashSet<>(); + Set seen = new HashSet(); Set exclusiveGroupPermissions = new HashSet<>(); HashMap> permissions = new HashMap<>(); @@ -125,7 +124,7 @@ public class PermissionCollection { SeenRule s = new SeenRule(section, permission, rule); boolean addRule; if (rule.isBlock()) { - addRule = seenBlockingRules.add(s); + addRule = true; } else { addRule = seen.add(s) && !rule.isDeny() && !exclusivePermissionExists; } diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java index 75063c8b99..54765ac558 100644 --- a/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java +++ b/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java @@ -299,6 +299,15 @@ public class RefControlTest { public void testBlockRule_ParentBlocksChild() { grant(local, PUSH, DEVS, "refs/tags/*"); grant(util.getParentConfig(), PUSH, ANONYMOUS_USERS, "refs/tags/*").setBlock(); + ProjectControl u = util.user(local, DEVS); + assertFalse("u can't update tag", u.controlForRef("refs/tags/V10").canUpdate()); + } + + @Test + public void testBlockRule_ParentBlocksChildEvenIfAlreadyBlockedInChild() { + grant(local, PUSH, DEVS, "refs/tags/*"); + grant(local, PUSH, ANONYMOUS_USERS, "refs/tags/*").setBlock(); + grant(util.getParentConfig(), PUSH, ANONYMOUS_USERS, "refs/tags/*").setBlock(); ProjectControl u = util.user(local, DEVS); assertFalse("u can't update tag", u.controlForRef("refs/tags/V10").canUpdate()); @@ -318,6 +327,23 @@ public class RefControlTest { assertFalse("u can't vote 2", range.contains(2)); } + @Test + public void testBlockLabelRange_ParentBlocksChildEvenIfAlreadyBlockedInChild() { + grant(local, LABEL + "Code-Review", -2, +2, DEVS, "refs/heads/*"); + grant(local, LABEL + "Code-Review", -2, +2, DEVS, "refs/heads/*").setBlock(); + grant(util.getParentConfig(), LABEL + "Code-Review", -2, +2, DEVS, + "refs/heads/*").setBlock(); + + ProjectControl u = util.user(local, DEVS); + + PermissionRange range = + u.controlForRef("refs/heads/master").getRange(LABEL + "Code-Review"); + assertTrue("u can vote -1", range.contains(-1)); + assertTrue("u can vote +1", range.contains(1)); + assertFalse("u can't vote -2", range.contains(-2)); + assertFalse("u can't vote 2", range.contains(2)); + } + @Test public void testUnblockNoForce() { grant(local, PUSH, ANONYMOUS_USERS, "refs/heads/*").setBlock();