diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt index ad5ea8205c..121c724455 100644 --- a/Documentation/rest-api-changes.txt +++ b/Documentation/rest-api-changes.txt @@ -4906,12 +4906,22 @@ need the FileInfo should make two requests. The request parameter `q` changes the response to return a list of all files (modified or unmodified) that contain that substring in the path name. This is useful to implement suggestion services -finding a file by partial name. +finding a file by partial name. Clients that also need the FileInfo +should make two requests. -The integer-valued request parameter `parent` changes the response to return a -list of the files which are different in this commit compared to the given -parent commit. This is useful for supporting review of merge commits. The value -is the 1-based index of the parent's position in the commit object. +For merge commits only, the integer-valued request parameter `parent` +changes the response to return a map of the files which are different +in this commit compared to the given parent commit. The value is the +1-based index of the parent's position in the commit object. If not +specified, the response contains a map of the files different in the +auto merge result. + +The request parameter `base` changes the response to return a map of the +files which are different in this commit compared to the given revision. The +revision must correspond to a patch set in the change. + +The `reviewed`, `q`, `parent`, and `base` options are mutually exclusive. +That is, only one of them may be used at a time. .Request ---- diff --git a/Documentation/rest-api-projects.txt b/Documentation/rest-api-projects.txt index f69c4ae52f..76151b40e0 100644 --- a/Documentation/rest-api-projects.txt +++ b/Documentation/rest-api-projects.txt @@ -3058,12 +3058,12 @@ link:config-gerrit.html#commentlink[commentlink]. |Field Name | |Description |`match` | |A JavaScript regular expression to match positions to be replaced with a hyperlink, as documented in -link#config-gerrit.html#commentlink.name.match[commentlink.name.match]. +link:config-gerrit.html#commentlink.name.match[commentlink.name.match]. |`link` | |The URL to direct the user to whenever the regular expression is matched, as documented in -link#config-gerrit.html#commentlink.name.link[commentlink.name.link]. +link:config-gerrit.html#commentlink.name.link[commentlink.name.link]. |`enabled` |optional|Whether the commentlink is enabled, as documented -in link#config-gerrit.html#commentlink.name.enabled[ +in link:config-gerrit.html#commentlink.name.enabled[ commentlink.name.enabled]. If not set the commentlink is enabled. |================================================== diff --git a/WORKSPACE b/WORKSPACE index af9ece666d..83f5b2a95d 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1053,8 +1053,8 @@ maven_jar( # and httpasyncclient as necessary. maven_jar( name = "elasticsearch-rest-client", - artifact = "org.elasticsearch.client:elasticsearch-rest-client:7.2.0", - sha1 = "39cf34068b0af284eaa9b8bd86a131cb24b322d5", + artifact = "org.elasticsearch.client:elasticsearch-rest-client:7.3.0", + sha1 = "3cdc211c8efb72c202107b40dee356f4f2f0f9bd", ) maven_jar( diff --git a/java/com/google/gerrit/elasticsearch/ElasticVersion.java b/java/com/google/gerrit/elasticsearch/ElasticVersion.java index e608e935f5..baf3e38cfa 100644 --- a/java/com/google/gerrit/elasticsearch/ElasticVersion.java +++ b/java/com/google/gerrit/elasticsearch/ElasticVersion.java @@ -25,9 +25,11 @@ public enum ElasticVersion { V6_5("6.5.*"), V6_6("6.6.*"), V6_7("6.7.*"), + V6_8("6.8.*"), V7_0("7.0.*"), V7_1("7.1.*"), - V7_2("7.2.*"); + V7_2("7.2.*"), + V7_3("7.3.*"); private final String version; private final Pattern pattern; diff --git a/java/com/google/gerrit/extensions/api/projects/CommitApi.java b/java/com/google/gerrit/extensions/api/projects/CommitApi.java index 6b3c1fbc27..a53fc742ab 100644 --- a/java/com/google/gerrit/extensions/api/projects/CommitApi.java +++ b/java/com/google/gerrit/extensions/api/projects/CommitApi.java @@ -17,10 +17,12 @@ package com.google.gerrit.extensions.api.projects; import com.google.gerrit.extensions.api.changes.ChangeApi; import com.google.gerrit.extensions.api.changes.CherryPickInput; import com.google.gerrit.extensions.api.changes.IncludedInInfo; +import com.google.gerrit.extensions.common.CommitInfo; import com.google.gerrit.extensions.restapi.NotImplementedException; import com.google.gerrit.extensions.restapi.RestApiException; public interface CommitApi { + CommitInfo get() throws RestApiException; ChangeApi cherryPick(CherryPickInput input) throws RestApiException; @@ -28,6 +30,11 @@ public interface CommitApi { /** A default implementation for source compatibility when adding new methods to the interface. */ class NotImplemented implements CommitApi { + @Override + public CommitInfo get() throws RestApiException { + throw new NotImplementedException(); + } + @Override public ChangeApi cherryPick(CherryPickInput input) throws RestApiException { throw new NotImplementedException(); diff --git a/java/com/google/gerrit/launcher/GerritLauncher.java b/java/com/google/gerrit/launcher/GerritLauncher.java index 077c763a1a..f6c395e7b6 100644 --- a/java/com/google/gerrit/launcher/GerritLauncher.java +++ b/java/com/google/gerrit/launcher/GerritLauncher.java @@ -66,7 +66,7 @@ public final class GerritLauncher { } /** - * Invokes a proram. + * Invokes a program. * *

Creates a new classloader to load and run the program class. To reuse a classloader across * calls (e.g. from tests), use {@link #invokeProgram(ClassLoader, String[])}. @@ -176,7 +176,7 @@ public final class GerritLauncher { } /** - * Invokes a proram in the provided {@code ClassLoader}. + * Invokes a program in the provided {@code ClassLoader}. * * @param loader classloader to load program class from. * @param origArgv arguments, as would be passed to {@code gerrit.war}. The first argument is the diff --git a/java/com/google/gerrit/server/api/projects/CommitApiImpl.java b/java/com/google/gerrit/server/api/projects/CommitApiImpl.java index 49eec6ea87..0a3b2369a7 100644 --- a/java/com/google/gerrit/server/api/projects/CommitApiImpl.java +++ b/java/com/google/gerrit/server/api/projects/CommitApiImpl.java @@ -21,10 +21,12 @@ import com.google.gerrit.extensions.api.changes.Changes; import com.google.gerrit.extensions.api.changes.CherryPickInput; import com.google.gerrit.extensions.api.changes.IncludedInInfo; import com.google.gerrit.extensions.api.projects.CommitApi; +import com.google.gerrit.extensions.common.CommitInfo; import com.google.gerrit.extensions.restapi.RestApiException; import com.google.gerrit.server.project.CommitResource; import com.google.gerrit.server.restapi.change.CherryPickCommit; import com.google.gerrit.server.restapi.project.CommitIncludedIn; +import com.google.gerrit.server.restapi.project.GetCommit; import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; @@ -34,6 +36,7 @@ public class CommitApiImpl implements CommitApi { } private final Changes changes; + private final GetCommit getCommit; private final CherryPickCommit cherryPickCommit; private final CommitIncludedIn includedIn; private final CommitResource commitResource; @@ -41,15 +44,26 @@ public class CommitApiImpl implements CommitApi { @Inject CommitApiImpl( Changes changes, + GetCommit getCommit, CherryPickCommit cherryPickCommit, CommitIncludedIn includedIn, @Assisted CommitResource commitResource) { this.changes = changes; + this.getCommit = getCommit; this.cherryPickCommit = cherryPickCommit; this.includedIn = includedIn; this.commitResource = commitResource; } + @Override + public CommitInfo get() throws RestApiException { + try { + return getCommit.apply(commitResource); + } catch (Exception e) { + throw asRestApiException("Cannot get commit info", e); + } + } + @Override public ChangeApi cherryPick(CherryPickInput input) throws RestApiException { try { diff --git a/java/com/google/gerrit/server/restapi/change/Files.java b/java/com/google/gerrit/server/restapi/change/Files.java index 2a0cd58f4d..d8928105a2 100644 --- a/java/com/google/gerrit/server/restapi/change/Files.java +++ b/java/com/google/gerrit/server/restapi/change/Files.java @@ -19,6 +19,7 @@ import com.google.common.flogger.FluentLogger; import com.google.common.hash.Hasher; import com.google.common.hash.Hashing; import com.google.gerrit.common.Nullable; +import com.google.gerrit.extensions.api.GerritApi; import com.google.gerrit.extensions.common.FileInfo; import com.google.gerrit.extensions.registration.DynamicMap; import com.google.gerrit.extensions.restapi.AuthException; @@ -27,8 +28,8 @@ import com.google.gerrit.extensions.restapi.CacheControl; import com.google.gerrit.extensions.restapi.ChildCollection; import com.google.gerrit.extensions.restapi.ETagView; import com.google.gerrit.extensions.restapi.IdString; -import com.google.gerrit.extensions.restapi.ResourceNotFoundException; import com.google.gerrit.extensions.restapi.Response; +import com.google.gerrit.extensions.restapi.RestApiException; import com.google.gerrit.extensions.restapi.RestView; import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Change; @@ -119,6 +120,7 @@ public class Files implements ChildCollection { private final PatchListCache patchListCache; private final PatchSetUtil psUtil; private final PluginItemContext accountPatchReviewStore; + private final GerritApi gApi; @Inject ListFiles( @@ -128,7 +130,8 @@ public class Files implements ChildCollection { GitRepositoryManager gitManager, PatchListCache patchListCache, PatchSetUtil psUtil, - PluginItemContext accountPatchReviewStore) { + PluginItemContext accountPatchReviewStore, + GerritApi gApi) { this.self = self; this.fileInfoJson = fileInfoJson; this.revisions = revisions; @@ -136,6 +139,7 @@ public class Files implements ChildCollection { this.patchListCache = patchListCache; this.psUtil = psUtil; this.accountPatchReviewStore = accountPatchReviewStore; + this.gApi = gApi; } public ListFiles setReviewed(boolean r) { @@ -145,9 +149,8 @@ public class Files implements ChildCollection { @Override public Response apply(RevisionResource resource) - throws AuthException, BadRequestException, ResourceNotFoundException, - RepositoryNotFoundException, IOException, PatchListNotAvailableException, - PermissionBackendException { + throws RestApiException, RepositoryNotFoundException, IOException, + PatchListNotAvailableException, PermissionBackendException { checkOptions(); if (reviewed) { return Response.ok(reviewed(resource)); @@ -165,7 +168,17 @@ public class Files implements ChildCollection { resource.getChange(), resource.getPatchSet().getRevision(), baseResource.getPatchSet())); - } else if (parentNum > 0) { + } else if (parentNum != 0) { + int parents = + gApi.changes() + .id(resource.getChange().getChangeId()) + .revision(resource.getPatchSet().getId().get()) + .commit(false) + .parents + .size(); + if (parentNum < 0 || parentNum > parents) { + throw new BadRequestException(String.format("invalid parent number: %d", parentNum)); + } r = Response.ok( fileInfoJson.toFileInfoMap( diff --git a/java/com/google/gerrit/server/rules/PrologEnvironment.java b/java/com/google/gerrit/server/rules/PrologEnvironment.java index a327d6e693..ba78724bfa 100644 --- a/java/com/google/gerrit/server/rules/PrologEnvironment.java +++ b/java/com/google/gerrit/server/rules/PrologEnvironment.java @@ -84,7 +84,6 @@ public class PrologEnvironment extends BufferingPrologControl { public void setPredicate(Predicate goal) { super.setPredicate(goal); int reductionLimit = args.reductionLimit(goal); - logger.atFine().log("setting reductionLimit %d", reductionLimit); setReductionLimit(reductionLimit); } @@ -223,6 +222,9 @@ public class PrologEnvironment extends BufferingPrologControl { private int reductionLimit(Predicate goal) { if (goal.getClass() == CONSULT_STREAM_2) { + logger.atFine().log( + "predicate class is CONSULT_STREAM_2: override reductionLimit with compileLimit (%d)", + compileLimit); return compileLimit; } return reductionLimit; diff --git a/javatests/com/google/gerrit/acceptance/api/project/CommitIT.java b/javatests/com/google/gerrit/acceptance/api/project/CommitIT.java new file mode 100644 index 0000000000..a341b3c64c --- /dev/null +++ b/javatests/com/google/gerrit/acceptance/api/project/CommitIT.java @@ -0,0 +1,151 @@ +// Copyright (C) 2017 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.api.project; + +import static com.google.common.truth.Truth.assertThat; +import static java.util.stream.Collectors.toList; +import static org.eclipse.jgit.lib.Constants.R_TAGS; + +import com.google.gerrit.acceptance.AbstractDaemonTest; +import com.google.gerrit.acceptance.NoHttpd; +import com.google.gerrit.acceptance.PushOneCommit.Result; +import com.google.gerrit.acceptance.TestAccount; +import com.google.gerrit.common.data.Permission; +import com.google.gerrit.extensions.api.changes.CherryPickInput; +import com.google.gerrit.extensions.api.changes.IncludedInInfo; +import com.google.gerrit.extensions.api.changes.ReviewInput; +import com.google.gerrit.extensions.api.projects.BranchInput; +import com.google.gerrit.extensions.api.projects.TagInput; +import com.google.gerrit.extensions.common.ChangeInfo; +import com.google.gerrit.extensions.common.ChangeMessageInfo; +import com.google.gerrit.extensions.common.CommitInfo; +import com.google.gerrit.extensions.common.GitPerson; +import com.google.gerrit.extensions.common.RevisionInfo; +import com.google.gerrit.reviewdb.client.Branch; +import java.util.Iterator; +import java.util.List; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.revwalk.RevCommit; +import org.junit.Test; + +@NoHttpd +public class CommitIT extends AbstractDaemonTest { + @Test + public void getCommitInfo() throws Exception { + Result result = createChange(); + String commitId = result.getCommit().getId().name(); + CommitInfo info = gApi.projects().name(project.get()).commit(commitId).get(); + assertThat(info.commit).isEqualTo(commitId); + assertThat(info.parents.stream().map(c -> c.commit).collect(toList())) + .containsExactly(result.getCommit().getParent(0).name()); + assertThat(info.subject).isEqualTo(result.getCommit().getShortMessage()); + assertPerson(info.author, admin); + assertPerson(info.committer, admin); + assertThat(info.webLinks).isNull(); + } + + @Test + public void includedInOpenChange() throws Exception { + Result result = createChange(); + assertThat(getIncludedIn(result.getCommit().getId()).branches).isEmpty(); + assertThat(getIncludedIn(result.getCommit().getId()).tags).isEmpty(); + } + + @Test + public void includedInMergedChange() throws Exception { + Result result = createChange(); + gApi.changes() + .id(result.getChangeId()) + .revision(result.getCommit().name()) + .review(ReviewInput.approve()); + gApi.changes().id(result.getChangeId()).revision(result.getCommit().name()).submit(); + + assertThat(getIncludedIn(result.getCommit().getId()).branches).containsExactly("master"); + assertThat(getIncludedIn(result.getCommit().getId()).tags).isEmpty(); + + grant(project, R_TAGS + "*", Permission.CREATE_TAG); + gApi.projects().name(result.getChange().project().get()).tag("test-tag").create(new TagInput()); + + assertThat(getIncludedIn(result.getCommit().getId()).tags).containsExactly("test-tag"); + + createBranch(new Branch.NameKey(project.get(), "test-branch")); + + assertThat(getIncludedIn(result.getCommit().getId()).branches) + .containsExactly("master", "test-branch"); + } + + @Test + public void cherryPickCommitWithoutChangeId() throws Exception { + // This test is a little superfluous, since the current cherry-pick code ignores + // the commit message of the to-be-cherry-picked change, using the one in + // CherryPickInput instead. + CherryPickInput input = new CherryPickInput(); + input.destination = "foo"; + input.message = "it goes to foo branch"; + gApi.projects().name(project.get()).branch(input.destination).create(new BranchInput()); + + RevCommit revCommit = createNewCommitWithoutChangeId("refs/heads/master", "a.txt", "content"); + ChangeInfo changeInfo = + gApi.projects().name(project.get()).commit(revCommit.getName()).cherryPick(input).get(); + + assertThat(changeInfo.messages).hasSize(1); + Iterator messageIterator = changeInfo.messages.iterator(); + String expectedMessage = + String.format("Patch Set 1: Cherry Picked from commit %s.", revCommit.getName()); + assertThat(messageIterator.next().message).isEqualTo(expectedMessage); + + RevisionInfo revInfo = changeInfo.revisions.get(changeInfo.currentRevision); + assertThat(revInfo).isNotNull(); + CommitInfo commitInfo = revInfo.commit; + assertThat(commitInfo.message) + .isEqualTo(input.message + "\n\nChange-Id: " + changeInfo.changeId + "\n"); + } + + @Test + public void cherryPickCommitWithChangeId() throws Exception { + CherryPickInput input = new CherryPickInput(); + input.destination = "foo"; + + RevCommit revCommit = createChange().getCommit(); + List footers = revCommit.getFooterLines("Change-Id"); + assertThat(footers).hasSize(1); + String changeId = footers.get(0); + + input.message = "it goes to foo branch\n\nChange-Id: " + changeId; + gApi.projects().name(project.get()).branch(input.destination).create(new BranchInput()); + + ChangeInfo changeInfo = + gApi.projects().name(project.get()).commit(revCommit.getName()).cherryPick(input).get(); + + assertThat(changeInfo.messages).hasSize(1); + Iterator messageIterator = changeInfo.messages.iterator(); + String expectedMessage = + String.format("Patch Set 1: Cherry Picked from commit %s.", revCommit.getName()); + assertThat(messageIterator.next().message).isEqualTo(expectedMessage); + + RevisionInfo revInfo = changeInfo.revisions.get(changeInfo.currentRevision); + assertThat(revInfo).isNotNull(); + assertThat(revInfo.commit.message).isEqualTo(input.message + "\n"); + } + + private IncludedInInfo getIncludedIn(ObjectId id) throws Exception { + return gApi.projects().name(project.get()).commit(id.name()).includedIn(); + } + + private static void assertPerson(GitPerson actual, TestAccount expected) { + assertThat(actual.email).isEqualTo(expected.email()); + assertThat(actual.name).isEqualTo(expected.fullName()); + } +} diff --git a/javatests/com/google/gerrit/acceptance/api/project/CommitIncludedInIT.java b/javatests/com/google/gerrit/acceptance/api/project/CommitIncludedInIT.java deleted file mode 100644 index 4b5fe1e9f8..0000000000 --- a/javatests/com/google/gerrit/acceptance/api/project/CommitIncludedInIT.java +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (C) 2017 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.api.project; - -import static com.google.common.truth.Truth.assertThat; -import static org.eclipse.jgit.lib.Constants.R_TAGS; - -import com.google.gerrit.acceptance.AbstractDaemonTest; -import com.google.gerrit.acceptance.NoHttpd; -import com.google.gerrit.acceptance.PushOneCommit.Result; -import com.google.gerrit.common.data.Permission; -import com.google.gerrit.extensions.api.changes.IncludedInInfo; -import com.google.gerrit.extensions.api.changes.ReviewInput; -import com.google.gerrit.extensions.api.projects.TagInput; -import com.google.gerrit.reviewdb.client.Branch; -import org.eclipse.jgit.lib.ObjectId; -import org.junit.Test; - -@NoHttpd -public class CommitIncludedInIT extends AbstractDaemonTest { - @Test - public void includedInOpenChange() throws Exception { - Result result = createChange(); - assertThat(getIncludedIn(result.getCommit().getId()).branches).isEmpty(); - assertThat(getIncludedIn(result.getCommit().getId()).tags).isEmpty(); - } - - @Test - public void includedInMergedChange() throws Exception { - Result result = createChange(); - gApi.changes() - .id(result.getChangeId()) - .revision(result.getCommit().name()) - .review(ReviewInput.approve()); - gApi.changes().id(result.getChangeId()).revision(result.getCommit().name()).submit(); - - assertThat(getIncludedIn(result.getCommit().getId()).branches).containsExactly("master"); - assertThat(getIncludedIn(result.getCommit().getId()).tags).isEmpty(); - - grant(project, R_TAGS + "*", Permission.CREATE_TAG); - gApi.projects().name(result.getChange().project().get()).tag("test-tag").create(new TagInput()); - - assertThat(getIncludedIn(result.getCommit().getId()).tags).containsExactly("test-tag"); - - createBranch(new Branch.NameKey(project.get(), "test-branch")); - - assertThat(getIncludedIn(result.getCommit().getId()).branches) - .containsExactly("master", "test-branch"); - } - - private IncludedInInfo getIncludedIn(ObjectId id) throws Exception { - return gApi.projects().name(project.get()).commit(id.name()).includedIn(); - } -} diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java index a19308ca27..5d7879c5d1 100644 --- a/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java +++ b/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java @@ -26,6 +26,7 @@ import static com.google.gerrit.extensions.client.ListChangesOption.DETAILED_LAB import static com.google.gerrit.reviewdb.client.Patch.COMMIT_MSG; import static com.google.gerrit.reviewdb.client.Patch.MERGE_LIST; import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS; +import static com.google.gerrit.testing.GerritJUnit.assertThrows; import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.stream.Collectors.toList; import static org.eclipse.jgit.lib.Constants.HEAD; @@ -1046,30 +1047,76 @@ public class RevisionIT extends AbstractDaemonTest { PushOneCommit.Result r = createChange(); Map files = gApi.changes().id(r.getChangeId()).revision(r.getCommit().name()).files(); - assertThat(files).hasSize(2); - assertThat(Iterables.all(files.keySet(), f -> f.matches(FILE_NAME + '|' + COMMIT_MSG))) - .isTrue(); + assertThat(files.keySet()).containsExactly(FILE_NAME, COMMIT_MSG); } @Test public void filesOnMergeCommitChange() throws Exception { PushOneCommit.Result r = createMergeCommitChange("refs/for/master"); - // list files against auto-merge + // List files against auto-merge assertThat(gApi.changes().id(r.getChangeId()).revision(r.getCommit().name()).files().keySet()) .containsExactly(COMMIT_MSG, MERGE_LIST, "foo", "bar"); - // list files against parent 1 + // List files against parent 1 assertThat(gApi.changes().id(r.getChangeId()).revision(r.getCommit().name()).files(1).keySet()) .containsExactly(COMMIT_MSG, MERGE_LIST, "bar"); - // list files against parent 2 + // List files against parent 2 assertThat(gApi.changes().id(r.getChangeId()).revision(r.getCommit().name()).files(2).keySet()) .containsExactly(COMMIT_MSG, MERGE_LIST, "foo"); } + @Test + public void filesOnMergeCommitChangeWithInvalidParent() throws Exception { + PushOneCommit.Result r = createMergeCommitChange("refs/for/master"); + + BadRequestException thrown = + assertThrows( + BadRequestException.class, + () -> + gApi.changes() + .id(r.getChangeId()) + .revision(r.getCommit().name()) + .files(3) + .keySet()); + assertThat(thrown).hasMessageThat().isEqualTo("invalid parent number: 3"); + thrown = + assertThrows( + BadRequestException.class, + () -> + gApi.changes() + .id(r.getChangeId()) + .revision(r.getCommit().name()) + .files(-1) + .keySet()); + assertThat(thrown).hasMessageThat().isEqualTo("invalid parent number: -1"); + } + + @Test + public void listFilesWithInvalidParent() throws Exception { + PushOneCommit.Result result1 = createChange(); + String changeId = result1.getChangeId(); + PushOneCommit.Result result2 = amendChange(changeId, SUBJECT, "b.txt", "b"); + String revId2 = result2.getCommit().name(); + + BadRequestException thrown = + assertThrows( + BadRequestException.class, + () -> gApi.changes().id(changeId).revision(revId2).files(2).keySet()); + assertThat(thrown).hasMessageThat().isEqualTo("invalid parent number: 2"); + + thrown = + assertThrows( + BadRequestException.class, + () -> gApi.changes().id(changeId).revision(revId2).files(-1).keySet()); + assertThat(thrown).hasMessageThat().isEqualTo("invalid parent number: -1"); + } + @Test public void listFilesOnDifferentBases() throws Exception { + RevCommit initialCommit = getHead(repo(), "HEAD"); + PushOneCommit.Result result1 = createChange(); String changeId = result1.getChangeId(); PushOneCommit.Result result2 = amendChange(changeId, SUBJECT, "b.txt", "b"); @@ -1092,6 +1139,19 @@ public class RevisionIT extends AbstractDaemonTest { .containsExactly(COMMIT_MSG, "b.txt", "c.txt"); assertThat(gApi.changes().id(changeId).revision(revId3).files(revId2).keySet()) .containsExactly(COMMIT_MSG, "c.txt"); + + ResourceNotFoundException thrown = + assertThrows( + ResourceNotFoundException.class, + () -> gApi.changes().id(changeId).revision(revId3).files(initialCommit.getName())); + assertThat(thrown).hasMessageThat().contains(initialCommit.getName()); + + String invalidRev = "deadbeef"; + thrown = + assertThrows( + ResourceNotFoundException.class, + () -> gApi.changes().id(changeId).revision(revId3).files(invalidRev)); + assertThat(thrown).hasMessageThat().contains(invalidRev); } @Test diff --git a/javatests/com/google/gerrit/acceptance/pgm/ElasticReindexIT.java b/javatests/com/google/gerrit/acceptance/pgm/ElasticReindexIT.java index 3fca29802f..c18c0927f9 100644 --- a/javatests/com/google/gerrit/acceptance/pgm/ElasticReindexIT.java +++ b/javatests/com/google/gerrit/acceptance/pgm/ElasticReindexIT.java @@ -32,12 +32,12 @@ public class ElasticReindexIT extends AbstractReindexTests { @ConfigSuite.Config public static Config elasticsearchV6() { - return getConfig(ElasticVersion.V6_7); + return getConfig(ElasticVersion.V6_8); } @ConfigSuite.Config public static Config elasticsearchV7() { - return getConfig(ElasticVersion.V7_2); + return getConfig(ElasticVersion.V7_3); } @Override diff --git a/javatests/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java b/javatests/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java index 2a8293f364..b3ab542dcf 100644 --- a/javatests/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java +++ b/javatests/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java @@ -32,15 +32,11 @@ import com.google.gerrit.extensions.api.changes.ChangeApi; import com.google.gerrit.extensions.api.changes.CherryPickInput; import com.google.gerrit.extensions.api.changes.NotifyHandling; import com.google.gerrit.extensions.api.changes.ReviewInput; -import com.google.gerrit.extensions.api.projects.BranchInput; import com.google.gerrit.extensions.client.ChangeStatus; import com.google.gerrit.extensions.client.GeneralPreferencesInfo; import com.google.gerrit.extensions.common.ChangeInfo; import com.google.gerrit.extensions.common.ChangeInput; -import com.google.gerrit.extensions.common.ChangeMessageInfo; -import com.google.gerrit.extensions.common.CommitInfo; import com.google.gerrit.extensions.common.MergeInput; -import com.google.gerrit.extensions.common.RevisionInfo; import com.google.gerrit.extensions.restapi.BadRequestException; import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.ResourceNotFoundException; @@ -53,7 +49,6 @@ import com.google.gerrit.server.submit.ChangeAlreadyMergedException; import com.google.gerrit.testing.FakeEmailSender.Message; import com.google.gerrit.testing.TestTimeUtil; import com.google.inject.Inject; -import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.jgit.lib.ObjectId; @@ -393,60 +388,6 @@ public class CreateChangeIT extends AbstractDaemonTest { assertCreateSucceeds(in); } - @Test - public void cherryPickCommitWithoutChangeId() throws Exception { - // This test is a little superfluous, since the current cherry-pick code ignores - // the commit message of the to-be-cherry-picked change, using the one in - // CherryPickInput instead. - CherryPickInput input = new CherryPickInput(); - input.destination = "foo"; - input.message = "it goes to foo branch"; - gApi.projects().name(project.get()).branch(input.destination).create(new BranchInput()); - - RevCommit revCommit = createNewCommitWithoutChangeId("refs/heads/master", "a.txt", "content"); - ChangeInfo changeInfo = - gApi.projects().name(project.get()).commit(revCommit.getName()).cherryPick(input).get(); - - assertThat(changeInfo.messages).hasSize(1); - Iterator messageIterator = changeInfo.messages.iterator(); - String expectedMessage = - String.format("Patch Set 1: Cherry Picked from commit %s.", revCommit.getName()); - assertThat(messageIterator.next().message).isEqualTo(expectedMessage); - - RevisionInfo revInfo = changeInfo.revisions.get(changeInfo.currentRevision); - assertThat(revInfo).isNotNull(); - CommitInfo commitInfo = revInfo.commit; - assertThat(commitInfo.message) - .isEqualTo(input.message + "\n\nChange-Id: " + changeInfo.changeId + "\n"); - } - - @Test - public void cherryPickCommitWithChangeId() throws Exception { - CherryPickInput input = new CherryPickInput(); - input.destination = "foo"; - - RevCommit revCommit = createChange().getCommit(); - List footers = revCommit.getFooterLines("Change-Id"); - assertThat(footers).hasSize(1); - String changeId = footers.get(0); - - input.message = "it goes to foo branch\n\nChange-Id: " + changeId; - gApi.projects().name(project.get()).branch(input.destination).create(new BranchInput()); - - ChangeInfo changeInfo = - gApi.projects().name(project.get()).commit(revCommit.getName()).cherryPick(input).get(); - - assertThat(changeInfo.messages).hasSize(1); - Iterator messageIterator = changeInfo.messages.iterator(); - String expectedMessage = - String.format("Patch Set 1: Cherry Picked from commit %s.", revCommit.getName()); - assertThat(messageIterator.next().message).isEqualTo(expectedMessage); - - RevisionInfo revInfo = changeInfo.revisions.get(changeInfo.currentRevision); - assertThat(revInfo).isNotNull(); - assertThat(revInfo.commit.message).isEqualTo(input.message + "\n"); - } - @Test public void createChangeOnExistingBranchNotPermitted() throws Exception { createBranch(new Branch.NameKey(project, "foo")); diff --git a/javatests/com/google/gerrit/acceptance/ssh/ElasticIndexIT.java b/javatests/com/google/gerrit/acceptance/ssh/ElasticIndexIT.java index f81ca4c5d2..6ccd9e0d6f 100644 --- a/javatests/com/google/gerrit/acceptance/ssh/ElasticIndexIT.java +++ b/javatests/com/google/gerrit/acceptance/ssh/ElasticIndexIT.java @@ -31,12 +31,12 @@ public class ElasticIndexIT extends AbstractIndexTests { @ConfigSuite.Config public static Config elasticsearchV6() { - return getConfig(ElasticVersion.V6_7); + return getConfig(ElasticVersion.V6_8); } @ConfigSuite.Config public static Config elasticsearchV7() { - return getConfig(ElasticVersion.V7_2); + return getConfig(ElasticVersion.V7_3); } @Override diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java b/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java index a0c40c7ed1..299777e7b9 100644 --- a/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java +++ b/javatests/com/google/gerrit/elasticsearch/ElasticContainer.java @@ -50,12 +50,16 @@ public class ElasticContainer extends ElasticsearchContainer { return "blacktop/elasticsearch:6.6.2"; case V6_7: return "blacktop/elasticsearch:6.7.2"; + case V6_8: + return "blacktop/elasticsearch:6.8.2"; case V7_0: return "blacktop/elasticsearch:7.0.1"; case V7_1: return "blacktop/elasticsearch:7.1.1"; case V7_2: - return "blacktop/elasticsearch:7.2.0"; + return "blacktop/elasticsearch:7.2.1"; + case V7_3: + return "blacktop/elasticsearch:7.3.0"; } throw new IllegalStateException("No tests for version: " + version.name()); } diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticV6QueryAccountsTest.java b/javatests/com/google/gerrit/elasticsearch/ElasticV6QueryAccountsTest.java index 219eecd5bd..e39c9b40ef 100644 --- a/javatests/com/google/gerrit/elasticsearch/ElasticV6QueryAccountsTest.java +++ b/javatests/com/google/gerrit/elasticsearch/ElasticV6QueryAccountsTest.java @@ -41,7 +41,7 @@ public class ElasticV6QueryAccountsTest extends AbstractQueryAccountsTest { return; } - container = ElasticContainer.createAndStart(ElasticVersion.V6_7); + container = ElasticContainer.createAndStart(ElasticVersion.V6_8); nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort()); } diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticV6QueryChangesTest.java b/javatests/com/google/gerrit/elasticsearch/ElasticV6QueryChangesTest.java index 1b0822c89d..00ed35f3e3 100644 --- a/javatests/com/google/gerrit/elasticsearch/ElasticV6QueryChangesTest.java +++ b/javatests/com/google/gerrit/elasticsearch/ElasticV6QueryChangesTest.java @@ -41,7 +41,7 @@ public class ElasticV6QueryChangesTest extends AbstractQueryChangesTest { return; } - container = ElasticContainer.createAndStart(ElasticVersion.V6_7); + container = ElasticContainer.createAndStart(ElasticVersion.V6_8); nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort()); } diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticV6QueryGroupsTest.java b/javatests/com/google/gerrit/elasticsearch/ElasticV6QueryGroupsTest.java index 2782b7f82d..7e52b3bbc5 100644 --- a/javatests/com/google/gerrit/elasticsearch/ElasticV6QueryGroupsTest.java +++ b/javatests/com/google/gerrit/elasticsearch/ElasticV6QueryGroupsTest.java @@ -41,7 +41,7 @@ public class ElasticV6QueryGroupsTest extends AbstractQueryGroupsTest { return; } - container = ElasticContainer.createAndStart(ElasticVersion.V6_7); + container = ElasticContainer.createAndStart(ElasticVersion.V6_8); nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort()); } diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticV6QueryProjectsTest.java b/javatests/com/google/gerrit/elasticsearch/ElasticV6QueryProjectsTest.java index f01138a375..21d6c4d1d7 100644 --- a/javatests/com/google/gerrit/elasticsearch/ElasticV6QueryProjectsTest.java +++ b/javatests/com/google/gerrit/elasticsearch/ElasticV6QueryProjectsTest.java @@ -41,7 +41,7 @@ public class ElasticV6QueryProjectsTest extends AbstractQueryProjectsTest { return; } - container = ElasticContainer.createAndStart(ElasticVersion.V6_7); + container = ElasticContainer.createAndStart(ElasticVersion.V6_8); nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort()); } diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryAccountsTest.java b/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryAccountsTest.java index a5c7c25787..4010fba814 100644 --- a/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryAccountsTest.java +++ b/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryAccountsTest.java @@ -41,7 +41,7 @@ public class ElasticV7QueryAccountsTest extends AbstractQueryAccountsTest { return; } - container = ElasticContainer.createAndStart(ElasticVersion.V7_2); + container = ElasticContainer.createAndStart(ElasticVersion.V7_3); nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort()); } diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryChangesTest.java b/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryChangesTest.java index 80ca2567f7..010411f45b 100644 --- a/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryChangesTest.java +++ b/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryChangesTest.java @@ -47,7 +47,7 @@ public class ElasticV7QueryChangesTest extends AbstractQueryChangesTest { return; } - container = ElasticContainer.createAndStart(ElasticVersion.V7_2); + container = ElasticContainer.createAndStart(ElasticVersion.V7_3); nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort()); client = HttpAsyncClients.createDefault(); client.start(); diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryGroupsTest.java b/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryGroupsTest.java index 59e5a18d6f..0a0502aaad 100644 --- a/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryGroupsTest.java +++ b/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryGroupsTest.java @@ -41,7 +41,7 @@ public class ElasticV7QueryGroupsTest extends AbstractQueryGroupsTest { return; } - container = ElasticContainer.createAndStart(ElasticVersion.V7_2); + container = ElasticContainer.createAndStart(ElasticVersion.V7_3); nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort()); } diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryProjectsTest.java b/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryProjectsTest.java index 17646eed80..d902b10c0a 100644 --- a/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryProjectsTest.java +++ b/javatests/com/google/gerrit/elasticsearch/ElasticV7QueryProjectsTest.java @@ -41,7 +41,7 @@ public class ElasticV7QueryProjectsTest extends AbstractQueryProjectsTest { return; } - container = ElasticContainer.createAndStart(ElasticVersion.V7_2); + container = ElasticContainer.createAndStart(ElasticVersion.V7_3); nodeInfo = new ElasticNodeInfo(container.getHttpHost().getPort()); } diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticVersionTest.java b/javatests/com/google/gerrit/elasticsearch/ElasticVersionTest.java index 1b405da77e..bdc0973d42 100644 --- a/javatests/com/google/gerrit/elasticsearch/ElasticVersionTest.java +++ b/javatests/com/google/gerrit/elasticsearch/ElasticVersionTest.java @@ -43,6 +43,9 @@ public class ElasticVersionTest extends GerritBaseTests { assertThat(ElasticVersion.forVersion("6.7.0")).isEqualTo(ElasticVersion.V6_7); assertThat(ElasticVersion.forVersion("6.7.1")).isEqualTo(ElasticVersion.V6_7); + assertThat(ElasticVersion.forVersion("6.8.0")).isEqualTo(ElasticVersion.V6_8); + assertThat(ElasticVersion.forVersion("6.8.1")).isEqualTo(ElasticVersion.V6_8); + assertThat(ElasticVersion.forVersion("7.0.0")).isEqualTo(ElasticVersion.V7_0); assertThat(ElasticVersion.forVersion("7.0.1")).isEqualTo(ElasticVersion.V7_0); @@ -51,6 +54,9 @@ public class ElasticVersionTest extends GerritBaseTests { assertThat(ElasticVersion.forVersion("7.2.0")).isEqualTo(ElasticVersion.V7_2); assertThat(ElasticVersion.forVersion("7.2.1")).isEqualTo(ElasticVersion.V7_2); + + assertThat(ElasticVersion.forVersion("7.3.0")).isEqualTo(ElasticVersion.V7_3); + assertThat(ElasticVersion.forVersion("7.3.1")).isEqualTo(ElasticVersion.V7_3); } @Test @@ -70,9 +76,11 @@ public class ElasticVersionTest extends GerritBaseTests { assertThat(ElasticVersion.V6_5.isAtLeastMinorVersion(ElasticVersion.V6_7)).isFalse(); assertThat(ElasticVersion.V6_6.isAtLeastMinorVersion(ElasticVersion.V6_7)).isFalse(); assertThat(ElasticVersion.V6_7.isAtLeastMinorVersion(ElasticVersion.V6_7)).isTrue(); + assertThat(ElasticVersion.V6_8.isAtLeastMinorVersion(ElasticVersion.V6_8)).isTrue(); assertThat(ElasticVersion.V7_0.isAtLeastMinorVersion(ElasticVersion.V6_7)).isFalse(); assertThat(ElasticVersion.V7_1.isAtLeastMinorVersion(ElasticVersion.V6_7)).isFalse(); assertThat(ElasticVersion.V7_2.isAtLeastMinorVersion(ElasticVersion.V6_7)).isFalse(); + assertThat(ElasticVersion.V7_3.isAtLeastMinorVersion(ElasticVersion.V6_7)).isFalse(); } @Test @@ -84,9 +92,11 @@ public class ElasticVersionTest extends GerritBaseTests { assertThat(ElasticVersion.V6_5.isV6OrLater()).isTrue(); assertThat(ElasticVersion.V6_6.isV6OrLater()).isTrue(); assertThat(ElasticVersion.V6_7.isV6OrLater()).isTrue(); + assertThat(ElasticVersion.V6_8.isV6OrLater()).isTrue(); assertThat(ElasticVersion.V7_0.isV6OrLater()).isTrue(); assertThat(ElasticVersion.V7_1.isV6OrLater()).isTrue(); assertThat(ElasticVersion.V7_2.isV6OrLater()).isTrue(); + assertThat(ElasticVersion.V7_3.isV6OrLater()).isTrue(); } @Test @@ -98,8 +108,10 @@ public class ElasticVersionTest extends GerritBaseTests { assertThat(ElasticVersion.V6_5.isV7OrLater()).isFalse(); assertThat(ElasticVersion.V6_6.isV7OrLater()).isFalse(); assertThat(ElasticVersion.V6_7.isV7OrLater()).isFalse(); + assertThat(ElasticVersion.V6_8.isV7OrLater()).isFalse(); assertThat(ElasticVersion.V7_0.isV7OrLater()).isTrue(); assertThat(ElasticVersion.V7_1.isV7OrLater()).isTrue(); assertThat(ElasticVersion.V7_2.isV7OrLater()).isTrue(); + assertThat(ElasticVersion.V7_3.isV7OrLater()).isTrue(); } } diff --git a/plugins/replication b/plugins/replication index 6038386d7e..0ab3a3d0ef 160000 --- a/plugins/replication +++ b/plugins/replication @@ -1 +1 @@ -Subproject commit 6038386d7eb1fd0a29817f24cf40f550266748ee +Subproject commit 0ab3a3d0ef8f98c7a3a8b3076830bea481a37bef diff --git a/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html b/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html index 4266b2255c..df7f3cff7d 100644 --- a/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html +++ b/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html @@ -121,9 +121,11 @@ shortcuts are. const Shortcut = { OPEN_SHORTCUT_HELP_DIALOG: 'OPEN_SHORTCUT_HELP_DIALOG', + GO_TO_USER_DASHBOARD: 'GO_TO_USER_DASHBOARD', GO_TO_OPENED_CHANGES: 'GO_TO_OPENED_CHANGES', GO_TO_MERGED_CHANGES: 'GO_TO_MERGED_CHANGES', GO_TO_ABANDONED_CHANGES: 'GO_TO_ABANDONED_CHANGES', + GO_TO_WATCHED_CHANGES: 'GO_TO_WATCHED_CHANGES', CURSOR_NEXT_CHANGE: 'CURSOR_NEXT_CHANGE', CURSOR_PREV_CHANGE: 'CURSOR_PREV_CHANGE', @@ -192,12 +194,16 @@ shortcuts are. _describe(Shortcut.SEARCH, ShortcutSection.EVERYWHERE, 'Search'); _describe(Shortcut.OPEN_SHORTCUT_HELP_DIALOG, ShortcutSection.EVERYWHERE, 'Show this dialog'); + _describe(Shortcut.GO_TO_USER_DASHBOARD, ShortcutSection.EVERYWHERE, + 'Go to User Dashboard'); _describe(Shortcut.GO_TO_OPENED_CHANGES, ShortcutSection.EVERYWHERE, 'Go to Opened Changes'); _describe(Shortcut.GO_TO_MERGED_CHANGES, ShortcutSection.EVERYWHERE, 'Go to Merged Changes'); _describe(Shortcut.GO_TO_ABANDONED_CHANGES, ShortcutSection.EVERYWHERE, 'Go to Abandoned Changes'); + _describe(Shortcut.GO_TO_WATCHED_CHANGES, ShortcutSection.EVERYWHERE, + 'Go to Watched Changes'); _describe(Shortcut.CURSOR_NEXT_CHANGE, ShortcutSection.ACTIONS, 'Select next change'); diff --git a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.html b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.html index 05b176c342..b10c98a309 100644 --- a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.html +++ b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.html @@ -43,33 +43,34 @@ limitations under the License. Loading... - + + + diff --git a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.js b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.js index a131f4f997..456421e2a8 100644 --- a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.js +++ b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.js @@ -197,10 +197,11 @@ }); for (const key of keys) { - if (!values[key]) { return; } + let text = values[key]; + if (!text) { text = ''; } // The value from the server being used to choose which item is // selected is in integer form, so this must be converted. - valuesArr.push({value: parseInt(key, 10), text: values[key]}); + valuesArr.push({value: parseInt(key, 10), text}); } return valuesArr; }, diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html index c2b28d6d35..c2d2036e9e 100644 --- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html +++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html @@ -195,6 +195,9 @@ limitations under the License.

+ diff --git a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html index b1433a3e9a..c523b5130e 100644 --- a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html +++ b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html @@ -349,6 +349,13 @@ limitations under the License. return this._navigate(this.getUrlForSearchQuery(query, opt_offset)); }, + /** + * Navigate to the user's dashboard + */ + navigateToUserDashboard() { + return this._navigate(this.getUrlForUserDashboard('self')); + }, + /** * @param {!Object} change The change object. * @param {number=} opt_patchNum diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.js b/polygerrit-ui/app/elements/core/gr-router/gr-router.js index 89a1f47f48..31ca388670 100644 --- a/polygerrit-ui/app/elements/core/gr-router/gr-router.js +++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.js @@ -1411,9 +1411,13 @@ }, _handleSettingsLegacyRoute(data) { + // email tokens may contain '+' but no space. + // The parameter parsing replaces all '+' with a space, + // undo that to have valid tokens. + const token = data.params[0].replace(/ /g, '+'); this._setParams({ view: Gerrit.Nav.View.SETTINGS, - emailToken: data.params[0], + emailToken: token, }); }, diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html index e12844bb82..16a4c666ab 100644 --- a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html +++ b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html @@ -670,6 +670,14 @@ limitations under the License. }); }); + test('_handleSettingsLegacyRoute with +', () => { + const data = {params: {0: 'my-token test'}}; + assertDataToParams(data, '_handleSettingsLegacyRoute', { + view: Gerrit.Nav.View.SETTINGS, + emailToken: 'my-token+test', + }); + }); + test('_handleSettingsRoute', () => { const data = {}; assertDataToParams(data, '_handleSettingsRoute', { diff --git a/polygerrit-ui/app/elements/gr-app.html b/polygerrit-ui/app/elements/gr-app.html index 99afd9a0f0..ad03adb70b 100644 --- a/polygerrit-ui/app/elements/gr-app.html +++ b/polygerrit-ui/app/elements/gr-app.html @@ -232,7 +232,8 @@ limitations under the License.
+ rel="noopener" + hidden$="[[!_showFeedbackUrl(_feedbackUrl)]]">Send feedback | Press “?” for keyboard shortcuts
diff --git a/polygerrit-ui/app/elements/gr-app.js b/polygerrit-ui/app/elements/gr-app.js index de9a6ad97e..ebf2020621 100644 --- a/polygerrit-ui/app/elements/gr-app.js +++ b/polygerrit-ui/app/elements/gr-app.js @@ -87,11 +87,7 @@ computed: '_computePluginScreenName(params)', }, _settingsUrl: String, - _feedbackUrl: { - type: String, - value: 'https://bugs.chromium.org/p/gerrit/issues/entry' + - '?template=PolyGerrit%20Issue', - }, + _feedbackUrl: String, // Used to allow searching on mobile mobileSearch: { type: Boolean, @@ -458,5 +454,13 @@ _mobileSearchToggle(e) { this.mobileSearch = !this.mobileSearch; }, + + _showFeedbackUrl(feedbackUrl) { + if (feedbackUrl) { + return feedbackUrl; + } + + return false; + }, }); })(); diff --git a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.html b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.html index 4c7edcfea7..73aa65f52c 100644 --- a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.html +++ b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.html @@ -16,6 +16,7 @@ limitations under the License. --> + @@ -48,9 +49,12 @@ limitations under the License. .deleteButton:not(.show) { display: none; } + .space { + margin-bottom: 1em; + }
-
+
@@ -80,6 +84,13 @@ limitations under the License.
+ +
+ + Link Another Identity + +
+
{ this._identities = id; @@ -64,5 +78,24 @@ filterIdentities(item) { return !item.identity.startsWith('username:'); }, + + _computeShowLinkAnotherIdentity(config) { + if (config && config.auth && + config.auth.git_basic_auth_policy) { + return AUTH.includes( + config.auth.git_basic_auth_policy.toUpperCase()); + } + + return false; + }, + + _computeLinkAnotherIdentity() { + const baseUrl = this.getBaseUrl() || ''; + let pathname = window.location.pathname; + if (baseUrl) { + pathname = '/' + pathname.substring(baseUrl.length); + } + return baseUrl + '/login/' + encodeURIComponent(pathname) + '?link'; + }, }); })(); diff --git a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.html b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.html index c77a1b9ece..5468d27079 100644 --- a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.html +++ b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.html @@ -122,5 +122,65 @@ limitations under the License. MockInteractions.tap(deleteBtn); assert.isTrue(deleteItem.called); }); + + test('_computeShowLinkAnotherIdentity', () => { + let serverConfig; + + serverConfig = { + auth: { + git_basic_auth_policy: 'OAUTH', + }, + }; + assert.isTrue(element._computeShowLinkAnotherIdentity(serverConfig)); + + serverConfig = { + auth: { + git_basic_auth_policy: 'OpenID', + }, + }; + assert.isTrue(element._computeShowLinkAnotherIdentity(serverConfig)); + + serverConfig = { + auth: { + git_basic_auth_policy: 'HTTP_LDAP', + }, + }; + assert.isFalse(element._computeShowLinkAnotherIdentity(serverConfig)); + + serverConfig = { + auth: { + git_basic_auth_policy: 'LDAP', + }, + }; + assert.isFalse(element._computeShowLinkAnotherIdentity(serverConfig)); + + serverConfig = { + auth: { + git_basic_auth_policy: 'HTTP', + }, + }; + assert.isFalse(element._computeShowLinkAnotherIdentity(serverConfig)); + + serverConfig = {}; + assert.isFalse(element._computeShowLinkAnotherIdentity(serverConfig)); + }); + + test('_showLinkAnotherIdentity', () => { + element.serverConfig = { + auth: { + git_basic_auth_policy: 'OAUTH', + }, + }; + + assert.isTrue(element._showLinkAnotherIdentity); + + element.serverConfig = { + auth: { + git_basic_auth_policy: 'LDAP', + }, + }; + + assert.isFalse(element._showLinkAnotherIdentity); + }); }); diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html index 1af152b34a..c382a5dfb7 100644 --- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html +++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html @@ -417,7 +417,7 @@ limitations under the License.

Identities

- +