Merge "Add asciidoc checks in the documentation makefile"
diff --git a/Documentation/error-messages.txt b/Documentation/error-messages.txt
index 6685ea1..58e9e02 100644
--- a/Documentation/error-messages.txt
+++ b/Documentation/error-messages.txt
@@ -26,13 +26,13 @@
* link:error-no-new-changes.html[no new changes]
* link:error-non-fast-forward.html[non-fast forward]
* link:error-not-a-gerrit-administrator.html[Not a Gerrit administrator]
-* link:error-not-a-gerrit-project.html[not a Gerrit project]
* link:error-not-permitted-to-create.html[Not permitted to create ...]
* link:error-not-signed-off-by.html[not Signed-off-by author/committer/uploader in commit message footer]
* link:error-not-valid-ref.html[not valid ref]
* link:error-change-upload-blocked.html[One or more refs/for/ names blocks change upload]
* link:error-permission-denied.html[Permission denied (publickey)]
* link:error-prohibited-by-gerrit.html[prohibited by Gerrit]
+* link:error-project-not-found.html[Project not found: ...]
* link:error-squash-commits-first.html[squash commits first]
* link:error-upload-denied.html[Upload denied for project \'...']
* link:error-not-allowed-to-upload-merges.html[you are not allowed to upload merges]
diff --git a/Documentation/error-not-a-gerrit-project.txt b/Documentation/error-project-not-found.txt
similarity index 96%
rename from Documentation/error-not-a-gerrit-project.txt
rename to Documentation/error-project-not-found.txt
index 58919d5..3fc0141 100644
--- a/Documentation/error-not-a-gerrit-project.txt
+++ b/Documentation/error-project-not-found.txt
@@ -1,5 +1,5 @@
-not a Gerrit project
-====================
+Project not found: ...
+======================
With this error message Gerrit rejects to push a commit if the git
repository to which the push is done does not exist as a project in
diff --git a/Documentation/rest-api-groups.txt b/Documentation/rest-api-groups.txt
index 73f4c90..522cc77 100644
--- a/Documentation/rest-api-groups.txt
+++ b/Documentation/rest-api-groups.txt
@@ -427,6 +427,9 @@
The new owner group must be provided in the request body.
+The new owner can be specified by name, by group UUID or by the legacy
+numeric group ID.
+
.Request
----
PUT /groups/9999c971bb4ab872aab759d8c49833ee6b9ff320/description HTTP/1.0
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/GetGroupIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/GetGroupIT.java
new file mode 100644
index 0000000..e76687e
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/GetGroupIT.java
@@ -0,0 +1,73 @@
+// Copyright (C) 2013 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.rest.group;
+
+import static com.google.gerrit.acceptance.rest.group.GroupAssert.assertGroupInfo;
+
+import com.google.common.reflect.TypeToken;
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.AccountCreator;
+import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.RestSession;
+import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.server.account.GroupCache;
+import com.google.gson.Gson;
+import com.google.inject.Inject;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class GetGroupIT extends AbstractDaemonTest {
+
+ @Inject
+ private AccountCreator accounts;
+
+ @Inject
+ private GroupCache groupCache;
+
+ private TestAccount admin;
+ private RestSession session;
+
+ @Before
+ public void setUp() throws Exception {
+ admin = accounts.create("admin", "admin@example.com", "Administrator",
+ "Administrators");
+ session = new RestSession(admin);
+ }
+
+ @Test
+ public void testGetGroup() throws IOException {
+ AccountGroup adminGroup = groupCache.get(new AccountGroup.NameKey("Administrators"));
+
+ // by UUID
+ testGetGroup("/groups/" + adminGroup.getGroupUUID().get(), adminGroup);
+
+ // by name
+ testGetGroup("/groups/" + adminGroup.getName(), adminGroup);
+
+ // by legacy numeric ID
+ testGetGroup("/groups/" + adminGroup.getId().get(), adminGroup);
+ }
+
+ private void testGetGroup(String url, AccountGroup expectedGroup) throws IOException {
+ RestResponse r = session.get(url);
+ @SuppressWarnings("serial")
+ GroupInfo group = (new Gson()).fromJson(r.getReader(), new TypeToken<GroupInfo>() {}.getType());
+ assertGroupInfo(expectedGroup, group);
+ }
+}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/ProjectUtil.java b/gerrit-common/src/main/java/com/google/gerrit/common/ProjectUtil.java
index f9dba0c..0fba41e 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/ProjectUtil.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/ProjectUtil.java
@@ -14,23 +14,20 @@
package com.google.gerrit.common;
-import org.eclipse.jgit.lib.Constants;
-
public class ProjectUtil {
public static String stripGitSuffix(String name) {
- String nameWithoutSuffix = name;
-
- if (nameWithoutSuffix.endsWith(Constants.DOT_GIT_EXT)) {
+ if (name.endsWith(".git")) {
// Be nice and drop the trailing ".git" suffix, which we never keep
// in our database, but clients might mistakenly provide anyway.
//
- nameWithoutSuffix = nameWithoutSuffix.substring(0, //
- nameWithoutSuffix.length() - Constants.DOT_GIT_EXT.length());
- while (nameWithoutSuffix.endsWith("/")) {
- nameWithoutSuffix =
- nameWithoutSuffix.substring(0, nameWithoutSuffix.length() - 1);
+ name = name.substring(0, name.length() - 4);
+ while (name.endsWith("/")) {
+ name = name.substring(0, name.length() - 1);
}
}
- return nameWithoutSuffix;
+ return name;
+ }
+
+ private ProjectUtil() {
}
}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/errors/NameAlreadyUsedException.java b/gerrit-common/src/main/java/com/google/gerrit/common/errors/NameAlreadyUsedException.java
index d3988ff..ea20e2e 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/errors/NameAlreadyUsedException.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/errors/NameAlreadyUsedException.java
@@ -18,13 +18,9 @@
public class NameAlreadyUsedException extends Exception {
private static final long serialVersionUID = 1L;
- public static final String MESSAGE = "Name Already Used";
-
- public NameAlreadyUsedException() {
- super(MESSAGE);
- }
+ public static final String MESSAGE = "Name Already Used: ";
public NameAlreadyUsedException(String name) {
- super(MESSAGE + ": " + name);
+ super(MESSAGE + name);
}
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
index 8a57515..0b57bcb 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
@@ -44,7 +44,6 @@
String notFoundTitle();
String notFoundBody();
- String nameAlreadyUsedBody();
String noSuchAccountTitle();
String noSuchGroupTitle();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
index 3eee2be..f7033e4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
@@ -27,7 +27,6 @@
notFoundTitle = Not Found
notFoundBody = The page you requested was not found, or you do not have permission to view this page.
-nameAlreadyUsedBody = The name is already in use.
noSuchAccountTitle = Code Review - Unknown User
noSuchGroupTitle = Code Review - Unknown Group
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.java
index 12e7402..8fc196a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.java
@@ -23,6 +23,7 @@
String noSuchAccountMessage(String who);
String noSuchGroupMessage(String who);
+ String nameAlreadyUsedBody(String alreadyUsedName);
String branchCreationFailed(String branchName, String error);
String invalidBranchName(String branchName);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.properties
index 84cf476..41caa44 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritMessages.properties
@@ -4,6 +4,7 @@
noSuchAccountMessage = {0} is not a registered user.
noSuchGroupMessage = Group {0} does not exist or is not visible to you.
+nameAlreadyUsedBody = The name {0} is already in use.
branchCreationFailed = Creating branch {0} failed. Error: {1}
invalidBranchName = The branch name {0} is not valid.
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchPanel.java
index fe9a834..2ae6005 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchPanel.java
@@ -23,8 +23,6 @@
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.event.dom.client.FocusEvent;
-import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
@@ -80,6 +78,9 @@
searchBox.addKeyPressHandler(new KeyPressHandler() {
@Override
public void onKeyPress(final KeyPressEvent event) {
+ if (searchBox.getVisibleLength() == SMALL_SIZE) {
+ sizeAnimation.run(true);
+ }
if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) {
if (!suggestionDisplay.isSuggestionSelected) {
doSearch();
@@ -87,14 +88,6 @@
}
}
});
- searchBox.addFocusHandler(new FocusHandler() {
- @Override
- public void onFocus(FocusEvent event) {
- if(searchBox.getVisibleLength() == SMALL_SIZE) {
- sizeAnimation.run(true);
- }
- }
- });
searchBox.addBlurHandler(new BlurHandler() {
@Override
public void onBlur(BlurEvent event) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/CreateProjectScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/CreateProjectScreen.java
index 555d023..7c880a9 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/CreateProjectScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/CreateProjectScreen.java
@@ -30,6 +30,7 @@
import com.google.gerrit.client.ui.ProjectsTable;
import com.google.gerrit.client.ui.Screen;
import com.google.gerrit.common.PageLinks;
+import com.google.gerrit.common.ProjectUtil;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
@@ -235,20 +236,7 @@
new GerritCallback<VoidResult>() {
@Override
public void onSuccess(VoidResult result) {
- String nameWithoutSuffix = projectName;
- if (nameWithoutSuffix.endsWith(".git")) {
- // Be nice and drop the trailing ".git" suffix, which we never
- // keep in our database, but clients might mistakenly provide
- // anyway.
- //
- nameWithoutSuffix = nameWithoutSuffix.substring(0, //
- nameWithoutSuffix.length() - 4);
- while (nameWithoutSuffix.endsWith("/")) {
- nameWithoutSuffix = nameWithoutSuffix.substring(//
- 0, nameWithoutSuffix.length() - 1);
- }
- }
-
+ String nameWithoutSuffix = ProjectUtil.stripGitSuffix(projectName);
History.newItem(Dispatcher.toProjectAdmin(new Project.NameKey(
nameWithoutSuffix), ProjectScreen.INFO));
}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/GerritCallback.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/GerritCallback.java
index eebbd5a..06d1f0b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/GerritCallback.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/GerritCallback.java
@@ -54,7 +54,9 @@
d.center();
} else if (isNameAlreadyUsed(caught)) {
- new ErrorDialog(Gerrit.C.nameAlreadyUsedBody()).center();
+ final String msg = caught.getMessage();
+ final String alreadyUsedName = msg.substring(NameAlreadyUsedException.MESSAGE.length());
+ new ErrorDialog(Gerrit.M.nameAlreadyUsedBody(alreadyUsedName)).center();
} else if (isNoSuchGroup(caught)) {
final String msg = caught.getMessage();
@@ -101,7 +103,7 @@
private static boolean isNameAlreadyUsed(final Throwable caught) {
return caught instanceof RemoteJsonException
- && caught.getMessage().equals(NameAlreadyUsedException.MESSAGE);
+ && caught.getMessage().startsWith(NameAlreadyUsedException.MESSAGE);
}
private static boolean isNoSuchGroup(final Throwable caught) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
index 79b05c2..8bd76ad 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
@@ -294,6 +294,10 @@
private Map<String, LabelInfo> labelsFor(ChangeData cd, boolean standard,
boolean detailed) throws OrmException {
+ if (!standard && !detailed) {
+ return null;
+ }
+
ChangeControl ctl = control(cd);
if (ctl == null) {
return Collections.emptyMap();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteReviewer.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteReviewer.java
index a7e5254..a121248 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteReviewer.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteReviewer.java
@@ -77,7 +77,7 @@
new Predicate<PatchSetApproval>() {
@Override
public boolean apply(PatchSetApproval input) {
- return input.getAccountId().equals(rsrc.getAccount().getId());
+ return input.getAccountId().equals(rsrc.getUser().getAccountId());
}
});
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetReviewer.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetReviewer.java
index 28f397c..8c41be8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetReviewer.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetReviewer.java
@@ -27,7 +27,7 @@
}
@Override
- public Object apply(ReviewerResource reviewerResource) throws OrmException {
- return json.format(reviewerResource);
+ public Object apply(ReviewerResource rsrc) throws OrmException {
+ return json.format(rsrc);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ListReviewers.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ListReviewers.java
index 1c68e94..48c054a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ListReviewers.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ListReviewers.java
@@ -32,20 +32,23 @@
private final AccountCache accountCache;
private final Provider<ReviewDb> dbProvider;
private final ReviewerJson json;
+ private final ReviewerResource.Factory resourceFactory;
@Inject
ListReviewers(AccountCache accountCache,
Provider<ReviewDb> dbProvider,
+ ReviewerResource.Factory resourceFactory,
ReviewerJson json) {
this.accountCache = accountCache;
this.dbProvider = dbProvider;
+ this.resourceFactory = resourceFactory;
this.json = json;
}
@Override
public Object apply(ChangeResource rsrc) throws BadRequestException,
OrmException {
- Map<Account.Id, Object> reviewers = Maps.newLinkedHashMap();
+ Map<Account.Id, ReviewerResource> reviewers = Maps.newLinkedHashMap();
ReviewDb db = dbProvider.get();
Change.Id changeId = rsrc.getChange().getId();
for (PatchSetApproval patchSetApproval
@@ -53,10 +56,9 @@
Account.Id accountId = patchSetApproval.getAccountId();
if (!reviewers.containsKey(accountId)) {
Account account = accountCache.get(accountId).getAccount();
- reviewers.put(accountId,
- json.format(new ReviewerResource(rsrc, account)));
+ reviewers.put(accountId, resourceFactory.create(rsrc, account));
}
}
- return reviewers.values();
+ return json.format(reviewers.values());
}
}
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 6586725..b00b3d2 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
@@ -71,6 +71,7 @@
install(new FactoryModule() {
@Override
protected void configure() {
+ factory(ReviewerResource.Factory.class);
factory(AccountInfo.Loader.Factory.class);
factory(EmailReviewComments.Factory.class);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerJson.java
index d474386..9479e67 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerJson.java
@@ -14,25 +14,104 @@
package com.google.gerrit.server.change;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.gerrit.common.data.ApprovalType;
+import com.google.gerrit.common.data.ApprovalTypes;
+import com.google.gerrit.common.data.PermissionRange;
import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.ApprovalCategoryValue;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.project.ChangeControl;
+import com.google.gerrit.server.workflow.CategoryFunction;
+import com.google.gerrit.server.workflow.FunctionState;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
public class ReviewerJson {
- ReviewerJson() {
+ private final Provider<ReviewDb> db;
+ private final ApprovalTypes approvalTypes;
+ private final FunctionState.Factory functionState;
+ private final AccountInfo.Loader.Factory accountLoaderFactory;
+
+ @Inject
+ ReviewerJson(Provider<ReviewDb> db,
+ ApprovalTypes approvalTypes,
+ FunctionState.Factory functionState,
+ AccountInfo.Loader.Factory accountLoaderFactory) {
+ this.db = db;
+ this.approvalTypes = approvalTypes;
+ this.functionState = functionState;
+ this.accountLoaderFactory = accountLoaderFactory;
}
- public ReviewerInfo format(ReviewerResource reviewerResource) {
- ReviewerInfo reviewerInfo = new ReviewerInfo();
- Account account = reviewerResource.getAccount();
- reviewerInfo.id = account.getId().toString();
- reviewerInfo.email = account.getPreferredEmail();
- reviewerInfo.name = account.getFullName();
- return reviewerInfo;
+ public List<ReviewerInfo> format(Collection<ReviewerResource> rsrcs) throws OrmException {
+ List<ReviewerInfo> infos = Lists.newArrayListWithCapacity(rsrcs.size());
+ AccountInfo.Loader loader = accountLoaderFactory.create(true);
+ for (ReviewerResource rsrc : rsrcs) {
+ ReviewerInfo info = formatOne(rsrc);
+ loader.put(info);
+ infos.add(info);
+ }
+ loader.fill();
+ return infos;
}
- public static class ReviewerInfo {
+ public List<ReviewerInfo> format(ReviewerResource rsrc) throws OrmException {
+ return format(ImmutableList.<ReviewerResource> of(rsrc));
+ }
+
+ private ReviewerInfo formatOne(ReviewerResource rsrc) throws OrmException {
+ Account.Id id = rsrc.getUser().getAccountId();
+ ReviewerInfo out = new ReviewerInfo(id);
+
+ Change change = rsrc.getChange();
+ PatchSet.Id psId = change.currentPatchSetId();
+
+ List<PatchSetApproval> approvals = db.get().patchSetApprovals()
+ .byPatchSetUser(psId, id).toList();
+
+ ChangeControl control = rsrc.getControl().forUser(rsrc.getUser());
+ FunctionState fs = functionState.create(control, psId, approvals);
+ for (ApprovalType at : approvalTypes.getApprovalTypes()) {
+ CategoryFunction.forCategory(at.getCategory()).run(at, fs);
+ }
+
+ out.approvals = Maps.newHashMapWithExpectedSize(approvals.size());
+ for (PatchSetApproval ca : approvals) {
+ for (PermissionRange pr : control.getLabelRanges()) {
+ if (pr.getMin() != 0 || pr.getMax() != 0) {
+ // TODO: Support arbitrary labels.
+ ApprovalType at = approvalTypes.byId(ca.getCategoryId());
+ if (at != null) {
+ out.approvals.put(at.getCategory().getLabelName(),
+ ApprovalCategoryValue.formatValue(ca.getValue()));
+ }
+ }
+ }
+ }
+ if (out.approvals.isEmpty()) {
+ out.approvals = null;
+ }
+
+ return out;
+ }
+
+ public static class ReviewerInfo extends AccountInfo {
final String kind = "gerritcodereview#reviewer";
- String id;
- String email;
- String name;
+ Map<String, String> approvals;
+
+ protected ReviewerInfo(Account.Id id) {
+ super(id);
+ }
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerResource.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerResource.java
index e93c175..23fba47 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerResource.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ReviewerResource.java
@@ -16,20 +16,37 @@
import com.google.gerrit.extensions.restapi.RestView;
import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.server.IdentifiedUser;
import com.google.inject.TypeLiteral;
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
public class ReviewerResource extends ChangeResource {
public static final TypeLiteral<RestView<ReviewerResource>> REVIEWER_KIND =
new TypeLiteral<RestView<ReviewerResource>>() {};
- private final Account account;
-
- public ReviewerResource(ChangeResource changeResource, Account account) {
- super(changeResource);
- this.account = account;
+ static interface Factory {
+ ReviewerResource create(ChangeResource rsrc, IdentifiedUser user);
+ ReviewerResource create(ChangeResource rsrc, Account account);
}
- public Account getAccount() {
- return account;
+ private final IdentifiedUser user;
+
+ @AssistedInject
+ ReviewerResource(@Assisted ChangeResource rsrc,
+ @Assisted IdentifiedUser user) {
+ super(rsrc);
+ this.user = user;
+ }
+
+ @AssistedInject
+ ReviewerResource(IdentifiedUser.GenericFactory userFactory,
+ @Assisted ChangeResource rsrc,
+ @Assisted Account account) {
+ this(rsrc, userFactory.create(account.getId()));
+ }
+
+ public IdentifiedUser getUser() {
+ return user;
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Reviewers.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Reviewers.java
index 267f357..e75f54c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Reviewers.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Reviewers.java
@@ -14,6 +14,7 @@
package com.google.gerrit.server.change;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AuthException;
@@ -28,6 +29,7 @@
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountCache;
+import com.google.gerrit.server.account.AccountResolver;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -38,15 +40,21 @@
ChildCollection<ChangeResource, ReviewerResource> {
private final DynamicMap<RestView<ReviewerResource>> views;
private final Provider<ReviewDb> dbProvider;
+ private final AccountResolver resolver;
+ private final ReviewerResource.Factory resourceFactory;
private final AccountCache accountCache;
private final Provider<ListReviewers> list;
@Inject
Reviewers(Provider<ReviewDb> dbProvider,
- DynamicMap<RestView<ReviewerResource>> views,
- AccountCache accountCache,
- Provider<ListReviewers> list) {
+ AccountResolver resolver,
+ ReviewerResource.Factory resourceFactory,
+ DynamicMap<RestView<ReviewerResource>> views,
+ AccountCache accountCache,
+ Provider<ListReviewers> list) {
this.dbProvider = dbProvider;
+ this.resolver = resolver;
+ this.resourceFactory = resourceFactory;
this.views = views;
this.accountCache = accountCache;
this.list = list;
@@ -69,22 +77,24 @@
if (id.equals("self")) {
CurrentUser user = rsrc.getControl().getCurrentUser();
if (user instanceof IdentifiedUser) {
- accountId = ((IdentifiedUser)user).getAccountId();
+ accountId = ((IdentifiedUser) user).getAccountId();
} else if (user instanceof AnonymousUser) {
throw new AuthException("Authentication required");
} else {
throw new ResourceNotFoundException(id);
}
- } else if (id.get().matches("^[0-9]+$")) {
- accountId = Account.Id.parse(id.get());
} else {
- throw new ResourceNotFoundException(id);
+ Set<Account.Id> matches = resolver.findAll(id.get());
+ if (matches.size() != 1) {
+ throw new ResourceNotFoundException(id);
+ }
+ accountId = Iterables.getOnlyElement(matches);
}
// See if the id exists as a reviewer for this change
if (fetchAccountIds(rsrc).contains(accountId)) {
Account account = accountCache.get(accountId).getAccount();
- return new ReviewerResource(rsrc, account);
+ return resourceFactory.create(rsrc, account);
}
throw new ResourceNotFoundException(id);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
index a7dcce7..9ce47a1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
@@ -15,11 +15,15 @@
package com.google.gerrit.server.git;
import static com.google.gerrit.server.git.MergeUtil.getSubmitter;
+
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
+import static java.util.concurrent.TimeUnit.DAYS;
+import com.google.common.base.Objects;
import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Iterables;
import com.google.common.collect.ListMultimap;
import com.google.gerrit.common.ChangeHooks;
import com.google.gerrit.common.data.ApprovalType;
@@ -116,6 +120,9 @@
private static final long LOCK_FAILURE_RETRY_DELAY =
MILLISECONDS.convert(15, SECONDS);
+ private static final long DUPLICATE_MESSAGE_INTERVAL =
+ MILLISECONDS.convert(1, DAYS);
+
private final GitRepositoryManager repoManager;
private final SchemaFactory<ReviewDb> schemaFactory;
private final ProjectCache projectCache;
@@ -798,25 +805,20 @@
// dependencies are also submitted. Perhaps the user just
// forgot to submit those.
//
- String txt =
- "Change could not be merged because of a missing dependency.";
- if (!isAlreadySent(c, txt)) {
- StringBuilder m = new StringBuilder();
- m.append(txt);
- m.append("\n");
+ StringBuilder m = new StringBuilder();
+ m.append("Change could not be merged because of a missing dependency.");
+ m.append("\n");
- m.append("\n");
+ m.append("\n");
- m.append("The following changes must also be submitted:\n");
+ m.append("The following changes must also be submitted:\n");
+ m.append("\n");
+ for (CodeReviewCommit missingCommit : commit.missing) {
+ m.append("* ");
+ m.append(missingCommit.change.getKey().get());
m.append("\n");
- for (CodeReviewCommit missingCommit : commit.missing) {
- m.append("* ");
- m.append(missingCommit.change.getKey().get());
- m.append("\n");
- }
- txt = m.toString();
}
- capable = new Capable(txt);
+ capable = new Capable(m.toString());
} else {
// It is impossible to submit this change as-is. The author
// needs to rebase it in order to work around the missing
@@ -867,30 +869,6 @@
}
}
- private boolean isAlreadySent(final Change c, final String prefix) {
- try {
- final List<ChangeMessage> msgList =
- db.changeMessages().byChange(c.getId()).toList();
- if (msgList.size() > 0) {
- final ChangeMessage last = msgList.get(msgList.size() - 1);
- if (last.getAuthor() == null && last.getMessage().startsWith(prefix)) {
- // The last message was written by us, and it said this
- // same message already. Its unlikely anything has changed
- // that would cause us to need to repeat ourselves.
- //
- return true;
- }
- }
-
- // The last message was not sent by us, or doesn't match the text
- // we are about to send.
- //
- return false;
- } catch (OrmException e) {
- return true;
- }
- }
-
private ChangeMessage message(final Change c, final String body) {
final String uuid;
try {
@@ -1039,8 +1017,31 @@
sendMergeFail(c, msg, true);
}
+ private boolean isDuplicate(ChangeMessage msg) {
+ try {
+ ChangeMessage last = Iterables.getLast(db.changeMessages().byChange(
+ msg.getPatchSetId().getParentKey()), null);
+ if (last != null) {
+ long lastMs = last.getWrittenOn().getTime();
+ long msgMs = msg.getWrittenOn().getTime();
+ if (Objects.equal(last.getAuthor(), msg.getAuthor())
+ && Objects.equal(last.getMessage(), msg.getMessage())
+ && msgMs - lastMs < DUPLICATE_MESSAGE_INTERVAL) {
+ return true;
+ }
+ }
+ } catch (OrmException err) {
+ log.warn("Cannot check previous merge failure message", err);
+ }
+ return false;
+ }
+
private void sendMergeFail(final Change c, final ChangeMessage msg,
final boolean makeNew) {
+ if (isDuplicate(msg)) {
+ return;
+ }
+
try {
db.changeMessages().insert(Collections.singleton(msg));
} catch (OrmException err) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/group/PutOwner.java b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutOwner.java
index ce6bc25..483cd07 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/group/PutOwner.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/group/PutOwner.java
@@ -15,7 +15,7 @@
package com.google.gerrit.server.group;
import com.google.common.base.Strings;
-import com.google.gerrit.common.data.GroupReference;
+import com.google.gerrit.common.data.GroupDescription;
import com.google.gerrit.common.errors.NoSuchGroupException;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
@@ -25,13 +25,12 @@
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.server.account.GroupBackend;
-import com.google.gerrit.server.account.GroupBackends;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.account.GroupControl;
import com.google.gerrit.server.group.PutOwner.Input;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
+import com.google.inject.Provider;
import java.util.Collections;
@@ -41,15 +40,15 @@
String owner;
}
- private final GroupBackend groupBackend;
+ private final Provider<GroupsCollection> groupsCollection;
private final GroupCache groupCache;
private final GroupControl.Factory controlFactory;
private final ReviewDb db;
@Inject
- PutOwner(GroupBackend groupBackend, GroupCache groupCache,
+ PutOwner(Provider<GroupsCollection> groupsCollection, GroupCache groupCache,
GroupControl.Factory controlFactory, ReviewDb db) {
- this.groupBackend = groupBackend;
+ this.groupsCollection = groupsCollection;
this.groupCache = groupCache;
this.controlFactory = controlFactory;
this.db = db;
@@ -70,21 +69,22 @@
throw new BadRequestException("owner is required");
}
- GroupReference owner =
- GroupBackends.findExactSuggestion(groupBackend, input.owner);
- if (owner == null) {
+ GroupDescription.Basic owner;
+ try {
+ owner = groupsCollection.get().parse(input.owner);
+ } catch (ResourceNotFoundException e) {
throw new BadRequestException(String.format("No such group: %s", input.owner));
}
try {
- GroupControl c = controlFactory.validateFor(owner.getUUID());
+ GroupControl c = controlFactory.validateFor(owner.getGroupUUID());
group = db.accountGroups().get(group.getId());
if (group == null) {
throw new ResourceNotFoundException();
}
- if (!group.getOwnerGroupUUID().equals(owner.getUUID())) {
- group.setOwnerGroupUUID(owner.getUUID());
+ if (!group.getOwnerGroupUUID().equals(owner.getGroupUUID())) {
+ group.setOwnerGroupUUID(owner.getGroupUUID());
db.accountGroups().update(Collections.singleton(group));
groupCache.evict(group);
}
diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ChangeSubject.vm b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ChangeSubject.vm
index a67c38c..acec1d1 100644
--- a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ChangeSubject.vm
+++ b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ChangeSubject.vm
@@ -31,7 +31,7 @@
## The ChangeSubject.vm template will determine the contents of the email
## subject line for ALL emails related to changes.
##
-#macro(elipses $length $str)
-#if($str.length() > $length)${str.substring(0,$length)}...#else$str#end
+#macro(ellipsis $length $str)
+#if($str.length() > $length)#set($length = $length - 3)${str.substring(0,$length)}...#else$str#end
#end
-Change in $projectName.replaceAll('/.*/', '...')[$branch.shortName]: #elipses(60, $change.subject)
+Change in $projectName.replaceAll('/.*/', '...')[$branch.shortName]: #ellipsis(63, $change.subject)
diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/Merged.vm b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/Merged.vm
index 8208062..22e29e8 100644
--- a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/Merged.vm
+++ b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/Merged.vm
@@ -32,9 +32,6 @@
## a change successfully merged to the head. It is a ChangeEmail: see
## ChangeSubject.vm and ChangeFooter.vm.
##
-#macro(elipses $length $str)
-#if($str.length() > $length)${str.substring(0,$length)}...#else$str#end
-#end
$fromName has submitted this change and it was merged.
Change subject: $change.subject