Merge "Fix all remaining lit lint errors"
diff --git a/Documentation/pg-plugin-endpoints.txt b/Documentation/pg-plugin-endpoints.txt
index c16d0d4..f2a72f1 100644
--- a/Documentation/pg-plugin-endpoints.txt
+++ b/Documentation/pg-plugin-endpoints.txt
@@ -228,3 +228,13 @@
+
current revision displayed, an instance of
link:rest-api-changes.html#revision-info[RevisionInfo]
+
+=== account-status-icon
+The `account-status-icon` extension point adds an icon to all account chips and
+labels.
+
+In addition to default parameters, the following are available:
+
+* `accountId`
++
+the Id of the account that the status icon should correspond to.
\ No newline at end of file
diff --git a/java/com/google/gerrit/server/git/CodeReviewCommit.java b/java/com/google/gerrit/server/git/CodeReviewCommit.java
index d7538ba..79df21a 100644
--- a/java/com/google/gerrit/server/git/CodeReviewCommit.java
+++ b/java/com/google/gerrit/server/git/CodeReviewCommit.java
@@ -24,6 +24,9 @@
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.submit.CommitMergeStatus;
import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
import java.util.Optional;
import java.util.Set;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
@@ -35,7 +38,10 @@
import org.eclipse.jgit.revwalk.RevWalk;
/** Extended commit entity with code review specific metadata. */
-public class CodeReviewCommit extends RevCommit {
+public class CodeReviewCommit extends RevCommit implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
/**
* Default ordering when merging multiple topologically-equivalent commits.
*
@@ -126,7 +132,7 @@
* Message for the status that is returned to the calling user if the status indicates a problem
* that prevents submit.
*/
- private Optional<String> statusMessage = Optional.empty();
+ private transient Optional<String> statusMessage = Optional.empty();
/** List of files in this commit that contain Git conflict markers. */
private ImmutableSet<String> filesWithGitConflicts;
@@ -191,4 +197,22 @@
public void setNotes(ChangeNotes notes) {
this.notes = notes;
}
+
+ /** Custom serialization due to {@link #statusMessage} not being Serializable by default. */
+ private void writeObject(ObjectOutputStream oos) throws IOException {
+ oos.defaultWriteObject();
+ if (this.statusMessage.isPresent()) {
+ oos.writeUTF(this.statusMessage.get());
+ }
+ }
+
+ /** Custom deserialization due to {@link #statusMessage} not being Serializable by default. */
+ private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
+ ois.defaultReadObject();
+ String statusMessage = null;
+ if (ois.available() > 0) {
+ statusMessage = ois.readUTF();
+ }
+ this.statusMessage = Optional.ofNullable(statusMessage);
+ }
}
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index 41f68c8..4e22933 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
@@ -1431,6 +1431,12 @@
private void parseCreate(ReceiveCommand cmd)
throws PermissionBackendException, NoSuchProjectException, IOException {
try (TraceTimer traceTimer = newTimer("parseCreate")) {
+ if (repo.resolve(cmd.getRefName()) != null) {
+ reject(
+ cmd,
+ String.format("Cannot create ref '%s' because it already exists.", cmd.getRefName()));
+ return;
+ }
RevObject obj;
try {
obj = receivePack.getRevWalk().parseAny(cmd.getNewId());
diff --git a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
index 2253202..ba1e1a7 100644
--- a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
+++ b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
@@ -1427,6 +1427,34 @@
}
@Test
+ public void pushToNonVisibleBranchIsRejected() throws Exception {
+ String master = "refs/heads/master";
+
+ projectOperations
+ .project(project)
+ .forUpdate()
+ .add(block(Permission.READ).ref(master).group(REGISTERED_USERS))
+ .update();
+
+ testRepo.branch("HEAD").commit().message("New Commit 1").insertChangeId().create();
+ // Since the branch is not visible to the caller, the command tries to create the ref resulting
+ // in the command being rejected because the ref already exists.
+ assertPushRejected(
+ pushHead(testRepo, master),
+ master,
+ "Cannot create ref 'refs/heads/master' because it already exists.");
+
+ projectOperations
+ .project(project)
+ .forUpdate()
+ .add(allow(Permission.READ).ref(master).group(REGISTERED_USERS))
+ .update();
+
+ testRepo.branch("HEAD").commit().message("New Commit 2").insertChangeId().create();
+ assertPushOk(pushHead(testRepo, master), master);
+ }
+
+ @Test
public void pushSameCommitTwiceUsingMagicBranchBaseOption() throws Exception {
projectOperations
.project(project)
diff --git a/javatests/com/google/gerrit/acceptance/rest/project/AbstractPushTag.java b/javatests/com/google/gerrit/acceptance/rest/project/AbstractPushTag.java
index 531357a..793f256 100644
--- a/javatests/com/google/gerrit/acceptance/rest/project/AbstractPushTag.java
+++ b/javatests/com/google/gerrit/acceptance/rest/project/AbstractPushTag.java
@@ -22,6 +22,7 @@
import static com.google.gerrit.acceptance.rest.project.AbstractPushTag.TagType.ANNOTATED;
import static com.google.gerrit.acceptance.rest.project.AbstractPushTag.TagType.LIGHTWEIGHT;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allow;
+import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.block;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.permissionKey;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
@@ -29,6 +30,7 @@
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.GitUtil;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Permission;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.testing.ConfigSuite;
@@ -191,33 +193,57 @@
pushTagDeletion(tagName, Status.OK);
}
+ @Test
+ public void pushToNonVisibleTagIsRejected() throws Exception {
+ allowTagCreation();
+ allowPushOnRefsTags();
+
+ String tagName = pushTagForExistingCommit(Status.OK);
+
+ removeReadFromRefsTags();
+ removeReadFromRefsHeads();
+
+ pushTag(
+ tagName,
+ /* newCommit= */ true,
+ /* force= */ false,
+ Status.REJECTED_OTHER_REASON,
+ /* expectedMessage= */ String.format(
+ "Cannot create ref '%s' because it already exists.", tagRef(tagName)));
+ }
+
private String pushTagForExistingCommit(Status expectedStatus) throws Exception {
- return pushTag(null, false, false, expectedStatus);
+ return pushTag(null, false, false, expectedStatus, /* expectedMessage= */ null);
}
private String pushTagForNewCommit(Status expectedStatus) throws Exception {
- return pushTag(null, true, false, expectedStatus);
+ return pushTag(null, true, false, expectedStatus, /* expectedMessage= */ null);
}
private void fastForwardTagToExistingCommit(String tagName, Status expectedStatus)
throws Exception {
- pushTag(tagName, false, false, expectedStatus);
+ pushTag(tagName, false, false, expectedStatus, /* expectedMessage= */ null);
}
private void fastForwardTagToNewCommit(String tagName, Status expectedStatus) throws Exception {
- pushTag(tagName, true, false, expectedStatus);
+ pushTag(tagName, true, false, expectedStatus, /* expectedMessage= */ null);
}
private void forceUpdateTagToExistingCommit(String tagName, Status expectedStatus)
throws Exception {
- pushTag(tagName, false, true, expectedStatus);
+ pushTag(tagName, false, true, expectedStatus, /* expectedMessage= */ null);
}
private void forceUpdateTagToNewCommit(String tagName, Status expectedStatus) throws Exception {
- pushTag(tagName, true, true, expectedStatus);
+ pushTag(tagName, true, true, expectedStatus, /* expectedMessage= */ null);
}
- private String pushTag(String tagName, boolean newCommit, boolean force, Status expectedStatus)
+ private String pushTag(
+ String tagName,
+ boolean newCommit,
+ boolean force,
+ Status expectedStatus,
+ @Nullable String expectedMessage)
throws Exception {
if (force) {
testRepo.reset(initialHead);
@@ -256,6 +282,9 @@
: GitUtil.pushTag(testRepo, tagName, !createTag);
RemoteRefUpdate refUpdate = r.getRemoteUpdate(tagRef);
assertWithMessage(tagType.name()).that(refUpdate.getStatus()).isEqualTo(expectedStatus);
+ if (expectedMessage != null) {
+ assertWithMessage(tagType.name()).that(refUpdate.getMessage()).isEqualTo(expectedMessage);
+ }
return tagName;
}
@@ -352,6 +381,22 @@
.update();
}
+ private void removeReadFromRefsTags() throws Exception {
+ projectOperations
+ .project(project)
+ .forUpdate()
+ .add(block(Permission.READ).ref("refs/tags/*").group(REGISTERED_USERS))
+ .update();
+ }
+
+ private void removeReadFromRefsHeads() throws Exception {
+ projectOperations
+ .project(project)
+ .forUpdate()
+ .add(block(Permission.READ).ref("refs/heads/*").group(REGISTERED_USERS))
+ .update();
+ }
+
private void commit(PersonIdent ident, String subject) throws Exception {
commitBuilder().ident(ident).message(subject + " (" + System.nanoTime() + ")").create();
}
diff --git a/javatests/com/google/gerrit/acceptance/server/git/CodeReviewCommitTest.java b/javatests/com/google/gerrit/acceptance/server/git/CodeReviewCommitTest.java
new file mode 100644
index 0000000..b5e1b07
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/server/git/CodeReviewCommitTest.java
@@ -0,0 +1,74 @@
+// Copyright (C) 2022 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.server.git;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.gerrit.entities.Project;
+import com.google.gerrit.server.git.CodeReviewCommit;
+import com.google.gerrit.testing.InMemoryRepositoryManager;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Repository;
+import org.junit.Test;
+
+/** Tests for {@link CodeReviewCommit}. */
+public class CodeReviewCommitTest {
+
+ @Test
+ public void checkSerializable_withStatusMessage() throws Exception {
+ CodeReviewCommit commit = new CodeReviewCommit(createCommit());
+ commit.setStatusMessage("Status");
+ CodeReviewCommit deserializedCommit = serializeAndReadBack(commit);
+ assertThat(deserializedCommit).isEqualTo(commit);
+ assertThat(deserializedCommit.getStatusMessage().get()).isEqualTo("Status");
+ }
+
+ @Test
+ public void checkSerializable_emptyStatusMessage() throws Exception {
+ CodeReviewCommit commit = new CodeReviewCommit(createCommit());
+ CodeReviewCommit deserializedCommit = serializeAndReadBack(commit);
+ assertThat(deserializedCommit).isEqualTo(commit);
+ assertThat(deserializedCommit.getStatusMessage().isPresent()).isFalse();
+ }
+
+ private CodeReviewCommit serializeAndReadBack(CodeReviewCommit codeReviewCommit)
+ throws Exception {
+ try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutputStream out = new ObjectOutputStream(bos)) {
+ out.writeObject(codeReviewCommit);
+ out.flush();
+ try (ByteArrayInputStream fileIn = new ByteArrayInputStream(bos.toByteArray());
+ ObjectInputStream in = new ObjectInputStream(fileIn); ) {
+ return (CodeReviewCommit) in.readObject();
+ }
+ }
+ }
+
+ private ObjectId createCommit() throws Exception {
+ InMemoryRepositoryManager repoManager = new InMemoryRepositoryManager();
+ Project.NameKey project = Project.nameKey("test");
+ try (Repository repo = repoManager.createRepository(project);
+ TestRepository<Repository> tr = new TestRepository<>(repo)) {
+ PersonIdent ident = new PersonIdent(new PersonIdent("Test Ident", "test@test.com"));
+ return tr.commit().author(ident).committer(ident).message("Test commit").create();
+ }
+ }
+}
diff --git a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
index 4d52ee9..7bbb93b 100644
--- a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
+++ b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
@@ -84,6 +84,7 @@
'is:open',
'is:owner',
'is:private',
+ 'is:pure-revert',
'is:reviewed',
'is:reviewer',
'is:starred',
diff --git a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts
index 3dba057..9ce62c1 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts
@@ -96,6 +96,7 @@
border: 1px solid var(--border-color);
display: inline-flex;
padding: 0 1px;
+ --account-label-padding-horizontal: 6px;
}
:host:focus {
border-color: transparent;
@@ -131,9 +132,6 @@
/* eslint-disable lit/prefer-static-styles */
const customStyle = html`
<style>
- .container {
- --account-label-padding-horizontal: 6px;
- }
gr-button.remove::part(paper-button),
gr-button.remove:hover::part(paper-button),
gr-button.remove:focus::part(paper-button) {
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts
index bff4e20..99e10ae 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts
@@ -17,6 +17,8 @@
import '@polymer/iron-icon/iron-icon';
import '../gr-avatar/gr-avatar';
import '../gr-hovercard-account/gr-hovercard-account';
+import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator';
+import '../../plugins/gr-endpoint-param/gr-endpoint-param';
import {getAppContext} from '../../../services/app-context';
import {getDisplayName} from '../../../utils/display-name-util';
import {isSelf, isServiceUser} from '../../../utils/account-util';
@@ -254,15 +256,16 @@
? html`<gr-avatar .account="${account}" imageSize="32"></gr-avatar>`
: ''}
<span class="text" part="gr-account-label-text">
- <span class="name"
- >${this._computeName(account, this.firstName, this._config)}</span
- >
+ <span class="name">
+ ${this._computeName(account, this.firstName, this._config)}
+ </span>
${!this.hideStatus && account.status
? html`<iron-icon
class="status"
icon="gr-icons:unavailable"
></iron-icon>`
: ''}
+ ${this.renderAccountStatusPlugins()}
</span>
</span>`;
}
@@ -281,6 +284,22 @@
});
}
+ // Note: account statuses from plugins are shown regardless of
+ // hideStatus setting
+ private renderAccountStatusPlugins() {
+ if (!this.account?._account_id) {
+ return;
+ }
+ return html`
+ <gr-endpoint-decorator name="account-status-icon">
+ <gr-endpoint-param
+ name="accountId"
+ .value="${this.account._account_id}"
+ ></gr-endpoint-param>
+ </gr-endpoint-decorator>
+ `;
+ }
+
handleKeyDown(e: KeyboardEvent) {
if (modifierPressed(e)) return;
// Only react to `return` and `space`.
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.ts b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.ts
index 731b7c4..edeb399 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.ts
@@ -75,6 +75,9 @@
<span class="name">
kermit
</span>
+ <gr-endpoint-decorator name="account-status-icon">
+ <gr-endpoint-param name="accountId"></gr-endpoint-param>
+ </gr-endpoint-decorator>
</span>
</span>
`);
diff --git a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.ts b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.ts
index bbb743a..f0c9106 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.ts
@@ -99,12 +99,6 @@
exportparts="gr-account-label-text: gr-account-link-text"
>
</gr-account-label>
- <gr-endpoint-decorator name="account-status">
- <gr-endpoint-param
- name="accountId"
- .value="${this.account._account_id}"
- ></gr-endpoint-param>
- </gr-endpoint-decorator>
</a>
</span>`;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_test.ts b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_test.ts
index 00990b8..a78f32f 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_test.ts
@@ -45,9 +45,6 @@
exportparts="gr-account-label-text: gr-account-link-text"
>
</gr-account-label>
- <gr-endpoint-decorator name="account-status">
- <gr-endpoint-param name="accountId"></gr-endpoint-param>
- </gr-endpoint-decorator>
</a>
</span>
`);