Merge "Sort email comment groups"
diff --git a/BUILD b/BUILD
index 7ec32be..5fd38c8 100644
--- a/BUILD
+++ b/BUILD
@@ -20,3 +20,7 @@
pkg_war(name = 'gerrit')
pkg_war(name = 'headless', ui = None)
pkg_war(name = 'release', ui = 'ui_optdbg_r', context = ['//plugins:core'])
+pkg_war(
+ name = "polygerrit",
+ ui = "polygerrit"
+)
diff --git a/Documentation/dev-bazel.txt b/Documentation/dev-bazel.txt
index f063b88..834bcae 100644
--- a/Documentation/dev-bazel.txt
+++ b/Documentation/dev-bazel.txt
@@ -38,15 +38,18 @@
bazel build gerrit
----
-[NOTE]
-PolyGerrit UI not yet working.
-
The output executable WAR will be placed in:
----
bazel-bin/gerrit.war
----
+to run,
+
+----
+ $(bazel info output_base)/external/local_jdk/bin/java \
+ -jar bazel-bin/release.war daemon -d ../gerrit_testsite
+----
=== Headless Mode
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index e5073b2..a258b32 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -1767,13 +1767,19 @@
HTTP/1.1 204 No Content
----
-[[delete-draft-change]]
-=== Delete Draft Change
+[[delete-change]]
+=== Delete Change
--
'DELETE /changes/link:#change-id[\{change-id\}]'
--
-Deletes a draft change.
+Deletes a change.
+
+New or abandoned changes can only be deleted by administrators. The deletion of
+merged changes isn't supported at the moment. Draft changes can only be deleted
+by their owner or other users who have the permissions to view and delete
+drafts. If the draft workflow is disabled, only administrators with those
+permissions may delete draft changes.
.Request
----
diff --git a/WORKSPACE b/WORKSPACE
index f01ad3f..ac50f4a 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -132,7 +132,7 @@
sha256 = '80d63c117736ae2fb9837b7a39576f3f0c5bd19cd75127886550c77b4c478f87',
)
-JGIT_VERS = '4.5.0.201609210915-r'
+load('//lib/jgit:jgit.bzl', 'JGIT_VERS')
maven_jar(
name = 'jgit',
@@ -481,12 +481,6 @@
)
maven_jar(
- name = 'lucene_misc',
- artifact = 'org.apache.lucene:lucene-misc:' + LUCENE_VERS,
- sha1 = '37bbe5a2fb429499dfbe75d750d1778881fff45d',
-)
-
-maven_jar(
name = 'lucene_sandbox',
artifact = 'org.apache.lucene:lucene-sandbox:' + LUCENE_VERS,
sha1 = '30a91f120706ba66732d5a974b56c6971b3c8a16',
diff --git a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/TestAccount.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/TestAccount.java
index c1a815a..63e0fa7 100644
--- a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/TestAccount.java
+++ b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/TestAccount.java
@@ -14,7 +14,8 @@
package com.google.gerrit.acceptance;
-import com.google.common.collect.FluentIterable;
+import static java.util.stream.Collectors.toList;
+
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.server.mail.Address;
@@ -24,22 +25,22 @@
import java.io.ByteArrayOutputStream;
import java.util.Arrays;
+import java.util.List;
public class TestAccount {
- public static FluentIterable<Account.Id> ids(
- Iterable<TestAccount> accounts) {
- return FluentIterable.from(accounts).transform(a -> a.id);
+ public static List<Account.Id> ids(List<TestAccount> accounts) {
+ return accounts.stream().map(a -> a.id).collect(toList());
}
- public static FluentIterable<Account.Id> ids(TestAccount... accounts) {
+ public static List<Account.Id> ids(TestAccount... accounts) {
return ids(Arrays.asList(accounts));
}
- public static FluentIterable<String> names(Iterable<TestAccount> accounts) {
- return FluentIterable.from(accounts).transform(a -> a.fullName);
+ public static List<String> names(List<TestAccount> accounts) {
+ return accounts.stream().map(a -> a.fullName).collect(toList());
}
- public static FluentIterable<String> names(TestAccount... accounts) {
+ public static List<String> names(TestAccount... accounts) {
return names(Arrays.asList(accounts));
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
index d995be6..8af4098 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -68,6 +68,7 @@
import com.google.gerrit.extensions.common.MergePatchSetInput;
import com.google.gerrit.extensions.common.RevisionInfo;
import com.google.gerrit.extensions.restapi.AuthException;
+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.UnprocessableEntityException;
@@ -398,7 +399,7 @@
}
@Test
- public void delete() throws Exception {
+ public void deleteDraftChange() throws Exception {
PushOneCommit.Result r = createChange("refs/drafts/master");
assertThat(query(r.getChangeId())).hasSize(1);
assertThat(info(r.getChangeId()).status).isEqualTo(ChangeStatus.DRAFT);
@@ -409,6 +410,110 @@
}
@Test
+ public void deleteNewChangeAsAdmin() throws Exception {
+ PushOneCommit.Result changeResult = createChange();
+ String changeId = changeResult.getChangeId();
+
+ gApi.changes()
+ .id(changeId)
+ .delete();
+
+ assertThat(query(changeId)).isEmpty();
+ }
+
+ @Test
+ @TestProjectInput(cloneAs = "user")
+ public void deleteNewChangeAsNormalUser() throws Exception {
+ PushOneCommit.Result changeResult =
+ pushFactory.create(db, user.getIdent(), testRepo)
+ .to("refs/for/master");
+ String changeId = changeResult.getChangeId();
+ Change.Id id = changeResult.getChange().getId();
+
+ setApiUser(user);
+ exception.expect(AuthException.class);
+ exception.expectMessage(String.format(
+ "Deleting change %s is not permitted", id));
+ gApi.changes()
+ .id(changeId)
+ .delete();
+ }
+
+ @Test
+ @TestProjectInput(cloneAs = "user")
+ public void deleteNewChangeOfAnotherUserAsAdmin() throws Exception {
+ PushOneCommit.Result changeResult =
+ pushFactory.create(db, user.getIdent(), testRepo)
+ .to("refs/for/master");
+ changeResult.assertOkStatus();
+ String changeId = changeResult.getChangeId();
+
+ setApiUser(admin);
+ gApi.changes()
+ .id(changeId)
+ .delete();
+
+ assertThat(query(changeId)).isEmpty();
+ }
+
+ @Test
+ @TestProjectInput(cloneAs = "user")
+ public void deleteAbandonedChangeAsNormalUser() throws Exception {
+ PushOneCommit.Result changeResult =
+ pushFactory.create(db, user.getIdent(), testRepo)
+ .to("refs/for/master");
+ String changeId = changeResult.getChangeId();
+ Change.Id id = changeResult.getChange().getId();
+
+ setApiUser(user);
+ gApi.changes()
+ .id(changeId)
+ .abandon();
+
+ exception.expect(AuthException.class);
+ exception.expectMessage(String.format(
+ "Deleting change %s is not permitted", id));
+ gApi.changes()
+ .id(changeId)
+ .delete();
+ }
+
+ @Test
+ @TestProjectInput(cloneAs = "user")
+ public void deleteAbandonedChangeOfAnotherUserAsAdmin() throws Exception {
+ PushOneCommit.Result changeResult =
+ pushFactory.create(db, user.getIdent(), testRepo)
+ .to("refs/for/master");
+ String changeId = changeResult.getChangeId();
+
+ gApi.changes()
+ .id(changeId)
+ .abandon();
+
+ gApi.changes()
+ .id(changeId)
+ .delete();
+
+ assertThat(query(changeId)).isEmpty();
+ }
+
+ @Test
+ public void deleteMergedChange() throws Exception {
+ PushOneCommit.Result changeResult = createChange();
+ String changeId = changeResult.getChangeId();
+ Change.Id id = changeResult.getChange().getId();
+
+ merge(changeResult);
+
+ exception.expect(MethodNotAllowedException.class);
+ exception.expectMessage(String.format(
+ "Deleting merged change %s is not allowed", id));
+ gApi.changes()
+ .id(changeId)
+ .delete();
+ }
+
+ @Test
public void rebaseUpToDateChange() throws Exception {
PushOneCommit.Result r = createChange();
exception.expect(ResourceConflictException.class);
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/group/GroupsIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/group/GroupsIT.java
index 78c0cda..f98e588 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/group/GroupsIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/group/GroupsIT.java
@@ -17,10 +17,9 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.acceptance.api.group.GroupAssert.assertGroupInfo;
import static com.google.gerrit.acceptance.rest.account.AccountAssert.assertAccountInfos;
+import static java.util.stream.Collectors.toList;
-import com.google.common.collect.FluentIterable;
import com.google.common.collect.Iterables;
-import com.google.common.collect.Ordering;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.acceptance.TestAccount;
@@ -397,10 +396,10 @@
@Test
public void testListAllGroups() throws Exception {
- List<String> expectedGroups = FluentIterable
- .from(groupCache.all())
- .transform(AccountGroup::getName)
- .toSortedList(Ordering.natural());
+ List<String> expectedGroups = groupCache.all().stream()
+ .map(a -> a.getName())
+ .sorted()
+ .collect(toList());
assertThat(expectedGroups.size()).isAtLeast(2);
assertThat(gApi.groups().list().getAsMap().keySet())
.containsExactlyElementsIn(expectedGroups).inOrder();
@@ -504,7 +503,7 @@
throws Exception {
assertMembers(
gApi.groups().id(group).members(),
- TestAccount.names(expectedMembers).toArray(String.class));
+ TestAccount.names(expectedMembers).stream().toArray(String[]::new));
assertAccountInfos(
Arrays.asList(expectedMembers),
gApi.groups().id(group).members());
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/DraftChangeIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/DraftChangeIT.java
index 2a32abe..eb6e433 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/DraftChangeIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/change/DraftChangeIT.java
@@ -22,20 +22,35 @@
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.acceptance.RestSession;
+import com.google.gerrit.acceptance.TestProjectInput;
+import com.google.gerrit.common.TimeUtil;
+import com.google.gerrit.common.data.Permission;
import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.client.ChangeStatus;
+import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.extensions.client.ReviewerState;
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.LabelInfo;
+import com.google.gerrit.extensions.common.RevisionInfo;
+import com.google.gerrit.extensions.restapi.AuthException;
+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.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.server.git.BatchUpdate;
+import com.google.gerrit.server.notedb.PatchSetState;
import com.google.gerrit.testutil.ConfigSuite;
+import com.google.inject.Inject;
import org.eclipse.jgit.lib.Config;
import org.junit.Test;
import java.util.Collection;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.stream.Collectors;
public class DraftChangeIT extends AbstractDaemonTest {
@ConfigSuite.Config
@@ -43,20 +58,8 @@
return allowDraftsDisabledConfig();
}
- @Test
- public void deleteChange() throws Exception {
- PushOneCommit.Result result = createChange();
- result.assertOkStatus();
- String changeId = result.getChangeId();
- String triplet = project.get() + "~master~" + changeId;
- ChangeInfo c = get(triplet);
- assertThat(c.id).isEqualTo(triplet);
- assertThat(c.status).isEqualTo(ChangeStatus.NEW);
- RestResponse response = deleteChange(changeId, adminRestSession);
- assertThat(response.getEntityContent())
- .isEqualTo("Change is not a draft: " + c._number);
- response.assertConflict();
- }
+ @Inject
+ private BatchUpdate.Factory updateFactory;
@Test
public void deleteDraftChange() throws Exception {
@@ -75,6 +78,104 @@
}
@Test
+ public void deleteDraftChangeOfAnotherUser() throws Exception {
+ assume().that(isAllowDrafts()).isTrue();
+ PushOneCommit.Result changeResult = createDraftChange();
+ changeResult.assertOkStatus();
+ String changeId = changeResult.getChangeId();
+ Change.Id id = changeResult.getChange().getId();
+
+ // The user needs to be able to see the draft change (which reviewers can).
+ gApi.changes()
+ .id(changeId)
+ .addReviewer(user.fullName);
+
+ setApiUser(user);
+ exception.expect(AuthException.class);
+ exception.expectMessage(String.format(
+ "Deleting change %s is not permitted", id));
+ gApi.changes()
+ .id(changeId)
+ .delete();
+ }
+
+ @Test
+ @TestProjectInput(cloneAs = "user")
+ public void deleteDraftChangeWhenDraftsNotAllowedAsNormalUser()
+ throws Exception {
+ assume().that(isAllowDrafts()).isFalse();
+
+ setApiUser(user);
+ // We can't create a draft change while the draft workflow is disabled.
+ // For this reason, we create a normal change and modify the database.
+ PushOneCommit.Result changeResult =
+ pushFactory.create(db, user.getIdent(), testRepo)
+ .to("refs/for/master");
+ Change.Id id = changeResult.getChange().getId();
+ markChangeAsDraft(id);
+ setDraftStatusOfPatchSetsOfChange(id, true);
+
+ String changeId = changeResult.getChangeId();
+ exception.expect(MethodNotAllowedException.class);
+ exception.expectMessage("Draft workflow is disabled");
+ gApi.changes()
+ .id(changeId)
+ .delete();
+ }
+
+ @Test
+ @TestProjectInput(cloneAs = "user")
+ public void deleteDraftChangeWhenDraftsNotAllowedAsAdmin() throws Exception {
+ assume().that(isAllowDrafts()).isFalse();
+
+ setApiUser(user);
+ // We can't create a draft change while the draft workflow is disabled.
+ // For this reason, we create a normal change and modify the database.
+ PushOneCommit.Result changeResult =
+ pushFactory.create(db, user.getIdent(), testRepo)
+ .to("refs/for/master");
+ Change.Id id = changeResult.getChange().getId();
+ markChangeAsDraft(id);
+ setDraftStatusOfPatchSetsOfChange(id, true);
+
+ String changeId = changeResult.getChangeId();
+
+ // Grant those permissions to admins.
+ grant(Permission.VIEW_DRAFTS, project, "refs/*");
+ grant(Permission.DELETE_DRAFTS, project, "refs/*");
+
+ try {
+ setApiUser(admin);
+ gApi.changes()
+ .id(changeId)
+ .delete();
+ } finally {
+ removePermission(Permission.DELETE_DRAFTS, project, "refs/*");
+ removePermission(Permission.VIEW_DRAFTS, project, "refs/*");
+ }
+
+ setApiUser(user);
+ assertThat(query(changeId)).isEmpty();
+ }
+
+ @Test
+ public void deleteDraftChangeWithNonDraftPatchSet() throws Exception {
+ assume().that(isAllowDrafts()).isTrue();
+
+ PushOneCommit.Result changeResult = createDraftChange();
+ Change.Id id = changeResult.getChange().getId();
+ setDraftStatusOfPatchSetsOfChange(id, false);
+
+ String changeId = changeResult.getChangeId();
+ exception.expect(ResourceConflictException.class);
+ exception.expectMessage(String.format(
+ "Cannot delete draft change %s: patch set 1 is not a draft", id));
+ gApi.changes()
+ .id(changeId)
+ .delete();
+ }
+
+ @Test
public void publishDraftChange() throws Exception {
assume().that(isAllowDrafts()).isTrue();
PushOneCommit.Result result = createDraftChange();
@@ -160,4 +261,90 @@
+ patchSet.getRevision().get()
+ "/publish");
}
+
+ private void markChangeAsDraft(Change.Id id) throws Exception {
+ try (BatchUpdate batchUpdate = updateFactory
+ .create(db, project, atrScope.get().getUser(), TimeUtil.nowTs())) {
+ batchUpdate.addOp(id, new MarkChangeAsDraftUpdateOp());
+ batchUpdate.execute();
+ }
+
+ ChangeStatus changeStatus = gApi.changes()
+ .id(id.get())
+ .get()
+ .status;
+ assertThat(changeStatus).isEqualTo(ChangeStatus.DRAFT);
+ }
+
+ private void setDraftStatusOfPatchSetsOfChange(Change.Id id,
+ boolean draftStatus) throws Exception {
+ try (BatchUpdate batchUpdate = updateFactory
+ .create(db, project, atrScope.get().getUser(), TimeUtil.nowTs())) {
+ batchUpdate.addOp(id, new DraftStatusOfPatchSetsUpdateOp(draftStatus));
+ batchUpdate.execute();
+ }
+
+ Boolean expectedDraftStatus = draftStatus ? Boolean.TRUE : null;
+ List<Boolean> patchSetDraftStatuses = getPatchSetDraftStatuses(id);
+ patchSetDraftStatuses.forEach(status ->
+ assertThat(status).isEqualTo(expectedDraftStatus));
+ }
+
+ private List<Boolean> getPatchSetDraftStatuses(Change.Id id)
+ throws Exception {
+ Collection<RevisionInfo> revisionInfos = gApi.changes()
+ .id(id.get())
+ .get(EnumSet.of(ListChangesOption.ALL_REVISIONS))
+ .revisions
+ .values();
+ return revisionInfos.stream()
+ .map(revisionInfo -> revisionInfo.draft)
+ .collect(Collectors.toList());
+ }
+
+ private class MarkChangeAsDraftUpdateOp extends BatchUpdate.Op {
+ @Override
+ public boolean updateChange(BatchUpdate.ChangeContext ctx)
+ throws Exception {
+ Change change = ctx.getChange();
+
+ // Change status in database.
+ change.setStatus(Change.Status.DRAFT);
+
+ // Change status in NoteDb.
+ PatchSet.Id currentPatchSetId = change.currentPatchSetId();
+ ctx.getUpdate(currentPatchSetId).setStatus(Change.Status.DRAFT);
+
+ return true;
+ }
+ }
+
+ private class DraftStatusOfPatchSetsUpdateOp extends BatchUpdate.Op {
+ private final boolean draftStatus;
+
+ DraftStatusOfPatchSetsUpdateOp(boolean draftStatus) {
+ this.draftStatus = draftStatus;
+ }
+
+ @Override
+ public boolean updateChange(BatchUpdate.ChangeContext ctx)
+ throws Exception {
+ Collection<PatchSet> patchSets = psUtil.byChange(db, ctx.getNotes());
+
+ // Change status in database.
+ patchSets.forEach(patchSet -> patchSet.setDraft(draftStatus));
+ db.patchSets().update(patchSets);
+
+ // Change status in NoteDb.
+ PatchSetState patchSetState = draftStatus ? PatchSetState.DRAFT
+ : PatchSetState.PUBLISHED;
+ patchSets.stream()
+ .map(PatchSet::getId)
+ .map(ctx::getUpdate)
+ .forEach(changeUpdate ->
+ changeUpdate.setPatchSetState(patchSetState));
+
+ return true;
+ }
+ }
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java
index ce7e8c9..a252aeb 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java
@@ -66,7 +66,6 @@
@GerritConfig(name = "gerrit.allProjects", value = "Root"),
@GerritConfig(name = "gerrit.allUsers", value = "Users"),
@GerritConfig(name = "gerrit.enableGwtUi", value = "true"),
- @GerritConfig(name = "gerrit.enablePolyGerrit", value = "true"),
@GerritConfig(name = "gerrit.reportBugText", value = "REPORT BUG"),
@GerritConfig(name = "gerrit.reportBugUrl", value = "https://example.com/report"),
diff --git a/gerrit-extension-api/BUILD b/gerrit-extension-api/BUILD
index b66617a..d242495 100644
--- a/gerrit-extension-api/BUILD
+++ b/gerrit-extension-api/BUILD
@@ -1,3 +1,4 @@
+load('//lib/jgit:jgit.bzl', 'JGIT_DOC_URL')
load('//tools/bzl:gwt.bzl', 'gwt_module')
SRC = 'src/main/java/com/google/gerrit/extensions/'
@@ -52,4 +53,5 @@
title = 'Gerrit Review Extension API Documentation',
libs = [':api'],
pkgs = ['com.google.gerrit.extensions'],
+ external_docs = [JGIT_DOC_URL],
)
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
index bd5dd69..629ad97 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
@@ -112,7 +112,7 @@
void publish() throws RestApiException;
/**
- * Deletes a draft change.
+ * Deletes a change.
*/
void delete() throws RestApiException;
diff --git a/gerrit-gwtui-common/BUCK b/gerrit-gwtui-common/BUCK
index d4d97a6..729b7e7 100644
--- a/gerrit-gwtui-common/BUCK
+++ b/gerrit-gwtui-common/BUCK
@@ -8,7 +8,6 @@
]
DEPS = ['//lib/gwt:user']
SRC = 'src/main/java/com/google/gerrit/'
-DIFFY = glob(['src/main/resources/com/google/gerrit/client/diffy*.png'])
gwt_module(
name = 'client',
@@ -36,9 +35,9 @@
visibility = ['PUBLIC'],
)
-prebuilt_jar(
+java_library(
name = 'diffy_logo',
- binary_jar = ':diffy_image_files_ln',
+ resources = glob(['src/main/resources/com/google/gerrit/client/diffy*.png']),
deps = [
'//lib:LICENSE-diffy',
'//lib:LICENSE-CC-BY3.0-unported',
@@ -46,17 +45,6 @@
visibility = ['PUBLIC'],
)
-genrule(
- name = 'diffy_image_files_ln',
- cmd = 'ln -s $(location :diffy_image_files) $OUT',
- out = 'diffy_images.jar',
-)
-
-java_library(
- name = 'diffy_image_files',
- resources = DIFFY,
-)
-
java_test(
name = 'client_tests',
srcs = glob(['src/test/java/**/*.java']),
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.java
index 63de389..99f3b9f2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.java
@@ -51,6 +51,6 @@
String abandoned();
String deleteChangeEdit();
- String deleteDraftChange();
+ String deleteChange();
String deleteDraftRevision();
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.properties
index 5b4f18f..dd4760d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeConstants.properties
@@ -34,5 +34,5 @@
deleteChangeEdit = Delete Change Edit?\n\
\n\
All changes made in the edit revision will be lost.
-deleteDraftChange = Delete Draft Change?
+deleteChange = Delete Change?
deleteDraftRevision = Delete Draft Revision?
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 436e0c3..fa3855e 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
@@ -495,15 +495,13 @@
}
private void initChangeAction(ChangeInfo info) {
- if (info.status() == Status.DRAFT) {
- NativeMap<ActionInfo> actions = info.hasActions()
- ? info.actions()
- : NativeMap.<ActionInfo> create();
- actions.copyKeysIntoChildren("id");
- if (actions.containsKey("/")) {
- deleteChange.setVisible(true);
- deleteChange.setTitle(actions.get("/").title());
- }
+ NativeMap<ActionInfo> actions = info.hasActions()
+ ? info.actions()
+ : NativeMap.create();
+ actions.copyKeysIntoChildren("id");
+ if (actions.containsKey("/")) {
+ deleteChange.setVisible(true);
+ deleteChange.setTitle(actions.get("/").title());
}
}
@@ -679,7 +677,7 @@
@UiHandler("deleteChange")
void onDeleteChange(@SuppressWarnings("unused") ClickEvent e) {
- if (Window.confirm(Resources.C.deleteDraftChange())) {
+ if (Window.confirm(Resources.C.deleteChange())) {
DraftActions.delete(changeId, publish, deleteRevision, deleteChange);
}
}
diff --git a/gerrit-pgm/BUCK b/gerrit-pgm/BUCK
index 5f2ef43..d5abf99 100644
--- a/gerrit-pgm/BUCK
+++ b/gerrit-pgm/BUCK
@@ -130,7 +130,6 @@
'//lib:gwtorm',
'//lib:protobuf',
'//lib:servlet-api-3_1',
- '//lib/auto:auto-value',
'//lib/prolog:cafeteria',
'//lib/prolog:compiler',
'//lib/prolog:runtime',
diff --git a/gerrit-pgm/BUILD b/gerrit-pgm/BUILD
index 8e3cbcf..4f2b609 100644
--- a/gerrit-pgm/BUILD
+++ b/gerrit-pgm/BUILD
@@ -120,7 +120,6 @@
'//lib:gwtorm',
'//lib:protobuf',
'//lib:servlet-api-3_1-without-neverlink',
- '//lib/auto:auto-value',
'//lib/prolog:cafeteria',
'//lib/prolog:compiler',
'//lib/prolog:runtime',
@@ -142,6 +141,7 @@
resources = glob([RSRCS + '*']),
deps = DEPS + REST_PGM_DEPS + [ # We want all these deps to be provided_deps
'//gerrit-launcher:launcher',
+ '//lib/auto:auto-value',
],
visibility = ['//visibility:public'],
)
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java
index eec700a..7d6dc32 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java
@@ -29,7 +29,7 @@
import com.google.gerrit.pgm.init.api.Section;
import com.google.gerrit.pgm.init.api.Section.Factory;
import com.google.gerrit.server.config.SitePaths;
-import com.google.gerrit.server.mail.send.OutgoingEmail;
+import com.google.gerrit.server.mail.EmailModule;
import com.google.inject.Binding;
import com.google.inject.Inject;
import com.google.inject.Injector;
@@ -156,7 +156,7 @@
private void extractMailExample(String orig) throws Exception {
Path ex = site.mail_dir.resolve(orig + ".example");
- extract(ex, OutgoingEmail.class, orig);
+ extract(ex, EmailModule.class, orig);
chmod(0444, ex);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCache.java
index c7a2241..3d966d2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCache.java
@@ -14,6 +14,7 @@
package com.google.gerrit.server.account;
+import com.google.common.collect.ImmutableList;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.reviewdb.client.AccountGroup;
@@ -31,8 +32,8 @@
@Nullable
AccountGroup get(AccountGroup.UUID uuid);
- /** @return sorted iteration of groups. */
- Iterable<AccountGroup> all();
+ /** @return sorted list of groups. */
+ ImmutableList<AccountGroup> all();
/** Notify the cache that a new group was constructed. */
void onCreateGroup(AccountGroup.NameKey newGroupName);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCacheImpl.java
index a2f4b65..4f5cc2b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCacheImpl.java
@@ -16,6 +16,7 @@
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableList;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupName;
import com.google.gerrit.reviewdb.server.ReviewDb;
@@ -32,7 +33,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
@@ -151,12 +151,12 @@
}
@Override
- public Iterable<AccountGroup> all() {
+ public ImmutableList<AccountGroup> all() {
try (ReviewDb db = schema.open()) {
- return Collections.unmodifiableList(db.accountGroups().all().toList());
+ return ImmutableList.copyOf(db.accountGroups().all());
} catch (OrmException e) {
log.warn("Cannot list internal groups", e);
- return Collections.emptyList();
+ return ImmutableList.of();
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/InternalGroupBackend.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/InternalGroupBackend.java
index 84660ec..2028654 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/InternalGroupBackend.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/InternalGroupBackend.java
@@ -28,7 +28,6 @@
import org.eclipse.jgit.lib.ObjectId;
import java.util.Collection;
-import java.util.stream.StreamSupport;
/** Implementation of GroupBackend for the internal group system. */
@Singleton
@@ -68,7 +67,7 @@
@Override
public Collection<GroupReference> suggest(final String name,
final ProjectControl project) {
- return StreamSupport.stream(groupCache.all().spliterator(), false)
+ return groupCache.all().stream()
.filter(group ->
// startsWithIgnoreCase && isVisible
group.getName().regionMatches(true, 0, name, 0, name.length())
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
index 31c70d9..a265160 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
@@ -45,7 +45,7 @@
import com.google.gerrit.server.change.Check;
import com.google.gerrit.server.change.CreateMergePatchSet;
import com.google.gerrit.server.change.DeleteAssignee;
-import com.google.gerrit.server.change.DeleteDraftChange;
+import com.google.gerrit.server.change.DeleteChange;
import com.google.gerrit.server.change.GetAssignee;
import com.google.gerrit.server.change.GetHashtags;
import com.google.gerrit.server.change.GetPastAssignees;
@@ -98,7 +98,7 @@
private final Provider<SubmittedTogether> submittedTogether;
private final PublishDraftPatchSet.CurrentRevision
publishDraftChange;
- private final DeleteDraftChange deleteDraftChange;
+ private final DeleteChange deleteChange;
private final GetTopic getTopic;
private final PutTopic putTopic;
private final PostReviewers postReviewers;
@@ -129,7 +129,7 @@
CreateMergePatchSet updateByMerge,
Provider<SubmittedTogether> submittedTogether,
PublishDraftPatchSet.CurrentRevision publishDraftChange,
- DeleteDraftChange deleteDraftChange,
+ DeleteChange deleteChange,
GetTopic getTopic,
PutTopic putTopic,
PostReviewers postReviewers,
@@ -159,7 +159,7 @@
this.updateByMerge = updateByMerge;
this.submittedTogether = submittedTogether;
this.publishDraftChange = publishDraftChange;
- this.deleteDraftChange = deleteDraftChange;
+ this.deleteChange = deleteChange;
this.getTopic = getTopic;
this.putTopic = putTopic;
this.postReviewers = postReviewers;
@@ -324,7 +324,7 @@
@Override
public void delete() throws RestApiException {
try {
- deleteDraftChange.apply(change, null);
+ deleteChange.apply(change, null);
} catch (UpdateException e) {
throw new RestApiException("Cannot delete change", e);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ConsistencyChecker.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ConsistencyChecker.java
index 30ed82f..20e5b9d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ConsistencyChecker.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ConsistencyChecker.java
@@ -658,7 +658,7 @@
public boolean updateChange(ChangeContext ctx)
throws OrmException, PatchSetInfoNotAvailableException {
// Delete dangling key references.
- ReviewDb db = DeleteDraftChangeOp.unwrap(ctx.getDb());
+ ReviewDb db = DeleteChangeOp.unwrap(ctx.getDb());
accountPatchReviewStore.get().clearReviewed(psId);
db.changeMessages().delete(
db.changeMessages().byChange(psId.getParentKey()));
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftChange.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteChange.java
similarity index 75%
rename from gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftChange.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteChange.java
index a125272..18d7074 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftChange.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteChange.java
@@ -22,10 +22,11 @@
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Change.Status;
import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.server.change.DeleteDraftChange.Input;
+import com.google.gerrit.server.change.DeleteChange.Input;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.git.BatchUpdate;
import com.google.gerrit.server.git.UpdateException;
+import com.google.gerrit.server.project.ChangeControl;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -34,25 +35,25 @@
import org.eclipse.jgit.lib.Config;
@Singleton
-public class DeleteDraftChange implements
+public class DeleteChange implements
RestModifyView<ChangeResource, Input>, UiAction<ChangeResource> {
public static class Input {
}
private final Provider<ReviewDb> db;
private final BatchUpdate.Factory updateFactory;
- private final Provider<DeleteDraftChangeOp> opProvider;
+ private final Provider<DeleteChangeOp> opProvider;
private final boolean allowDrafts;
@Inject
- public DeleteDraftChange(Provider<ReviewDb> db,
+ public DeleteChange(Provider<ReviewDb> db,
BatchUpdate.Factory updateFactory,
- Provider<DeleteDraftChangeOp> opProvider,
+ Provider<DeleteChangeOp> opProvider,
@GerritServerConfig Config cfg) {
this.db = db;
this.updateFactory = updateFactory;
this.opProvider = opProvider;
- this.allowDrafts = DeleteDraftChangeOp.allowDrafts(cfg);
+ this.allowDrafts = DeleteChangeOp.allowDrafts(cfg);
}
@Override
@@ -71,14 +72,21 @@
@Override
public UiAction.Description getDescription(ChangeResource rsrc) {
try {
+ Change.Status status = rsrc.getChange().getStatus();
+ ChangeControl changeControl = rsrc.getControl();
+ boolean visible = isActionAllowed(changeControl, status)
+ && changeControl.canDelete(db.get(), status);
return new UiAction.Description()
.setLabel("Delete")
- .setTitle("Delete draft change " + rsrc.getId())
- .setVisible(allowDrafts
- && rsrc.getChange().getStatus() == Status.DRAFT
- && rsrc.getControl().canDeleteDraft(db.get()));
+ .setTitle("Delete change " + rsrc.getId())
+ .setVisible(visible);
} catch (OrmException e) {
throw new IllegalStateException(e);
}
}
+
+ private boolean isActionAllowed(ChangeControl changeControl,
+ Status status) {
+ return status != Status.DRAFT || allowDrafts || changeControl.isAdmin();
+ }
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftChangeOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteChangeOp.java
similarity index 82%
rename from gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftChangeOp.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteChangeOp.java
index 4ed6a25..0e77a50 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftChangeOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteChangeOp.java
@@ -44,7 +44,7 @@
import java.io.IOException;
import java.util.Collection;
-class DeleteDraftChangeOp extends BatchUpdate.Op {
+class DeleteChangeOp extends BatchUpdate.Op {
static boolean allowDrafts(Config cfg) {
return cfg.getBoolean("change", "allowDrafts", true);
}
@@ -68,7 +68,7 @@
private Change.Id id;
@Inject
- DeleteDraftChangeOp(PatchSetUtil psUtil,
+ DeleteChangeOp(PatchSetUtil psUtil,
StarredChangesUtil starredChangesUtil,
DynamicItem<AccountPatchReviewStore> accountPatchReviewStore,
@GerritServerConfig Config cfg) {
@@ -82,16 +82,18 @@
public boolean updateChange(ChangeContext ctx) throws RestApiException,
OrmException, IOException, NoSuchChangeException {
checkState(ctx.getOrder() == BatchUpdate.Order.DB_BEFORE_REPO,
- "must use DeleteDraftChangeOp with DB_BEFORE_REPO");
- checkState(id == null, "cannot reuse DeleteDraftChangeOp");
+ "must use DeleteChangeOp with DB_BEFORE_REPO");
+ checkState(id == null, "cannot reuse DeleteChangeOp");
id = ctx.getChange().getId();
Collection<PatchSet> patchSets = psUtil.byChange(ctx.getDb(),
ctx.getNotes());
ensureDeletable(ctx, id, patchSets);
- deleteChangeElementsFromDb(ctx, id);
+ // Cleaning up is only possible as long as the change and its elements are
+ // still part of the database.
cleanUpReferences(ctx, id, patchSets);
+ deleteChangeElementsFromDb(ctx, id);
ctx.deleteChange();
return true;
@@ -100,19 +102,25 @@
private void ensureDeletable(ChangeContext ctx, Change.Id id,
Collection<PatchSet> patchSets) throws ResourceConflictException,
MethodNotAllowedException, OrmException, AuthException {
- if (ctx.getChange().getStatus() != Change.Status.DRAFT) {
- throw new ResourceConflictException("Change is not a draft: " + id);
+ Change.Status status = ctx.getChange().getStatus();
+ if (status == Change.Status.MERGED) {
+ throw new MethodNotAllowedException("Deleting merged change " + id
+ + " is not allowed");
}
- if (!allowDrafts) {
- throw new MethodNotAllowedException("Draft workflow is disabled");
+
+ if (!ctx.getControl().canDelete(ctx.getDb(), status)) {
+ throw new AuthException("Deleting change " + id + " is not permitted");
}
- if (!ctx.getControl().canDeleteDraft(ctx.getDb())) {
- throw new AuthException("Not permitted to delete this draft change");
- }
- for (PatchSet ps : patchSets) {
- if (!ps.isDraft()) {
- throw new ResourceConflictException("Cannot delete draft change " + id
- + ": patch set " + ps.getPatchSetId() + " is not a draft");
+
+ if (status == Change.Status.DRAFT) {
+ if (!allowDrafts && !ctx.getControl().isAdmin()) {
+ throw new MethodNotAllowedException("Draft workflow is disabled");
+ }
+ for (PatchSet ps : patchSets) {
+ if (!ps.isDraft()) {
+ throw new ResourceConflictException("Cannot delete draft change " + id
+ + ": patch set " + ps.getPatchSetId() + " is not a draft");
+ }
}
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftPatchSet.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftPatchSet.java
index 1cd8726..e473e39 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftPatchSet.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftPatchSet.java
@@ -59,7 +59,7 @@
private final BatchUpdate.Factory updateFactory;
private final PatchSetInfoFactory patchSetInfoFactory;
private final PatchSetUtil psUtil;
- private final Provider<DeleteDraftChangeOp> deleteChangeOpProvider;
+ private final Provider<DeleteChangeOp> deleteChangeOpProvider;
private final DynamicItem<AccountPatchReviewStore> accountPatchReviewStore;
private final boolean allowDrafts;
@@ -68,7 +68,7 @@
BatchUpdate.Factory updateFactory,
PatchSetInfoFactory patchSetInfoFactory,
PatchSetUtil psUtil,
- Provider<DeleteDraftChangeOp> deleteChangeOpProvider,
+ Provider<DeleteChangeOp> deleteChangeOpProvider,
DynamicItem<AccountPatchReviewStore> accountPatchReviewStore,
@GerritServerConfig Config cfg) {
this.db = db;
@@ -97,7 +97,7 @@
private Collection<PatchSet> patchSetsBeforeDeletion;
private PatchSet patchSet;
- private DeleteDraftChangeOp deleteChangeOp;
+ private DeleteChangeOp deleteChangeOp;
private Op(PatchSet.Id psId) {
this.psId = psId;
@@ -116,7 +116,7 @@
if (!allowDrafts) {
throw new MethodNotAllowedException("Draft workflow is disabled");
}
- if (!ctx.getControl().canDeleteDraft(ctx.getDb())) {
+ if (!ctx.getControl().canDelete(ctx.getDb(), Change.Status.DRAFT)) {
throw new AuthException("Not permitted to delete this draft patch set");
}
@@ -146,8 +146,8 @@
psUtil.delete(ctx.getDb(), ctx.getUpdate(patchSet.getId()), patchSet);
accountPatchReviewStore.get().clearReviewed(psId);
- // Use the unwrap from DeleteDraftChangeOp to handle BatchUpdateReviewDb.
- ReviewDb db = DeleteDraftChangeOp.unwrap(ctx.getDb());
+ // Use the unwrap from DeleteChangeOp to handle BatchUpdateReviewDb.
+ ReviewDb db = DeleteChangeOp.unwrap(ctx.getDb());
db.changeMessages().delete(db.changeMessages().byPatchSet(psId));
db.patchComments().delete(db.patchComments().byPatchSet(psId));
db.patchSetApprovals().delete(db.patchSetApprovals().byPatchSet(psId));
@@ -195,7 +195,7 @@
rsrc.getPatchSet().getPatchSetId()))
.setVisible(allowDrafts
&& rsrc.getPatchSet().isDraft()
- && rsrc.getControl().canDeleteDraft(db.get())
+ && rsrc.getControl().canDelete(db.get(), Change.Status.DRAFT)
&& psCount > 1);
} catch (OrmException e) {
throw new IllegalStateException(e);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java
index bb76084..9ff9833 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java
@@ -68,7 +68,7 @@
post(CHANGE_KIND, "check").to(Check.class);
put(CHANGE_KIND, "topic").to(PutTopic.class);
delete(CHANGE_KIND, "topic").to(PutTopic.class);
- delete(CHANGE_KIND).to(DeleteDraftChange.class);
+ delete(CHANGE_KIND).to(DeleteChange.class);
post(CHANGE_KIND, "abandon").to(Abandon.class);
post(CHANGE_KIND, "hashtags").to(PostHashtags.class);
post(CHANGE_KIND, "publish").to(PublishDraftPatchSet.CurrentRevision.class);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritOptions.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritOptions.java
index c181f79..ab4b463 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritOptions.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritOptions.java
@@ -33,7 +33,7 @@
boolean forcePolyGerritDev) {
this.slave = slave;
this.enablePolyGerrit = forcePolyGerritDev
- || cfg.getBoolean("gerrit", null, "enablePolyGerrit", false);
+ || cfg.getBoolean("gerrit", null, "enablePolyGerrit", true);
this.enableGwtUi = cfg.getBoolean("gerrit", null, "enableGwtUi", true);
this.forcePolyGerritDev = forcePolyGerritDev;
this.headless = headless || (!enableGwtUi && !enablePolyGerrit);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java
index d23cac4..85c3d15 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/ListGroups.java
@@ -45,6 +45,7 @@
import org.kohsuke.args4j.Option;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
@@ -314,11 +315,11 @@
return groups;
}
- private List<AccountGroup> filterGroups(final Iterable<AccountGroup> groups) {
- final List<AccountGroup> filteredGroups = new ArrayList<>();
- final boolean isAdmin =
+ private List<AccountGroup> filterGroups(Collection<AccountGroup> groups) {
+ List<AccountGroup> filteredGroups = new ArrayList<>(groups.size());
+ boolean isAdmin =
identifiedUser.get().getCapabilities().canAdministrateServer();
- for (final AccountGroup group : groups) {
+ for (AccountGroup group : groups) {
if (!Strings.isNullOrEmpty(matchSubstring)) {
if (!group.getName().toLowerCase(Locale.US)
.contains(matchSubstring.toLowerCase(Locale.US))) {
@@ -326,7 +327,7 @@
}
}
if (!isAdmin) {
- final GroupControl c = groupControlFactory.controlFor(group);
+ GroupControl c = groupControlFactory.controlFor(group);
if (!c.isVisible()) {
continue;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RepoSequence.java b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RepoSequence.java
index 8172906..e4a6f7c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RepoSequence.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/notedb/RepoSequence.java
@@ -83,7 +83,8 @@
.withStopStrategy(StopStrategies.stopAfterDelay(30, TimeUnit.SECONDS));
}
- private static Retryer<RefUpdate.Result> RETRYER = retryerBuilder().build();
+ private static final Retryer<RefUpdate.Result> RETRYER =
+ retryerBuilder().build();
private final GitRepositoryManager repoManager;
private final Project.NameKey projectName;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java
index 5cc461f..c4d8dcd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java
@@ -261,10 +261,23 @@
&& isVisible(db);
}
- /** Can this user delete this draft change or any draft patch set of this change? */
- public boolean canDeleteDraft(final ReviewDb db) throws OrmException {
- return (isOwner() || getRefControl().canDeleteDrafts())
- && isVisible(db);
+ /** Can this user delete this change or any patch set of this change? */
+ public boolean canDelete(ReviewDb db, Change.Status status)
+ throws OrmException {
+ if (!isVisible(db)) {
+ return false;
+ }
+
+ switch (status) {
+ case DRAFT:
+ return (isOwner() || getRefControl().canDeleteDrafts());
+ case NEW:
+ case ABANDONED:
+ return isAdmin();
+ case MERGED:
+ default:
+ return false;
+ }
}
/** Can this user rebase this change? */
@@ -377,6 +390,10 @@
return false;
}
+ public boolean isAdmin() {
+ return getUser().getCapabilities().canAdministrateServer();
+ }
+
/** @return true if the user is allowed to remove this reviewer. */
public boolean canRemoveReviewer(PatchSetApproval approval) {
return canRemoveReviewer(approval.getAccountId(), approval.getValue());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
index eaec021..3387f06 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
@@ -17,11 +17,10 @@
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.gerrit.server.ApprovalsUtil.sortApprovals;
+import static java.util.stream.Collectors.toList;
import com.google.auto.value.AutoValue;
import com.google.common.base.MoreObjects;
-import com.google.common.base.Predicate;
-import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMultimap;
@@ -94,6 +93,8 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
public class ChangeData {
private static final int BATCH_SIZE = 50;
@@ -108,12 +109,8 @@
}
public static Map<Change.Id, ChangeData> asMap(List<ChangeData> changes) {
- Map<Change.Id, ChangeData> result =
- Maps.newHashMapWithExpectedSize(changes.size());
- for (ChangeData cd : changes) {
- result.put(cd.getId(), cd);
- }
- return result;
+ return changes.stream().collect(
+ Collectors.toMap(ChangeData::getId, cd -> cd));
}
public static void ensureChangeLoaded(Iterable<ChangeData> changes)
@@ -898,14 +895,14 @@
* @throws OrmException an error occurred reading the database.
*/
public Collection<PatchSet> visiblePatchSets() throws OrmException {
- Predicate<PatchSet> predicate = ps -> {
+ Predicate<? super PatchSet> predicate = ps -> {
try {
return changeControl().isPatchVisible(ps, db);
} catch (OrmException e) {
return false;
}
};
- return FluentIterable.from(patchSets()).filter(predicate).toList();
+ return patchSets().stream().filter(predicate).collect(toList());
}
public void setPatchSets(Collection<PatchSet> patchSets) {
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
index 5686dc3..1ff5aac 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
@@ -36,6 +36,8 @@
import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.query.change.InternalChangeQuery;
import com.google.gerrit.server.schema.SchemaCreator;
+import com.google.gerrit.server.util.ManualRequestContext;
+import com.google.gerrit.server.util.OneOffRequestContext;
import com.google.gerrit.server.util.RequestContext;
import com.google.gerrit.server.util.ThreadLocalRequestContext;
import com.google.gerrit.testutil.ConfigSuite;
@@ -97,6 +99,9 @@
@Inject
protected ThreadLocalRequestContext requestContext;
+ @Inject
+ protected OneOffRequestContext oneOffRequestContext;
+
protected LifecycleManager lifecycle;
protected ReviewDb db;
protected AccountInfo currentUserInfo;
@@ -405,18 +410,20 @@
private Account.Id createAccount(String username, String fullName,
String email, boolean active) throws Exception {
- Account.Id id =
- accountManager.authenticate(AuthRequest.forUser(username)).getAccountId();
- if (email != null) {
- accountManager.link(id, AuthRequest.forEmail(email));
+ try (ManualRequestContext ctx = oneOffRequestContext.open()) {
+ Account.Id id =
+ accountManager.authenticate(AuthRequest.forUser(username)).getAccountId();
+ if (email != null) {
+ accountManager.link(id, AuthRequest.forEmail(email));
+ }
+ Account a = db.accounts().get(id);
+ a.setFullName(fullName);
+ a.setPreferredEmail(email);
+ a.setActive(active);
+ db.accounts().update(ImmutableList.of(a));
+ accountCache.evict(id);
+ return id;
}
- Account a = db.accounts().get(id);
- a.setFullName(fullName);
- a.setPreferredEmail(email);
- a.setActive(active);
- db.accounts().update(ImmutableList.of(a));
- accountCache.evict(id);
- return id;
}
private void addEmails(AccountInfo account, String... emails)
diff --git a/lib/JGIT_VERSION b/lib/JGIT_VERSION
index b7f7c84..569cf59 100644
--- a/lib/JGIT_VERSION
+++ b/lib/JGIT_VERSION
@@ -1,6 +1,4 @@
+include_defs('//lib/jgit/jgit.bzl')
include_defs('//lib/maven.defs')
REPO = MAVEN_CENTRAL # Leave here even if set to MAVEN_CENTRAL.
-VERS = '4.5.0.201609210915-r'
-DOC_VERS = VERS # Set to VERS unless using a snapshot
-JGIT_DOC_URL="http://download.eclipse.org/jgit/site/" + DOC_VERS + "/apidocs"
diff --git a/lib/jgit/jgit.bzl b/lib/jgit/jgit.bzl
new file mode 100644
index 0000000..996e44d
--- /dev/null
+++ b/lib/jgit/jgit.bzl
@@ -0,0 +1,3 @@
+JGIT_VERS = '4.5.0.201609210915-r'
+DOC_VERS = JGIT_VERS # Set to VERS unless using a snapshot
+JGIT_DOC_URL="http://download.eclipse.org/jgit/site/" + DOC_VERS + "/apidocs"
diff --git a/lib/jgit/org.eclipse.jgit.archive/BUCK b/lib/jgit/org.eclipse.jgit.archive/BUCK
index 7c967b3..02f99c6 100644
--- a/lib/jgit/org.eclipse.jgit.archive/BUCK
+++ b/lib/jgit/org.eclipse.jgit.archive/BUCK
@@ -3,7 +3,7 @@
maven_jar(
name = 'jgit-archive',
- id = 'org.eclipse.jgit:org.eclipse.jgit.archive:' + VERS,
+ id = 'org.eclipse.jgit:org.eclipse.jgit.archive:' + JGIT_VERS,
sha1 = '2db2e7666672a31fa41b7e1dadcba51df6d30954',
license = 'jgit',
repository = REPO,
diff --git a/lib/jgit/org.eclipse.jgit.http.server/BUCK b/lib/jgit/org.eclipse.jgit.http.server/BUCK
index 06865cb..5dd3777 100644
--- a/lib/jgit/org.eclipse.jgit.http.server/BUCK
+++ b/lib/jgit/org.eclipse.jgit.http.server/BUCK
@@ -3,7 +3,7 @@
maven_jar(
name = 'jgit-servlet',
- id = 'org.eclipse.jgit:org.eclipse.jgit.http.server:' + VERS,
+ id = 'org.eclipse.jgit:org.eclipse.jgit.http.server:' + JGIT_VERS,
sha1 = '6e36638888918d9941dddec7e2abe1f162cc74d9',
license = 'jgit',
repository = REPO,
diff --git a/lib/jgit/org.eclipse.jgit.junit/BUCK b/lib/jgit/org.eclipse.jgit.junit/BUCK
index 77b637a..e5cd5c0 100644
--- a/lib/jgit/org.eclipse.jgit.junit/BUCK
+++ b/lib/jgit/org.eclipse.jgit.junit/BUCK
@@ -3,7 +3,7 @@
maven_jar(
name = 'junit',
- id = 'org.eclipse.jgit:org.eclipse.jgit.junit:' + VERS,
+ id = 'org.eclipse.jgit:org.eclipse.jgit.junit:' + JGIT_VERS,
sha1 = 'e8fb1d81f588c3174a9730bdecdbde9faa04140a',
license = 'DO_NOT_DISTRIBUTE',
repository = REPO,
diff --git a/lib/jgit/org.eclipse.jgit/BUCK b/lib/jgit/org.eclipse.jgit/BUCK
index 458703c..74338de 100644
--- a/lib/jgit/org.eclipse.jgit/BUCK
+++ b/lib/jgit/org.eclipse.jgit/BUCK
@@ -3,7 +3,7 @@
maven_jar(
name = 'jgit',
- id = 'org.eclipse.jgit:org.eclipse.jgit:' + VERS,
+ id = 'org.eclipse.jgit:org.eclipse.jgit:' + JGIT_VERS,
bin_sha1 = '3e3d0b73dcf4ad649f37758ea8502d92f3d299de',
src_sha1 = 'fc352952db91a4046e4b832145eb2dc8afce8db1',
license = 'jgit',
diff --git a/plugins/replication b/plugins/replication
index 3212bcd..bc37211 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit 3212bcd4f2c0dc791a99af97ee98df70746f2306
+Subproject commit bc37211df3cc7b7516974142d78232197c49ce29
diff --git a/tools/bzl/javadoc.bzl b/tools/bzl/javadoc.bzl
index c479e2c..dcaa611 100644
--- a/tools/bzl/javadoc.bzl
+++ b/tools/bzl/javadoc.bzl
@@ -26,6 +26,7 @@
transitive_jar_paths = [j.path for j in transitive_jar_set]
dir = ctx.outputs.zip.path + ".dir"
source = ctx.outputs.zip.path + ".source"
+ external_docs = ["http://docs.oracle.com/javase/8/docs/api"] + ctx.attr.external_docs
cmd = [
"rm -rf %s" % source,
"mkdir %s" % source,
@@ -41,7 +42,7 @@
"-notimestamp",
"-quiet",
"-windowtitle '%s'" % ctx.attr.title,
- "-link", "http://docs.oracle.com/javase/8/docs/api",
+ " ".join(['-link %s' % url for url in external_docs]),
"-sourcepath %s" % source,
"-subpackages ",
":".join(ctx.attr.pkgs),
@@ -61,6 +62,7 @@
"libs": attr.label_list(allow_files = False),
"pkgs": attr.string_list(),
"title": attr.string(),
+ "external_docs": attr.string_list(),
"_javadoc": attr.label(
default = Label("@local_jdk//:bin/javadoc"),
single_file = True,
diff --git a/tools/bzl/pkg_war.bzl b/tools/bzl/pkg_war.bzl
index aa7d07f..a9d3e2e 100644
--- a/tools/bzl/pkg_war.bzl
+++ b/tools/bzl/pkg_war.bzl
@@ -53,10 +53,11 @@
]
def _make_war(input_dir, output):
- return ''.join([
- '(root=$(pwd) && ',
- 'cd %s && ' % input_dir,
- 'zip -9qr ${root}/%s .)' % (output.path),
+ return '(%s)' % ' && '.join([
+ 'root=$(pwd)',
+ 'cd %s' % input_dir,
+ "find . -exec touch -t 198001010000 '{}' ';' 2> /dev/null",
+ 'zip -9qr ${root}/%s .' % (output.path),
])
def _war_impl(ctx):
@@ -126,8 +127,11 @@
def pkg_war(name, ui = 'ui_optdbg', context = [], **kwargs):
ui_deps = []
- if ui:
+ if ui == 'polygerrit' or ui == 'ui_optdbg' or ui == 'ui_optdbg_r':
+ ui_deps.append('//polygerrit-ui/app:polygerrit_ui')
+ if ui != 'polygerrit':
ui_deps.append('//gerrit-gwtui:%s' % ui)
+
_pkg_war(
name = name,
libs = LIBS,
diff --git a/tools/bzl/setup-intellij.sh b/tools/bzl/setup-intellij.sh
new file mode 100644
index 0000000..57df8c8
--- /dev/null
+++ b/tools/bzl/setup-intellij.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+# This script sets up a 'bazel_external' libraries for maven jars and Auto classes.
+#
+# To use:
+#
+# * Start IntelliJ
+# * Go to "project structure" (Ctrl-Alt-Shift-S),
+# * Go to "Libraries",
+# * Right click "bazel_external"
+# * Select "Add to Module"
+# * Select all modules, click OK
+# * Click "Apply"
+
+mkdir -p .idea/libraries/
+dest=.idea/libraries/bazel_external.xml
+
+cat <<EOF > $dest
+ <component name="libraryTable">
+ <library name="bazel_external">
+ <CLASSES>
+EOF
+
+for jar in $(bazel query --nohost_deps --output=location 'kind(file,deps(kind(java_import,deps(//...))))' | grep 'source file .*jar$' | sed 's|/BUILD:[0-9]*:[0-9]*: source file [^:]*:|/|' ); do
+cat <<EOF >> $dest
+ <root url="jar://$jar!/" />
+EOF
+done
+
+cat <<EOF >> $dest
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+</component>
+EOF
+
+dest=.idea/libraries/bazel_autogen.xml
+cat <<EOF > $dest
+<component name="libraryTable">
+ <library name="bazel_autogen">
+ <CLASSES />
+ <JAVADOC />
+ <SOURCES>
+EOF
+
+not_found=""
+
+for dep in $(bazel query 'rdeps(//...,//lib/auto:auto-value,1) - //lib/auto:auto-value'); do
+ root=$(echo $dep | sed 's|//\(.*\):\(.*\)|bazel-bin/\1/_javac/\2/lib\2_sourcegenfiles|g')
+ if [[ ! -d $root ]]; then
+ # for some reason, tests don't have the "lib" prefix.
+ root=$(echo $dep | sed 's|//\(.*\):\(.*\)|bazel-bin/\1/_javac/\2/\2_sourcegenfiles|g')
+ fi
+ if [[ ! -d $root ]]; then
+ not_found="$not_found $root"
+ fi
+cat <<EOF >> $dest
+ <root url="file://\$PROJECT_DIR\$/$root" />
+EOF
+done
+
+cat <<EOF >> $dest
+ </SOURCES>
+ </library>
+</component>
+EOF
+
+
+if [[ -n "$not_found" ]]; then
+ echo "some generated roots were missing. Did you run 'bazel build' yet?"
+fi