Merge "CM3: Add support for dark themes"
diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt
index c59f0e9..2e9c83c 100644
--- a/Documentation/dev-plugins.txt
+++ b/Documentation/dev-plugins.txt
@@ -424,6 +424,14 @@
plugins will make use of the setXXX methods on the ReceivePack to
set additional properties on it.
+[[post-receive-hook]]
+== Post Receive-Pack Hooks
+
+Plugins may register PostReceiveHook instances in order to get
+notified when JGit successfully receives a pack. This may be useful
+for those plugins which would like to monitor changes in Git
+repositories.
+
[[ssh]]
== SSH Commands
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 036392c..0708278 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -3083,6 +3083,8 @@
|`disliked` |optional|One user who disliked this label on the change
(voted negatively, but not the minimum value) as an
link:rest-api-accounts.html#account-info[AccountInfo] entity.
+|`blocking` |optional|If `true`, the label blocks submit operation.
+If not set, the default is false.
|`value` |optional|The voting value of the user who
recommended/disliked this label on the change if it is not
"`+1`"/"`-1`".
diff --git a/ReleaseNotes/ReleaseNotes-2.8.2.txt b/ReleaseNotes/ReleaseNotes-2.8.2.txt
index 67a1135..9b72a77 100644
--- a/ReleaseNotes/ReleaseNotes-2.8.2.txt
+++ b/ReleaseNotes/ReleaseNotes-2.8.2.txt
@@ -66,12 +66,46 @@
an internal server error.
* link:https://code.google.com/p/gerrit/issues/detail?id=2331[Issue 2331]:
-Make sure change-merged event contains correct patch set number.
+Make sure `change-merged` event contains correct patch set number.
+
When a change is submitted with the cherry-pick strategy, or when the
change is rebased with the "rebase if necessary" strategy, a new patch
set is created. The newly created patch set was not being set in the
-change-merged event.
+`change-merged` event.
+
+* Guard against `diff.mnemonicprefix` in `commit-msg` hook.
++
+When `diff.mnemonicprefix` was enabled in the git config, committing
+changes with `git commit -v` caused the diff to be included in the
+generated commit message.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2453[Issue 2453]:
+Fix submit rule evaluation for non blocking labels.
++
+Putting a negative score on a label configured as `NoBlock` was causing
+the submit button to be disabled.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2331[Issue 2331]:
+Allow to create branch with new commits.
++
+Branches could not be created with a new commit which is not on other branches
+already.
+
+* Fix incompatibility between "Rebase if Necessary" and "copy scores".
++
+When a project was set up with "Rebase if Necessary", one of its labels had
+`copyAllScoresOnTrivialRebase` or `copyMaxScore`, and a change that actually
+needed a trivial rebase was submitted, Gerrit first rebased the change, and in
+the process copied the approval for the label. It then copied all the
+approvals, including the one already copied, which resulted in a constraint
+violation on the database.
+
+* Add `Implementation-Vendor` default manifest entry for plugins.
++
+In buck, the `java_binary` rule merges manifest entries from dependent JARs
+unless the input JAR possesses these entries itself. This was causing some
+plugins to display the wrong vendor information if they had dependency on
+another JAR file that provided a `Implementation-Vendor` value.
* Remove dependency on joda time library in gerrit launcher.
+
@@ -141,6 +175,19 @@
have a wide display, and better fit on more narrow displays by
splitting the available width at 50%.
+* Fire `comment-added` stream event even when mail notification is not sent.
++
+Unchecking the "and send email" option on the change screen prevented the
+`comment-added` event from being sent to the event stream.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2493[Issue 2493]:
+Set uploader to current user in `patchset-created` event upon rebasing
+a change in the UI.
++
+When a change was rebased from the change screen, the `uploader` field
+of the `patchset-created` event was incorrectly set to the original
+change uploader, rather than the user that performed the rebase.
+
ssh
---
@@ -170,6 +217,8 @@
* Fix aliasing of SSH commands.
+* link:https://code.google.com/p/gerrit/issues/detail?id=2515[Issue 2515]:
+Fix internal server error when updating an existing label with `gerrit review`.
Replication Plugin
------------------
@@ -221,3 +270,7 @@
* Add a link from the plugin documentation to the validation listeners API
documentation.
+
+* Remove double border around code snippets.
+
+* Add border around tables.
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
index 6e6ef37..5c5746b 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -22,6 +22,7 @@
import com.google.common.base.Joiner;
import com.google.common.primitives.Chars;
import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.api.changes.RevisionApi;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.ListChangesOption;
import com.google.gerrit.extensions.restapi.RestApiException;
@@ -196,4 +197,10 @@
protected static Gson newGson() {
return OutputFormat.JSON_COMPACT.newGson();
}
+
+ protected RevisionApi revision(PushOneCommit.Result r) throws Exception {
+ return gApi.changes()
+ .id(r.getChangeId())
+ .current();
+ }
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/CustomLabelIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/CustomLabelIT.java
new file mode 100644
index 0000000..f38ac89
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/CustomLabelIT.java
@@ -0,0 +1,153 @@
+// 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.acceptance.server.project;
+
+import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
+import static com.google.gerrit.server.project.Util.category;
+import static com.google.gerrit.server.project.Util.grant;
+import static com.google.gerrit.server.project.Util.value;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.common.data.LabelType;
+import com.google.gerrit.common.data.Permission;
+import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.LabelInfo;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.server.config.AllProjectsName;
+import com.google.gerrit.server.git.MetaDataUpdate;
+import com.google.gerrit.server.git.ProjectConfig;
+import com.google.gerrit.server.group.SystemGroupBackend;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.inject.Inject;
+
+import org.junit.Before;
+import org.junit.Test;
+
+@NoHttpd
+public class CustomLabelIT extends AbstractDaemonTest {
+
+ @Inject
+ private ProjectCache projectCache;
+
+ @Inject
+ private AllProjectsName allProjects;
+
+ @Inject
+ private MetaDataUpdate.Server metaDataUpdateFactory;
+
+ private final LabelType Q = category("CustomLabel",
+ value(1, "Positive"),
+ value(0, "No score"),
+ value(-1, "Negative"));
+
+ @Before
+ public void setUp() throws Exception {
+ ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
+ AccountGroup.UUID anonymousUsers =
+ SystemGroupBackend.getGroup(ANONYMOUS_USERS).getUUID();
+ grant(cfg, Permission.forLabel(Q.getName()), -1, 1, anonymousUsers,
+ "refs/heads/*");
+ saveProjectConfig(cfg);
+ }
+
+ @Test
+ public void customLabelNoOp_NegativeVoteNotBlock() throws Exception {
+ Q.setFunctionName("NoOp");
+ saveLabelConfig();
+ PushOneCommit.Result r = createChange();
+ revision(r).review(new ReviewInput().label(Q.getName(), -1));
+ ChangeInfo c = get(r.getChangeId());
+ LabelInfo q = c.labels.get(Q.getName());
+ assertEquals(1, q.all.size());
+ assertNotNull(q.rejected);
+ assertNull(q.blocking);
+ }
+
+ @Test
+ public void customLabelNoBlock_NegativeVoteNotBlock() throws Exception {
+ Q.setFunctionName("NoBlock");
+ saveLabelConfig();
+ PushOneCommit.Result r = createChange();
+ revision(r).review(new ReviewInput().label(Q.getName(), -1));
+ ChangeInfo c = get(r.getChangeId());
+ LabelInfo q = c.labels.get(Q.getName());
+ assertEquals(1, q.all.size());
+ assertNotNull(q.rejected);
+ assertNull(q.blocking);
+ }
+
+ @Test
+ public void customLabelMaxNoBlock_NegativeVoteNotBlock() throws Exception {
+ Q.setFunctionName("MaxNoBlock");
+ saveLabelConfig();
+ PushOneCommit.Result r = createChange();
+ revision(r).review(new ReviewInput().label(Q.getName(), -1));
+ ChangeInfo c = get(r.getChangeId());
+ LabelInfo q = c.labels.get(Q.getName());
+ assertEquals(1, q.all.size());
+ assertNotNull(q.rejected);
+ assertNull(q.blocking);
+ }
+
+ @Test
+ public void customLabelAnyWithBlock_NegativeVoteBlock() throws Exception {
+ Q.setFunctionName("AnyWithBlock");
+ saveLabelConfig();
+ PushOneCommit.Result r = createChange();
+ revision(r).review(new ReviewInput().label(Q.getName(), -1));
+ ChangeInfo c = get(r.getChangeId());
+ LabelInfo q = c.labels.get(Q.getName());
+ assertEquals(1, q.all.size());
+ assertNull(q.disliked);
+ assertNotNull(q.rejected);
+ assertTrue(q.blocking);
+ }
+
+ @Test
+ public void customLabelMaxWithBlock_NegativeVoteBlock() throws Exception {
+ saveLabelConfig();
+ PushOneCommit.Result r = createChange();
+ revision(r).review(new ReviewInput().label(Q.getName(), -1));
+ ChangeInfo c = get(r.getChangeId());
+ LabelInfo q = c.labels.get(Q.getName());
+ assertEquals(1, q.all.size());
+ assertNull(q.disliked);
+ assertNotNull(q.rejected);
+ assertTrue(q.blocking);
+ }
+
+ private void saveLabelConfig() throws Exception {
+ ProjectConfig cfg = projectCache.checkedGet(allProjects).getConfig();
+ cfg.getLabelSections().put(Q.getName(), Q);
+ saveProjectConfig(cfg);
+ }
+
+ private void saveProjectConfig(ProjectConfig cfg) throws Exception {
+ MetaDataUpdate md = metaDataUpdateFactory.create(allProjects);
+ try {
+ cfg.commit(md);
+ } finally {
+ md.close();
+ }
+ projectCache.evict(allProjects);
+ }
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java
index e94d8f3..a2dd8ec 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/server/project/LabelTypeIT.java
@@ -15,7 +15,6 @@
package com.google.gerrit.acceptance.server.project;
import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.gerrit.extensions.common.ListChangesOption.DETAILED_LABELS;
import static org.junit.Assert.assertEquals;
import com.google.gerrit.acceptance.AbstractDaemonTest;
@@ -23,7 +22,6 @@
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.extensions.api.changes.ReviewInput;
-import com.google.gerrit.extensions.api.changes.RevisionApi;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.LabelInfo;
import com.google.gerrit.server.config.AllProjectsName;
@@ -235,12 +233,6 @@
}
}
- private RevisionApi revision(PushOneCommit.Result r) throws Exception {
- return gApi.changes()
- .id(r.getChangeId())
- .current();
- }
-
private void merge(PushOneCommit.Result r) throws Exception {
revision(r).review(ReviewInput.approve());
revision(r).submit();
@@ -261,7 +253,7 @@
throws Exception {
// Don't use asserts from PushOneCommit so we can test the round-trip
// through JSON instead of querying the DB directly.
- ChangeInfo c = get(r.getChangeId(), DETAILED_LABELS);
+ ChangeInfo c = get(r.getChangeId());
LabelInfo cr = c.labels.get("Code-Review");
assertEquals(1, cr.all.size());
assertEquals("Administrator", cr.all.get(0).name);
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/LabelInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/LabelInfo.java
index 508fd7e..fd6008f 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/LabelInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/LabelInfo.java
@@ -26,4 +26,5 @@
public Map<String, String> values;
public Short value;
public Boolean optional;
+ public Boolean blocking;
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ErrorDialog.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ErrorDialog.java
index 8048c4d..700c701 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ErrorDialog.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ErrorDialog.java
@@ -75,7 +75,7 @@
center.add(body);
center.add(buttons);
- setText(Gerrit.C.errorDialogTitle());
+ setText(Gerrit.C.errorTitle());
addStyleName(Gerrit.RESOURCES.css().errorDialog());
add(center);
@@ -155,8 +155,9 @@
}
}
- public void setText(final String t) {
+ public ErrorDialog setText(final String t) {
text.setText(t);
+ return this;
}
@Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
index c0f91d3..2d20b98 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
@@ -29,8 +29,9 @@
String registerDialogTitle();
String loginTypeUnsupported();
- String errorDialogTitle();
+ String errorTitle();
String errorDialogContinue();
+ String warnTitle();
String confirmationDialogOk();
String confirmationDialogCancel();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
index 27cc303..af530f4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
@@ -10,8 +10,9 @@
registerDialogTitle = Code Review - Register New Account
loginTypeUnsupported = Sign in is not available.
-errorDialogTitle = Code Review - Error
+errorTitle = Code Review - Error
errorDialogContinue = Continue
+warnTitle = Code Review - Warning
confirmationDialogOk = OK
confirmationDialogCancel = Cancel
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
index 1155b9b..b3f0f65 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
@@ -631,11 +631,21 @@
if (allowedCommands.contains(DownloadCommand.CHECKOUT)
|| allowedCommands.contains(DownloadCommand.DEFAULT_DOWNLOADS)) {
commands.add(cmdLinkfactory.new CloneCommandLink());
+ if (Gerrit.getConfig().getSshdAddress() != null && hasUserName()) {
+ commands.add(
+ cmdLinkfactory.new CloneWithCommitMsgHookCommandLink(getProjectKey()));
+ }
}
}
}
}
+ private static boolean hasUserName() {
+ return Gerrit.isSignedIn()
+ && Gerrit.getUserAccount().getUserName() != null
+ && Gerrit.getUserAccount().getUserName().length() > 0;
+ }
+
private class LabeledWidgetsGrid extends FlexTable {
private String labelSuffix;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Labels.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Labels.java
index a88edfa..2680347 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Labels.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Labels.java
@@ -126,10 +126,12 @@
break;
case REJECT:
case IMPOSSIBLE:
- if (current) {
- statusText.setInnerText("Not " + name);
+ if (label.blocking()) {
+ if (current) {
+ statusText.setInnerText("Not " + name);
+ }
+ canSubmit = false;
}
- canSubmit = false;
break;
default:
break;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java
index bc752cf..bfe70b8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfo.java
@@ -160,6 +160,7 @@
public final native String value_text(String n) /*-{ return this.values[n]; }-*/;
public final native boolean optional() /*-{ return this.optional ? true : false; }-*/;
+ public final native boolean blocking() /*-{ return this.blocking ? true : false; }-*/;
final native short _value()
/*-{
if (this.value) return this.value;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadCommandLink.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadCommandLink.java
index 7a477fa..0c0f529 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadCommandLink.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/download/DownloadCommandLink.java
@@ -17,9 +17,11 @@
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand;
+import com.google.gerrit.reviewdb.client.Project;
import com.google.gwt.aria.client.Roles;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwtexpui.clippy.client.CopyableLabel;
@@ -115,6 +117,55 @@
}
}
+ public class CloneWithCommitMsgHookCommandLink extends DownloadCommandLink {
+ private final Project.NameKey project;
+
+ public CloneWithCommitMsgHookCommandLink(Project.NameKey project) {
+ super(DownloadCommand.CHECKOUT, "clone with commmit-msg hook");
+ this.project = project;
+ }
+
+ @Override
+ protected void setCurrentUrl(DownloadUrlLink link) {
+ widget.setVisible(true);
+
+ String sshPort = "29418";
+ String sshAddr = Gerrit.getConfig().getSshdAddress();
+ int p = sshAddr.lastIndexOf(':');
+ if (p != -1 && !sshAddr.endsWith(":")) {
+ sshPort = sshAddr.substring(p + 1);
+ }
+
+ StringBuilder cmd = new StringBuilder();
+ cmd.append("git clone ");
+ cmd.append(link.getUrlData());
+ cmd.append(" && scp -p -P ");
+ cmd.append(sshPort);
+ cmd.append(" ");
+ cmd.append(Gerrit.getUserAccount().getUserName());
+ cmd.append("@");
+
+ if (sshAddr.startsWith("*:") || p == -1) {
+ cmd.append(Window.Location.getHostName());
+ } else {
+ cmd.append(sshAddr.substring(0, p));
+ }
+
+ cmd.append(":hooks/commit-msg ");
+
+ p = project.get().lastIndexOf('/');
+ if (p != -1) {
+ cmd.append(project.get().substring(p + 1));
+ } else {
+ cmd.append(project.get());
+ }
+
+ cmd.append("/.git/hooks/");
+
+ copyLabel.setText(cmd.toString());
+ }
+ }
+
public CopyableCommandLinkFactory(CopyableLabel label, Widget widget) {
copyLabel = label;
this.widget = widget;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java
index fa2eb32..ad96f24 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java
@@ -526,7 +526,8 @@
new ErrorDialog(PatchUtil.C.intralineFailure()).show();
} else if (intralineTimeout) {
intralineTimeout = false;
- new ErrorDialog(PatchUtil.C.intralineTimeout()).show();
+ new ErrorDialog(PatchUtil.C.intralineTimeout()).setText(
+ Gerrit.C.warnTitle()).show();
}
if (topView != null && prefs.get().isRetainHeader()) {
setTopView(topView);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java
index feee430..03d54e4 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java
@@ -15,6 +15,7 @@
package com.google.gerrit.httpd;
import com.google.common.cache.Cache;
+import com.google.common.collect.Lists;
import com.google.gerrit.common.data.Capable;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Project;
@@ -48,6 +49,8 @@
import org.eclipse.jgit.http.server.resolver.AsIsFileService;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.PostReceiveHook;
+import org.eclipse.jgit.transport.PostReceiveHookChain;
import org.eclipse.jgit.transport.ReceivePack;
import org.eclipse.jgit.transport.UploadPack;
import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
@@ -247,13 +250,16 @@
private final AsyncReceiveCommits.Factory factory;
private final TransferConfig config;
private DynamicSet<ReceivePackInitializer> receivePackInitializers;
+ private DynamicSet<PostReceiveHook> postReceiveHooks;
@Inject
ReceiveFactory(AsyncReceiveCommits.Factory factory, TransferConfig config,
- DynamicSet<ReceivePackInitializer> receivePackInitializers) {
+ DynamicSet<ReceivePackInitializer> receivePackInitializers,
+ DynamicSet<PostReceiveHook> postReceiveHooks) {
this.factory = factory;
this.config = config;
this.receivePackInitializers = receivePackInitializers;
+ this.postReceiveHooks = postReceiveHooks;
}
@Override
@@ -273,6 +279,8 @@
rp.setTimeout(config.getTimeout());
rp.setMaxObjectSizeLimit(config.getMaxObjectSizeLimit());
init(pc.getProject().getNameKey(), rp);
+ rp.setPostReceiveHook(PostReceiveHookChain.newChain(
+ Lists.newArrayList(postReceiveHooks)));
req.setAttribute(ATT_RC, rc);
return rp;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeInfoMapper.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeInfoMapper.java
index 4faae5d..9d813fc 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeInfoMapper.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeInfoMapper.java
@@ -117,6 +117,7 @@
lo.disliked = fromAcountInfo(li.disliked);
lo.value = li.value;
lo.optional = li.optional;
+ lo.blocking = li.blocking;
lo.values = li.values;
if (li.all != null) {
lo.all = Lists.newArrayListWithExpectedSize(li.all.size());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
index 6d2dc58..ad6b804 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
@@ -456,6 +456,7 @@
break;
case REJECT:
n.rejected = accountLoader.get(r.appliedBy);
+ n.blocking = true;
break;
default:
break;
@@ -1002,6 +1003,7 @@
public Short value;
public Boolean optional;
+ public Boolean blocking;
void addApproval(ApprovalInfo ai) {
if (all == 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 dd5101d..b581c67 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
@@ -104,6 +104,7 @@
private boolean draft;
private boolean runHooks;
private boolean sendMail;
+ private Account.Id uploader;
@Inject
public PatchSetInserter(ChangeHooks hooks,
@@ -205,6 +206,11 @@
return this;
}
+ public PatchSetInserter setUploader(Account.Id uploader) {
+ this.uploader = uploader;
+ return this;
+ }
+
public Change insert() throws InvalidChangeOperationException, OrmException,
IOException {
init();
@@ -321,6 +327,9 @@
patchSet.setRevision(new RevId(commit.name()));
}
patchSet.setDraft(draft);
+ if (uploader != null) {
+ patchSet.setUploader(uploader);
+ }
}
private void validate() throws InvalidChangeOperationException {
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 d9ec669..25c63b5 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
@@ -395,7 +395,7 @@
continue;
}
- PatchSetApproval c = current.remove(name);
+ PatchSetApproval c = current.remove(lt.getName());
String normName = lt.getName();
if (ent.getValue() == null || ent.getValue() == 0) {
// User requested delete of this label.
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 b0fe0b5..8de6904 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
@@ -299,6 +299,7 @@
.setCopyLabels(true)
.setValidatePolicy(validate)
.setDraft(originalPatchSet.isDraft())
+ .setUploader(uploader.getAccountId())
.setSendMail(sendMail)
.setRunHooks(runHooks);
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 bd4b56f..c6598d4 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
@@ -126,6 +126,7 @@
import com.google.inject.internal.UniqueAnnotations;
import org.apache.velocity.runtime.RuntimeInstance;
+import org.eclipse.jgit.transport.PostReceiveHook;
import java.util.List;
import java.util.Set;
@@ -245,6 +246,7 @@
DynamicMap.mapOf(binder(), CapabilityDefinition.class);
DynamicSet.setOf(binder(), GitReferenceUpdatedListener.class);
DynamicSet.setOf(binder(), ReceivePackInitializer.class);
+ DynamicSet.setOf(binder(), PostReceiveHook.class);
DynamicSet.setOf(binder(), NewProjectCreatedListener.class);
DynamicSet.setOf(binder(), ProjectDeletedListener.class);
DynamicSet.setOf(binder(), HeadUpdatedListener.class);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
index ac2bf9f..847eaee 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
@@ -954,7 +954,7 @@
}
RefControl ctl = projectControl.controlForRef(cmd.getRefName());
- if (ctl.canCreate(rp.getRevWalk(), obj)) {
+ if (ctl.canCreate(rp.getRevWalk(), obj, allRefs.values().contains(obj))) {
validateNewCommits(ctl, cmd);
batch.addCommand(cmd);
} else {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java
index 1096a09..5424887 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java
@@ -269,6 +269,9 @@
for (final Map.Entry<Branch.NameKey, ObjectId> me : modules.entrySet()) {
RevCommit c = myRw.parseCommit(me.getValue());
+ if (c == null) {
+ continue;
+ }
msgbuf.append("\nProject: ");
msgbuf.append(me.getKey().getParentKey().get());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/RebaseIfNecessary.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/RebaseIfNecessary.java
index 7a6ce7a..a97b3fd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/RebaseIfNecessary.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/strategy/RebaseIfNecessary.java
@@ -99,8 +99,9 @@
args.db, n.notes(), n.getPatchsetId())) {
approvals.add(new PatchSetApproval(newPatchSet.getId(), a));
}
- args.db.patchSetApprovals().insert(approvals);
-
+ // rebaseChange.rebase() may already have copied some approvals,
+ // use upsert, not insert, to avoid constraint violation on database
+ args.db.patchSetApprovals().upsert(approvals);
newMergeTip =
(CodeReviewCommit) args.rw.parseCommit(ObjectId
.fromString(newPatchSet.getRevision().get()));
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java
index 621809a..8e8c844 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java
@@ -127,7 +127,7 @@
}
}
- if (!refControl.canCreate(rw, object)) {
+ if (!refControl.canCreate(rw, object, true)) {
throw new AuthException("Cannot create \"" + ref + "\"");
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
index a6ad374..858ff91 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
@@ -233,9 +233,10 @@
*
* @param rw revision pool {@code object} was parsed in.
* @param object the object the user will start the reference with.
+ * @param existsOnServer the object exists on server or not.
* @return {@code true} if the user specified can create a new Git ref
*/
- public boolean canCreate(RevWalk rw, RevObject object) {
+ public boolean canCreate(RevWalk rw, RevObject object, boolean existsOnServer) {
if (!canWrite()) {
return false;
}
@@ -253,8 +254,8 @@
if (object instanceof RevCommit) {
return getCurrentUser().getCapabilities().canAdministrateServer()
|| (owner && !isBlocked(Permission.CREATE))
- || (canPerform(Permission.CREATE) && projectControl.canReadCommit(rw,
- (RevCommit) object));
+ || (canPerform(Permission.CREATE) && (!existsOnServer && canUpdate() || projectControl
+ .canReadCommit(rw, (RevCommit) object)));
} else if (object instanceof RevTag) {
final RevTag tag = (RevTag) object;
try {
diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/tools/root/hooks/commit-msg b/gerrit-server/src/main/resources/com/google/gerrit/server/tools/root/hooks/commit-msg
index 12dcd52..d8f009b 100644
--- a/gerrit-server/src/main/resources/com/google/gerrit/server/tools/root/hooks/commit-msg
+++ b/gerrit-server/src/main/resources/com/google/gerrit/server/tools/root/hooks/commit-msg
@@ -26,7 +26,7 @@
#
add_ChangeId() {
clean_message=`sed -e '
- /^diff --git a\/.*/{
+ /^diff --git .*/{
s///
q
}
@@ -81,7 +81,7 @@
# Skip the line starting with the diff command and everything after it,
# up to the end of the file, assuming it is only patch data.
# If more than one line before the diff was empty, strip all but one.
- /^diff --git a/ {
+ /^diff --git / {
blankLines = 0
while (getline) { }
next
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 58f329f..a3c2cf5 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
@@ -14,6 +14,7 @@
package com.google.gerrit.sshd.commands;
+import com.google.common.collect.Lists;
import com.google.gerrit.common.data.Capable;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Account;
@@ -32,6 +33,8 @@
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.transport.AdvertiseRefsHook;
+import org.eclipse.jgit.transport.PostReceiveHook;
+import org.eclipse.jgit.transport.PostReceiveHookChain;
import org.eclipse.jgit.transport.ReceivePack;
import org.kohsuke.args4j.Option;
import org.slf4j.Logger;
@@ -64,6 +67,9 @@
@Inject
private DynamicSet<ReceivePackInitializer> receivePackInitializers;
+ @Inject
+ private DynamicSet<PostReceiveHook> postReceiveHooks;
+
private final Set<Account.Id> reviewerId = new HashSet<Account.Id>();
private final Set<Account.Id> ccId = new HashSet<Account.Id>();
@@ -103,6 +109,8 @@
rp.setMaxObjectSizeLimit(config.getEffectiveMaxObjectSizeLimit(
projectControl.getProjectState()));
init(rp);
+ rp.setPostReceiveHook(PostReceiveHookChain.newChain(
+ Lists.newArrayList(postReceiveHooks)));
try {
rp.receive(in, out, err);
} catch (UnpackException badStream) {
diff --git a/tools/default.defs b/tools/default.defs
index 0df8c1f..ff4b936 100644
--- a/tools/default.defs
+++ b/tools/default.defs
@@ -152,7 +152,8 @@
mf_src = []
mf_cmd += 'echo "Manifest-Version: 1.0" >$OUT;'
mf_cmd += 'echo "Gerrit-ApiType: %s" >>$OUT;' % type
- mf_cmd += 'echo "Implementation-Version: $v" >>$OUT'
+ mf_cmd += 'echo "Implementation-Version: $v" >>$OUT;'
+ mf_cmd += 'echo "Implementation-Vendor: Gerrit Code Review" >>$OUT'
for line in manifest_entries:
mf_cmd += ';echo "%s" >> $OUT' % line
genrule(