Merge branch 'stable-2.16' into stable-3.0

* stable-2.16:
  Revert "Migrate from old-style legacy .java provider to the new JavaInfo."
  Catch all exceptions for reporting on Schema_130 migration
  Migrate from old-style legacy .java provider to the new JavaInfo.
  Update git submodules
  AuthRequest: Fix Javadoc for return values
  ChangeApi: Add methods to get change comments/drafts as list
  Update git submodules
  ListChangeComments: Extend ListChangeDrafts
  Upgrade Go Bazel rules to the latest version
  detach -> detached
  Fix anchor tag for settings page

Change-Id: I248de55870ecfa2583533cd63ed91874550b6b67
This commit is contained in:
David Pursehouse
2019-08-15 12:10:10 +09:00
8 changed files with 150 additions and 36 deletions

View File

@@ -83,8 +83,11 @@ closure_repositories(
# Golang support for PolyGerrit local dev server. # Golang support for PolyGerrit local dev server.
http_archive( http_archive(
name = "io_bazel_rules_go", name = "io_bazel_rules_go",
sha256 = "6776d68ebb897625dead17ae510eac3d5f6342367327875210df44dbe2aeeb19", sha256 = "f04d2373bcaf8aa09bccb08a98a57e721306c8f6043a2a0ee610fd6853dcde3d",
url = "https://github.com/bazelbuild/rules_go/releases/download/0.17.1/rules_go-0.17.1.tar.gz", urls = [
"https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/rules_go/releases/download/0.18.6/rules_go-0.18.6.tar.gz",
"https://github.com/bazelbuild/rules_go/releases/download/0.18.6/rules_go-0.18.6.tar.gz",
],
) )
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")

View File

@@ -326,6 +326,15 @@ public interface ChangeApi {
*/ */
Map<String, List<CommentInfo>> comments() throws RestApiException; Map<String, List<CommentInfo>> comments() throws RestApiException;
/**
* Get all published comments on a change as a list.
*
* @return comments as a list; comments have the {@code revision} field set to indicate their
* patch set.
* @throws RestApiException
*/
List<CommentInfo> commentsAsList() throws RestApiException;
/** /**
* Get all robot comments on a change. * Get all robot comments on a change.
* *
@@ -344,6 +353,15 @@ public interface ChangeApi {
*/ */
Map<String, List<CommentInfo>> drafts() throws RestApiException; Map<String, List<CommentInfo>> drafts() throws RestApiException;
/**
* Get all draft comments for the current user on a change as a list.
*
* @return drafts as a list; comments have the {@code revision} field set to indicate their patch
* set.
* @throws RestApiException
*/
List<CommentInfo> draftsAsList() throws RestApiException;
ChangeInfo check() throws RestApiException; ChangeInfo check() throws RestApiException;
ChangeInfo check(FixInput fix) throws RestApiException; ChangeInfo check(FixInput fix) throws RestApiException;
@@ -551,6 +569,11 @@ public interface ChangeApi {
throw new NotImplementedException(); throw new NotImplementedException();
} }
@Override
public List<CommentInfo> commentsAsList() throws RestApiException {
throw new NotImplementedException();
}
@Override @Override
public Map<String, List<RobotCommentInfo>> robotComments() throws RestApiException { public Map<String, List<RobotCommentInfo>> robotComments() throws RestApiException {
throw new NotImplementedException(); throw new NotImplementedException();
@@ -561,6 +584,11 @@ public interface ChangeApi {
throw new NotImplementedException(); throw new NotImplementedException();
} }
@Override
public List<CommentInfo> draftsAsList() throws RestApiException {
throw new NotImplementedException();
}
@Override @Override
public ChangeInfo check() throws RestApiException { public ChangeInfo check() throws RestApiException {
throw new NotImplementedException(); throw new NotImplementedException();

View File

@@ -556,6 +556,15 @@ class ChangeApiImpl implements ChangeApi {
} }
} }
@Override
public List<CommentInfo> commentsAsList() throws RestApiException {
try {
return listComments.getComments(change);
} catch (Exception e) {
throw asRestApiException("Cannot get comments", e);
}
}
@Override @Override
public Map<String, List<RobotCommentInfo>> robotComments() throws RestApiException { public Map<String, List<RobotCommentInfo>> robotComments() throws RestApiException {
try { try {
@@ -574,6 +583,15 @@ class ChangeApiImpl implements ChangeApi {
} }
} }
@Override
public List<CommentInfo> draftsAsList() throws RestApiException {
try {
return listDrafts.getComments(change);
} catch (Exception e) {
throw asRestApiException("Cannot get drafts", e);
}
}
@Override @Override
public ChangeInfo check() throws RestApiException { public ChangeInfo check() throws RestApiException {
try { try {

View File

@@ -31,7 +31,7 @@ public abstract class AuthRequest {
/** /**
* Returns the username to be authenticated. * Returns the username to be authenticated.
* *
* @return username for authentication or null for anonymous access. * @return username for authentication or {@code empty} for anonymous access.
*/ */
public final Optional<String> getUsername() { public final Optional<String> getUsername() {
return username; return username;
@@ -40,7 +40,7 @@ public abstract class AuthRequest {
/** /**
* Returns the user's credentials * Returns the user's credentials
* *
* @return user's credentials or null * @return user's credentials or {@code empty}.
*/ */
public final Optional<String> getPassword() { public final Optional<String> getPassword() {
return password; return password;

View File

@@ -14,44 +14,37 @@
package com.google.gerrit.server.restapi.change; package com.google.gerrit.server.restapi.change;
import com.google.gerrit.extensions.common.CommentInfo; import com.google.gerrit.reviewdb.client.Comment;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.server.CommentsUtil; import com.google.gerrit.server.CommentsUtil;
import com.google.gerrit.server.change.ChangeResource; import com.google.gerrit.server.change.ChangeResource;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.query.change.ChangeData; import com.google.gerrit.server.query.change.ChangeData;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import java.util.List;
import java.util.Map;
@Singleton @Singleton
public class ListChangeComments implements RestReadView<ChangeResource> { public class ListChangeComments extends ListChangeDrafts {
private final ChangeData.Factory changeDataFactory;
private final Provider<CommentJson> commentJson;
private final CommentsUtil commentsUtil;
@Inject @Inject
ListChangeComments( ListChangeComments(
ChangeData.Factory changeDataFactory, ChangeData.Factory changeDataFactory,
Provider<CommentJson> commentJson, Provider<CommentJson> commentJson,
CommentsUtil commentsUtil) { CommentsUtil commentsUtil) {
this.changeDataFactory = changeDataFactory; super(changeDataFactory, commentJson, commentsUtil);
this.commentJson = commentJson;
this.commentsUtil = commentsUtil;
} }
@Override @Override
public Map<String, List<CommentInfo>> apply(ChangeResource rsrc) protected Iterable<Comment> listComments(ChangeResource rsrc) {
throws AuthException, PermissionBackendException {
ChangeData cd = changeDataFactory.create(rsrc.getNotes()); ChangeData cd = changeDataFactory.create(rsrc.getNotes());
return commentJson return commentsUtil.publishedByChange(cd.notes());
.get() }
.setFillAccounts(true)
.setFillPatchSet(true) @Override
.newCommentFormatter() protected boolean includeAuthorInfo() {
.format(commentsUtil.publishedByChange(cd.notes())); return true;
}
@Override
public boolean requireAuthentication() {
return false;
} }
} }

View File

@@ -22,6 +22,7 @@ import com.google.gerrit.server.CommentsUtil;
import com.google.gerrit.server.change.ChangeResource; import com.google.gerrit.server.change.ChangeResource;
import com.google.gerrit.server.permissions.PermissionBackendException; import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.query.change.ChangeData; import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.restapi.change.CommentJson.CommentFormatter;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import com.google.inject.Singleton; import com.google.inject.Singleton;
@@ -30,9 +31,9 @@ import java.util.Map;
@Singleton @Singleton
public class ListChangeDrafts implements RestReadView<ChangeResource> { public class ListChangeDrafts implements RestReadView<ChangeResource> {
private final ChangeData.Factory changeDataFactory; protected final ChangeData.Factory changeDataFactory;
private final Provider<CommentJson> commentJson; protected final Provider<CommentJson> commentJson;
private final CommentsUtil commentsUtil; protected final CommentsUtil commentsUtil;
@Inject @Inject
ListChangeDrafts( ListChangeDrafts(
@@ -44,20 +45,41 @@ public class ListChangeDrafts implements RestReadView<ChangeResource> {
this.commentsUtil = commentsUtil; this.commentsUtil = commentsUtil;
} }
protected Iterable<Comment> listComments(ChangeResource rsrc) {
ChangeData cd = changeDataFactory.create(rsrc.getNotes());
return commentsUtil.draftByChangeAuthor(cd.notes(), rsrc.getUser().getAccountId());
}
protected boolean includeAuthorInfo() {
return false;
}
public boolean requireAuthentication() {
return true;
}
@Override @Override
public Map<String, List<CommentInfo>> apply(ChangeResource rsrc) public Map<String, List<CommentInfo>> apply(ChangeResource rsrc)
throws AuthException, PermissionBackendException { throws AuthException, PermissionBackendException {
if (!rsrc.getUser().isIdentifiedUser()) { if (requireAuthentication() && !rsrc.getUser().isIdentifiedUser()) {
throw new AuthException("Authentication required"); throw new AuthException("Authentication required");
} }
ChangeData cd = changeDataFactory.create(rsrc.getNotes()); return getCommentFormatter().format(listComments(rsrc));
List<Comment> drafts = }
commentsUtil.draftByChangeAuthor(cd.notes(), rsrc.getUser().getAccountId());
public List<CommentInfo> getComments(ChangeResource rsrc)
throws AuthException, PermissionBackendException {
if (requireAuthentication() && !rsrc.getUser().isIdentifiedUser()) {
throw new AuthException("Authentication required");
}
return getCommentFormatter().formatAsList(listComments(rsrc));
}
private CommentFormatter getCommentFormatter() {
return commentJson return commentJson
.get() .get()
.setFillAccounts(false) .setFillAccounts(includeAuthorInfo())
.setFillPatchSet(true) .setFillPatchSet(true)
.newCommentFormatter() .newCommentFormatter();
.format(drafts);
} }
} }

View File

@@ -111,6 +111,11 @@ public class CommentsIT extends AbstractDaemonTest {
assertThat(result).hasSize(1); assertThat(result).hasSize(1);
CommentInfo actual = Iterables.getOnlyElement(result.get(comment.path)); CommentInfo actual = Iterables.getOnlyElement(result.get(comment.path));
assertThat(comment).isEqualTo(infoToDraft(path).apply(actual)); assertThat(comment).isEqualTo(infoToDraft(path).apply(actual));
List<CommentInfo> list = getDraftCommentsAsList(changeId);
assertThat(list).hasSize(1);
actual = list.get(0);
assertThat(comment).isEqualTo(infoToDraft(path).apply(actual));
} }
} }
@@ -133,6 +138,10 @@ public class CommentsIT extends AbstractDaemonTest {
assertThat(result).hasSize(1); assertThat(result).hasSize(1);
assertThat(Lists.transform(result.get(path), infoToDraft(path))) assertThat(Lists.transform(result.get(path), infoToDraft(path)))
.containsExactly(c1, c2, c3, c4); .containsExactly(c1, c2, c3, c4);
List<CommentInfo> list = getDraftCommentsAsList(changeId);
assertThat(list).hasSize(4);
assertThat(Lists.transform(list, infoToDraft(path))).containsExactly(c1, c2, c3, c4);
} }
} }
@@ -235,6 +244,9 @@ public class CommentsIT extends AbstractDaemonTest {
assertThat(result).isNotEmpty(); assertThat(result).isNotEmpty();
assertThat(Lists.transform(result.get(file), infoToInput(file))) assertThat(Lists.transform(result.get(file), infoToInput(file)))
.containsExactly(c1, c2, c3, c4); .containsExactly(c1, c2, c3, c4);
List<CommentInfo> list = getPublishedCommentsAsList(changeId);
assertThat(Lists.transform(list, infoToInput(file))).containsExactly(c1, c2, c3, c4);
} }
// for the commit message comments on the auto-merge are not possible // for the commit message comments on the auto-merge are not possible
@@ -253,6 +265,9 @@ public class CommentsIT extends AbstractDaemonTest {
Map<String, List<CommentInfo>> result = getPublishedComments(changeId, revId); Map<String, List<CommentInfo>> result = getPublishedComments(changeId, revId);
assertThat(result).isNotEmpty(); assertThat(result).isNotEmpty();
assertThat(Lists.transform(result.get(file), infoToInput(file))).containsExactly(c1, c2, c3); assertThat(Lists.transform(result.get(file), infoToInput(file))).containsExactly(c1, c2, c3);
List<CommentInfo> list = getPublishedCommentsAsList(changeId);
assertThat(Lists.transform(list, infoToInput(file))).containsExactly(c1, c2, c3);
} }
} }
@@ -277,6 +292,7 @@ public class CommentsIT extends AbstractDaemonTest {
String changeId = r.getChangeId(); String changeId = r.getChangeId();
String revId = r.getCommit().getName(); String revId = r.getCommit().getName();
assertThat(getPublishedComments(changeId, revId)).isEmpty(); assertThat(getPublishedComments(changeId, revId)).isEmpty();
assertThat(getPublishedCommentsAsList(changeId)).isEmpty();
List<CommentInput> expectedComments = new ArrayList<>(); List<CommentInput> expectedComments = new ArrayList<>();
for (Integer line : lines) { for (Integer line : lines) {
@@ -293,6 +309,10 @@ public class CommentsIT extends AbstractDaemonTest {
List<CommentInfo> actualComments = result.get(file); List<CommentInfo> actualComments = result.get(file);
assertThat(Lists.transform(actualComments, infoToInput(file))) assertThat(Lists.transform(actualComments, infoToInput(file)))
.containsExactlyElementsIn(expectedComments); .containsExactlyElementsIn(expectedComments);
List<CommentInfo> list = getPublishedCommentsAsList(changeId);
assertThat(Lists.transform(list, infoToInput(file)))
.containsExactlyElementsIn(expectedComments);
} }
@Test @Test
@@ -1093,11 +1113,19 @@ public class CommentsIT extends AbstractDaemonTest {
return gApi.changes().id(changeId).revision(revId).comments(); return gApi.changes().id(changeId).revision(revId).comments();
} }
private List<CommentInfo> getPublishedCommentsAsList(String changeId) throws Exception {
return gApi.changes().id(changeId).commentsAsList();
}
private Map<String, List<CommentInfo>> getDraftComments(String changeId, String revId) private Map<String, List<CommentInfo>> getDraftComments(String changeId, String revId)
throws Exception { throws Exception {
return gApi.changes().id(changeId).revision(revId).drafts(); return gApi.changes().id(changeId).revision(revId).drafts();
} }
private List<CommentInfo> getDraftCommentsAsList(String changeId) throws Exception {
return gApi.changes().id(changeId).draftsAsList();
}
private CommentInfo getDraftComment(String changeId, String revId, String uuid) throws Exception { private CommentInfo getDraftComment(String changeId, String revId, String uuid) throws Exception {
return gApi.changes().id(changeId).revision(revId).draft(uuid).get(); return gApi.changes().id(changeId).revision(revId).draft(uuid).get();
} }

View File

@@ -158,6 +158,9 @@
], ],
attached() { attached() {
// Polymer 2: anchor tag won't work on shadow DOM
// we need to manually calling scrollIntoView when hash changed
this.listen(window, 'location-change', '_handleLocationChange');
this.fire('title-change', {title: 'Settings'}); this.fire('title-change', {title: 'Settings'});
this._isDark = !!window.localStorage.getItem('dark-theme'); this._isDark = !!window.localStorage.getItem('dark-theme');
@@ -214,9 +217,28 @@
this._loadingPromise = Promise.all(promises).then(() => { this._loadingPromise = Promise.all(promises).then(() => {
this._loading = false; this._loading = false;
// Handle anchor tag for initial load
this._handleLocationChange();
}); });
}, },
detached() {
this.unlisten(window, 'location-change', '_handleLocationChange');
},
_handleLocationChange() {
// Handle anchor tag after dom attached
const urlHash = window.location.hash;
if (urlHash) {
// Use shadowRoot for Polymer 2
const elem = (this.shadowRoot || document).querySelector(urlHash);
if (elem) {
elem.scrollIntoView();
}
}
},
reloadAccountDetail() { reloadAccountDetail() {
Promise.all([ Promise.all([
this.$.accountInfo.loadData(), this.$.accountInfo.loadData(),