Merge branch 'stable-3.4'
* stable-3.4:
Add a test for case insensitive repo search
Documentation/linux-quickstart: Remove outdated note
Update git submodules
AS ops shouldn't count towards change.maxUpdates limit
Fix regression - enable insensitive search for repo search
Change-Id: Id139d0561c636b3c821ac4ee8897fa3d1fe74d03
diff --git a/Documentation/linux-quickstart.txt b/Documentation/linux-quickstart.txt
index 29bb409..e34071f 100644
--- a/Documentation/linux-quickstart.txt
+++ b/Documentation/linux-quickstart.txt
@@ -19,8 +19,7 @@
. A Unix-based server, including any Linux flavor, MacOS, or Berkeley Software
Distribution (BSD).
-. Java SE Runtime Environment version 1.8. Gerrit is not compatible with Java
- 9 or newer yet.
+. Java SE Runtime Environment version 11 and up.
== Download Gerrit
diff --git a/java/com/google/gerrit/server/notedb/ChangeNotesCommit.java b/java/com/google/gerrit/server/notedb/ChangeNotesCommit.java
index 71cb8c9..76573f6 100644
--- a/java/com/google/gerrit/server/notedb/ChangeNotesCommit.java
+++ b/java/com/google/gerrit/server/notedb/ChangeNotesCommit.java
@@ -15,9 +15,12 @@
package com.google.gerrit.server.notedb;
import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_ATTENTION;
+import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_PATCH_SET;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.MultimapBuilder;
+import com.google.common.collect.Sets;
import com.google.gerrit.server.git.InMemoryInserter;
import com.google.gerrit.server.git.InsertedObject;
import java.io.IOException;
@@ -127,4 +130,14 @@
}
return footerLines.get(key.getName().toLowerCase());
}
+
+ public boolean isAttentionSetCommitOnly(boolean hasChangeMessage) {
+ return !hasChangeMessage
+ && footerLines
+ .keySet()
+ .equals(
+ Sets.newHashSet(
+ FOOTER_PATCH_SET.getName().toLowerCase(),
+ FOOTER_ATTENTION.getName().toLowerCase()));
+ }
}
diff --git a/java/com/google/gerrit/server/notedb/ChangeNotesParser.java b/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
index f4d6cd3..f12176b 100644
--- a/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
+++ b/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
@@ -327,7 +327,6 @@
}
private void parse(ChangeNotesCommit commit) throws ConfigInvalidException {
- updateCount++;
Timestamp commitTimestamp = getCommitTimestamp(commit);
createdOn = commitTimestamp;
@@ -370,7 +369,8 @@
originalSubject = currSubject;
}
- parseChangeMessage(psId, accountId, realAccountId, commit, commitTimestamp);
+ boolean hasChangeMessage =
+ parseChangeMessage(psId, accountId, realAccountId, commit, commitTimestamp);
if (topic == null) {
topic = parseTopic(commit);
}
@@ -435,6 +435,9 @@
previousWorkInProgressFooter = null;
parseWorkInProgress(commit);
+ if (countTowardsMaxUpdatesLimit(commit, hasChangeMessage)) {
+ updateCount++;
+ }
}
private void parseSubmission(ChangeNotesCommit commit, Timestamp commitTimestamp)
@@ -720,7 +723,7 @@
}
}
- private void parseChangeMessage(
+ private boolean parseChangeMessage(
PatchSet.Id psId,
Account.Id accountId,
Account.Id realAccountId,
@@ -728,7 +731,7 @@
Timestamp ts) {
Optional<String> changeMsgString = getChangeMessageString(commit);
if (!changeMsgString.isPresent()) {
- return;
+ return false;
}
ChangeMessage changeMessage =
@@ -740,7 +743,7 @@
changeMsgString.get(),
realAccountId,
tag);
- allChangeMessages.add(changeMessage);
+ return allChangeMessages.add(changeMessage);
}
public static Optional<String> getChangeMessageString(ChangeNotesCommit commit) {
@@ -1197,4 +1200,9 @@
.orElseThrow(
() -> parseException("cannot retrieve account id: %s", ident.getEmailAddress()));
}
+
+ protected boolean countTowardsMaxUpdatesLimit(
+ ChangeNotesCommit commit, boolean hasChangeMessage) {
+ return !commit.isAttentionSetCommitOnly(hasChangeMessage);
+ }
}
diff --git a/javatests/com/google/gerrit/server/notedb/ChangeNotesCommitTest.java b/javatests/com/google/gerrit/server/notedb/ChangeNotesCommitTest.java
new file mode 100644
index 0000000..f105cf1
--- /dev/null
+++ b/javatests/com/google/gerrit/server/notedb/ChangeNotesCommitTest.java
@@ -0,0 +1,124 @@
+// Copyright (C) 2021 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.notedb;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.gerrit.entities.Change;
+import com.google.gerrit.server.util.time.TimeUtil;
+import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ChangeNotesCommitTest extends AbstractChangeNotesTest {
+ private TestRepository<InMemoryRepository> testRepo;
+ private ChangeNotesCommit.ChangeNotesRevWalk walk;
+
+ @Before
+ public void setUpTestRepo() throws Exception {
+ testRepo = new TestRepository<>(repo);
+ walk = ChangeNotesCommit.newRevWalk(repo);
+ }
+
+ @After
+ public void tearDownTestRepo() throws Exception {
+ walk.close();
+ }
+
+ @Test
+ public void attentionSetCommitOnlyWhenNoChangeMessageIsPresentAndCorrectFooter()
+ throws Exception {
+ RevCommit commit =
+ writeCommit(
+ "Update patch set 1\n"
+ + "\n"
+ + "Patch-set: 1\n"
+ + "Attention: {\"person_ident\":\"Gerrit User 1000000 \\u003c1000000@adce0b11-8f2e-4ab6-ac69-e675f183d871\\u003e\",\"operation\":\"ADD\",\"reason\":\"Added by Administrator using the hovercard menu\"}");
+
+ newParser(commit).parseAll();
+ assertThat(((ChangeNotesCommit) commit).isAttentionSetCommitOnly(false)).isEqualTo(true);
+ }
+
+ @Test
+ public void noAttentionSetCommitOnlyWhenNoChangeMessageIsPresentAndFooterNotOnlyAS()
+ throws Exception {
+ RevCommit commit =
+ writeCommit(
+ "Update patch set 1\n"
+ + "\n"
+ + "Patch-set: 1\n"
+ + "Subject: Change subject\n"
+ + "Attention: {\"person_ident\":\"Gerrit User 1000000 \\u003c1000000@adce0b11-8f2e-4ab6-ac69-e675f183d871\\u003e\",\"operation\":\"ADD\",\"reason\":\"Added by Administrator using the hovercard menu\"}");
+
+ newParser(commit).parseAll();
+ assertThat(((ChangeNotesCommit) commit).isAttentionSetCommitOnly(false)).isEqualTo(false);
+ }
+
+ @Test
+ public void noAttentionSetCommitOnlyWhenNoChangeMessageIsPresentAndGenericFooter()
+ throws Exception {
+ RevCommit commit = writeCommit("Update patch set 1\n" + "\n" + "Patch-set: 1\n");
+
+ newParser(commit).parseAll();
+ assertThat(((ChangeNotesCommit) commit).isAttentionSetCommitOnly(false)).isEqualTo(false);
+ }
+
+ @Test
+ public void noAttentionSetCommitOnlyWhenChangeMessageIsPresent() throws Exception {
+ RevCommit commit =
+ writeCommit(
+ "Update patch set 1\n"
+ + "\n"
+ + "Patch-set: 1\n"
+ + "Attention: {\"person_ident\":\"Gerrit User 1000000 \\u003c1000000@adce0b11-8f2e-4ab6-ac69-e675f183d871\\u003e\",\"operation\":\"ADD\",\"reason\":\"Added by Administrator using the hovercard menu\"}");
+
+ newParser(commit).parseAll();
+ assertThat(((ChangeNotesCommit) commit).isAttentionSetCommitOnly(true)).isEqualTo(false);
+ }
+
+ private ChangeNotesParser newParser(ObjectId tip) throws Exception {
+ walk.reset();
+ ChangeNoteJson changeNoteJson = injector.getInstance(ChangeNoteJson.class);
+ return new ChangeNotesParser(newChange().getId(), tip, walk, changeNoteJson, args.metrics);
+ }
+
+ private RevCommit writeCommit(String body) throws Exception {
+ Change change = newChange(true);
+ ChangeNotes notes = newNotes(change).load();
+ ChangeNoteUtil noteUtil = injector.getInstance(ChangeNoteUtil.class);
+ PersonIdent author =
+ noteUtil.newAccountIdIdent(changeOwner.getAccount().id(), TimeUtil.nowTs(), serverIdent);
+ try (ObjectInserter ins = testRepo.getRepository().newObjectInserter()) {
+ CommitBuilder cb = new CommitBuilder();
+ cb.setParentId(notes.getRevision());
+ cb.setAuthor(author);
+ cb.setCommitter(new PersonIdent(serverIdent, author.getWhen()));
+ cb.setTreeId(testRepo.tree());
+ cb.setMessage(body);
+ ObjectId id = ins.insert(cb);
+ ins.flush();
+ RevCommit commit = walk.parseCommit(id);
+ walk.parseBody(commit);
+ return commit;
+ }
+ }
+}
diff --git a/javatests/com/google/gerrit/server/notedb/ChangeNotesParserTest.java b/javatests/com/google/gerrit/server/notedb/ChangeNotesParserTest.java
index 5bfe97c..6a32fa1 100644
--- a/javatests/com/google/gerrit/server/notedb/ChangeNotesParserTest.java
+++ b/javatests/com/google/gerrit/server/notedb/ChangeNotesParserTest.java
@@ -497,6 +497,73 @@
}
@Test
+ public void attentionSetOnlyShouldNotCountTowardsMaxUpdatesLimit() throws Exception {
+ RevCommit commit =
+ writeCommit(
+ "Update patch set 1\n"
+ + "\n"
+ + "Patch-set: 1\n"
+ + "Attention: {\"person_ident\":\"Gerrit User 1000000 \\u003c1000000@adce0b11-8f2e-4ab6-ac69-e675f183d871\\u003e\",\"operation\":\"ADD\",\"reason\":\"Added by Administrator using the hovercard menu\"}",
+ false);
+ ChangeNotesParser changeNotesParser = newParser(commit);
+ changeNotesParser.parseAll();
+ final boolean hasChangeMessage = false;
+ assertThat(
+ changeNotesParser.countTowardsMaxUpdatesLimit(
+ (ChangeNotesCommit) commit, hasChangeMessage))
+ .isEqualTo(false);
+ }
+
+ @Test
+ public void attentionSetWithExtraFooterShouldCountTowardsMaxUpdatesLimit() throws Exception {
+ RevCommit commit =
+ writeCommit(
+ "Update patch set 1\n"
+ + "\n"
+ + "Patch-set: 1\n"
+ + "Subject: Change subject\n"
+ + "Attention: {\"person_ident\":\"Gerrit User 1000000 \\u003c1000000@adce0b11-8f2e-4ab6-ac69-e675f183d871\\u003e\",\"operation\":\"ADD\",\"reason\":\"Added by Administrator using the hovercard menu\"}",
+ false);
+ ChangeNotesParser changeNotesParser = newParser(commit);
+ changeNotesParser.parseAll();
+ final boolean hasChangeMessage = false;
+ assertThat(
+ changeNotesParser.countTowardsMaxUpdatesLimit(
+ (ChangeNotesCommit) commit, hasChangeMessage))
+ .isEqualTo(true);
+ }
+
+ @Test
+ public void changeWithoutAttentionSetShouldCountTowardsMaxUpdatesLimit() throws Exception {
+ RevCommit commit = writeCommit("Update WIP change\n" + "\n" + "Patch-set: 1\n", true);
+ ChangeNotesParser changeNotesParser = newParser(commit);
+ changeNotesParser.parseAll();
+ final boolean hasChangeMessage = false;
+ assertThat(
+ changeNotesParser.countTowardsMaxUpdatesLimit(
+ (ChangeNotesCommit) commit, hasChangeMessage))
+ .isEqualTo(true);
+ }
+
+ @Test
+ public void attentionSetWithCommentShouldCountTowardsMaxUpdatesLimit() throws Exception {
+ RevCommit commit =
+ writeCommit(
+ "Update patch set 1\n"
+ + "\n"
+ + "Patch-set: 1\n"
+ + "Attention: {\"person_ident\":\"Gerrit User 1000000 \\u003c1000000@adce0b11-8f2e-4ab6-ac69-e675f183d871\\u003e\",\"operation\":\"ADD\",\"reason\":\"Added by Administrator using the hovercard menu\"}",
+ false);
+ ChangeNotesParser changeNotesParser = newParser(commit);
+ changeNotesParser.parseAll();
+ final boolean hasChangeMessage = true;
+ assertThat(
+ changeNotesParser.countTowardsMaxUpdatesLimit(
+ (ChangeNotesCommit) commit, hasChangeMessage))
+ .isEqualTo(true);
+ }
+
+ @Test
public void caseInsensitiveFooters() throws Exception {
assertParseSucceeds(
"Update change\n"
diff --git a/javatests/com/google/gerrit/server/notedb/OpenRepoTest.java b/javatests/com/google/gerrit/server/notedb/OpenRepoTest.java
new file mode 100644
index 0000000..e4c2196
--- /dev/null
+++ b/javatests/com/google/gerrit/server/notedb/OpenRepoTest.java
@@ -0,0 +1,143 @@
+// Copyright (C) 2021 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.notedb;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.testing.GerritJUnit.assertThrows;
+
+import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ListMultimap;
+import com.google.gerrit.entities.AttentionSetUpdate;
+import com.google.gerrit.entities.Change;
+import com.google.gerrit.server.update.ChainedReceiveCommands;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.ReceiveCommand;
+import org.junit.Test;
+
+public class OpenRepoTest extends AbstractChangeNotesTest {
+
+ private final Optional<Integer> NO_UPDATES_AT_ALL = Optional.of(0);
+ private final Optional<Integer> ONLY_ONE_UPDATE = Optional.of(1);
+ private final Optional<Integer> ONLY_TWO_UPDATES = Optional.of(2);
+ private final Optional<Integer> MAX_PATCH_SETS = Optional.empty();
+
+ private FakeChainedReceiveCommands fakeChainedReceiveCommands;
+
+ @Override
+ public void setUpTestEnvironment() throws Exception {
+ super.setUpTestEnvironment();
+ fakeChainedReceiveCommands = new FakeChainedReceiveCommands(repo);
+ }
+
+ @Test
+ public void throwExceptionWhenExceedingMaxUpdatesLimit() throws Exception {
+ try (OpenRepo openRepo = openRepo()) {
+ Change c = newChange();
+ ChangeUpdate update = newUpdate(c, changeOwner);
+ update.setStatus(Change.Status.NEW);
+
+ ListMultimap<String, ChangeUpdate> changeUpdates =
+ new ImmutableListMultimap.Builder<String, ChangeUpdate>().put("one", update).build();
+
+ assertThrows(
+ LimitExceededException.class,
+ () -> openRepo.addUpdates(changeUpdates, NO_UPDATES_AT_ALL, MAX_PATCH_SETS));
+ }
+ }
+
+ @Test
+ public void allowExceedingLimitWhenAttentionSetUpdateOnly() throws Exception {
+ try (OpenRepo openRepo = openRepo()) {
+ Change c = newChange();
+ ChangeUpdate update = newUpdate(c, changeOwner);
+ update.setStatus(Change.Status.NEW);
+
+ // Add to attention set
+ AttentionSetUpdate attentionSetUpdate =
+ AttentionSetUpdate.createForWrite(
+ otherUser.getAccountId(), AttentionSetUpdate.Operation.ADD, "test");
+ update.addToPlannedAttentionSetUpdates(ImmutableSet.of(attentionSetUpdate));
+
+ ListMultimap<String, ChangeUpdate> changeUpdates =
+ new ImmutableListMultimap.Builder<String, ChangeUpdate>().put("one", update).build();
+
+ openRepo.addUpdates(changeUpdates, NO_UPDATES_AT_ALL, MAX_PATCH_SETS);
+
+ assertThat(fakeChainedReceiveCommands.commands.size()).isEqualTo(1);
+ }
+ }
+
+ @Test
+ public void attentionSetUpdateShouldNotContributeToOperationsCount() throws Exception {
+ try (OpenRepo openRepo = openRepo()) {
+ Change c1 = newChange();
+
+ ChangeUpdate update1 = newUpdateForNewChange(c1, changeOwner);
+ // Add to attention set
+ AttentionSetUpdate attentionSetUpdate =
+ AttentionSetUpdate.createForWrite(
+ otherUser.getAccountId(), AttentionSetUpdate.Operation.ADD, "test");
+ update1.addToPlannedAttentionSetUpdates(ImmutableSet.of(attentionSetUpdate));
+
+ ChangeUpdate update2 = newUpdateForNewChange(c1, changeOwner);
+ update2.setStatus(Change.Status.NEW);
+
+ ListMultimap<String, ChangeUpdate> changeUpdates =
+ new ImmutableListMultimap.Builder<String, ChangeUpdate>().put("two", update2).build();
+
+ openRepo.addUpdates(changeUpdates, ONLY_TWO_UPDATES, MAX_PATCH_SETS);
+
+ assertThat(fakeChainedReceiveCommands.commands.size()).isEqualTo(1);
+ }
+ }
+
+ @Test
+ public void normalChangeShouldContributeToOperationsCount() throws Exception {
+ try (OpenRepo openRepo = openRepo()) {
+ Change c1 = newChange();
+
+ ChangeUpdate update2 = newUpdateForNewChange(c1, changeOwner);
+ update2.setStatus(Change.Status.NEW);
+
+ ListMultimap<String, ChangeUpdate> changeUpdates =
+ new ImmutableListMultimap.Builder<String, ChangeUpdate>().put("two", update2).build();
+
+ assertThrows(
+ LimitExceededException.class,
+ () -> openRepo.addUpdates(changeUpdates, ONLY_ONE_UPDATE, MAX_PATCH_SETS));
+ }
+ }
+
+ private static class FakeChainedReceiveCommands extends ChainedReceiveCommands {
+ Map<String, ReceiveCommand> commands = new HashMap<>();
+
+ public FakeChainedReceiveCommands(Repository repo) {
+ super(repo);
+ }
+
+ @Override
+ public void add(ReceiveCommand cmd) {
+ commands.put(cmd.getRefName(), cmd);
+ }
+ }
+
+ private OpenRepo openRepo() {
+ return new OpenRepo(repo, rw, null, fakeChainedReceiveCommands, false);
+ }
+}
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.js b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.js
index c8e058e..4864af5 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.js
@@ -23,20 +23,22 @@
const basicFixture = fixtureFromElement('gr-repo-list');
-let counter;
-const repoGenerator = () => {
+function createRepo(name, counter) {
return {
- id: `test${++counter}`,
- name: `test`,
+ id: `${name}${counter}`,
+ name: `${name}`,
state: 'ACTIVE',
web_links: [
{
name: 'diffusion',
- url: `https://phabricator.example.org/r/project/test${counter}`,
+ url: `https://phabricator.example.org/r/project/${name}${counter}`,
},
],
};
-};
+}
+
+let counter;
+const repoGenerator = () => createRepo('test', ++counter);
suite('gr-repo-list tests', () => {
let element;
@@ -123,6 +125,15 @@
done();
});
});
+
+ test('filter is case insensitive', async () => {
+ const repoStub = stubRestApi('getRepos');
+ const repos = [createRepo('aSDf', 0)];
+ repoStub.withArgs('asdf').returns(Promise.resolve(repos));
+ element._filter = 'asdf';
+ await element._getRepos('asdf', 25, 0);
+ assert.equal(element._repos.length, 1);
+ });
});
suite('loading', () => {