Merge "Compute only as many owned paths as needed, not all"
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/ChangedFiles.java b/java/com/google/gerrit/plugins/codeowners/backend/ChangedFiles.java
index 4fdab65..c96af17 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/ChangedFiles.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/ChangedFiles.java
@@ -200,10 +200,14 @@
RevCommit baseCommit = revCommit.getParentCount() > 0 ? revCommit.getParent(0) : null;
logger.atFine().log("baseCommit = %s", baseCommit != null ? baseCommit.name() : "n/a");
+ // Detecting renames is expensive (since it requires Git to load and compare file contents of
+ // added and deleted files) and can significantly increase the latency for changes that touch
+ // large files. To avoid this latency we do not enable the rename detection on the
+ // DiffFormater. As a result of this renamed files will be returned as 2 ChangedFile's, one
+ // for the deletion of the old path and one for the addition of the new path.
try (DiffFormatter diffFormatter = new DiffFormatter(DisabledOutputStream.INSTANCE)) {
diffFormatter.setReader(revWalk.getObjectReader(), repoConfig);
diffFormatter.setDiffComparator(RawTextComparator.DEFAULT);
- diffFormatter.setDetectRenames(true);
List<DiffEntry> diffEntries = diffFormatter.scan(baseCommit, revCommit);
ImmutableSet<ChangedFile> changedFiles =
diffEntries.stream().map(ChangedFile::create).collect(toImmutableSet());
diff --git a/java/com/google/gerrit/plugins/codeowners/testing/ChangedFileSubject.java b/java/com/google/gerrit/plugins/codeowners/testing/ChangedFileSubject.java
index 805eccd..069122c 100644
--- a/java/com/google/gerrit/plugins/codeowners/testing/ChangedFileSubject.java
+++ b/java/com/google/gerrit/plugins/codeowners/testing/ChangedFileSubject.java
@@ -17,10 +17,13 @@
import static com.google.common.truth.Truth.assertAbout;
import static com.google.gerrit.truth.OptionalSubject.optionals;
+import com.google.common.collect.ImmutableList;
import com.google.common.truth.FailureMetadata;
import com.google.common.truth.Subject;
import com.google.gerrit.plugins.codeowners.common.ChangedFile;
+import com.google.gerrit.truth.ListSubject;
import com.google.gerrit.truth.OptionalSubject;
+import java.util.Collection;
/** {@link Subject} for doing assertions on {@link ChangedFile}s. */
public class ChangedFileSubject extends Subject {
@@ -34,6 +37,12 @@
return assertAbout(changedFiles()).that(changedFile);
}
+ /** Starts fluent chain to do assertions on a collection of {@link ChangedFile}s. */
+ public static ListSubject<ChangedFileSubject, ChangedFile> assertThatCollection(
+ Collection<ChangedFile> changedFiles) {
+ return ListSubject.assertThat(ImmutableList.copyOf(changedFiles), changedFiles());
+ }
+
/** Creates subject factory for mapping {@link ChangedFile}s to {@link ChangedFileSubject}s. */
public static Subject.Factory<ChangedFileSubject, ChangedFile> changedFiles() {
return ChangedFileSubject::new;
diff --git a/java/com/google/gerrit/plugins/codeowners/testing/FileCodeOwnerStatusSubject.java b/java/com/google/gerrit/plugins/codeowners/testing/FileCodeOwnerStatusSubject.java
index 03948f1..3a81908 100644
--- a/java/com/google/gerrit/plugins/codeowners/testing/FileCodeOwnerStatusSubject.java
+++ b/java/com/google/gerrit/plugins/codeowners/testing/FileCodeOwnerStatusSubject.java
@@ -20,11 +20,13 @@
import static com.google.gerrit.plugins.codeowners.testing.PathCodeOwnerStatusSubject.pathCodeOwnerStatuses;
import static com.google.gerrit.truth.OptionalSubject.optionals;
+import com.google.common.collect.ImmutableList;
import com.google.common.truth.FailureMetadata;
import com.google.common.truth.Subject;
import com.google.gerrit.plugins.codeowners.backend.FileCodeOwnerStatus;
import com.google.gerrit.truth.ListSubject;
import com.google.gerrit.truth.OptionalSubject;
+import java.util.Collection;
import java.util.stream.Stream;
/** {@link Subject} for doing assertions on {@link FileCodeOwnerStatus}es. */
@@ -39,6 +41,13 @@
fileCodeOwnerStatuses.collect(toImmutableList()), fileCodeOwnerStatuses());
}
+ /** Starts fluent chain to do assertions on a collection of {@link FileCodeOwnerStatus}es. */
+ public static ListSubject<FileCodeOwnerStatusSubject, FileCodeOwnerStatus> assertThatCollection(
+ Collection<FileCodeOwnerStatus> fileCodeOwnerStatuses) {
+ return ListSubject.assertThat(
+ ImmutableList.copyOf(fileCodeOwnerStatuses), fileCodeOwnerStatuses());
+ }
+
private static Factory<FileCodeOwnerStatusSubject, FileCodeOwnerStatus> fileCodeOwnerStatuses() {
return FileCodeOwnerStatusSubject::new;
}
diff --git a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/GetCodeOwnerStatusIT.java b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/GetCodeOwnerStatusIT.java
index 64b24f8..531f118 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/GetCodeOwnerStatusIT.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/GetCodeOwnerStatusIT.java
@@ -78,6 +78,100 @@
}
@Test
+ public void getStatusForRenamedFile() throws Exception {
+ TestAccount user2 = accountCreator.user2();
+
+ codeOwnerConfigOperations
+ .newCodeOwnerConfig()
+ .project(project)
+ .branch("master")
+ .folderPath("/foo/bar")
+ .addCodeOwnerEmail(user.email())
+ .create();
+ codeOwnerConfigOperations
+ .newCodeOwnerConfig()
+ .project(project)
+ .branch("master")
+ .folderPath("/foo/baz")
+ .addCodeOwnerEmail(user2.email())
+ .create();
+
+ String oldPath = "foo/bar/abc.txt";
+ String newPath = "foo/baz/abc.txt";
+ String changeId = createChangeWithFileRename(oldPath, newPath);
+
+ CodeOwnerStatusInfo codeOwnerStatus =
+ changeCodeOwnersApiFactory.change(changeId).getCodeOwnerStatus();
+ assertThat(codeOwnerStatus).hasFileCodeOwnerStatusesThat().hasSize(2);
+ FileCodeOwnerStatusInfoSubject fileCodeOwnerStatusInfoSubject1 =
+ assertThat(codeOwnerStatus).hasFileCodeOwnerStatusesThat().element(0);
+ fileCodeOwnerStatusInfoSubject1.hasChangeTypeThat().isEqualTo(ChangeType.DELETED);
+ fileCodeOwnerStatusInfoSubject1.hasOldPathStatusThat().value().hasPathThat().isEqualTo(oldPath);
+ fileCodeOwnerStatusInfoSubject1
+ .hasOldPathStatusThat()
+ .value()
+ .hasStatusThat()
+ .isEqualTo(CodeOwnerStatus.INSUFFICIENT_REVIEWERS);
+ FileCodeOwnerStatusInfoSubject fileCodeOwnerStatusInfoSubject2 =
+ assertThat(codeOwnerStatus).hasFileCodeOwnerStatusesThat().element(1);
+ fileCodeOwnerStatusInfoSubject2.hasChangeTypeThat().isEqualTo(ChangeType.ADDED);
+ fileCodeOwnerStatusInfoSubject2.hasNewPathStatusThat().value().hasPathThat().isEqualTo(newPath);
+ fileCodeOwnerStatusInfoSubject2
+ .hasNewPathStatusThat()
+ .value()
+ .hasStatusThat()
+ .isEqualTo(CodeOwnerStatus.INSUFFICIENT_REVIEWERS);
+
+ // Add a reviewer that is a code owner of the old path.
+ gApi.changes().id(changeId).addReviewer(user.email());
+
+ codeOwnerStatus = changeCodeOwnersApiFactory.change(changeId).getCodeOwnerStatus();
+ assertThat(codeOwnerStatus).hasFileCodeOwnerStatusesThat().hasSize(2);
+ fileCodeOwnerStatusInfoSubject1 =
+ assertThat(codeOwnerStatus).hasFileCodeOwnerStatusesThat().element(0);
+ fileCodeOwnerStatusInfoSubject1.hasChangeTypeThat().isEqualTo(ChangeType.DELETED);
+ fileCodeOwnerStatusInfoSubject1.hasOldPathStatusThat().value().hasPathThat().isEqualTo(oldPath);
+ fileCodeOwnerStatusInfoSubject1
+ .hasOldPathStatusThat()
+ .value()
+ .hasStatusThat()
+ .isEqualTo(CodeOwnerStatus.PENDING);
+ fileCodeOwnerStatusInfoSubject2 =
+ assertThat(codeOwnerStatus).hasFileCodeOwnerStatusesThat().element(1);
+ fileCodeOwnerStatusInfoSubject2.hasChangeTypeThat().isEqualTo(ChangeType.ADDED);
+ fileCodeOwnerStatusInfoSubject2.hasNewPathStatusThat().value().hasPathThat().isEqualTo(newPath);
+ fileCodeOwnerStatusInfoSubject2
+ .hasNewPathStatusThat()
+ .value()
+ .hasStatusThat()
+ .isEqualTo(CodeOwnerStatus.INSUFFICIENT_REVIEWERS);
+
+ // Add a reviewer that is a code owner of the new path.
+ gApi.changes().id(changeId).addReviewer(user2.email());
+
+ codeOwnerStatus = changeCodeOwnersApiFactory.change(changeId).getCodeOwnerStatus();
+ assertThat(codeOwnerStatus).hasFileCodeOwnerStatusesThat().hasSize(2);
+ fileCodeOwnerStatusInfoSubject1 =
+ assertThat(codeOwnerStatus).hasFileCodeOwnerStatusesThat().element(0);
+ fileCodeOwnerStatusInfoSubject1.hasChangeTypeThat().isEqualTo(ChangeType.DELETED);
+ fileCodeOwnerStatusInfoSubject1.hasOldPathStatusThat().value().hasPathThat().isEqualTo(oldPath);
+ fileCodeOwnerStatusInfoSubject1
+ .hasOldPathStatusThat()
+ .value()
+ .hasStatusThat()
+ .isEqualTo(CodeOwnerStatus.PENDING);
+ fileCodeOwnerStatusInfoSubject2 =
+ assertThat(codeOwnerStatus).hasFileCodeOwnerStatusesThat().element(1);
+ fileCodeOwnerStatusInfoSubject2.hasChangeTypeThat().isEqualTo(ChangeType.ADDED);
+ fileCodeOwnerStatusInfoSubject2.hasNewPathStatusThat().value().hasPathThat().isEqualTo(newPath);
+ fileCodeOwnerStatusInfoSubject2
+ .hasNewPathStatusThat()
+ .value()
+ .hasStatusThat()
+ .isEqualTo(CodeOwnerStatus.PENDING);
+ }
+
+ @Test
public void getCodeOwnerStatusIfCodeOwnersFunctionalityIsDisabled() throws Exception {
disableCodeOwnersForProject(project);
String path = "foo/bar.baz";
diff --git a/javatests/com/google/gerrit/plugins/codeowners/backend/ChangedFilesTest.java b/javatests/com/google/gerrit/plugins/codeowners/backend/ChangedFilesTest.java
index 3cf1aaf..34e0cb2 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/backend/ChangedFilesTest.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/backend/ChangedFilesTest.java
@@ -17,6 +17,7 @@
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.plugins.codeowners.testing.ChangedFileSubject.assertThat;
+import static com.google.gerrit.plugins.codeowners.testing.ChangedFileSubject.assertThatCollection;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
import static org.junit.Assert.fail;
@@ -35,6 +36,7 @@
import com.google.gerrit.plugins.codeowners.acceptance.AbstractCodeOwnersTest;
import com.google.gerrit.plugins.codeowners.common.ChangedFile;
import com.google.gerrit.plugins.codeowners.common.MergeCommitStrategy;
+import com.google.gerrit.plugins.codeowners.testing.ChangedFileSubject;
import com.google.gerrit.plugins.codeowners.util.JgitPath;
import com.google.gerrit.server.change.ChangeResource;
import com.google.gerrit.server.change.RevisionResource;
@@ -135,13 +137,21 @@
gApi.changes().id(changeId).current().files();
+ // A renamed file is reported as addition of new path + deletion of old path. This is because
+ // ChangedFiles uses a DiffFormatter without rename detection (because rename detection requires
+ // loading the file contents which is too expensive).
ImmutableSet<ChangedFile> changedFilesSet = changedFiles.compute(getRevisionResource(changeId));
- assertThat(changedFilesSet).hasSize(1);
- ChangedFile changedFile = Iterables.getOnlyElement(changedFilesSet);
- assertThat(changedFile).hasNewPath().value().isEqualTo(Paths.get(newPath));
- assertThat(changedFile).hasOldPath().value().isEqualTo(Paths.get(oldPath));
- assertThat(changedFile).isRename();
- assertThat(changedFile).isNoDeletion();
+ assertThat(changedFilesSet).hasSize(2);
+ ChangedFileSubject changedFile1 = assertThatCollection(changedFilesSet).element(0);
+ changedFile1.hasNewPath().value().isEqualTo(Paths.get(newPath));
+ changedFile1.hasOldPath().isEmpty();
+ changedFile1.isNoRename();
+ changedFile1.isNoDeletion();
+ ChangedFileSubject changedFile2 = assertThatCollection(changedFilesSet).element(1);
+ changedFile2.hasNewPath().isEmpty();
+ changedFile2.hasOldPath().value().isEqualTo(Paths.get(oldPath));
+ changedFile2.isNoRename();
+ changedFile2.isDeletion();
}
@Test
diff --git a/javatests/com/google/gerrit/plugins/codeowners/backend/CodeOwnerApprovalCheckTest.java b/javatests/com/google/gerrit/plugins/codeowners/backend/CodeOwnerApprovalCheckTest.java
index f2c55e4..d23f647 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/backend/CodeOwnerApprovalCheckTest.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/backend/CodeOwnerApprovalCheckTest.java
@@ -18,6 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allowLabel;
import static com.google.gerrit.plugins.codeowners.testing.FileCodeOwnerStatusSubject.assertThat;
+import static com.google.gerrit.plugins.codeowners.testing.FileCodeOwnerStatusSubject.assertThatCollection;
import static com.google.gerrit.plugins.codeowners.testing.FileCodeOwnerStatusSubject.assertThatStream;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
@@ -187,24 +188,29 @@
requestScopeOperations.setApiUser(user2.id());
recommend(changeId);
- Stream<FileCodeOwnerStatus> fileCodeOwnerStatuses =
- codeOwnerApprovalCheck.getFileStatuses(getChangeNotes(changeId));
- FileCodeOwnerStatusSubject fileCodeOwnerStatusSubject =
- assertThatStream(fileCodeOwnerStatuses).onlyElement();
- fileCodeOwnerStatusSubject.hasNewPathStatus().value().hasPathThat().isEqualTo(newPath);
- fileCodeOwnerStatusSubject
+ ImmutableList<FileCodeOwnerStatus> fileCodeOwnerStatuses =
+ codeOwnerApprovalCheck.getFileStatuses(getChangeNotes(changeId)).collect(toImmutableList());
+ assertThatCollection(fileCodeOwnerStatuses).hasSize(2);
+ FileCodeOwnerStatusSubject fileCodeOwnerStatusSubject1 =
+ assertThatCollection(fileCodeOwnerStatuses).element(0);
+ fileCodeOwnerStatusSubject1.hasNewPathStatus().value().hasPathThat().isEqualTo(newPath);
+ fileCodeOwnerStatusSubject1
.hasNewPathStatus()
.value()
.hasStatusThat()
.isEqualTo(CodeOwnerStatus.INSUFFICIENT_REVIEWERS);
- fileCodeOwnerStatusSubject.hasOldPathStatus().value().hasPathThat().isEqualTo(oldPath);
- fileCodeOwnerStatusSubject
+ fileCodeOwnerStatusSubject1.hasChangedFile().isNoRename();
+ fileCodeOwnerStatusSubject1.hasChangedFile().isNoDeletion();
+ FileCodeOwnerStatusSubject fileCodeOwnerStatusSubject2 =
+ assertThatCollection(fileCodeOwnerStatuses).element(1);
+ fileCodeOwnerStatusSubject2.hasOldPathStatus().value().hasPathThat().isEqualTo(oldPath);
+ fileCodeOwnerStatusSubject2
.hasOldPathStatus()
.value()
.hasStatusThat()
.isEqualTo(CodeOwnerStatus.INSUFFICIENT_REVIEWERS);
- fileCodeOwnerStatusSubject.hasChangedFile().isRename();
- fileCodeOwnerStatusSubject.hasChangedFile().isNoDeletion();
+ fileCodeOwnerStatusSubject2.hasChangedFile().isNoRename();
+ fileCodeOwnerStatusSubject2.hasChangedFile().isDeletion();
}
@Test
@@ -321,24 +327,29 @@
requestScopeOperations.setApiUser(user2.id());
recommend(changeId);
- Stream<FileCodeOwnerStatus> fileCodeOwnerStatuses =
- codeOwnerApprovalCheck.getFileStatuses(getChangeNotes(changeId));
- FileCodeOwnerStatusSubject fileCodeOwnerStatusSubject =
- assertThatStream(fileCodeOwnerStatuses).onlyElement();
- fileCodeOwnerStatusSubject.hasNewPathStatus().value().hasPathThat().isEqualTo(newPath);
- fileCodeOwnerStatusSubject
- .hasNewPathStatus()
- .value()
- .hasStatusThat()
- .isEqualTo(CodeOwnerStatus.INSUFFICIENT_REVIEWERS);
- fileCodeOwnerStatusSubject.hasOldPathStatus().value().hasPathThat().isEqualTo(oldPath);
- fileCodeOwnerStatusSubject
+ ImmutableList<FileCodeOwnerStatus> fileCodeOwnerStatuses =
+ codeOwnerApprovalCheck.getFileStatuses(getChangeNotes(changeId)).collect(toImmutableList());
+ assertThatCollection(fileCodeOwnerStatuses).hasSize(2);
+ FileCodeOwnerStatusSubject fileCodeOwnerStatusSubject1 =
+ assertThatCollection(fileCodeOwnerStatuses).element(0);
+ fileCodeOwnerStatusSubject1.hasOldPathStatus().value().hasPathThat().isEqualTo(oldPath);
+ fileCodeOwnerStatusSubject1
.hasOldPathStatus()
.value()
.hasStatusThat()
.isEqualTo(CodeOwnerStatus.PENDING);
- fileCodeOwnerStatusSubject.hasChangedFile().isRename();
- fileCodeOwnerStatusSubject.hasChangedFile().isNoDeletion();
+ fileCodeOwnerStatusSubject1.hasChangedFile().isNoRename();
+ fileCodeOwnerStatusSubject1.hasChangedFile().isDeletion();
+ FileCodeOwnerStatusSubject fileCodeOwnerStatusSubject2 =
+ assertThatCollection(fileCodeOwnerStatuses).element(1);
+ fileCodeOwnerStatusSubject2.hasNewPathStatus().value().hasPathThat().isEqualTo(newPath);
+ fileCodeOwnerStatusSubject2
+ .hasNewPathStatus()
+ .value()
+ .hasStatusThat()
+ .isEqualTo(CodeOwnerStatus.INSUFFICIENT_REVIEWERS);
+ fileCodeOwnerStatusSubject2.hasChangedFile().isNoRename();
+ fileCodeOwnerStatusSubject2.hasChangedFile().isNoDeletion();
}
@Test
@@ -358,24 +369,29 @@
requestScopeOperations.setApiUser(user2.id());
recommend(changeId);
- Stream<FileCodeOwnerStatus> fileCodeOwnerStatuses =
- codeOwnerApprovalCheck.getFileStatuses(getChangeNotes(changeId));
- FileCodeOwnerStatusSubject fileCodeOwnerStatusSubject =
- assertThatStream(fileCodeOwnerStatuses).onlyElement();
- fileCodeOwnerStatusSubject.hasNewPathStatus().value().hasPathThat().isEqualTo(newPath);
- fileCodeOwnerStatusSubject
- .hasNewPathStatus()
- .value()
- .hasStatusThat()
- .isEqualTo(CodeOwnerStatus.PENDING);
- fileCodeOwnerStatusSubject.hasOldPathStatus().value().hasPathThat().isEqualTo(oldPath);
- fileCodeOwnerStatusSubject
+ ImmutableList<FileCodeOwnerStatus> fileCodeOwnerStatuses =
+ codeOwnerApprovalCheck.getFileStatuses(getChangeNotes(changeId)).collect(toImmutableList());
+ assertThatCollection(fileCodeOwnerStatuses).hasSize(2);
+ FileCodeOwnerStatusSubject fileCodeOwnerStatusSubject1 =
+ assertThatCollection(fileCodeOwnerStatuses).element(0);
+ fileCodeOwnerStatusSubject1.hasOldPathStatus().value().hasPathThat().isEqualTo(oldPath);
+ fileCodeOwnerStatusSubject1
.hasOldPathStatus()
.value()
.hasStatusThat()
.isEqualTo(CodeOwnerStatus.INSUFFICIENT_REVIEWERS);
- fileCodeOwnerStatusSubject.hasChangedFile().isRename();
- fileCodeOwnerStatusSubject.hasChangedFile().isNoDeletion();
+ fileCodeOwnerStatusSubject1.hasChangedFile().isNoRename();
+ fileCodeOwnerStatusSubject1.hasChangedFile().isDeletion();
+ FileCodeOwnerStatusSubject fileCodeOwnerStatusSubject2 =
+ assertThatCollection(fileCodeOwnerStatuses).element(1);
+ fileCodeOwnerStatusSubject2.hasNewPathStatus().value().hasPathThat().isEqualTo(newPath);
+ fileCodeOwnerStatusSubject2
+ .hasNewPathStatus()
+ .value()
+ .hasStatusThat()
+ .isEqualTo(CodeOwnerStatus.PENDING);
+ fileCodeOwnerStatusSubject2.hasChangedFile().isNoRename();
+ fileCodeOwnerStatusSubject2.hasChangedFile().isNoDeletion();
}
@Test
@@ -473,24 +489,29 @@
requestScopeOperations.setApiUser(user.id());
recommend(changeId);
- Stream<FileCodeOwnerStatus> fileCodeOwnerStatuses =
- codeOwnerApprovalCheck.getFileStatuses(getChangeNotes(changeId));
- FileCodeOwnerStatusSubject fileCodeOwnerStatusSubject =
- assertThatStream(fileCodeOwnerStatuses).onlyElement();
- fileCodeOwnerStatusSubject.hasNewPathStatus().value().hasPathThat().isEqualTo(newPath);
- fileCodeOwnerStatusSubject
- .hasNewPathStatus()
- .value()
- .hasStatusThat()
- .isEqualTo(CodeOwnerStatus.INSUFFICIENT_REVIEWERS);
- fileCodeOwnerStatusSubject.hasOldPathStatus().value().hasPathThat().isEqualTo(oldPath);
- fileCodeOwnerStatusSubject
+ ImmutableList<FileCodeOwnerStatus> fileCodeOwnerStatuses =
+ codeOwnerApprovalCheck.getFileStatuses(getChangeNotes(changeId)).collect(toImmutableList());
+ assertThatCollection(fileCodeOwnerStatuses).hasSize(2);
+ FileCodeOwnerStatusSubject fileCodeOwnerStatusSubject1 =
+ assertThatCollection(fileCodeOwnerStatuses).element(0);
+ fileCodeOwnerStatusSubject1.hasOldPathStatus().value().hasPathThat().isEqualTo(oldPath);
+ fileCodeOwnerStatusSubject1
.hasOldPathStatus()
.value()
.hasStatusThat()
.isEqualTo(CodeOwnerStatus.APPROVED);
- fileCodeOwnerStatusSubject.hasChangedFile().isRename();
- fileCodeOwnerStatusSubject.hasChangedFile().isNoDeletion();
+ fileCodeOwnerStatusSubject1.hasChangedFile().isNoRename();
+ fileCodeOwnerStatusSubject1.hasChangedFile().isDeletion();
+ FileCodeOwnerStatusSubject fileCodeOwnerStatusSubject2 =
+ assertThatCollection(fileCodeOwnerStatuses).element(1);
+ fileCodeOwnerStatusSubject2.hasNewPathStatus().value().hasPathThat().isEqualTo(newPath);
+ fileCodeOwnerStatusSubject2
+ .hasNewPathStatus()
+ .value()
+ .hasStatusThat()
+ .isEqualTo(CodeOwnerStatus.INSUFFICIENT_REVIEWERS);
+ fileCodeOwnerStatusSubject2.hasChangedFile().isNoRename();
+ fileCodeOwnerStatusSubject2.hasChangedFile().isNoDeletion();
}
@Test
@@ -506,24 +527,29 @@
requestScopeOperations.setApiUser(user.id());
recommend(changeId);
- Stream<FileCodeOwnerStatus> fileCodeOwnerStatuses =
- codeOwnerApprovalCheck.getFileStatuses(getChangeNotes(changeId));
- FileCodeOwnerStatusSubject fileCodeOwnerStatusSubject =
- assertThatStream(fileCodeOwnerStatuses).onlyElement();
- fileCodeOwnerStatusSubject.hasNewPathStatus().value().hasPathThat().isEqualTo(newPath);
- fileCodeOwnerStatusSubject
- .hasNewPathStatus()
- .value()
- .hasStatusThat()
- .isEqualTo(CodeOwnerStatus.APPROVED);
- fileCodeOwnerStatusSubject.hasOldPathStatus().value().hasPathThat().isEqualTo(oldPath);
- fileCodeOwnerStatusSubject
+ ImmutableList<FileCodeOwnerStatus> fileCodeOwnerStatuses =
+ codeOwnerApprovalCheck.getFileStatuses(getChangeNotes(changeId)).collect(toImmutableList());
+ assertThatCollection(fileCodeOwnerStatuses).hasSize(2);
+ FileCodeOwnerStatusSubject fileCodeOwnerStatusSubject1 =
+ assertThatCollection(fileCodeOwnerStatuses).element(0);
+ fileCodeOwnerStatusSubject1.hasOldPathStatus().value().hasPathThat().isEqualTo(oldPath);
+ fileCodeOwnerStatusSubject1
.hasOldPathStatus()
.value()
.hasStatusThat()
.isEqualTo(CodeOwnerStatus.INSUFFICIENT_REVIEWERS);
- fileCodeOwnerStatusSubject.hasChangedFile().isRename();
- fileCodeOwnerStatusSubject.hasChangedFile().isNoDeletion();
+ fileCodeOwnerStatusSubject1.hasChangedFile().isNoRename();
+ fileCodeOwnerStatusSubject1.hasChangedFile().isDeletion();
+ FileCodeOwnerStatusSubject fileCodeOwnerStatusSubject2 =
+ assertThatCollection(fileCodeOwnerStatuses).element(1);
+ fileCodeOwnerStatusSubject2.hasNewPathStatus().value().hasPathThat().isEqualTo(newPath);
+ fileCodeOwnerStatusSubject2
+ .hasNewPathStatus()
+ .value()
+ .hasStatusThat()
+ .isEqualTo(CodeOwnerStatus.APPROVED);
+ fileCodeOwnerStatusSubject2.hasChangedFile().isNoRename();
+ fileCodeOwnerStatusSubject2.hasChangedFile().isNoDeletion();
}
@Test
@@ -672,18 +698,13 @@
String changeId = createChangeWithFileRename(oldPath, newPath);
amendChange(user, changeId);
- Stream<FileCodeOwnerStatus> fileCodeOwnerStatuses =
- codeOwnerApprovalCheck.getFileStatuses(getChangeNotes(changeId));
- FileCodeOwnerStatusSubject fileCodeOwnerStatusSubject =
- assertThatStream(fileCodeOwnerStatuses).onlyElement();
- fileCodeOwnerStatusSubject.hasNewPathStatus().value().hasPathThat().isEqualTo(newPath);
- fileCodeOwnerStatusSubject
- .hasNewPathStatus()
- .value()
- .hasStatusThat()
- .isEqualTo(CodeOwnerStatus.INSUFFICIENT_REVIEWERS);
- fileCodeOwnerStatusSubject.hasOldPathStatus().value().hasPathThat().isEqualTo(oldPath);
- fileCodeOwnerStatusSubject
+ ImmutableList<FileCodeOwnerStatus> fileCodeOwnerStatuses =
+ codeOwnerApprovalCheck.getFileStatuses(getChangeNotes(changeId)).collect(toImmutableList());
+ assertThatCollection(fileCodeOwnerStatuses).hasSize(2);
+ FileCodeOwnerStatusSubject fileCodeOwnerStatusSubject1 =
+ assertThatCollection(fileCodeOwnerStatuses).element(0);
+ fileCodeOwnerStatusSubject1.hasOldPathStatus().value().hasPathThat().isEqualTo(oldPath);
+ fileCodeOwnerStatusSubject1
.hasOldPathStatus()
.value()
.hasStatusThat()
@@ -691,8 +712,18 @@
implicitApprovalsEnabled
? CodeOwnerStatus.APPROVED
: CodeOwnerStatus.INSUFFICIENT_REVIEWERS);
- fileCodeOwnerStatusSubject.hasChangedFile().isRename();
- fileCodeOwnerStatusSubject.hasChangedFile().isNoDeletion();
+ fileCodeOwnerStatusSubject1.hasChangedFile().isNoRename();
+ fileCodeOwnerStatusSubject1.hasChangedFile().isDeletion();
+ FileCodeOwnerStatusSubject fileCodeOwnerStatusSubject2 =
+ assertThatCollection(fileCodeOwnerStatuses).element(1);
+ fileCodeOwnerStatusSubject2.hasNewPathStatus().value().hasPathThat().isEqualTo(newPath);
+ fileCodeOwnerStatusSubject2
+ .hasNewPathStatus()
+ .value()
+ .hasStatusThat()
+ .isEqualTo(CodeOwnerStatus.INSUFFICIENT_REVIEWERS);
+ fileCodeOwnerStatusSubject2.hasChangedFile().isNoRename();
+ fileCodeOwnerStatusSubject2.hasChangedFile().isNoDeletion();
}
@Test
@@ -719,12 +750,23 @@
String changeId = createChangeWithFileRename(oldPath, newPath);
amendChange(user, changeId);
- Stream<FileCodeOwnerStatus> fileCodeOwnerStatuses =
- codeOwnerApprovalCheck.getFileStatuses(getChangeNotes(changeId));
- FileCodeOwnerStatusSubject fileCodeOwnerStatusSubject =
- assertThatStream(fileCodeOwnerStatuses).onlyElement();
- fileCodeOwnerStatusSubject.hasNewPathStatus().value().hasPathThat().isEqualTo(newPath);
- fileCodeOwnerStatusSubject
+ ImmutableList<FileCodeOwnerStatus> fileCodeOwnerStatuses =
+ codeOwnerApprovalCheck.getFileStatuses(getChangeNotes(changeId)).collect(toImmutableList());
+ assertThatCollection(fileCodeOwnerStatuses).hasSize(2);
+ FileCodeOwnerStatusSubject fileCodeOwnerStatusSubject1 =
+ assertThatCollection(fileCodeOwnerStatuses).element(0);
+ fileCodeOwnerStatusSubject1.hasOldPathStatus().value().hasPathThat().isEqualTo(oldPath);
+ fileCodeOwnerStatusSubject1
+ .hasOldPathStatus()
+ .value()
+ .hasStatusThat()
+ .isEqualTo(CodeOwnerStatus.INSUFFICIENT_REVIEWERS);
+ fileCodeOwnerStatusSubject1.hasChangedFile().isNoRename();
+ fileCodeOwnerStatusSubject1.hasChangedFile().isDeletion();
+ FileCodeOwnerStatusSubject fileCodeOwnerStatusSubject2 =
+ assertThatCollection(fileCodeOwnerStatuses).element(1);
+ fileCodeOwnerStatusSubject2.hasNewPathStatus().value().hasPathThat().isEqualTo(newPath);
+ fileCodeOwnerStatusSubject2
.hasNewPathStatus()
.value()
.hasStatusThat()
@@ -732,14 +774,8 @@
implicitApprovalsEnabled
? CodeOwnerStatus.APPROVED
: CodeOwnerStatus.INSUFFICIENT_REVIEWERS);
- fileCodeOwnerStatusSubject.hasOldPathStatus().value().hasPathThat().isEqualTo(oldPath);
- fileCodeOwnerStatusSubject
- .hasOldPathStatus()
- .value()
- .hasStatusThat()
- .isEqualTo(CodeOwnerStatus.INSUFFICIENT_REVIEWERS);
- fileCodeOwnerStatusSubject.hasChangedFile().isRename();
- fileCodeOwnerStatusSubject.hasChangedFile().isNoDeletion();
+ fileCodeOwnerStatusSubject2.hasChangedFile().isNoRename();
+ fileCodeOwnerStatusSubject2.hasChangedFile().isNoDeletion();
}
@Test
diff --git a/resources/Documentation/config.md b/resources/Documentation/config.md
index dc5ac94..8207d33 100644
--- a/resources/Documentation/config.md
+++ b/resources/Documentation/config.md
@@ -147,7 +147,7 @@
(e.g. because they are bots and cannot react to review requests), they
can be added to the `Service Users` group (since members of this group
are not suggested as code owners).\
- Can be specified multiple time to set multiple global code owners.\
+ Can be specified multiple times to set multiple global code owners.\
Can be overridden per project by setting
[codeOwners.globalCodeOwner](#codeOwnersGlobalCodeOwner) in
`@PLUGIN@.config`.\
@@ -543,7 +543,7 @@
(e.g. because they are bots and cannot react to review requests), they
can be added to the `Service Users` group (since members of this group
are not suggested as code owners).\
- Can be specified multiple time to set multiple global code owners.\
+ Can be specified multiple times to set multiple global code owners.\
Overrides the global setting
[plugin.@PLUGIN@.globalCodeOwner](#pluginCodeOwnersGlobalCodeOwner) in
`gerrit.config` and the `codeOwners.globalCodeOwner` setting from parent
diff --git a/resources/Documentation/rest-api.md b/resources/Documentation/rest-api.md
index c0e608b..29d5fd8 100644
--- a/resources/Documentation/rest-api.md
+++ b/resources/Documentation/rest-api.md
@@ -615,17 +615,6 @@
"path": "docs/todo.txt",
"status": "PENDING"
}
- },
- {
- "change_type": "RENAMED",
- "old_path_status" {
- "path": "user-introduction.txt",
- "status": "INSUFFICIENT_REVIEWERS"
- },
- "new_path_status" {
- "path": "docs/user-intro.md",
- "status": "APPROVED"
- }
}
]
}
@@ -949,7 +938,7 @@
| Field Name | | Description |
| ------------- | -------- | ----------- |
-| `change_type` | optional | The type of the file modification. Can be `ADDED`, `MODIFIED`, `DELETED`, `RENAMED` or `COPIED`. Not set if `MODIFIED`.
+| `change_type` | optional | The type of the file modification. Can be `ADDED`, `MODIFIED`, `DELETED`, `RENAMED` or `COPIED`. Not set if `MODIFIED`. Renamed files might appear as separate addition and deletion or with type=RENAMED. Copied files might appear as addition or with type=COPIED.
| `old_path_status` | optional | The code owner status for the old path as [PathCodeOwnerStatusInfo](#path-code-owner-status-info) entity. Only set if `change_type` is `DELETED` or `RENAMED`.
| `new_path_status` | optional | The code owner status for the new path as [PathCodeOwnerStatusInfo](#path-code-owner-status-info) entity. Not set if `change_type` is `DELETED`.