Merge "google-java-format: Add support for version 1.22.0"
diff --git a/Documentation/rest-api-projects.txt b/Documentation/rest-api-projects.txt
index fa30c87..b0e1b49 100644
--- a/Documentation/rest-api-projects.txt
+++ b/Documentation/rest-api-projects.txt
@@ -2514,6 +2514,53 @@
]
----
+SortBy(sortby)::
+Sort the returned tags by one of the supported sort options: ref (default), creation_time.
++
+.Request
+----
+ GET /projects/work%2Fmy-project/tags?sortby=creation_time HTTP/1.0
+----
++
+.Response
+----
+ HTTP/1.1 200 OK
+ Content-Disposition: attachment
+ Content-Type: application/json; charset=UTF-8
+
+ )]}'
+ [
+ {
+ "ref": "refs/tags/v1.0",
+ "revision": "49ce77fdcfd3398dc0dedbe016d1a425fd52d666",
+ "object": "1624f5af8ae89148d1a3730df8c290413e3dcf30",
+ "message": "Annotated tag",
+ "tagger": {
+ "name": "David Pursehouse",
+ "email": "david.pursehouse@sonymobile.com",
+ "date": "2014-10-06 07:35:03.000000000",
+ "tz": 540
+ }
+ },
+ {
+ "ref": "refs/tags/v3.0",
+ "revision": "c628685b3c5a3614571ecb5c8fceb85db9112313",
+ "object": "1624f5af8ae89148d1a3730df8c290413e3dcf30",
+ "message": "Signed tag\n-----BEGIN PGP SIGNATURE-----\nVersion: GnuPG v1.4.11 (GNU/Linux)\n\niQEcBAABAgAGBQJUMlqYAAoJEPI2qVPgglptp7MH/j+KFcittFbxfSnZjUl8n5IZ\nveZo7wE+syjD9sUbMH4EGv0WYeVjphNTyViBof+stGTNkB0VQzLWI8+uWmOeiJ4a\nzj0LsbDOxodOEMI5tifo02L7r4Lzj++EbqtKv8IUq2kzYoQ2xjhKfFiGjeYOn008\n9PGnhNblEHZgCHguGR6GsfN8bfA2XNl9B5Ysl5ybX1kAVs/TuLZR4oDMZ/pW2S75\nhuyNnSgcgq7vl2gLGefuPs9lxkg5Fj3GZr7XPZk4pt/x1oiH7yXxV4UzrUwg2CC1\nfHrBlNbQ4uJNY8TFcwof52Z0cagM5Qb/ZSLglHbqEDGA68HPqbwf5z2hQyU2/U4\u003d\n\u003dZtUX\n-----END PGP SIGNATURE-----",
+ "tagger": {
+ "name": "David Pursehouse",
+ "email": "david.pursehouse@sonymobile.com",
+ "date": "2014-10-06 09:02:16.000000000",
+ "tz": 540
+ }
+ },
+ {
+ "ref": "refs/tags/v2.0",
+ "revision": "1624f5af8ae89148d1a3730df8c290413e3dcf30"
+ }
+ ]
+----
+
Substring(m)::
Limit the results to those tags that match the specified substring.
+
diff --git a/java/com/google/gerrit/extensions/api/projects/ProjectApi.java b/java/com/google/gerrit/extensions/api/projects/ProjectApi.java
index fa94e0d..0b1b6b0 100644
--- a/java/com/google/gerrit/extensions/api/projects/ProjectApi.java
+++ b/java/com/google/gerrit/extensions/api/projects/ProjectApi.java
@@ -22,6 +22,7 @@
import com.google.gerrit.extensions.common.BatchLabelInput;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.LabelDefinitionInfo;
+import com.google.gerrit.extensions.common.ListTagSortOption;
import com.google.gerrit.extensions.common.ProjectInfo;
import com.google.gerrit.extensions.common.SubmitRequirementInfo;
import com.google.gerrit.extensions.restapi.NotImplementedException;
@@ -76,6 +77,7 @@
protected String substring;
protected String regex;
protected String nextPageToken;
+ protected ListTagSortOption sortBy = ListTagSortOption.REF;
public abstract List<T> get() throws RestApiException;
@@ -94,6 +96,11 @@
return this;
}
+ public ListRefsRequest<T> withSortBy(ListTagSortOption sortBy) {
+ this.sortBy = sortBy;
+ return this;
+ }
+
public ListRefsRequest<T> withNextPageToken(String token) {
this.nextPageToken = token;
return this;
@@ -121,6 +128,10 @@
return descendingOrder;
}
+ public ListTagSortOption getSortBy() {
+ return sortBy;
+ }
+
public String getNextPageToken() {
return nextPageToken;
}
diff --git a/java/com/google/gerrit/extensions/common/ListTagSortOption.java b/java/com/google/gerrit/extensions/common/ListTagSortOption.java
new file mode 100644
index 0000000..2140924
--- /dev/null
+++ b/java/com/google/gerrit/extensions/common/ListTagSortOption.java
@@ -0,0 +1,20 @@
+// Copyright (C) 2024 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.extensions.common;
+
+public enum ListTagSortOption {
+ REF,
+ CREATION_TIME,
+}
diff --git a/java/com/google/gerrit/server/CmdLineParserModule.java b/java/com/google/gerrit/server/CmdLineParserModule.java
index be6b4cd8..c523a29 100644
--- a/java/com/google/gerrit/server/CmdLineParserModule.java
+++ b/java/com/google/gerrit/server/CmdLineParserModule.java
@@ -18,12 +18,14 @@
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.PatchSet;
+import com.google.gerrit.extensions.common.ListTagSortOption;
import com.google.gerrit.extensions.config.FactoryModule;
import com.google.gerrit.server.args4j.AccountGroupIdHandler;
import com.google.gerrit.server.args4j.AccountGroupUUIDHandler;
import com.google.gerrit.server.args4j.AccountIdHandler;
import com.google.gerrit.server.args4j.ChangeIdHandler;
import com.google.gerrit.server.args4j.InstantHandler;
+import com.google.gerrit.server.args4j.ListTagSortOptionHandler;
import com.google.gerrit.server.args4j.ObjectIdHandler;
import com.google.gerrit.server.args4j.PatchSetIdHandler;
import com.google.gerrit.server.args4j.ProjectHandler;
@@ -54,6 +56,7 @@
registerOptionHandler(PatchSet.Id.class, PatchSetIdHandler.class);
registerOptionHandler(ProjectState.class, ProjectHandler.class);
registerOptionHandler(SocketAddress.class, SocketAddressHandler.class);
+ registerOptionHandler(ListTagSortOption.class, ListTagSortOptionHandler.class);
}
private <T> void registerOptionHandler(Class<T> type, Class<? extends OptionHandler<T>> impl) {
diff --git a/java/com/google/gerrit/server/args4j/ListTagSortOptionHandler.java b/java/com/google/gerrit/server/args4j/ListTagSortOptionHandler.java
new file mode 100644
index 0000000..9359ca1
--- /dev/null
+++ b/java/com/google/gerrit/server/args4j/ListTagSortOptionHandler.java
@@ -0,0 +1,54 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.args4j;
+
+import static com.google.gerrit.util.cli.Localizable.localizable;
+
+import com.google.gerrit.extensions.common.ListTagSortOption;
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+import org.kohsuke.args4j.spi.OptionHandler;
+import org.kohsuke.args4j.spi.Parameters;
+import org.kohsuke.args4j.spi.Setter;
+
+public class ListTagSortOptionHandler extends OptionHandler<ListTagSortOption> {
+ @Inject
+ public ListTagSortOptionHandler(
+ @Assisted CmdLineParser parser,
+ @Assisted OptionDef option,
+ @Assisted Setter<ListTagSortOption> setter) {
+ super(parser, option, setter);
+ }
+
+ @Override
+ public int parseArguments(Parameters params) throws CmdLineException {
+ String param = params.getParameter(0);
+ try {
+ setter.addValue(ListTagSortOption.valueOf(param.toUpperCase()));
+ return 1;
+ } catch (IllegalArgumentException e) {
+ throw new CmdLineException(
+ owner, localizable("\"%s\" is not a valid sort option: %s"), param, e.getMessage());
+ }
+ }
+
+ @Override
+ public String getDefaultMetaVariable() {
+ return "SORT";
+ }
+}
diff --git a/java/com/google/gerrit/server/restapi/project/ListTags.java b/java/com/google/gerrit/server/restapi/project/ListTags.java
index 5eca1fc..24bbb24 100644
--- a/java/com/google/gerrit/server/restapi/project/ListTags.java
+++ b/java/com/google/gerrit/server/restapi/project/ListTags.java
@@ -15,12 +15,12 @@
package com.google.gerrit.server.restapi.project;
import static com.google.gerrit.entities.RefNames.isConfigRef;
-import static java.util.Comparator.comparing;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.entities.Project;
import com.google.gerrit.extensions.api.projects.ProjectApi.ListRefsRequest;
import com.google.gerrit.extensions.api.projects.TagInfo;
+import com.google.gerrit.extensions.common.ListTagSortOption;
import com.google.gerrit.extensions.common.WebLinkInfo;
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
@@ -59,6 +59,7 @@
private final GitRepositoryManager repoManager;
private final PermissionBackend permissionBackend;
private final WebLinks links;
+ private final TagSorter tagSorter;
@Option(
name = "--limit",
@@ -81,7 +82,7 @@
@Option(
name = "--descending",
aliases = {"-d"},
- usage = "sort the returned tags in descending order")
+ usage = "return the tags in descending order")
public void setDescendingOrder(boolean descendingOrder) {
this.descendingOrder = descendingOrder;
}
@@ -104,18 +105,31 @@
this.matchRegex = matchRegex;
}
+ @Option(
+ name = "--sort-by",
+ aliases = {"-sortby"},
+ usage = "sort the tags")
+ private void setSortBy(ListTagSortOption sortBy) {
+ this.sortBy = sortBy;
+ }
+
private int limit;
private int start;
private boolean descendingOrder;
private String matchSubstring;
private String matchRegex;
+ private ListTagSortOption sortBy = ListTagSortOption.REF;
@Inject
public ListTags(
- GitRepositoryManager repoManager, PermissionBackend permissionBackend, WebLinks webLinks) {
+ GitRepositoryManager repoManager,
+ PermissionBackend permissionBackend,
+ WebLinks webLinks,
+ TagSorter tagSorter) {
this.repoManager = repoManager;
this.permissionBackend = permissionBackend;
this.links = webLinks;
+ this.tagSorter = tagSorter;
}
public ListTags request(ListRefsRequest<TagInfo> request) {
@@ -124,6 +138,7 @@
this.setDescendingOrder(request.getDescendingOrder());
this.setMatchSubstring(request.getSubstring());
this.setMatchRegex(request.getRegex());
+ this.setSortBy(request.getSortBy());
return this;
}
@@ -147,7 +162,7 @@
}
}
- tags.sort(comparing(t -> t.ref));
+ tagSorter.sort(sortBy, tags, descendingOrder);
if (descendingOrder) {
Collections.reverse(tags);
}
diff --git a/java/com/google/gerrit/server/restapi/project/TagSorter.java b/java/com/google/gerrit/server/restapi/project/TagSorter.java
new file mode 100644
index 0000000..4776ce1
--- /dev/null
+++ b/java/com/google/gerrit/server/restapi/project/TagSorter.java
@@ -0,0 +1,46 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.restapi.project;
+
+import static java.util.Comparator.comparing;
+
+import com.google.gerrit.extensions.api.projects.TagInfo;
+import com.google.gerrit.extensions.common.ListTagSortOption;
+import com.google.inject.Inject;
+import java.sql.Timestamp;
+import java.util.Comparator;
+import java.util.List;
+
+public class TagSorter {
+ @Inject
+ public TagSorter() {}
+
+ /** Sort the tags by the given sort option, in place */
+ public void sort(ListTagSortOption sortBy, List<TagInfo> tags, boolean descendingOrder) {
+ switch (sortBy) {
+ case CREATION_TIME:
+ Comparator<Timestamp> nullsComparator =
+ descendingOrder
+ ? Comparator.nullsFirst(Comparator.naturalOrder())
+ : Comparator.nullsLast(Comparator.naturalOrder());
+ tags.sort(comparing(t -> t.created, nullsComparator));
+ break;
+ case REF:
+ default:
+ tags.sort(comparing(t -> t.ref));
+ break;
+ }
+ }
+}
diff --git a/javatests/com/google/gerrit/acceptance/rest/project/TagsIT.java b/javatests/com/google/gerrit/acceptance/rest/project/TagsIT.java
index b69ca1c..e2809b0 100644
--- a/javatests/com/google/gerrit/acceptance/rest/project/TagsIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/project/TagsIT.java
@@ -27,6 +27,7 @@
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.acceptance.PushOneCommit;
+import com.google.gerrit.acceptance.UseClockStep;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
import com.google.gerrit.entities.AccessSection;
@@ -35,6 +36,7 @@
import com.google.gerrit.extensions.api.projects.TagApi;
import com.google.gerrit.extensions.api.projects.TagInfo;
import com.google.gerrit.extensions.api.projects.TagInput;
+import com.google.gerrit.extensions.common.ListTagSortOption;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
@@ -120,6 +122,7 @@
}
@Test
+ @UseClockStep
public void listTags() throws Exception {
createTags();
@@ -160,6 +163,19 @@
// with descending order
result = getTags().withDescendingOrder(true).get();
assertTagList(FluentIterable.from(Lists.reverse(testTags)), result);
+
+ // with sortBy creation time
+ result = getTags().withSortBy(ListTagSortOption.CREATION_TIME).get();
+ assertTagList(FluentIterable.from(Lists.reverse(testTags)), result);
+
+ // with sortBy, descending order and limit
+ result =
+ getTags()
+ .withDescendingOrder(true)
+ .withLimit(2)
+ .withSortBy(ListTagSortOption.CREATION_TIME)
+ .get();
+ assertTagList(FluentIterable.from(ImmutableList.of("tag-A", "tag-B")), result);
}
@Test
@@ -481,9 +497,10 @@
TagInput input = new TagInput();
input.revision = revision;
- for (String tagname : testTags) {
+ // Creating the tags in reverse order to allow testing the sortBy option
+ for (String tagname : Lists.reverse(testTags)) {
+ input.message = tagname; // This updates the 'created' time of the tag
TagInfo result = tag(tagname).create(input).get();
- assertThat(result.revision).isEqualTo(input.revision);
assertThat(result.ref).isEqualTo(R_TAGS + tagname);
}
}
diff --git a/javatests/com/google/gerrit/server/restapi/project/TagSorterTest.java b/javatests/com/google/gerrit/server/restapi/project/TagSorterTest.java
new file mode 100644
index 0000000..9a926a2
--- /dev/null
+++ b/javatests/com/google/gerrit/server/restapi/project/TagSorterTest.java
@@ -0,0 +1,83 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.restapi.project;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.gerrit.extensions.api.projects.TagInfo;
+import com.google.gerrit.extensions.common.ListTagSortOption;
+import com.google.gerrit.extensions.common.WebLinkInfo;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TagSorterTest {
+ private static final String revision = "dfdd715e31db256dfba48239f83f9b8da4bc243f";
+ private static final boolean canDelete = true;
+ private static final List<WebLinkInfo> webLinks = new ArrayList<>();
+ private static final TagSorter tagSorter = new TagSorter();
+ private List<TagInfo> tags;
+
+ @Before
+ public void initializeTags() {
+ tags = createTags();
+ }
+
+ @Test
+ public void testSortTagsByRef() {
+ tagSorter.sort(ListTagSortOption.REF, tags, false);
+
+ assertThat(tags.get(0).ref).isEqualTo("refs/tags/v1.0");
+ assertThat(tags.get(1).ref).isEqualTo("refs/tags/v2.0");
+ assertThat(tags.get(2).ref).isEqualTo("refs/tags/v3.0");
+ assertThat(tags.get(3).ref).isEqualTo("refs/tags/v4.0");
+ }
+
+ @Test
+ public void testSortTagsByCreationTime() {
+ tagSorter.sort(ListTagSortOption.CREATION_TIME, tags, false);
+
+ assertThat(tags.get(0).ref).isEqualTo("refs/tags/v2.0");
+ assertThat(tags.get(1).ref).isEqualTo("refs/tags/v3.0");
+ assertThat(tags.get(2).ref).isEqualTo("refs/tags/v1.0");
+ assertThat(tags.get(3).ref).isEqualTo("refs/tags/v4.0");
+ }
+
+ @Test
+ public void testSortTagsByCreationTimeDescendingOrder() {
+ tagSorter.sort(ListTagSortOption.CREATION_TIME, tags, true);
+
+ assertThat(tags.get(0).ref).isEqualTo("refs/tags/v4.0");
+ assertThat(tags.get(1).ref).isEqualTo("refs/tags/v2.0");
+ assertThat(tags.get(2).ref).isEqualTo("refs/tags/v3.0");
+ assertThat(tags.get(3).ref).isEqualTo("refs/tags/v1.0");
+ }
+
+ private List<TagInfo> createTags() {
+ Instant t1 = Instant.now();
+ Instant t2 = t1.minusSeconds(10);
+ Instant t3 = t1.minusSeconds(1);
+
+ List<TagInfo> tags = new ArrayList<>();
+ tags.add(new TagInfo("refs/tags/v1.0", revision, canDelete, webLinks, t1));
+ tags.add(new TagInfo("refs/tags/v2.0", revision, canDelete, webLinks, t2));
+ tags.add(new TagInfo("refs/tags/v3.0", revision, canDelete, webLinks, t3));
+ tags.add(new TagInfo("refs/tags/v4.0", revision, canDelete, webLinks, (Instant) null));
+
+ return tags;
+ }
+}
diff --git a/polygerrit-ui/app/constants/reporting.ts b/polygerrit-ui/app/constants/reporting.ts
index dded0c6..37a17ba 100644
--- a/polygerrit-ui/app/constants/reporting.ts
+++ b/polygerrit-ui/app/constants/reporting.ts
@@ -146,6 +146,7 @@
GENERATE_SUGGESTION_ENABLED = 'generate_suggestion_enabled',
// User disabled generating suggestions
GENERATE_SUGGESTION_DISABLED = 'generate_suggestion_disabled',
+ GENERATE_SUGGESTION_EDITED = 'generate_suggestion_edited',
START_REVIEW = 'start-review',
CODE_REVIEW_APPROVAL = 'code-review-approval',
FILE_LIST_DIFF_COLLAPSED = 'file-list-diff-collapsed',
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
index 16a783c..48d7b1b 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
@@ -232,6 +232,9 @@
generatedSuggestionId?: string;
@state()
+ addedGeneratedSuggestion?: string;
+
+ @state()
suggestionsProvider?: SuggestionsProvider;
@state()
@@ -1149,9 +1152,10 @@
private handleAddGeneratedSuggestion(code: string) {
const addNewLine = this.messageText.length !== 0;
- this.messageText += `${
+ this.addedGeneratedSuggestion = `${
addNewLine ? '\n' : ''
}${USER_SUGGESTION_START_PATTERN}${code}${'\n```'}`;
+ this.messageText += this.addedGeneratedSuggestion;
}
private generateSuggestEdit() {
@@ -1665,6 +1669,7 @@
} else {
// No need to make a backend call when nothing has changed.
while (this.somethingToSave()) {
+ this.trackGeneratedSuggestionEdit();
this.comment = await this.rawSave({showToast: true});
if (isError(this.comment)) return;
}
@@ -1746,6 +1751,19 @@
);
this.closeDeleteCommentModal();
}
+
+ private trackGeneratedSuggestionEdit() {
+ const wasGeneratedSuggestionEdited =
+ this.addedGeneratedSuggestion &&
+ !this.messageText.includes(this.addedGeneratedSuggestion);
+ if (wasGeneratedSuggestionEdited) {
+ this.reporting.reportInteraction(Interaction.GENERATE_SUGGESTION_EDITED, {
+ uuid: this.generatedSuggestionId,
+ commentId: this.comment?.id ?? '',
+ });
+ this.addedGeneratedSuggestion = undefined;
+ }
+ }
}
declare global {