Merge branch 'stable-2.9'

* stable-2.9:
  Link to solved issues from 2.9 release notes
  Reindex: Include exception cause when dying
  Fix the request wrapper for http requests served from plugins
  Fix a possibility to overcome BLOCK permission
  Add asciidoc build back in the Documentation folder
  Change CopyableLabel to hide onKeyUp

Conflicts:
	gerrit-server/src/main/java/com/google/gerrit/server/project/PermissionCollection.java

Change-Id: I1ebcc44873eb12acd80b4a0a98d22a73c69a886c
This commit is contained in:
David Pursehouse
2014-05-16 10:55:32 +09:00
11 changed files with 492 additions and 68 deletions

2
Documentation/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*.html
/.published

95
Documentation/Makefile Normal file
View File

@@ -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 $@+ $@

View File

@@ -0,0 +1,29 @@
[attributes]
asterisk=&#42;
plus=&#43;
caret=&#94;
startsb=&#91;
endsb=&#93;
tilde=&#126;
[specialsections]
GERRIT=gerrituplink
[gerrituplink]
<hr style="
height: 2px;
color: silver;
margin-top: 1.2em;
margin-bottom: 0.5em;
">
[macros]
(?u)^(?P<name>get)::(?P<target>\S*?)$=#
[get-blockmacro]
<a id="{target}" onmousedown="javascript:
var i = document.URL.lastIndexOf('/Documentation/');
var url = document.URL.substring(0, i) + '{target}';
document.getElementById('{target}').href = url;">
GET {target} HTTP/1.0
</a>

View File

@@ -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

View File

@@ -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;

View File

@@ -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;
}
}
}

View File

@@ -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<String> webUrl;
@@ -94,8 +91,7 @@ class HttpPluginServlet extends HttpServlet
private final RestApiServlet managerApi;
private List<Plugin> pending = Lists.newArrayList();
private String base;
private String authorizedBase;
private ContextMapper wrapper;
private final ConcurrentMap<String, PluginHolder> 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<String> 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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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();

View File

@@ -109,8 +109,7 @@ public class PermissionCollection {
List<AccessSection> sections = Lists.newArrayList(sectionToProject.keySet());
sorter.sort(ref, sections);
Set<SeenRule> seen = new HashSet<>();
Set<SeenRule> seenBlockingRules = new HashSet<>();
Set<SeenRule> seen = new HashSet<SeenRule>();
Set<String> exclusiveGroupPermissions = new HashSet<>();
HashMap<String, List<PermissionRule>> 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;
}

View File

@@ -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();