Merge "Fix split text issue"
diff --git a/Documentation/config-project-config.txt b/Documentation/config-project-config.txt
index 5da617f..5483d85 100644
--- a/Documentation/config-project-config.txt
+++ b/Documentation/config-project-config.txt
@@ -20,6 +20,11 @@
that you will have to configure push rights for the +refs/meta/config+ name
space if you'd like to use the possibility to automate permission updates.
+== Property inheritance
+
+If a property is set to INHERIT, then the value from the parent project is
+used. If the property is not set in any parent project, the default value is
+FALSE.
[[file-project_config]]
== The file +project.config+
@@ -173,6 +178,22 @@
Default is `INHERIT`, which means that this property is inherited from
the parent project.
+[[receive.rejectImplicitMerges]]receive.rejectImplicitMerges::
++
+Controls whether a check for implicit merges will be performed when changes are
+pushed for review. An implicit merge is a case where merging an open change
+would implicitly merge another branch into the target branch. Typically, this
+happens when a change is done on master and, by mistake, pushed to a stable branch
+for review. When submitting such change, master would be implicitly merged into
+stable without anyone noticing that. When this option is set to 'true' Gerrit
+will reject the push if an implicit merge is detected.
++
+This check is only done for non-merge commits, merge commits are not subject of
+the implicit merge check.
++
+Default is `INHERIT`, which means that this property is inherited from
+the parent project.
+
[[submit-section]]
=== Submit section
diff --git a/Documentation/dev-build-plugins.txt b/Documentation/dev-build-plugins.txt
index 2c04d17..13071df 100644
--- a/Documentation/dev-build-plugins.txt
+++ b/Documentation/dev-build-plugins.txt
@@ -36,7 +36,7 @@
* build and install `SNAPSHOT` version of plugin API in local Maven repository:
----
-buck build api_install
+./tools/maven/api.sh install
----
=== Exception 2:
diff --git a/Documentation/dev-release-deploy-config.txt b/Documentation/dev-release-deploy-config.txt
index 921244f..900e95c 100644
--- a/Documentation/dev-release-deploy-config.txt
+++ b/Documentation/dev-release-deploy-config.txt
@@ -143,10 +143,9 @@
----
[NOTE]
-In case of JGit the `pom.xml` already contains a distributionManagement
-section. Replace the existing distributionManagement section with this snippet
-in order to deploy the artifacts only in the gerrit-maven repository.
-
+In case of JGit the `pom.xml` already contains a `distributionManagement`
+section. To deploy the artifacts to the `gerrit-maven` repository, replace
+the existing `distributionManagement` section with this snippet.
* Add these two snippets to the `pom.xml` to enable the wagon provider:
diff --git a/Documentation/dev-release-jgit.txt b/Documentation/dev-release-jgit.txt
index f6d4d68..1a8b501 100644
--- a/Documentation/dev-release-jgit.txt
+++ b/Documentation/dev-release-jgit.txt
@@ -1,33 +1,44 @@
-= Making a Release of JGit
+= Making a Snapshot Release of JGit
This step is only necessary if we need to create an unofficial JGit
snapshot release and publish it to the
link:https://developers.google.com/storage/[Google Cloud Storage].
+[[prepare-environment]]
+== Prepare the Maven Environment
+
+First, make sure you have done the necessary
+link:dev-release-deploy-config.html#deploy-configuration-settings-xml[
+configuration in Maven `settings.xml`].
+
+To apply the necessary settings in JGit's `pom.xml`, follow the instructions
+in link:dev-release-deploy-config.html#deploy-configuration-subprojects[
+Configuration for Subprojects in `pom.xml`], or apply the provided diff by
+executing the following command in the JGit workspace:
+
+----
+ git apply /path/to/gerrit/tools/jgit-snapshot-deploy-pom.diff
+----
[[prepare-release]]
== Prepare the Release
-Since JGit has its own release process we do not push any release tags
-for JGit. Instead we will use the output of the `git describe` as the
-version of the current JGit snapshot.
+Since JGit has its own release process we do not push any release tags. Instead
+we will use the output of `git describe` as the version of the current JGit
+snapshot.
+
+In the JGit workspace, execute the following command:
----
./tools/version.sh --release $(git describe)
----
-
[[publish-release]]
== Publish the Release
-* Make sure you have done the configuration needed for deployment:
-** link:dev-release-deploy-config.html#deploy-configuration-settings-xml[
-Configuration in Maven `settings.xml`]
-** link:dev-release-deploy-config.html#deploy-configuration-subprojects[
-Configuration for Subprojects in `pom.xml`]
+To deploy the new snapshot, execute the following command in the JGit
+workspace:
-* Deploy the new snapshot. From JGit workspace execute:
-+
----
mvn deploy
----
diff --git a/Documentation/dev-release.txt b/Documentation/dev-release.txt
index 984cbcc..96695db 100644
--- a/Documentation/dev-release.txt
+++ b/Documentation/dev-release.txt
@@ -153,7 +153,7 @@
----
buck clean
buck build --no-cache release docs
- buck build api_install
+ ./tools/maven/api.sh install
----
* Sanity check WAR
@@ -185,13 +185,13 @@
* Push the WAR to Maven Central:
+
----
- sh tools/maven/api.sh war_deploy
+ ./tools/maven/api.sh war_deploy
----
* Push the plugin artifacts to Maven Central:
+
----
- sh tools/maven/api.sh deploy
+ ./tools/maven/api.sh deploy
----
+
If no artifacts are uploaded, clean the `buck-out` folder and retry:
diff --git a/Documentation/rest-api-projects.txt b/Documentation/rest-api-projects.txt
index 2dc203d..457a287 100644
--- a/Documentation/rest-api-projects.txt
+++ b/Documentation/rest-api-projects.txt
@@ -733,6 +733,7 @@
"create_new_change_for_all_not_in_target": "INHERIT",
"enable_signed_push": "INHERIT",
"require_signed_push": "INHERIT",
+ "reject_implicit_merges": "INHERIT",
"require_change_id": "TRUE",
"max_object_size_limit": "10m",
"submit_type": "REBASE_IF_NECESSARY",
@@ -786,6 +787,11 @@
"configured_value": "INHERIT",
"inherited_value": false
},
+ "reject_implicit_merges": {
+ "value": false,
+ "configured_value": "INHERIT",
+ "inherited_value": false
+ },
"max_object_size_limit": {
"value": "10m",
"configured_value": "10m",
@@ -2305,6 +2311,9 @@
|`require_signed_push`|optional, not set if signed push is disabled|
link:#inherited-boolean-info[InheritedBooleanInfo] that tells whether
signed push validation is required on the project.
+|`reject_implicit_merges`|optional|
+link:#inherited-boolean-info[InheritedBooleanInfo] that tells whether
+implicit merges should be rejected on changes pushed to the project.
|`max_object_size_limit` ||
The link:config-gerrit.html#receive.maxObjectSizeLimit[max object size
limit] of this project as a link:#max-object-size-limit-info[
@@ -2373,6 +2382,11 @@
directly to a branch or tag. +
Can be `TRUE`, `FALSE` or `INHERIT`. +
If not set, this setting is not updated.
+|`reject_implicit_merges` |optional|
+Whether a check for implicit merges will be performed when changes
+are pushed for review. +
+Can be `TRUE`, `FALSE` or `INHERIT`. +
+If not set, this setting is not updated.
|`max_object_size_limit` |optional|
The link:config-gerrit.html#receive.maxObjectSizeLimit[max object size
limit] of this project as a link:#max-object-size-limit-info[
diff --git a/Documentation/user-submodules.txt b/Documentation/user-submodules.txt
index 7b5f0a6..2754b45 100644
--- a/Documentation/user-submodules.txt
+++ b/Documentation/user-submodules.txt
@@ -189,18 +189,28 @@
Gerrit will only automatically update superprojects where the
submodules are hosted on the same Gerrit instance as the
-superproject. Gerrit determines this by checking the hostname of the
-submodule specified in the .gitmodules file and comparing it to the
-hostname from the link:config-gerrit.html#gerrit.canonicalWebUrl[`gerrit.canonicalWebUrl`].
+superproject. Gerrit determines this by checking that the URL of the
+submodule specified in the .gitmodules file starts with
+link:config-gerrit.html#gerrit.canonicalWebUrl[`gerrit.canonicalWebUrl`].
+The protocol part is ignored in this check.
It is currently not possible to use the submodule subscription feature
-with a canonical web URL hostname that differs from the hostname of
-the submodule. Instead relative submodules should be used.
+with a canonical web URL that differs from the first part of
+the submodule URL. Instead relative submodules should be used.
-The Gerrit instance administrator group should always certify to
-provide the canonical web URL value in its configuration file. Users
-should certify to use the correct hostname of the running Gerrit
-instance to add/subscribe submodules.
+The Gerrit instance administrator should ensure that the canonical web
+URL value is specified in its configuration file. Users should ensure
+that they use the correct hostname of the running Gerrit instance when
+adding submodule subscriptions.
+
+When converting an existing submodule to use subscription by adding
+a `branch` field into the .gitmodules file, Gerrit does not change
+the revision of the submodule (i.e. update the superproject's gitlink)
+until the next time the branch of the submodule advances. In other words,
+if the currently used revision of the submodule is not the branch's head,
+adding a subscription will not cause an immediate update to the head. In
+this case the revision must be manually updated at the same time as adding
+the subscription.
=== Relative submodules
diff --git a/Documentation/user-upload.txt b/Documentation/user-upload.txt
index 4a90800..dc79018 100644
--- a/Documentation/user-upload.txt
+++ b/Documentation/user-upload.txt
@@ -144,7 +144,13 @@
notify them of new changes will be automatically sent an email
message when the push is completed.
+[[push_options]]
+=== Push Options
+
+Additional options may be specified when pushing changes.
+
[[notify]]
+==== Email Notifications
Uploaders can control to whom email notifications are sent by setting
the `notify` option:
@@ -166,6 +172,8 @@
----
[[topic]]
+==== Topic
+
To include a short tag associated with all of the changes in the
same group, such as the local topic branch name, append it after
the destination branch name or add it with the command line flag
@@ -181,6 +189,8 @@
----
[[message]]
+==== Message
+
A comment message can be applied to the change by using the `message` (or `m`)
option:
@@ -193,6 +203,8 @@
it will then be applied as "This is a rebase on master".
[[review_labels]]
+==== Review Labels
+
Review labels can be applied to the change by using the `label` (or `l`)
option in the reference:
@@ -211,6 +223,8 @@
the label range allows it).
[[change_edit]]
+==== Change Edits
+
A change edit can be pushed by specifying the `edit` (or `e`) option on
the reference:
@@ -243,6 +257,9 @@
$ git push tr:kernel/common HEAD:refs/for/experimental
----
+[[reviewers]]
+==== Reviewers
+
Specific reviewers can be requested and/or additional 'carbon
copies' of the notification message may be sent by including the
`reviewer` (or `r`) and `cc` options in the reference:
diff --git a/ReleaseNotes/ReleaseNotes-2.13.txt b/ReleaseNotes/ReleaseNotes-2.13.txt
index 25e730e..6e8c1a5 100644
--- a/ReleaseNotes/ReleaseNotes-2.13.txt
+++ b/ReleaseNotes/ReleaseNotes-2.13.txt
@@ -295,12 +295,25 @@
=== Misc
+* New project option to reject implicit merge commits.
++
+The 'Reject Implicit Merges' option can be enabled to prevent non-merge commits
+from implicitly bringing unwanted changes into a branch. This can happen for
+example when a commit is made based on one branch but is mistakenly pushed to
+another, for example based on `refs/heads/master` but pushed to `refs/for/stable`.
+
* New link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.13/access-control.html#category_add_patch_set[
Add Patch Set capability] to control who is allowed to upload a new patch
set to an existing change.
* link:https://bugs.chromium.org/p/gerrit/issues/detail?id=4015[Issue 4015]:
-Allow setting a comment message when uploading a change.
+Allow setting a
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.13/user-upload.html#message[
+comment message] when uploading a change.
+
+* Allow to specify
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.13/user-upload.html#notify[
+who should be notified by email] when uploading a change.
* link:https://bugs.chromium.org/p/gerrit/issues/detail?id=3220[Issue 3220]:
Append approval info to every comment-added stream event and hook.
diff --git a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java
index e46176e..5505263 100644
--- a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java
+++ b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java
@@ -388,6 +388,11 @@
.contains(expectedMessage.toLowerCase());
}
+ public String getMessage() {
+ RemoteRefUpdate refUpdate = result.getRemoteUpdate(ref);
+ return message(refUpdate);
+ }
+
private String message(RemoteRefUpdate refUpdate) {
StringBuilder b = new StringBuilder();
if (refUpdate.getMessage() != null) {
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java
index 93525a4..932205a 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/accounts/AccountIT.java
@@ -199,6 +199,15 @@
}
@Test
+ public void active() throws Exception {
+ assertThat(gApi.accounts().id("user").getActive()).isTrue();
+ gApi.accounts().id("user").setActive(false);
+ assertThat(gApi.accounts().id("user").getActive()).isFalse();
+ gApi.accounts().id("user").setActive(true);
+ assertThat(gApi.accounts().id("user").getActive()).isTrue();
+ }
+
+ @Test
public void starUnstarChange() throws Exception {
PushOneCommit.Result r = createChange();
String triplet = project.get() + "~master~" + r.getChangeId();
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
index b2c047a..36ed03a 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
@@ -19,6 +19,7 @@
import static com.google.gerrit.acceptance.PushOneCommit.FILE_NAME;
import static com.google.gerrit.acceptance.PushOneCommit.PATCH;
import static com.google.gerrit.acceptance.PushOneCommit.SUBJECT;
+import static com.google.gerrit.reviewdb.client.Patch.COMMIT_MSG;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.eclipse.jgit.lib.Constants.HEAD;
@@ -44,17 +45,17 @@
import com.google.gerrit.extensions.client.SubmitType;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.ChangeMessageInfo;
+import com.google.gerrit.extensions.common.ChangeType;
import com.google.gerrit.extensions.common.CommentInfo;
import com.google.gerrit.extensions.common.DiffInfo;
+import com.google.gerrit.extensions.common.FileInfo;
import com.google.gerrit.extensions.common.MergeableInfo;
import com.google.gerrit.extensions.common.RevisionInfo;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BinaryResult;
import com.google.gerrit.extensions.restapi.ETagView;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
-import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
-import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.server.change.GetRevisionActions;
import com.google.gerrit.server.change.RevisionResource;
import com.google.gerrit.server.git.ProjectConfig;
@@ -63,13 +64,16 @@
import com.google.inject.Inject;
import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Before;
import org.junit.Test;
import java.io.ByteArrayOutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -512,17 +516,17 @@
@Test
public void files() throws Exception {
PushOneCommit.Result r = createChange();
- assertThat(Iterables.all(gApi.changes()
+ Map<String, FileInfo> files = gApi.changes()
.id(r.getChangeId())
.revision(r.getCommit().name())
- .files()
- .keySet(), new Predicate<String>() {
- @Override
- public boolean apply(String file) {
- return file.matches(FILE_NAME + '|' + Patch.COMMIT_MSG);
- }
- }))
- .isTrue();
+ .files();
+ assertThat(files).hasSize(2);
+ assertThat(Iterables.all(files.keySet(), new Predicate<String>() {
+ @Override
+ public boolean apply(String file) {
+ return file.matches(FILE_NAME + '|' + COMMIT_MSG);
+ }
+ })).isTrue();
}
@Test
@@ -535,7 +539,7 @@
.revision(r.getCommit().name())
.files()
.keySet()
- ).containsExactly(Patch.COMMIT_MSG, "foo", "bar");
+ ).containsExactly(COMMIT_MSG, "foo", "bar");
// list files against parent 1
assertThat(gApi.changes()
@@ -543,7 +547,7 @@
.revision(r.getCommit().name())
.files(1)
.keySet()
- ).containsExactly(Patch.COMMIT_MSG, "bar");
+ ).containsExactly(COMMIT_MSG, "bar");
// list files against parent 2
assertThat(gApi.changes()
@@ -551,19 +555,14 @@
.revision(r.getCommit().name())
.files(2)
.keySet()
- ).containsExactly(Patch.COMMIT_MSG, "foo");
+ ).containsExactly(COMMIT_MSG, "foo");
}
@Test
public void diff() throws Exception {
PushOneCommit.Result r = createChange();
- DiffInfo diff = gApi.changes()
- .id(r.getChangeId())
- .revision(r.getCommit().name())
- .file(FILE_NAME)
- .diff();
- assertThat(diff.metaA).isNull();
- assertThat(diff.metaB.lines).isEqualTo(1);
+ assertDiffForNewFile(r, FILE_NAME, FILE_CONTENT);
+ assertDiffForNewFile(r, COMMIT_MSG, r.getCommit().getFullMessage());
}
@Test
@@ -583,19 +582,6 @@
}
@Test
- public void diffNonExistingFile() throws Exception {
- PushOneCommit.Result r = createChange();
-
- exception.expect(ResourceNotFoundException.class);
- exception.expectMessage("non-existing");
- gApi.changes()
- .id(r.getChangeId())
- .revision(r.getCommit().name())
- .file("non-existing")
- .diff();
- }
-
- @Test
public void diffOnMergeCommitChange() throws Exception {
PushOneCommit.Result r = createMergeCommitChange("refs/for/master");
@@ -640,15 +626,8 @@
@Test
public void content() throws Exception {
PushOneCommit.Result r = createChange();
- BinaryResult bin = gApi.changes()
- .id(r.getChangeId())
- .revision(r.getCommit().name())
- .file(FILE_NAME)
- .content();
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- bin.writeTo(os);
- String res = new String(os.toByteArray(), UTF_8);
- assertThat(res).isEqualTo(FILE_CONTENT);
+ assertContent(r, FILE_NAME, FILE_CONTENT);
+ assertContent(r, COMMIT_MSG, r.getCommit().getFullMessage());
}
@Test
@@ -852,4 +831,88 @@
assertThat(eTag).isNotEqualTo(oldETag);
return eTag;
}
+
+ private void assertContent(PushOneCommit.Result pushResult, String path,
+ String expectedContent) throws Exception {
+ BinaryResult bin = gApi.changes()
+ .id(pushResult.getChangeId())
+ .revision(pushResult.getCommit().name())
+ .file(path)
+ .content();
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ bin.writeTo(os);
+ String res = new String(os.toByteArray(), UTF_8);
+ assertThat(res).isEqualTo(expectedContent);
+ }
+
+ private void assertDiffForNewFile(PushOneCommit.Result pushResult, String path,
+ String expectedContentSideB) throws Exception {
+ DiffInfo diff = gApi.changes()
+ .id(pushResult.getChangeId())
+ .revision(pushResult.getCommit().name())
+ .file(path)
+ .diff();
+
+ List<String> expectedLines = new ArrayList<>();
+ if (path.equals(COMMIT_MSG)) {
+ RevCommit c = pushResult.getCommit();
+
+ RevCommit parentCommit = c.getParents()[0];
+ String parentCommitId = testRepo.getRevWalk().getObjectReader()
+ .abbreviate(parentCommit.getId(), 8).name();
+ expectedLines.add("Parent: " + parentCommitId + " ("
+ + parentCommit.getShortMessage() + ")");
+
+ SimpleDateFormat dtfmt =
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", Locale.US);
+ PersonIdent author = c.getAuthorIdent();
+ dtfmt.setTimeZone(author.getTimeZone());
+ expectedLines.add("Author: " + author.getName() + " <"
+ + author.getEmailAddress() + ">");
+ expectedLines.add("AuthorDate: "
+ + dtfmt.format(Long.valueOf(author.getWhen().getTime())));
+
+ PersonIdent committer = c.getCommitterIdent();
+ dtfmt.setTimeZone(committer.getTimeZone());
+ expectedLines.add("Commit: " + committer.getName() + " <"
+ + committer.getEmailAddress() + ">");
+ expectedLines.add("CommitDate: "
+ + dtfmt.format(Long.valueOf(committer.getWhen().getTime())));
+ expectedLines.add("");
+ }
+
+ for (String line : expectedContentSideB.split("\n")) {
+ expectedLines.add(line);
+ }
+
+ assertThat(diff.binary).isNull();
+ assertThat(diff.changeType).isEqualTo(ChangeType.ADDED);
+ assertThat(diff.diffHeader).isNotNull();
+ assertThat(diff.intralineStatus).isNull();
+ assertThat(diff.webLinks).isNull();
+
+ assertThat(diff.metaA).isNull();
+ assertThat(diff.metaB).isNotNull();
+ assertThat(diff.metaB.commitId).isEqualTo(pushResult.getCommit().name());
+ assertThat(diff.metaB.contentType).isEqualTo(
+ path.equals(COMMIT_MSG)
+ ? "text/x-gerrit-commit-message"
+ : "text/plain");
+ assertThat(diff.metaB.lines).isEqualTo(expectedLines.size());
+ assertThat(diff.metaB.name).isEqualTo(path);
+ assertThat(diff.metaB.webLinks).isNotNull();
+
+ assertThat(diff.content).hasSize(1);
+ DiffInfo.ContentEntry contentEntry = diff.content.get(0);
+ assertThat(contentEntry.b).hasSize(expectedLines.size());
+ for (int i = 0; i < contentEntry.b.size(); i++) {
+ assertThat(contentEntry.b.get(i)).isEqualTo(expectedLines.get(i));
+ }
+ assertThat(contentEntry.a).isNull();
+ assertThat(contentEntry.ab).isNull();
+ assertThat(contentEntry.common).isNull();
+ assertThat(contentEntry.editA).isNull();
+ assertThat(contentEntry.editB).isNull();
+ assertThat(contentEntry.skip).isNull();
+ }
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/ImplicitMergeCheckIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/ImplicitMergeCheckIT.java
new file mode 100644
index 0000000..e7097f0
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/ImplicitMergeCheckIT.java
@@ -0,0 +1,98 @@
+// Copyright (C) 2015 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.git;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.acceptance.GitUtil.pushHead;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.extensions.client.InheritableBoolean;
+import com.google.gerrit.server.git.ProjectConfig;
+
+import org.eclipse.jgit.lib.ObjectId;
+import org.junit.Test;
+
+public class ImplicitMergeCheckIT extends AbstractDaemonTest {
+
+ @Test
+ public void implicitMergeViaFastForward() throws Exception {
+ setRejectImplicitMerges();
+
+ pushHead(testRepo, "refs/heads/stable", false);
+ PushOneCommit.Result m = push("refs/heads/master", "0", "file", "0");
+ PushOneCommit.Result c = push("refs/for/stable", "1", "file", "1");
+
+ c.assertMessage(implicitMergeOf(m.getCommit()));
+ c.assertErrorStatus();
+ }
+
+ @Test
+ public void implicitMergeViaRealMerge() throws Exception {
+ setRejectImplicitMerges();
+
+ ObjectId base = repo().exactRef("HEAD").getObjectId();
+ push("refs/heads/stable", "0", "f", "0");
+ testRepo.reset(base);
+ PushOneCommit.Result m = push("refs/heads/master", "1", "f", "1");
+ PushOneCommit.Result c = push("refs/for/stable", "2", "f", "2");
+
+ c.assertMessage(implicitMergeOf(m.getCommit()));
+ c.assertErrorStatus();
+ }
+
+ @Test
+ public void implicitMergeCheckOff() throws Exception {
+ ObjectId base = repo().exactRef("HEAD").getObjectId();
+ push("refs/heads/stable", "0", "f", "0");
+ testRepo.reset(base);
+ PushOneCommit.Result m = push("refs/heads/master", "1", "f", "1");
+ PushOneCommit.Result c = push("refs/for/stable", "2", "f", "2");
+
+ assertThat(c.getMessage().toLowerCase()).doesNotContain(
+ implicitMergeOf(m.getCommit()));
+ }
+
+ @Test
+ public void notImplicitMerge_noWarning() throws Exception {
+ setRejectImplicitMerges();
+
+ ObjectId base = repo().exactRef("HEAD").getObjectId();
+ push("refs/heads/stable", "0", "f", "0");
+ testRepo.reset(base);
+ PushOneCommit.Result m = push("refs/heads/master", "1", "f", "1");
+ PushOneCommit.Result c = push("refs/for/master", "2", "f", "2");
+
+ assertThat(c.getMessage().toLowerCase()).doesNotContain(
+ implicitMergeOf(m.getCommit()));
+ }
+
+ private static String implicitMergeOf(ObjectId commit) {
+ return "implicit merge of " + commit.abbreviate(7).name();
+ }
+
+ private void setRejectImplicitMerges() throws Exception {
+ ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
+ cfg.getProject().setRejectImplicitMerges(InheritableBoolean.TRUE);
+ saveProjectConfig(project, cfg);
+ }
+
+ private PushOneCommit.Result push(String ref, String subject,
+ String fileName, String content) throws Exception {
+ PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo,
+ subject, fileName, content);
+ return push.to(ref);
+ }
+}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/AccountApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/AccountApi.java
index c1cb3ec..9765bbf 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/AccountApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/accounts/AccountApi.java
@@ -34,6 +34,9 @@
public interface AccountApi {
AccountInfo get() throws RestApiException;
+ boolean getActive() throws RestApiException;
+ void setActive(boolean active) throws RestApiException;
+
String getAvatarUrl(int size) throws RestApiException;
GeneralPreferencesInfo getPreferences() throws RestApiException;
@@ -85,6 +88,16 @@
}
@Override
+ public boolean getActive() throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void setActive(boolean active) throws RestApiException {
+ throw new NotImplementedException();
+ }
+
+ @Override
public String getAvatarUrl(int size) throws RestApiException {
throw new NotImplementedException();
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ConfigInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ConfigInfo.java
index d42bf7b..81c999bc 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ConfigInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ConfigInfo.java
@@ -31,6 +31,7 @@
public InheritedBooleanInfo requireChangeId;
public InheritedBooleanInfo enableSignedPush;
public InheritedBooleanInfo requireSignedPush;
+ public InheritedBooleanInfo rejectImplicitMerges;
public MaxObjectSizeLimitInfo maxObjectSizeLimit;
public SubmitType submitType;
public ProjectState state;
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ConfigInput.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ConfigInput.java
index 71aa24a..8ab13f6 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ConfigInput.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/projects/ConfigInput.java
@@ -29,6 +29,7 @@
public InheritableBoolean requireChangeId;
public InheritableBoolean enableSignedPush;
public InheritableBoolean requireSignedPush;
+ public InheritableBoolean rejectImplicitMerges;
public String maxObjectSizeLimit;
public SubmitType submitType;
public ProjectState state;
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/ChangeAbandonedListener.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/ChangeAbandonedListener.java
index 40b84a3..d18f3e5 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/ChangeAbandonedListener.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/ChangeAbandonedListener.java
@@ -15,14 +15,11 @@
package com.google.gerrit.extensions.events;
import com.google.gerrit.extensions.annotations.ExtensionPoint;
-import com.google.gerrit.extensions.common.AccountInfo;
/** Notified whenever a Change is abandoned. */
@ExtensionPoint
public interface ChangeAbandonedListener {
interface Event extends RevisionEvent {
- @Deprecated
- AccountInfo getAbandoner();
String getReason();
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/ChangeMergedListener.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/ChangeMergedListener.java
index d0ca6d6..de74a86 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/ChangeMergedListener.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/ChangeMergedListener.java
@@ -15,14 +15,11 @@
package com.google.gerrit.extensions.events;
import com.google.gerrit.extensions.annotations.ExtensionPoint;
-import com.google.gerrit.extensions.common.AccountInfo;
/** Notified whenever a Change is merged. */
@ExtensionPoint
public interface ChangeMergedListener {
interface Event extends RevisionEvent {
- @Deprecated
- AccountInfo getMerger();
/**
* Represents the merged Revision when the submit strategy is cherry-pick or
* rebase-if-necessary.
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/ChangeRestoredListener.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/ChangeRestoredListener.java
index e5f3330..f533339 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/ChangeRestoredListener.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/ChangeRestoredListener.java
@@ -15,14 +15,11 @@
package com.google.gerrit.extensions.events;
import com.google.gerrit.extensions.annotations.ExtensionPoint;
-import com.google.gerrit.extensions.common.AccountInfo;
/** Notified whenever a Change is restored. */
@ExtensionPoint
public interface ChangeRestoredListener {
interface Event extends RevisionEvent {
- @Deprecated
- AccountInfo getRestorer();
String getReason();
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/CommentAddedListener.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/CommentAddedListener.java
index 6c82034..e8388a9 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/CommentAddedListener.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/CommentAddedListener.java
@@ -15,7 +15,6 @@
package com.google.gerrit.extensions.events;
import com.google.gerrit.extensions.annotations.ExtensionPoint;
-import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.ApprovalInfo;
import java.util.Map;
@@ -24,8 +23,6 @@
@ExtensionPoint
public interface CommentAddedListener {
interface Event extends RevisionEvent {
- @Deprecated
- AccountInfo getAuthor();
String getComment();
Map<String, ApprovalInfo> getApprovals();
Map<String, ApprovalInfo> getOldApprovals();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/DraftPublishedListener.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/DraftPublishedListener.java
index 3857468..1fc574b 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/DraftPublishedListener.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/DraftPublishedListener.java
@@ -15,14 +15,11 @@
package com.google.gerrit.extensions.events;
import com.google.gerrit.extensions.annotations.ExtensionPoint;
-import com.google.gerrit.extensions.common.AccountInfo;
/** Notified whenever a Draft is published. */
@ExtensionPoint
public interface DraftPublishedListener {
interface Event extends RevisionEvent {
- @Deprecated
- AccountInfo getPublisher();
}
void onDraftPublished(Event event);
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/HashtagsEditedListener.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/HashtagsEditedListener.java
index c49b0f3..ad13267 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/HashtagsEditedListener.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/HashtagsEditedListener.java
@@ -15,7 +15,6 @@
package com.google.gerrit.extensions.events;
import com.google.gerrit.extensions.annotations.ExtensionPoint;
-import com.google.gerrit.extensions.common.AccountInfo;
import java.util.Collection;
@@ -23,8 +22,6 @@
@ExtensionPoint
public interface HashtagsEditedListener {
interface Event extends ChangeEvent {
- @Deprecated
- AccountInfo getEditor();
Collection<String> getHashtags();
Collection<String> getAddedHashtags();
Collection<String> getRemovedHashtags();
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/RevisionCreatedListener.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/RevisionCreatedListener.java
index 5e4e095..8d148b7 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/RevisionCreatedListener.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/RevisionCreatedListener.java
@@ -15,14 +15,11 @@
package com.google.gerrit.extensions.events;
import com.google.gerrit.extensions.annotations.ExtensionPoint;
-import com.google.gerrit.extensions.common.AccountInfo;
/** Notified whenever a Change Revision is created. */
@ExtensionPoint
public interface RevisionCreatedListener {
interface Event extends RevisionEvent {
- @Deprecated
- AccountInfo getUploader();
}
void onRevisionCreated(Event event);
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/TopicEditedListener.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/TopicEditedListener.java
index 68ba22c..0c36d9d 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/TopicEditedListener.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/events/TopicEditedListener.java
@@ -15,14 +15,11 @@
package com.google.gerrit.extensions.events;
import com.google.gerrit.extensions.annotations.ExtensionPoint;
-import com.google.gerrit.extensions.common.AccountInfo;
/** Notified whenever a Change Topic is changed. */
@ExtensionPoint
public interface TopicEditedListener {
interface Event extends ChangeEvent {
- @Deprecated
- AccountInfo getEditor();
String getOldTopic();
}
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/BinaryResult.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/BinaryResult.java
index 068d9a0..4fc9ab6 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/BinaryResult.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/restapi/BinaryResult.java
@@ -86,12 +86,6 @@
}
/** Set the character set used to encode text data and return {@code this}. */
- @Deprecated
- public BinaryResult setCharacterEncoding(String encoding) {
- return setCharacterEncoding(Charset.forName(encoding));
- }
-
- /** Set the character set used to encode text data and return {@code this}. */
public BinaryResult setCharacterEncoding(Charset encoding) {
characterEncoding = encoding;
return this;
@@ -235,7 +229,7 @@
StringResult(String str) {
super(str.getBytes(UTF_8));
setContentType("text/plain");
- setCharacterEncoding(UTF_8.name());
+ setCharacterEncoding(UTF_8);
this.str = str;
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
index 511be5f..984c5a3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
@@ -45,6 +45,7 @@
String enableSignedPush();
String requireSignedPush();
String requireChangeID();
+ String rejectImplicitMerges();
String headingMaxObjectSizeLimit();
String headingGroupOptions();
String isVisibleToAll();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
index 3896cad..2fe5978 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
@@ -27,6 +27,7 @@
enableSignedPush = Enable signed push
requireSignedPush = Require signed push
requireChangeID = Require <code>Change-Id</code> in commit message
+rejectImplicitMerges = Reject implicit merges when changes are pushed for review
headingMaxObjectSizeLimit = Maximum Git object size limit
headingGroupOptions = Group Options
isVisibleToAll = Make group visible to all registered users.
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 c948a8e..e1cfa90 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
@@ -85,6 +85,7 @@
private ListBox newChangeForAllNotInTarget;
private ListBox enableSignedPush;
private ListBox requireSignedPush;
+ private ListBox rejectImplicitMerges;
private NpTextBox maxObjectSizeLimit;
private Label effectiveMaxObjectSizeLimit;
private Map<String, Map<String, HasEnabled>> pluginConfigWidgets;
@@ -184,6 +185,7 @@
contributorAgreements.setEnabled(isOwner);
signedOffBy.setEnabled(isOwner);
requireChangeID.setEnabled(isOwner);
+ rejectImplicitMerges.setEnabled(isOwner);
maxObjectSizeLimit.setEnabled(isOwner);
if (pluginConfigWidgets != null) {
@@ -253,6 +255,10 @@
grid.add(Util.C.requireSignedPush(), requireSignedPush);
}
+ rejectImplicitMerges = newInheritedBooleanBox();
+ saveEnabler.listenTo(rejectImplicitMerges);
+ grid.addHtml(Util.C.rejectImplicitMerges(), rejectImplicitMerges);
+
maxObjectSizeLimit = new NpTextBox();
saveEnabler.listenTo(maxObjectSizeLimit);
effectiveMaxObjectSizeLimit = new Label();
@@ -383,6 +389,7 @@
setBool(enableSignedPush, result.enableSignedPush());
setBool(requireSignedPush, result.requireSignedPush());
}
+ setBool(rejectImplicitMerges, result.rejectImplicitMerges());
setSubmitType(result.submitType());
setState(result.state());
maxObjectSizeLimit.setText(result.maxObjectSizeLimit().configuredValue());
@@ -659,7 +666,7 @@
ProjectApi.setConfig(getProjectKey(), descTxt.getText().trim(),
getBool(contributorAgreements), getBool(contentMerge),
getBool(signedOffBy), getBool(newChangeForAllNotInTarget), getBool(requireChangeID),
- esp, rsp,
+ esp, rsp, getBool(rejectImplicitMerges),
maxObjectSizeLimit.getText().trim(),
SubmitType.valueOf(submitType.getValue(submitType.getSelectedIndex())),
ProjectState.valueOf(state.getValue(state.getSelectedIndex())),
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen.java
index 482d8b4..f997412 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen.java
@@ -107,8 +107,13 @@
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
public class ChangeScreen extends Screen {
+ private static final Logger logger =
+ Logger.getLogger(ChangeScreen.class.getName());
+
interface Binder extends UiBinder<HTMLPanel, ChangeScreen> {}
private static final Binder uiBinder = GWT.create(Binder.class);
@@ -914,7 +919,7 @@
}
private void loadConfigInfo(final ChangeInfo info, String base) {
- RevisionInfo rev = info.revision(revision);
+ final RevisionInfo rev = info.revision(revision);
RevisionInfo b = resolveRevisionOrPatchSetId(info, base, null);
CallbackGroup group = new CallbackGroup();
@@ -929,9 +934,25 @@
} else {
loadDiff(b, rev, lastReply, group);
}
- group.done();
+ group.addListener(new AsyncCallback<Void>() {
+ @Override
+ public void onSuccess(Void result) {
+ loadConfigInfo(info, rev);
+ }
- group = new CallbackGroup();
+ @Override
+ public void onFailure(Throwable caught) {
+ logger.log(Level.SEVERE,
+ "Loading file list and inline comments failed: "
+ + caught.getMessage());
+ loadConfigInfo(info, rev);
+ }
+ });
+ group.done();
+ }
+
+ private void loadConfigInfo(final ChangeInfo info, RevisionInfo rev) {
+ CallbackGroup group = new CallbackGroup();
loadCommit(rev, group);
if (loaded) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java
index cc5c9b7..2d868da 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RelatedChanges.java
@@ -215,10 +215,11 @@
EnumSet.of(ListChangesOption.CURRENT_REVISION, ListChangesOption.CURRENT_COMMIT),
new TabChangeListCallback(Tab.CHERRY_PICKS, info.project(), revision));
- // TODO(sbeller): show only on latest revision
- ChangeApi.change(info.legacyId().get()).view("submitted_together")
- .get(new TabChangeListCallback(Tab.SUBMITTED_TOGETHER,
- info.project(), revision));
+ if (info.currentRevision().equals(revision)) {
+ ChangeApi.change(info.legacyId().get()).view("submitted_together")
+ .get(new TabChangeListCallback(Tab.SUBMITTED_TOGETHER,
+ info.project(), revision));
+ }
if (!Gerrit.info().change().isSubmitWholeTopicEnabled()
&& info.topic() != null && !"".equals(info.topic())) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ConfigInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ConfigInfo.java
index 96b25c5..9751b3b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ConfigInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ConfigInfo.java
@@ -56,6 +56,9 @@
public final native InheritedBooleanInfo requireSignedPush()
/*-{ return this.require_signed_push; }-*/;
+ public final native InheritedBooleanInfo rejectImplicitMerges()
+ /*-{ return this.reject_implicit_merges; }-*/;
+
public final SubmitType submitType() {
return SubmitType.valueOf(submitTypeRaw());
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java
index 8e29e4c..10932bc 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectApi.java
@@ -118,6 +118,7 @@
InheritableBoolean requireChangeId,
InheritableBoolean enableSignedPush,
InheritableBoolean requireSignedPush,
+ InheritableBoolean rejectImplicitMerges,
String maxObjectSizeLimit,
SubmitType submitType, ProjectState state,
Map<String, Map<String, ConfigParameterValue>> pluginConfigValues,
@@ -135,6 +136,7 @@
if (requireSignedPush != null) {
in.setRequireSignedPush(requireSignedPush);
}
+ in.setRejectImplicitMerges(rejectImplicitMerges);
in.setMaxObjectSizeLimit(maxObjectSizeLimit);
in.setSubmitType(submitType);
in.setState(state);
@@ -267,6 +269,12 @@
private native void setRequireSignedPushRaw(String v)
/*-{ if(v)this.require_signed_push=v; }-*/;
+ final void setRejectImplicitMerges(InheritableBoolean v) {
+ setRejectImplicitMergesRaw(v.name());
+ }
+ private native void setRejectImplicitMergesRaw(String v)
+ /*-{ if(v)this.reject_implicit_merges=v; }-*/;
+
final native void setMaxObjectSizeLimit(String l)
/*-{ if(l)this.max_object_size_limit=l; }-*/;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/UrlModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/UrlModule.java
index fff43d3..eb77aa7 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/UrlModule.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/UrlModule.java
@@ -29,6 +29,7 @@
import com.google.gerrit.httpd.restapi.ChangesRestApiServlet;
import com.google.gerrit.httpd.restapi.ConfigRestApiServlet;
import com.google.gerrit.httpd.restapi.GroupsRestApiServlet;
+import com.google.gerrit.httpd.restapi.PluginsRestApiServlet;
import com.google.gerrit.httpd.restapi.ProjectsRestApiServlet;
import com.google.gerrit.httpd.rpc.doc.QueryDocumentationFilter;
import com.google.gerrit.reviewdb.client.Change;
@@ -103,6 +104,7 @@
serveRegex("^/(?:a/)?changes/(.*)$").with(ChangesRestApiServlet.class);
serveRegex("^/(?:a/)?config/(.*)$").with(ConfigRestApiServlet.class);
serveRegex("^/(?:a/)?groups/(.*)?$").with(GroupsRestApiServlet.class);
+ serveRegex("^/(?:a/)?plugins/(.*)?$").with(PluginsRestApiServlet.class);
serveRegex("^/(?:a/)?projects/(.*)?$").with(ProjectsRestApiServlet.class);
filter("/Documentation/").through(QueryDocumentationFilter.class);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/NoSuchFileException.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/PluginsRestApiServlet.java
similarity index 61%
rename from gerrit-server/src/main/java/com/google/gerrit/server/project/NoSuchFileException.java
rename to gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/PluginsRestApiServlet.java
index 97173d2..196b067 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/NoSuchFileException.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/PluginsRestApiServlet.java
@@ -12,12 +12,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.project;
+package com.google.gerrit.httpd.restapi;
-public class NoSuchFileException extends Exception {
+import com.google.gerrit.server.plugins.PluginsCollection;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+@Singleton
+public class PluginsRestApiServlet extends RestApiServlet {
private static final long serialVersionUID = 1L;
- public NoSuchFileException(String fileName) {
- super(fileName);
+ @Inject
+ PluginsRestApiServlet(RestApiServlet.Globals globals,
+ Provider<PluginsCollection> plugins) {
+ super(globals, plugins);
}
}
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneChangeIndex.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneChangeIndex.java
index 77b364c..672d12a 100644
--- a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneChangeIndex.java
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneChangeIndex.java
@@ -322,6 +322,9 @@
IndexSearcher[] searchers = new IndexSearcher[indexes.size()];
try {
int realLimit = opts.start() + opts.limit();
+ if (Integer.MAX_VALUE - opts.limit() < opts.start()) {
+ realLimit = Integer.MAX_VALUE;
+ }
TopFieldDocs[] hits = new TopFieldDocs[indexes.size()];
for (int i = 0; i < indexes.size(); i++) {
searchers[i] = indexes.get(i).acquire();
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Project.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Project.java
index 86e6894..74ebb25 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Project.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Project.java
@@ -99,6 +99,8 @@
protected InheritableBoolean enableSignedPush;
protected InheritableBoolean requireSignedPush;
+ protected InheritableBoolean rejectImplicitMerges;
+
protected Project() {
}
@@ -151,6 +153,10 @@
return maxObjectSizeLimit;
}
+ public InheritableBoolean getRejectImplicitMerges() {
+ return rejectImplicitMerges;
+ }
+
public void setUseContributorAgreements(final InheritableBoolean u) {
useContributorAgreements = u;
}
@@ -196,6 +202,10 @@
maxObjectSizeLimit = limit;
}
+ public void setRejectImplicitMerges(InheritableBoolean check) {
+ rejectImplicitMerges = check;
+ }
+
public SubmitType getSubmitType() {
return submitType;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetActive.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetActive.java
index 10b6df9..9864b45 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetActive.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetActive.java
@@ -14,7 +14,6 @@
package com.google.gerrit.server.account;
-import com.google.gerrit.extensions.restapi.BinaryResult;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.inject.Singleton;
@@ -22,9 +21,9 @@
@Singleton
public class GetActive implements RestReadView<AccountResource> {
@Override
- public Object apply(AccountResource rsrc) {
+ public Response<String> apply(AccountResource rsrc) {
if (rsrc.getUser().getAccount().isActive()) {
- return BinaryResult.create("ok\n");
+ return Response.ok("ok");
}
return Response.none();
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/PutAccount.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutAccount.java
index 9197011..239b954 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/PutAccount.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutAccount.java
@@ -15,7 +15,9 @@
package com.google.gerrit.server.account;
import com.google.gerrit.extensions.api.accounts.AccountInput;
+import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.inject.Singleton;
@@ -23,7 +25,7 @@
public class PutAccount
implements RestModifyView<AccountResource, AccountInput> {
@Override
- public Object apply(AccountResource resource, AccountInput input)
+ public Response<AccountInfo> apply(AccountResource resource, AccountInput input)
throws ResourceConflictException {
throw new ResourceConflictException("account exists");
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/PutAgreement.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutAgreement.java
index 2fdf666..b8b902f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/PutAgreement.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/PutAgreement.java
@@ -22,6 +22,7 @@
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
@@ -68,7 +69,7 @@
}
@Override
- public Object apply(AccountResource resource, AgreementInput input)
+ public Response<String> apply(AccountResource resource, AgreementInput input)
throws IOException, OrmException, RestApiException {
if (!agreementsEnabled) {
throw new MethodNotAllowedException("contributor agreements disabled");
@@ -103,7 +104,7 @@
addMembers.addMembers(group.getId(), ImmutableList.of(account.getId()));
agreementSignup.fire(account, agreementName);
- return agreementName;
+ return Response.ok(agreementName);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java
index 2af9f1d..3533fe8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java
@@ -14,6 +14,8 @@
package com.google.gerrit.server.api.accounts;
+import static javax.servlet.http.HttpServletResponse.SC_OK;
+
import com.google.gerrit.common.RawInputUtil;
import com.google.gerrit.common.errors.EmailException;
import com.google.gerrit.extensions.api.accounts.AccountApi;
@@ -31,6 +33,7 @@
import com.google.gerrit.extensions.common.GpgKeyInfo;
import com.google.gerrit.extensions.common.SshKeyInfo;
import com.google.gerrit.extensions.restapi.IdString;
+import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.TopLevelResource;
import com.google.gerrit.server.GpgException;
@@ -38,8 +41,10 @@
import com.google.gerrit.server.account.AccountResource;
import com.google.gerrit.server.account.AddSshKey;
import com.google.gerrit.server.account.CreateEmail;
+import com.google.gerrit.server.account.DeleteActive;
import com.google.gerrit.server.account.DeleteSshKey;
import com.google.gerrit.server.account.DeleteWatchedProjects;
+import com.google.gerrit.server.account.GetActive;
import com.google.gerrit.server.account.GetAgreements;
import com.google.gerrit.server.account.GetAvatar;
import com.google.gerrit.server.account.GetDiffPreferences;
@@ -48,6 +53,7 @@
import com.google.gerrit.server.account.GetSshKeys;
import com.google.gerrit.server.account.GetWatchedProjects;
import com.google.gerrit.server.account.PostWatchedProjects;
+import com.google.gerrit.server.account.PutActive;
import com.google.gerrit.server.account.PutAgreement;
import com.google.gerrit.server.account.SetDiffPreferences;
import com.google.gerrit.server.account.SetEditPreferences;
@@ -99,6 +105,9 @@
private final SshKeys sshKeys;
private final GetAgreements getAgreements;
private final PutAgreement putAgreement;
+ private final GetActive getActive;
+ private final PutActive putActive;
+ private final DeleteActive deleteActive;
@Inject
AccountApiImpl(AccountLoader.Factory ailf,
@@ -126,6 +135,9 @@
SshKeys sshKeys,
GetAgreements getAgreements,
PutAgreement putAgreement,
+ GetActive getActive,
+ PutActive putActive,
+ DeleteActive deleteActive,
@Assisted AccountResource account) {
this.account = account;
this.accountLoaderFactory = ailf;
@@ -153,6 +165,9 @@
this.gpgApiAdapter = gpgApiAdapter;
this.getAgreements = getAgreements;
this.putAgreement = putAgreement;
+ this.getActive = getActive;
+ this.putActive = putActive;
+ this.deleteActive = deleteActive;
}
@Override
@@ -169,6 +184,25 @@
}
@Override
+ public boolean getActive() throws RestApiException {
+ Response<String> result = getActive.apply(account);
+ return result.statusCode() == SC_OK && result.value().equals("ok");
+ }
+
+ @Override
+ public void setActive(boolean active) throws RestApiException {
+ try {
+ if (active) {
+ putActive.apply(account, new PutActive.Input());
+ } else {
+ deleteActive.apply(account, new DeleteActive.Input());
+ }
+ } catch (OrmException | IOException e) {
+ throw new RestApiException("Cannot set active", e);
+ }
+ }
+
+ @Override
public String getAvatarUrl(int size) throws RestApiException {
getAvatar.setSize(size);
return getAvatar.apply(account).location();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java
index 9f2f526..5cf5895 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetDiff.java
@@ -49,7 +49,6 @@
import com.google.gerrit.server.patch.PatchScriptFactory;
import com.google.gerrit.server.project.InvalidChangeOperationException;
import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gerrit.server.project.NoSuchFileException;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState;
import com.google.gwtorm.server.OrmException;
@@ -273,7 +272,7 @@
r.caching(CacheControl.PRIVATE(7, TimeUnit.DAYS));
}
return r;
- } catch (NoSuchChangeException | NoSuchFileException e) {
+ } catch (NoSuchChangeException e) {
throw new ResourceNotFoundException(e.getMessage(), e);
} catch (LargeObjectException e) {
throw new ResourceConflictException(e.getMessage(), e);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/PostCaches.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/PostCaches.java
index 33a458e..f7968c8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/PostCaches.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/PostCaches.java
@@ -67,7 +67,7 @@
}
@Override
- public Object apply(ConfigResource rsrc, Input input)
+ public Response<String> apply(ConfigResource rsrc, Input input)
throws AuthException, BadRequestException, UnprocessableEntityException {
if (input == null || input.operation == null) {
throw new BadRequestException("operation must be specified");
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeAbandoned.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeAbandoned.java
index dd49272..c76e76b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeAbandoned.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeAbandoned.java
@@ -83,22 +83,15 @@
private static class Event extends AbstractRevisionEvent
implements ChangeAbandonedListener.Event {
- private final AccountInfo abandoner;
private final String reason;
Event(ChangeInfo change, RevisionInfo revision, AccountInfo abandoner,
String reason, Timestamp when, NotifyHandling notifyHandling) {
super(change, revision, abandoner, when, notifyHandling);
- this.abandoner = abandoner;
this.reason = reason;
}
@Override
- public AccountInfo getAbandoner() {
- return abandoner;
- }
-
- @Override
public String getReason() {
return reason;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeMerged.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeMerged.java
index 94df1d1..378f2b7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeMerged.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeMerged.java
@@ -81,22 +81,15 @@
private static class Event extends AbstractRevisionEvent
implements ChangeMergedListener.Event {
- private final AccountInfo merger;
private final String newRevisionId;
Event(ChangeInfo change, RevisionInfo revision, AccountInfo merger,
String newRevisionId, Timestamp when) {
super(change, revision, merger, when, NotifyHandling.ALL);
- this.merger = merger;
this.newRevisionId = newRevisionId;
}
@Override
- public AccountInfo getMerger() {
- return merger;
- }
-
- @Override
public String getNewRevisionId() {
return newRevisionId;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeRestored.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeRestored.java
index c853609..05e0d21 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeRestored.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/ChangeRestored.java
@@ -82,22 +82,15 @@
private static class Event extends AbstractRevisionEvent
implements ChangeRestoredListener.Event {
- private AccountInfo restorer;
private String reason;
Event(ChangeInfo change, RevisionInfo revision, AccountInfo restorer,
String reason, Timestamp when) {
super(change, revision, restorer, when, NotifyHandling.ALL);
- this.restorer = restorer;
this.reason = reason;
}
@Override
- public AccountInfo getRestorer() {
- return restorer;
- }
-
- @Override
public String getReason() {
return reason;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/CommentAdded.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/CommentAdded.java
index 85ad8b6..8e27ce9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/CommentAdded.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/CommentAdded.java
@@ -90,7 +90,6 @@
private static class Event extends AbstractRevisionEvent
implements CommentAddedListener.Event {
- private final AccountInfo author;
private final String comment;
private final Map<String, ApprovalInfo> approvals;
private final Map<String, ApprovalInfo> oldApprovals;
@@ -99,18 +98,12 @@
String comment, Map<String, ApprovalInfo> approvals,
Map<String, ApprovalInfo> oldApprovals, Timestamp when) {
super(change, revision, author, when, NotifyHandling.ALL);
- this.author = author;
this.comment = comment;
this.approvals = approvals;
this.oldApprovals = oldApprovals;
}
@Override
- public AccountInfo getAuthor() {
- return author;
- }
-
- @Override
public String getComment() {
return comment;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/DraftPublished.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/DraftPublished.java
index 0895cb8..6b8ce3d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/DraftPublished.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/DraftPublished.java
@@ -78,17 +78,10 @@
private static class Event extends AbstractRevisionEvent
implements DraftPublishedListener.Event {
- private final AccountInfo publisher;
Event(ChangeInfo change, RevisionInfo revision, AccountInfo publisher,
Timestamp when) {
super(change, revision, publisher, when, NotifyHandling.ALL);
- this.publisher = publisher;
- }
-
- @Override
- public AccountInfo getPublisher() {
- return publisher;
}
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/HashtagsEdited.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/HashtagsEdited.java
index fe42d02..f18b963 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/HashtagsEdited.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/HashtagsEdited.java
@@ -81,7 +81,6 @@
private static class Event extends AbstractChangeEvent
implements HashtagsEditedListener.Event {
- private AccountInfo editor;
private Collection<String> updatedHashtags;
private Collection<String> addedHashtags;
private Collection<String> removedHashtags;
@@ -89,18 +88,12 @@
Event(ChangeInfo change, AccountInfo editor, Collection<String> updated,
Collection<String> added, Collection<String> removed, Timestamp when) {
super(change, editor, when, NotifyHandling.ALL);
- this.editor = editor;
this.updatedHashtags = updated;
this.addedHashtags = added;
this.removedHashtags = removed;
}
@Override
- public AccountInfo getEditor() {
- return editor;
- }
-
- @Override
public Collection<String> getHashtags() {
return updatedHashtags;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/RevisionCreated.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/RevisionCreated.java
index 98fa05e..71bc9ec 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/RevisionCreated.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/RevisionCreated.java
@@ -81,17 +81,10 @@
private static class Event extends AbstractRevisionEvent
implements RevisionCreatedListener.Event {
- private final AccountInfo uploader;
Event(ChangeInfo change, RevisionInfo revision, AccountInfo uploader,
Timestamp when, NotifyHandling notify) {
super(change, revision, uploader, when, notify);
- this.uploader = uploader;
- }
-
- @Override
- public AccountInfo getUploader() {
- return uploader;
}
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/TopicEdited.java b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/TopicEdited.java
index 0a0a8ca..77c1647 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/TopicEdited.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/extensions/events/TopicEdited.java
@@ -75,22 +75,15 @@
private static class Event extends AbstractChangeEvent
implements TopicEditedListener.Event {
- private final AccountInfo editor;
private final String oldTopic;
Event(ChangeInfo change, AccountInfo editor, String oldTopic,
Timestamp when) {
super(change, editor, when, NotifyHandling.ALL);
- this.editor = editor;
this.oldTopic = oldTopic;
}
@Override
- public AccountInfo getEditor() {
- return editor;
- }
-
- @Override
public String getOldTopic() {
return oldTopic;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
index 64d9a9c..1721ae2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
@@ -125,6 +125,7 @@
private static final String KEY_CHECK_RECEIVED_OBJECTS = "checkReceivedObjects";
private static final String KEY_ENABLE_SIGNED_PUSH = "enableSignedPush";
private static final String KEY_REQUIRE_SIGNED_PUSH = "requireSignedPush";
+ private static final String KEY_REJECT_IMPLICIT_MERGES = "rejectImplicitMerges";
private static final String SUBMIT = "submit";
private static final String KEY_ACTION = "action";
@@ -491,6 +492,8 @@
p.setRequireSignedPush(getEnum(rc, RECEIVE, null,
KEY_REQUIRE_SIGNED_PUSH, InheritableBoolean.INHERIT));
p.setMaxObjectSizeLimit(rc.getString(RECEIVE, null, KEY_MAX_OBJECT_SIZE_LIMIT));
+ p.setRejectImplicitMerges(getEnum(rc, RECEIVE, null,
+ KEY_REJECT_IMPLICIT_MERGES, InheritableBoolean.INHERIT));
p.setSubmitType(getEnum(rc, SUBMIT, null, KEY_ACTION, defaultSubmitAction));
p.setUseContentMerge(getEnum(rc, SUBMIT, null, KEY_MERGE_CONTENT, InheritableBoolean.INHERIT));
@@ -940,6 +943,8 @@
p.getEnableSignedPush(), InheritableBoolean.INHERIT);
set(rc, RECEIVE, null, KEY_REQUIRE_SIGNED_PUSH,
p.getRequireSignedPush(), InheritableBoolean.INHERIT);
+ set(rc, RECEIVE, null, KEY_REJECT_IMPLICIT_MERGES,
+ p.getRejectImplicitMerges(), InheritableBoolean.INHERIT);
set(rc, SUBMIT, null, KEY_ACTION, p.getSubmitType(), defaultSubmitAction);
set(rc, SUBMIT, null, KEY_MERGE_CONTENT, p.getUseContentMerge(), InheritableBoolean.INHERIT);
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 b431397..697f2c0 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
@@ -1642,8 +1642,8 @@
rp.getRevWalk().sort(RevSort.TOPO);
rp.getRevWalk().sort(RevSort.REVERSE, true);
try {
- rp.getRevWalk().markStart(
- rp.getRevWalk().parseCommit(magicBranch.cmd.getNewId()));
+ RevCommit start = rp.getRevWalk().parseCommit(magicBranch.cmd.getNewId());
+ rp.getRevWalk().markStart(start);
if (magicBranch.baseCommit != null) {
logDebug("Marking {} base commits uninteresting",
magicBranch.baseCommit.size());
@@ -1669,6 +1669,15 @@
receiveConfig.getEffectiveMaxBatchChangesLimit(user);
int total = 0;
int alreadyTracked = 0;
+ boolean rejectImplicitMerges = start.getParentCount() == 1
+ && projectCache.get(project.getNameKey()).isRejectImplicitMerges();
+ Set<RevCommit> mergedParents;
+ if (rejectImplicitMerges) {
+ mergedParents = new HashSet<>();
+ } else {
+ mergedParents = null;
+ }
+
for (;;) {
RevCommit c = rp.getRevWalk().next();
if (c == null) {
@@ -1678,6 +1687,14 @@
String name = c.name();
groupCollector.visit(c);
Collection<Ref> existingRefs = existing.get(c);
+
+ if (rejectImplicitMerges) {
+ for (RevCommit p : c.getParents()) {
+ mergedParents.add(p);
+ }
+ mergedParents.remove(c);
+ }
+
if (!existingRefs.isEmpty()) { // Commit is already tracked.
alreadyTracked++;
// Corner cases where an existing commit might need a new group:
@@ -1751,6 +1768,10 @@
+ " lookups", total, alreadyTracked, newChanges.size(),
pending.size());
+ if (rejectImplicitMerges) {
+ rejectImplicitMerges(mergedParents);
+ }
+
for (Iterator<ChangeLookup> itr = pending.iterator(); itr.hasNext();) {
ChangeLookup p = itr.next();
if (newChangeIds.contains(p.changeKey)) {
@@ -1867,6 +1888,38 @@
}
}
+ private void rejectImplicitMerges(Set<RevCommit> mergedParents)
+ throws MissingObjectException, IncorrectObjectTypeException, IOException {
+ if (!mergedParents.isEmpty()) {
+ Ref targetRef = allRefs.get(magicBranch.ctl.getRefName());
+ if (targetRef != null) {
+ RevWalk rw = rp.getRevWalk();
+ RevCommit tip = rw.parseCommit(targetRef.getObjectId());
+ boolean containsImplicitMerges = true;
+ for (RevCommit p : mergedParents) {
+ containsImplicitMerges &= !rw.isMergedInto(p, tip);
+ }
+
+ if (containsImplicitMerges) {
+ rw.reset();
+ for (RevCommit p : mergedParents) {
+ rw.markStart(p);
+ }
+ rw.markUninteresting(tip);
+ RevCommit c;
+ while ((c = rw.next()) != null) {
+ rw.parseBody(c);
+ messages.add(new CommitValidationMessage(
+ "ERROR: Implicit Merge of " + c.abbreviate(7).name()
+ + " " + c.getShortMessage(), false));
+
+ }
+ reject(magicBranch.cmd, "implicit merges detected");
+ }
+ }
+ }
+ }
+
private void markHeadsAsUninteresting(RevWalk rw, @Nullable String forRef) {
int i = 0;
for (Ref ref : allRefs.values()) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java
index 7c9ca7d..2424a6d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java
@@ -32,7 +32,6 @@
import com.google.gerrit.server.patch.PatchFile;
import com.google.gerrit.server.patch.PatchList;
import com.google.gerrit.server.patch.PatchListNotAvailableException;
-import com.google.gerrit.server.project.NoSuchFileException;
import com.google.gwtorm.client.KeyUtil;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
@@ -147,7 +146,7 @@
try {
currentFileData =
new PatchFile(repo, patchList, pk.get());
- } catch (IOException | NoSuchFileException e) {
+ } catch (IOException e) {
log.warn(String.format(
"Cannot load %s from %s in %s",
pk.getFileName(),
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MailSoyTofuProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MailSoyTofuProvider.java
index 6b24e48..badedbc 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MailSoyTofuProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MailSoyTofuProvider.java
@@ -50,7 +50,7 @@
"RegisterNewEmail.soy",
"ReplacePatchSet.soy",
"Restored.soy",
- "Reverted.soy"
+ "Reverted.soy",
};
private final SitePaths site;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/OutgoingEmail.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/OutgoingEmail.java
index be81b2c..11a439b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/OutgoingEmail.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/OutgoingEmail.java
@@ -500,9 +500,8 @@
Path filePath = args.site.mail_dir.resolve(velocityName);
if (Files.isRegularFile(filePath)) {
return velocifyFile(velocityName);
- } else {
- return soyTextTemplate(name);
}
+ return soyTextTemplate(name);
}
public String joinStrings(Iterable<Object> in, String joiner) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchFile.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchFile.java
index 5008807..e570b3a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchFile.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchFile.java
@@ -16,7 +16,6 @@
import com.google.gerrit.common.errors.NoSuchEntityException;
import com.google.gerrit.reviewdb.client.Patch;
-import com.google.gerrit.server.project.NoSuchFileException;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
@@ -45,7 +44,7 @@
public PatchFile(final Repository repo, final PatchList patchList,
final String fileName) throws MissingObjectException,
- IncorrectObjectTypeException, IOException, NoSuchFileException {
+ IncorrectObjectTypeException, IOException {
this.repo = repo;
this.entry = patchList.get(fileName);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchList.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchList.java
index 01b7563..2a4afb3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchList.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchList.java
@@ -27,7 +27,6 @@
import com.google.gerrit.common.Nullable;
import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gerrit.server.project.NoSuchFileException;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.ObjectId;
@@ -135,13 +134,10 @@
return r;
}
- /** Find an entry by name. */
- public PatchListEntry get(String fileName) throws NoSuchFileException {
- int index = search(fileName);
- if (0 <= index) {
- return patches[index];
- }
- throw new NoSuchFileException(fileName);
+ /** Find an entry by name, returning an empty entry if not present. */
+ public PatchListEntry get(final String fileName) {
+ final int index = search(fileName);
+ return 0 <= index ? patches[index] : PatchListEntry.empty(fileName);
}
private int search(final String fileName) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListEntry.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListEntry.java
index cc913ff..3266f01 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListEntry.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListEntry.java
@@ -46,6 +46,13 @@
import java.util.List;
public class PatchListEntry {
+ private static final byte[] EMPTY_HEADER = {};
+
+ static PatchListEntry empty(final String fileName) {
+ return new PatchListEntry(ChangeType.MODIFIED, PatchType.UNIFIED, null,
+ fileName, EMPTY_HEADER, Collections.<Edit> emptyList(), 0, 0, 0, 0);
+ }
+
private final ChangeType changeType;
private final PatchType patchType;
private final String oldName;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptFactory.java
index 16d44f0..a7d2523 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchScriptFactory.java
@@ -44,7 +44,6 @@
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.InvalidChangeOperationException;
import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gerrit.server.project.NoSuchFileException;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Provider;
import com.google.inject.assistedinject.Assisted;
@@ -191,7 +190,7 @@
@Override
public PatchScript call() throws OrmException, NoSuchChangeException,
LargeObjectException, AuthException,
- InvalidChangeOperationException, IOException, NoSuchFileException {
+ InvalidChangeOperationException, IOException {
if (parentNum < 0) {
validatePatchSetId(psa);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ConfigInfoImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ConfigInfoImpl.java
index 570c2d2..a7ba217 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ConfigInfoImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ConfigInfoImpl.java
@@ -39,7 +39,6 @@
import java.util.TreeMap;
public class ConfigInfoImpl extends ConfigInfo {
-
public ConfigInfoImpl(boolean serverEnableSignedPush,
ProjectControl control,
TransferConfig config,
@@ -60,6 +59,7 @@
new InheritedBooleanInfo();
InheritedBooleanInfo enableSignedPush = new InheritedBooleanInfo();
InheritedBooleanInfo requireSignedPush = new InheritedBooleanInfo();
+ InheritedBooleanInfo rejectImplicitMerges = new InheritedBooleanInfo();
useContributorAgreements.value = projectState.isUseContributorAgreements();
useSignedOffBy.value = projectState.isUseSignedOffBy();
@@ -77,6 +77,7 @@
p.getCreateNewChangeForAllNotInTarget();
enableSignedPush.configuredValue = p.getEnableSignedPush();
requireSignedPush.configuredValue = p.getRequireSignedPush();
+ rejectImplicitMerges.configuredValue = p.getRejectImplicitMerges();
ProjectState parentState = Iterables.getFirst(projectState
.parents(), null);
@@ -90,12 +91,14 @@
parentState.isCreateNewChangeForAllNotInTarget();
enableSignedPush.inheritedValue = projectState.isEnableSignedPush();
requireSignedPush.inheritedValue = projectState.isRequireSignedPush();
+ rejectImplicitMerges.inheritedValue = projectState.isRejectImplicitMerges();
}
this.useContributorAgreements = useContributorAgreements;
this.useSignedOffBy = useSignedOffBy;
this.useContentMerge = useContentMerge;
this.requireChangeId = requireChangeId;
+ this.rejectImplicitMerges = rejectImplicitMerges;
this.createNewChangeForAllNotInTarget = createNewChangeForAllNotInTarget;
if (serverEnableSignedPush) {
this.enableSignedPush = enableSignedPush;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
index 9e5c35f..68d236e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
@@ -440,6 +440,15 @@
});
}
+ public boolean isRejectImplicitMerges() {
+ return getInheritableBoolean(new Function<Project, InheritableBoolean>() {
+ @Override
+ public InheritableBoolean apply(Project input) {
+ return input.getRejectImplicitMerges();
+ }
+ });
+ }
+
public LabelTypes getLabelTypes() {
Map<String, LabelType> types = new LinkedHashMap<>();
for (ProjectState s : treeInOrder()) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutBranch.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutBranch.java
index e06fb86..52bbdf3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutBranch.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutBranch.java
@@ -14,6 +14,7 @@
package com.google.gerrit.server.project;
+import com.google.gerrit.extensions.api.projects.BranchInfo;
import com.google.gerrit.extensions.api.projects.BranchInput;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.RestModifyView;
@@ -23,7 +24,7 @@
public class PutBranch implements RestModifyView<BranchResource, BranchInput> {
@Override
- public Object apply(BranchResource rsrc, BranchInput input)
+ public BranchInfo apply(BranchResource rsrc, BranchInput input)
throws ResourceConflictException {
throw new ResourceConflictException("Branch \"" + rsrc.getBranchInfo().ref
+ "\" already exists");
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutConfig.java
index b91818b..19b5b26 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutConfig.java
@@ -145,6 +145,10 @@
}
}
+ if (input.rejectImplicitMerges != null) {
+ p.setRejectImplicitMerges(input.rejectImplicitMerges);
+ }
+
if (input.maxObjectSizeLimit != null) {
p.setMaxObjectSizeLimit(input.maxObjectSizeLimit);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutTag.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutTag.java
index a87882e..1be4b0e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/PutTag.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/PutTag.java
@@ -14,6 +14,7 @@
package com.google.gerrit.server.project;
+import com.google.gerrit.extensions.api.projects.TagInfo;
import com.google.gerrit.extensions.api.projects.TagInput;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.RestModifyView;
@@ -21,7 +22,7 @@
public class PutTag implements RestModifyView<TagResource, TagInput> {
@Override
- public Object apply(TagResource resource, TagInput input)
+ public TagInfo apply(TagResource resource, TagInput input)
throws ResourceConflictException {
throw new ResourceConflictException("Tag \"" + resource.getTagInfo().ref
+ "\" already exists");
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/SetDashboard.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/SetDashboard.java
index cda548a..594763e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/SetDashboard.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/SetDashboard.java
@@ -20,7 +20,9 @@
import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
+import com.google.gerrit.server.project.DashboardsCollection.DashboardInfo;
import com.google.gerrit.server.project.SetDashboard.Input;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -44,7 +46,7 @@
}
@Override
- public Object apply(DashboardResource resource, Input input)
+ public Response<DashboardInfo> apply(DashboardResource resource, Input input)
throws AuthException, BadRequestException, ResourceConflictException,
MethodNotAllowedException, ResourceNotFoundException, IOException {
if (resource.isProjectDefault()) {
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/patch/PatchListEntryTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/patch/PatchListEntryTest.java
new file mode 100644
index 0000000..bff557c
--- /dev/null
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/patch/PatchListEntryTest.java
@@ -0,0 +1,37 @@
+// 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.
+
+package com.google.gerrit.server.patch;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import com.google.gerrit.reviewdb.client.Patch;
+
+import org.junit.Test;
+
+public class PatchListEntryTest {
+ @Test
+ public void testEmpty1() {
+ final String name = "empty-file";
+ final PatchListEntry e = PatchListEntry.empty(name);
+ assertNull(e.getOldName());
+ assertEquals(name, e.getNewName());
+ assertSame(Patch.PatchType.UNIFIED, e.getPatchType());
+ assertSame(Patch.ChangeType.MODIFIED, e.getChangeType());
+ assertTrue(e.getEdits().isEmpty());
+ }
+}
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
index c7034b5..eece232 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
@@ -226,7 +226,6 @@
_handleKey: function(e) {
if (this.shouldSupressKeyboardShortcut(e)) { return; }
-
switch (e.keyCode) {
case 37: // left
if (e.shiftKey && this._showInlineDiffs) {
@@ -241,9 +240,14 @@
}
break;
case 73: // 'i'
- if (!e.shiftKey) { return; }
- e.preventDefault();
- this._toggleInlineDiffs();
+ if (e.shiftKey) {
+ e.preventDefault();
+ this._toggleInlineDiffs();
+ } else if (this.selectedIndex !== undefined) {
+ e.preventDefault();
+ var expanded = this._files[this.selectedIndex].__expanded;
+ this.set(['_files', this.selectedIndex, '__expanded'], !expanded);
+ }
break;
case 40: // down
case 74: // 'j'
@@ -378,12 +382,13 @@
},
_computeDiffURL: function(changeNum, patchRange, path) {
+ // @see Issue 4255 regarding double-encoding.
return '/c/' +
encodeURIComponent(changeNum) +
'/' +
encodeURIComponent(this._patchRangeStr(patchRange)) +
'/' +
- path;
+ encodeURIComponent(encodeURIComponent(path));
},
_patchRangeStr: function(patchRange) {
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
index f90ee68..3fe785e 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.html
@@ -80,62 +80,77 @@
});
});
- test('toggle left diff via shortcut', function() {
- var toggleLeftDiffStub = sinon.stub();
- sinon.stub(element, 'diffs', {get: function() {
- return [{toggleLeftDiff: toggleLeftDiffStub}];
- }});
- MockInteractions.pressAndReleaseKeyOn(element, 65, 'shift'); // 'A'
- assert.isTrue(toggleLeftDiffStub.calledOnce);
- });
+ suite('keyboard shortcuts', function() {
+ setup(function() {
+ element._files = [
+ {__path: '/COMMIT_MSG', __expanded: false},
+ {__path: 'file_added_in_rev2.txt', __expanded: false},
+ {__path: 'myfile.txt', __expanded: false},
+ ];
+ element.changeNum = '42';
+ element.patchRange = {
+ basePatchNum: 'PARENT',
+ patchNum: '2',
+ };
+ element.selectedIndex = 0;
+ });
- test('keyboard shortcuts', function() {
- var toggleInlineDiffsStub = sinon.stub(element, '_toggleInlineDiffs');
- MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift'); // 'I'
- assert.isTrue(toggleInlineDiffsStub.calledOnce);
- toggleInlineDiffsStub.restore();
+ test('toggle left diff via shortcut', function() {
+ var toggleLeftDiffStub = sinon.stub();
+ sinon.stub(element, 'diffs', {get: function() {
+ return [{toggleLeftDiff: toggleLeftDiffStub}];
+ }});
+ MockInteractions.pressAndReleaseKeyOn(element, 65, 'shift'); // 'A'
+ assert.isTrue(toggleLeftDiffStub.calledOnce);
+ });
- element._files = [
- {__path: '/COMMIT_MSG', __expanded: false},
- {__path: 'file_added_in_rev2.txt', __expanded: false},
- {__path: 'myfile.txt', __expanded: false},
- ];
- element.changeNum = '42';
- element.patchRange = {
- basePatchNum: 'PARENT',
- patchNum: '2',
- };
- element.selectedIndex = 0;
+ test('keyboard shortcuts', function() {
+ var toggleInlineDiffsStub = sinon.stub(element, '_toggleInlineDiffs');
+ MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift'); // 'I'
+ assert.isTrue(toggleInlineDiffsStub.calledOnce);
+ toggleInlineDiffsStub.restore();
- flushAsynchronousOperations();
- var elementItems = Polymer.dom(element.root).querySelectorAll(
- '.row:not(.header)');
- assert.equal(elementItems.length, 3);
- assert.isTrue(elementItems[0].hasAttribute('selected'));
- assert.isFalse(elementItems[1].hasAttribute('selected'));
- assert.isFalse(elementItems[2].hasAttribute('selected'));
- MockInteractions.pressAndReleaseKeyOn(element, 74); // 'J'
- assert.equal(element.selectedIndex, 1);
- MockInteractions.pressAndReleaseKeyOn(element, 74); // 'J'
+ flushAsynchronousOperations();
+ var elementItems = Polymer.dom(element.root).querySelectorAll(
+ '.row:not(.header)');
+ assert.equal(elementItems.length, 3);
+ assert.isTrue(elementItems[0].hasAttribute('selected'));
+ assert.isFalse(elementItems[1].hasAttribute('selected'));
+ assert.isFalse(elementItems[2].hasAttribute('selected'));
+ MockInteractions.pressAndReleaseKeyOn(element, 74); // 'J'
+ assert.equal(element.selectedIndex, 1);
+ MockInteractions.pressAndReleaseKeyOn(element, 74); // 'J'
- var showStub = sinon.stub(page, 'show');
- assert.equal(element.selectedIndex, 2);
- MockInteractions.pressAndReleaseKeyOn(element, 13); // 'ENTER'
- assert(showStub.lastCall.calledWith('/c/42/2/myfile.txt'),
- 'Should navigate to /c/42/2/myfile.txt');
+ var showStub = sinon.stub(page, 'show');
+ assert.equal(element.selectedIndex, 2);
+ MockInteractions.pressAndReleaseKeyOn(element, 13); // 'ENTER'
+ assert(showStub.lastCall.calledWith('/c/42/2/myfile.txt'),
+ 'Should navigate to /c/42/2/myfile.txt');
- MockInteractions.pressAndReleaseKeyOn(element, 75); // 'K'
- assert.equal(element.selectedIndex, 1);
- MockInteractions.pressAndReleaseKeyOn(element, 79); // 'O'
- assert(showStub.lastCall.calledWith('/c/42/2/file_added_in_rev2.txt'),
- 'Should navigate to /c/42/2/file_added_in_rev2.txt');
+ MockInteractions.pressAndReleaseKeyOn(element, 75); // 'K'
+ assert.equal(element.selectedIndex, 1);
+ MockInteractions.pressAndReleaseKeyOn(element, 79); // 'O'
+ assert(showStub.lastCall.calledWith('/c/42/2/file_added_in_rev2.txt'),
+ 'Should navigate to /c/42/2/file_added_in_rev2.txt');
- MockInteractions.pressAndReleaseKeyOn(element, 75); // 'K'
- MockInteractions.pressAndReleaseKeyOn(element, 75); // 'K'
- MockInteractions.pressAndReleaseKeyOn(element, 75); // 'K'
- assert.equal(element.selectedIndex, 0);
+ MockInteractions.pressAndReleaseKeyOn(element, 75); // 'K'
+ MockInteractions.pressAndReleaseKeyOn(element, 75); // 'K'
+ MockInteractions.pressAndReleaseKeyOn(element, 75); // 'K'
+ assert.equal(element.selectedIndex, 0);
- showStub.restore();
+ showStub.restore();
+ });
+
+ test('i key shows/hides selected inline diff', function() {
+ element.selectedIndex = 0;
+ MockInteractions.pressAndReleaseKeyOn(element, 73); // 'I'
+ assert.isTrue(element._files[0].__expanded);
+ MockInteractions.pressAndReleaseKeyOn(element, 73); // 'I'
+ assert.isFalse(element._files[0].__expanded);
+ element.selectedIndex = 1;
+ MockInteractions.pressAndReleaseKeyOn(element, 73); // 'I'
+ assert.isTrue(element._files[1].__expanded);
+ });
});
test('comment filtering', function() {
@@ -296,5 +311,19 @@
assert.isFalse(element.diffs[0].hidden);
diffStub.restore();
});
+
+ test('file name should be double-escaped', function() {
+ element._files = [
+ {__path: 'my+file.txt'},
+ ];
+ element.changeNum = '42';
+ element.patchRange = {
+ basePatchNum: 'PARENT',
+ patchNum: '2',
+ };
+ flushAsynchronousOperations();
+ assert.equal(
+ element.$$('a').getAttribute('href'), '/c/42/2/my%252Bfile.txt');
+ });
});
</script>
diff --git a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.html b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.html
index 7291199..3a9f909 100644
--- a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.html
+++ b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.html
@@ -155,7 +155,7 @@
</tr>
<tr>
<td><span class="key">a</span></td>
- <td>Review and publish comments</td>
+ <td>Open reply dialog to publish comments and add reviewers</td>
</tr>
<tr>
<td></td><td class="header">File list</td>
@@ -173,6 +173,10 @@
<td>Show selected file</td>
</tr>
<tr>
+ <td><span class="key">i</span></td>
+ <td>Show/hide selected inline diff</td>
+ </tr>
+ <tr>
<td></td><td class="header">Diffs</td>
</tr>
<tr>
@@ -297,7 +301,7 @@
</tr>
<tr>
<td><span class="key">a</span></td>
- <td>Review and publish comments</td>
+ <td>Open reply dialog to publish comments and add reviewers</td>
</tr>
<tr>
<td><span class="key">,</span></td>
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.js b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
index ac9e03d..d9bf8ac 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router.js
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
@@ -134,12 +134,13 @@
};
// Don't allow diffing the same patch number against itself.
if (params.basePatchNum === params.patchNum) {
+ // @see Issue 4255 regarding double-encoding.
page.redirect('/c/' +
encodeURIComponent(params.changeNum) +
'/' +
encodeURIComponent(params.patchNum) +
'/' +
- encodeURIComponent(params.path));
+ encodeURIComponent(encodeURIComponent(params.path)));
return;
}
normalizePatchRangeParams(params);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js
index 670885a..6844416 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js
@@ -340,6 +340,9 @@
side,
this._comments.meta.projectConfig);
threadEl.comments = comments;
+ if (opt_side) {
+ threadEl.setAttribute('data-side', opt_side);
+ }
return threadEl;
};
@@ -363,11 +366,14 @@
GrDiffBuilder.prototype._createTextEl = function(line, opt_side) {
var td = this._createElement('td');
+ var text = line.text;
if (line.type !== GrDiffLine.Type.BLANK) {
td.classList.add('content');
+ if (!text) {
+ text = '\xa0';
+ }
}
td.classList.add(line.type);
- var text = line.text;
var html = util.escapeHTML(text);
html = this._addTabWrappers(html, this._prefs.tab_size);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.html b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.html
index 09cab0b..bc55129 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.html
@@ -18,17 +18,19 @@
<dom-module id="gr-diff-selection">
<template>
<style>
- .contentWrapper ::content .content {
+ .contentWrapper ::content .content,
+ .contentWrapper ::content .contextControl {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
- :host.selected-right .contentWrapper ::content .right + .content,
- :host.selected-left .contentWrapper ::content .left + .content,
- :host.selected-right .contentWrapper ::content .unified .right ~ .content,
- :host.selected-left .contentWrapper ::content .unified .left ~ .content {
+ :host.selected-right .contentWrapper ::content .side-by-side .right + .content,
+ :host.selected-left .contentWrapper ::content .side-by-side .left + .content,
+ :host.selected-right .contentWrapper ::content .unified .right.lineNum ~ .content,
+ :host.selected-left .contentWrapper ::content .unified .left.lineNum ~ .content:not(.both),
+ :host .contentWrapper ::content .unified .gr-diff-comment .message {
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.js b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.js
index 7d0b7ea..80e758e 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.js
@@ -56,7 +56,8 @@
},
_handleCopy: function(e) {
- if (!e.target.classList.contains('content')) {
+ if (!e.target.classList.contains('contentText') &&
+ !e.target.classList.contains('gr-syntax')) {
return;
}
var lineEl = this.diffBuilder.getLineElByChild(e.target);
@@ -69,17 +70,17 @@
e.preventDefault();
},
- _getSelectedText: function(opt_side) {
+ _getSelectedText: function(side) {
var sel = window.getSelection();
if (sel.rangeCount != 1) {
return; // No multi-select support yet.
}
var range = sel.getRangeAt(0);
var fragment = range.cloneContents();
- var selector = '.content,td.content:nth-of-type(1)';
- if (opt_side) {
- selector = '.' + opt_side + ' + ' + selector;
- }
+ var selector = '.contentText';
+ selector += '[data-side="' + side + '"]';
+ selector += ':not(:empty)';
+
var contentEls = Polymer.dom(fragment).querySelectorAll(selector);
if (contentEls.length === 0) {
return fragment.textContent;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.html b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.html
index f99e373..4472ebd 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.html
@@ -30,21 +30,33 @@
<table>
<tr>
<td class="lineNum left">1</td>
- <td class="content">ba ba</td>
+ <td class="content">
+ <div class="contentText" data-side="left">ba ba</div>
+ </td>
<td class="lineNum right">1</td>
- <td class="content">some other text</td>
+ <td class="content">
+ <div class="contentText" data-side="right">some other text</div>
+ </td>
</tr>
<tr>
<td class="lineNum left">2</td>
- <td class="content">zin</td>
+ <td class="content">
+ <div class="contentText" data-side="left">zin</div>
+ </td>
<td class="lineNum right">2</td>
- <td class="content">more more more</td>
+ <td class="content">
+ <div class="contentText" data-side="right">more more more</div>
+ </td>
</tr>
<tr>
<td class="lineNum left">2</td>
- <td class="content">ga ga</td>
+ <td class="content">
+ <div class="contentText" data-side="left">ga ga</div>
+ </td>
<td class="lineNum right">3</td>
- <td class="other">some other text</td>
+ <td class="other">
+ <div class="contentText" data-side="right">some other text</div>
+ </td>
</tr>
</table>
</gr-diff-selection>
@@ -105,36 +117,37 @@
test('asks for text for right side Elements', function() {
element._cachedDiffBuilder.getSideByLineEl.returns('left');
sinon.stub(element, '_getSelectedText');
- emulateCopyOn(element.querySelector('td.content'));
+ emulateCopyOn(element.querySelector('div.contentText'));
assert.deepEqual(['left'], element._getSelectedText.lastCall.args);
});
test('reacts to copy for content Elements', function() {
sinon.stub(element, '_getSelectedText');
- emulateCopyOn(element.querySelector('td.content'));
+ emulateCopyOn(element.querySelector('div.contentText'));
assert.isTrue(element._getSelectedText.called);
});
test('copy event is prevented for content Elements', function() {
sinon.stub(element, '_getSelectedText');
- var event = emulateCopyOn(element.querySelector('td.content'));
+ var event = emulateCopyOn(element.querySelector('div.contentText'));
assert.isTrue(event.preventDefault.called);
});
test('inserts text into clipboard on copy', function() {
sinon.stub(element, '_getSelectedText').returns('the text');
- var event = emulateCopyOn(element.querySelector('td.content'));
+ var event = emulateCopyOn(element.querySelector('div.contentText'));
assert.deepEqual(
['Text', 'the text'], event.clipboardData.setData.lastCall.args);
});
test('copies content correctly', function() {
element.classList.add('selected-left');
+ element.classList.remove('selected-right');
var selection = window.getSelection();
var range = document.createRange();
- range.setStart(element.querySelector('td.content').firstChild, 3);
+ range.setStart(element.querySelector('div.contentText').firstChild, 3);
range.setEnd(
- element.querySelectorAll('td.content')[4].firstChild, 2);
+ element.querySelectorAll('div.contentText')[4].firstChild, 2);
selection.addRange(range);
assert.equal('ba\nzin\nga\n', element._getSelectedText('left'));
});
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
index 2573ad1..38a6746 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
@@ -180,7 +180,8 @@
id="modeSelect"
is="gr-select"
bind-value="{{changeViewState.diffMode}}"
- hidden$="[[_computeModeSelectHidden(_isImageDiff)]]">
+ hidden$="[[_computeModeSelectHidden(_isImageDiff)]]"
+ on-change="_handleDropdownChange">
<option value="SIDE_BY_SIDE">Side By Side</option>
<option value="UNIFIED_DIFF">Unified</option>
</select>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
index 7111ee5..7d9f9d8 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
@@ -488,5 +488,9 @@
this.$.cursor.moveToLineNumber(detail.number, detail.side);
history.pushState(null, null, '#' + this.$.cursor.getAddress());
},
+
+ _handleDropdownChange: function(e) {
+ e.target.blur();
+ },
});
})();
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html
index c21bd90..c9c27c5 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html
@@ -377,7 +377,7 @@
test('diff mode selector correctly toggles the diff', function() {
var select = element.$.modeSelect;
var diffDisplay = element.$.diff;
-
+ var blurSpy = sinon.spy(select, 'blur');
element._userPrefs = {diff_view: 'SIDE_BY_SIDE'};
// The mode selected in the view state reflects the selected option.
@@ -398,6 +398,7 @@
assert.equal(element._getDiffViewMode(), newMode);
assert.equal(element._getDiffViewMode(), select.value);
assert.equal(element._getDiffViewMode(), diffDisplay.viewMode);
+ assert(blurSpy.called, 'select should be blurred after selection');
});
test('diff mode selector initializes from preferences', function() {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
index 2431fb0..36a18fc 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
@@ -91,13 +91,6 @@
vertical-align: top;
white-space: pre;
}
- .contentText:empty:before {
- /**
- * Insert glyph to prevent empty diff content from collapsing.
- * "\200B" is a 'ZERO WIDTH SPACE' (U+200B)
- */
- content: "\200B";
- }
.contextLineNum:before,
.lineNum:before {
display: inline-block;
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.js b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.js
index 24d36c4..b50043e 100644
--- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.js
+++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.js
@@ -33,6 +33,7 @@
rangeStr = leftPatch + '..' + rangeStr;
}
page.show('/c/' + this.changeNum + '/' + rangeStr + '/' + this.path);
+ e.target.blur();
},
_computeLeftSelected: function(patchNum, patchRange) {
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html
index c7e1196..95789bc 100644
--- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html
@@ -63,6 +63,7 @@
var showStub = sinon.stub(page, 'show');
var leftSelectEl = element.$.leftPatchSelect;
var rightSelectEl = element.$.rightPatchSelect;
+ var blurSpy = sinon.spy(leftSelectEl, 'blur');
element.changeNum = '42';
element.path = 'path/to/file.txt';
element.availablePatches = ['1', '2', '3'];
@@ -77,6 +78,7 @@
'Should navigate to /c/42/3/path/to/file.txt');
leftSelectEl.value = '1';
element.fire('change', {}, {node: leftSelectEl});
+ assert(blurSpy.called, 'Dropdown should be blurred after selection');
} else if (numEvents == 2) {
assert(showStub.lastCall.calledWithExactly(
'/c/42/1..3/path/to/file.txt'),
diff --git a/tools/jgit-snapshot-deploy-pom.diff b/tools/jgit-snapshot-deploy-pom.diff
new file mode 100644
index 0000000..01f50e4
--- /dev/null
+++ b/tools/jgit-snapshot-deploy-pom.diff
@@ -0,0 +1,43 @@
+diff --git a/pom.xml b/pom.xml
+index d256bbb..7e523fd 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -226,6 +226,10 @@
+
+ <pluginRepositories>
+ <pluginRepository>
++ <id>gerrit-maven</id>
++ <url>https://gerrit-maven.commondatastorage.googleapis.com</url>
++ </pluginRepository>
++ <pluginRepository>
+ <id>repo.eclipse.org.cbi-releases</id>
+ <url>https://repo.eclipse.org/content/repositories/cbi-releases/</url>
+ </pluginRepository>
+@@ -236,6 +240,13 @@
+ </pluginRepositories>
+
+ <build>
++ <extensions>
++ <extension>
++ <groupId>com.googlesource.gerrit</groupId>
++ <artifactId>gs-maven-wagon</artifactId>
++ <version>3.3</version>
++ </extension>
++ </extensions>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+@@ -649,9 +660,10 @@
+
+ <distributionManagement>
+ <repository>
+- <id>repo.eclipse.org</id>
+- <name>JGit Maven Repository - Releases</name>
+- <url>https://repo.eclipse.org/content/repositories/jgit-releases/</url>
++ <id>gerrit-maven-repository</id>
++ <name>Gerrit Maven Repository</name>
++ <url>gs://gerrit-maven</url>
++ <uniqueVersion>true</uniqueVersion>
+ </repository>
+ <snapshotRepository>
+ <id>repo.eclipse.org</id>