Merge "Evaluate and return submit requirements with ChangeInfo"
diff --git a/Documentation/config-labels.txt b/Documentation/config-labels.txt
index f5346c1..b4e65b0 100644
--- a/Documentation/config-labels.txt
+++ b/Documentation/config-labels.txt
@@ -280,7 +280,7 @@
Gerrit currently supports the following predicates:
-==== change-kind:{REWORK,TRIVIAL_REBASE,MERGE_FIRST_PARENT_UPDATE,NO_CODE_CHANGE,NO_CHANGE}
+==== changekind:{REWORK,TRIVIAL_REBASE,MERGE_FIRST_PARENT_UPDATE,NO_CODE_CHANGE,NO_CHANGE}
Matches if the diff between two patch sets was of a certain change kind.
diff --git a/java/com/google/gerrit/server/CommentsUtil.java b/java/com/google/gerrit/server/CommentsUtil.java
index b752791..344549e 100644
--- a/java/com/google/gerrit/server/CommentsUtil.java
+++ b/java/com/google/gerrit/server/CommentsUtil.java
@@ -42,8 +42,9 @@
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.notedb.ChangeUpdate;
-import com.google.gerrit.server.patch.PatchListCache;
-import com.google.gerrit.server.patch.PatchListNotAvailableException;
+import com.google.gerrit.server.patch.DiffNotAvailableException;
+import com.google.gerrit.server.patch.DiffOperations;
+import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import com.google.gerrit.server.update.ChangeContext;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -52,6 +53,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
@@ -108,21 +110,21 @@
private static final Ordering<Comparable<?>> NULLS_FIRST = Ordering.natural().nullsFirst();
+ private final DiffOperations diffOperations;
private final GitRepositoryManager repoManager;
private final AllUsersName allUsers;
private final String serverId;
- private final PatchListCache patchListCache;
@Inject
CommentsUtil(
+ DiffOperations diffOperations,
GitRepositoryManager repoManager,
AllUsersName allUsers,
- @GerritServerId String serverId,
- PatchListCache patchListCache) {
+ @GerritServerId String serverId) {
+ this.diffOperations = diffOperations;
this.repoManager = repoManager;
this.allUsers = allUsers;
this.serverId = serverId;
- this.patchListCache = patchListCache;
}
public HumanComment newHumanComment(
@@ -411,7 +413,7 @@
int parentNumber = Math.abs(side);
return resolveParentCommit(change.getProject(), patchset, parentNumber);
}
- return Optional.of(resolveAutoMergeCommit(change, patchset));
+ return Optional.ofNullable(resolveAutoMergeCommit(change, patchset));
}
return Optional.of(patchset.commitId());
}
@@ -429,12 +431,18 @@
}
}
+ @Nullable
private ObjectId resolveAutoMergeCommit(Change change, PatchSet patchset) {
try {
// TODO(ghareeb): Adjust after the auto-merge code was moved out of the diff caches. Also
// unignore the test in PortedCommentsIT.
- return patchListCache.getOldId(change, patchset, null);
- } catch (PatchListNotAvailableException e) {
+ Map<String, FileDiffOutput> modifiedFiles =
+ diffOperations.listModifiedFilesAgainstParent(
+ change.getProject(), patchset.commitId(), /* parentNum= */ null);
+ return modifiedFiles.isEmpty()
+ ? null
+ : modifiedFiles.values().iterator().next().oldCommitId();
+ } catch (DiffNotAvailableException e) {
throw new StorageException(e);
}
}
diff --git a/java/com/google/gerrit/server/patch/AutoMerger.java b/java/com/google/gerrit/server/patch/AutoMerger.java
index b99e2d2..8d1e0ff 100644
--- a/java/com/google/gerrit/server/patch/AutoMerger.java
+++ b/java/com/google/gerrit/server/patch/AutoMerger.java
@@ -31,6 +31,8 @@
import com.google.gerrit.server.logging.Metadata;
import com.google.gerrit.server.update.RepoView;
import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
import java.io.IOException;
import java.util.Optional;
import org.eclipse.jgit.dircache.DirCache;
@@ -70,6 +72,7 @@
* <p>The second point means that these commits are referenced from NoteDb. The consequence of this
* is that these refs should never be deleted.
*/
+@Singleton
public class AutoMerger {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@@ -88,7 +91,7 @@
private final Counter1<OperationType> counter;
private final Timer1<OperationType> latency;
- private final PersonIdent gerritIdent;
+ private final Provider<PersonIdent> gerritIdentProvider;
private final boolean save;
private final ThreeWayMergeStrategy configuredMergeStrategy;
@@ -96,7 +99,7 @@
AutoMerger(
MetricMaker metricMaker,
@GerritServerConfig Config cfg,
- @GerritPersonIdent PersonIdent gerritIdent) {
+ @GerritPersonIdent Provider<PersonIdent> gerritIdentProvider) {
this.counter =
metricMaker.newCounter(
"git/auto-merge/num_operations",
@@ -110,7 +113,7 @@
.setUnit("milliseconds"),
Field.ofEnum(OperationType.class, "type", Metadata.Builder::operationName).build());
this.save = cacheAutomerge(cfg);
- this.gerritIdent = gerritIdent;
+ this.gerritIdentProvider = gerritIdentProvider;
this.configuredMergeStrategy = MergeUtil.getMergeStrategy(cfg);
}
@@ -224,7 +227,9 @@
// the input commit, using the server name and timezone.
PersonIdent ident =
new PersonIdent(
- gerritIdent, merge.getCommitterIdent().getWhen(), gerritIdent.getTimeZone());
+ gerritIdentProvider.get(),
+ merge.getCommitterIdent().getWhen(),
+ gerritIdentProvider.get().getTimeZone());
CommitBuilder cb = new CommitBuilder();
cb.setAuthor(ident);
cb.setCommitter(ident);
diff --git a/java/com/google/gerrit/server/patch/BaseCommitUtil.java b/java/com/google/gerrit/server/patch/BaseCommitUtil.java
index 7c06a62..dd930378 100644
--- a/java/com/google/gerrit/server/patch/BaseCommitUtil.java
+++ b/java/com/google/gerrit/server/patch/BaseCommitUtil.java
@@ -21,6 +21,7 @@
import com.google.gerrit.server.git.InMemoryInserter;
import com.google.gerrit.server.git.MergeUtil;
import com.google.inject.Inject;
+import com.google.inject.Singleton;
import java.io.IOException;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Constants;
@@ -34,6 +35,7 @@
import org.eclipse.jgit.revwalk.RevWalk;
/** A utility class for computing the base commit / parent for a specific patchset commit. */
+@Singleton
class BaseCommitUtil {
private final AutoMerger autoMerger;
private final ThreeWayMergeStrategy mergeStrategy;
diff --git a/java/com/google/gerrit/server/patch/DiffOperationsImpl.java b/java/com/google/gerrit/server/patch/DiffOperationsImpl.java
index dbbb7a6..fd30868 100644
--- a/java/com/google/gerrit/server/patch/DiffOperationsImpl.java
+++ b/java/com/google/gerrit/server/patch/DiffOperationsImpl.java
@@ -44,6 +44,7 @@
import com.google.gerrit.server.patch.gitfilediff.GitFileDiffCacheImpl.DiffAlgorithm;
import com.google.inject.Inject;
import com.google.inject.Module;
+import com.google.inject.Singleton;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -60,6 +61,7 @@
* Provides different file diff operations. Uses the underlying Git/Gerrit caches to speed up the
* diff computation.
*/
+@Singleton
public class DiffOperationsImpl implements DiffOperations {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
diff --git a/java/com/google/gerrit/server/patch/diff/ModifiedFilesCacheImpl.java b/java/com/google/gerrit/server/patch/diff/ModifiedFilesCacheImpl.java
index 6023c0e..e168386 100644
--- a/java/com/google/gerrit/server/patch/diff/ModifiedFilesCacheImpl.java
+++ b/java/com/google/gerrit/server/patch/diff/ModifiedFilesCacheImpl.java
@@ -34,6 +34,7 @@
import com.google.gerrit.server.patch.gitdiff.ModifiedFile;
import com.google.inject.Inject;
import com.google.inject.Module;
+import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
import com.google.inject.name.Named;
import java.io.IOException;
@@ -56,6 +57,7 @@
* and the result will be exactly the same as the caller can get from {@link
* GitModifiedFilesCache#get(GitModifiedFilesCacheKey)}
*/
+@Singleton
public class ModifiedFilesCacheImpl implements ModifiedFilesCache {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
diff --git a/java/com/google/gerrit/server/patch/filediff/FileDiffCacheImpl.java b/java/com/google/gerrit/server/patch/filediff/FileDiffCacheImpl.java
index 2133474..0794775 100644
--- a/java/com/google/gerrit/server/patch/filediff/FileDiffCacheImpl.java
+++ b/java/com/google/gerrit/server/patch/filediff/FileDiffCacheImpl.java
@@ -44,6 +44,7 @@
import com.google.gerrit.server.patch.gitfilediff.GitFileDiffCacheImpl.DiffAlgorithmFactory;
import com.google.inject.Inject;
import com.google.inject.Module;
+import com.google.inject.Singleton;
import com.google.inject.name.Named;
import java.io.IOException;
import java.util.ArrayList;
@@ -76,6 +77,7 @@
* org.eclipse.jgit.lib.Constants#EMPTY_TREE_ID}, the git diff will be evaluated against the empty
* tree.
*/
+@Singleton
public class FileDiffCacheImpl implements FileDiffCache {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
diff --git a/java/com/google/gerrit/server/patch/gitdiff/GitModifiedFilesCacheImpl.java b/java/com/google/gerrit/server/patch/gitdiff/GitModifiedFilesCacheImpl.java
index b3b82bb..9b96da1 100644
--- a/java/com/google/gerrit/server/patch/gitdiff/GitModifiedFilesCacheImpl.java
+++ b/java/com/google/gerrit/server/patch/gitdiff/GitModifiedFilesCacheImpl.java
@@ -29,6 +29,7 @@
import com.google.gerrit.server.patch.DiffNotAvailableException;
import com.google.inject.Inject;
import com.google.inject.Module;
+import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
import com.google.inject.name.Named;
import java.io.IOException;
@@ -43,6 +44,7 @@
import org.eclipse.jgit.util.io.DisabledOutputStream;
/** Implementation of the {@link GitModifiedFilesCache} */
+@Singleton
public class GitModifiedFilesCacheImpl implements GitModifiedFilesCache {
private static final String GIT_MODIFIED_FILES = "git_modified_files";
private static final ImmutableMap<ChangeType, Patch.ChangeType> changeTypeMap =
diff --git a/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiffCacheImpl.java b/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiffCacheImpl.java
index 97cf37d32..4bc6b87 100644
--- a/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiffCacheImpl.java
+++ b/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiffCacheImpl.java
@@ -31,6 +31,7 @@
import com.google.gerrit.server.patch.DiffNotAvailableException;
import com.google.inject.Inject;
import com.google.inject.Module;
+import com.google.inject.Singleton;
import com.google.inject.name.Named;
import java.io.IOException;
import java.util.Collection;
@@ -52,6 +53,7 @@
import org.eclipse.jgit.util.io.DisabledOutputStream;
/** Implementation of the {@link GitFileDiffCache} */
+@Singleton
public class GitFileDiffCacheImpl implements GitFileDiffCache {
private static final String GIT_DIFF = "git_file_diff";
diff --git a/java/com/google/gerrit/server/query/approval/ApprovalQueryBuilder.java b/java/com/google/gerrit/server/query/approval/ApprovalQueryBuilder.java
index c3594f5..f412cc7 100644
--- a/java/com/google/gerrit/server/query/approval/ApprovalQueryBuilder.java
+++ b/java/com/google/gerrit/server/query/approval/ApprovalQueryBuilder.java
@@ -51,7 +51,7 @@
}
@Operator
- public Predicate<ApprovalContext> changeKind(String term) throws QueryParseException {
+ public Predicate<ApprovalContext> changekind(String term) throws QueryParseException {
return new ChangeKindPredicate(toEnumValue(ChangeKind.class, term));
}
diff --git a/java/com/google/gerrit/server/restapi/change/CommentPorter.java b/java/com/google/gerrit/server/restapi/change/CommentPorter.java
index d1d4544..35d512a 100644
--- a/java/com/google/gerrit/server/restapi/change/CommentPorter.java
+++ b/java/com/google/gerrit/server/restapi/change/CommentPorter.java
@@ -29,7 +29,6 @@
import com.google.gerrit.entities.Patch;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.Project;
-import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
import com.google.gerrit.metrics.Counter0;
import com.google.gerrit.metrics.Description;
import com.google.gerrit.metrics.MetricMaker;
@@ -39,16 +38,17 @@
import com.google.gerrit.server.logging.TraceContext.TraceTimer;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.patch.DiffMappings;
+import com.google.gerrit.server.patch.DiffNotAvailableException;
+import com.google.gerrit.server.patch.DiffOperations;
import com.google.gerrit.server.patch.GitPositionTransformer;
import com.google.gerrit.server.patch.GitPositionTransformer.BestPositionOnConflict;
import com.google.gerrit.server.patch.GitPositionTransformer.FileMapping;
import com.google.gerrit.server.patch.GitPositionTransformer.Mapping;
import com.google.gerrit.server.patch.GitPositionTransformer.Position;
import com.google.gerrit.server.patch.GitPositionTransformer.PositionedEntity;
-import com.google.gerrit.server.patch.PatchList;
-import com.google.gerrit.server.patch.PatchListCache;
-import com.google.gerrit.server.patch.PatchListKey;
-import com.google.gerrit.server.patch.PatchListNotAvailableException;
+import com.google.gerrit.server.patch.filediff.FileDiffOutput;
+import com.google.gerrit.server.patch.filediff.FileEdits;
+import com.google.gerrit.server.patch.filediff.TaggedEdit;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.util.List;
@@ -102,15 +102,15 @@
}
}
+ private final DiffOperations diffOperations;
private final GitPositionTransformer positionTransformer =
new GitPositionTransformer(BestPositionOnConflict.INSTANCE);
- private final PatchListCache patchListCache;
private final CommentsUtil commentsUtil;
private final Metrics metrics;
@Inject
- public CommentPorter(PatchListCache patchListCache, CommentsUtil commentsUtil, Metrics metrics) {
- this.patchListCache = patchListCache;
+ public CommentPorter(DiffOperations diffOperations, CommentsUtil commentsUtil, Metrics metrics) {
+ this.diffOperations = diffOperations;
this.commentsUtil = commentsUtil;
this.metrics = metrics;
}
@@ -283,7 +283,7 @@
PatchSet originalPatchset,
PatchSet targetPatchset,
short side)
- throws PatchListNotAvailableException {
+ throws DiffNotAvailableException {
try (TraceTimer ignored =
TraceContext.newTimer(
"Loading commit mappings",
@@ -311,18 +311,26 @@
private ImmutableSet<Mapping> loadCommitMappings(
Project.NameKey project, ObjectId originalCommit, ObjectId targetCommit)
- throws PatchListNotAvailableException {
+ throws DiffNotAvailableException {
try (TraceTimer ignored =
TraceContext.newTimer(
"Computing diffs", Metadata.builder().commit(originalCommit.name()).build())) {
- PatchList patchList =
- patchListCache.get(
- PatchListKey.againstCommit(originalCommit, targetCommit, Whitespace.IGNORE_NONE),
- project);
- return patchList.getPatches().stream().map(DiffMappings::toMapping).collect(toImmutableSet());
+ Map<String, FileDiffOutput> modifiedFiles =
+ diffOperations.listModifiedFiles(project, originalCommit, targetCommit);
+ return modifiedFiles.values().stream()
+ .map(CommentPorter::getFileEdits)
+ .map(DiffMappings::toMapping)
+ .collect(toImmutableSet());
}
}
+ private static FileEdits getFileEdits(FileDiffOutput fileDiffOutput) {
+ return FileEdits.create(
+ fileDiffOutput.edits().stream().map(TaggedEdit::edit).collect(toImmutableList()),
+ fileDiffOutput.oldPath(),
+ fileDiffOutput.newPath());
+ }
+
private ImmutableSet<Mapping> getFallbackMappings(List<HumanComment> comments) {
// Consider all files as deleted. -> Comments will be ported to the fallback destination, which
// currently are patchset-level comments.
diff --git a/javatests/com/google/gerrit/server/restapi/change/CommentPorterTest.java b/javatests/com/google/gerrit/server/restapi/change/CommentPorterTest.java
index ebb2f38..46f9c5a 100644
--- a/javatests/com/google/gerrit/server/restapi/change/CommentPorterTest.java
+++ b/javatests/com/google/gerrit/server/restapi/change/CommentPorterTest.java
@@ -22,6 +22,7 @@
import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.truth.Correspondence;
import com.google.gerrit.entities.Account;
@@ -35,12 +36,8 @@
import com.google.gerrit.metrics.DisabledMetricMaker;
import com.google.gerrit.server.CommentsUtil;
import com.google.gerrit.server.notedb.ChangeNotes;
-import com.google.gerrit.server.patch.ComparisonType;
-import com.google.gerrit.server.patch.PatchList;
-import com.google.gerrit.server.patch.PatchListCache;
-import com.google.gerrit.server.patch.PatchListEntry;
-import com.google.gerrit.server.patch.PatchListKey;
-import com.google.gerrit.server.patch.PatchListNotAvailableException;
+import com.google.gerrit.server.patch.DiffNotAvailableException;
+import com.google.gerrit.server.patch.DiffOperations;
import com.google.gerrit.server.restapi.change.CommentPorter.Metrics;
import com.google.gerrit.truth.NullAwareCorrespondence;
import java.sql.Timestamp;
@@ -60,7 +57,7 @@
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
- @Mock private PatchListCache patchListCache;
+ @Mock private DiffOperations diffOperations;
@Mock private CommentsUtil commentsUtil;
private static final CommentPorter.Metrics metrics = new Metrics(new DisabledMetricMaker());
@@ -76,12 +73,13 @@
PatchSet patchset2 = createPatchset(PatchSet.id(changeId, 2));
ChangeNotes changeNotes = mockChangeNotes(project, change, patchset1, patchset2);
- CommentPorter commentPorter = new CommentPorter(patchListCache, commentsUtil, metrics);
+ CommentPorter commentPorter = new CommentPorter(diffOperations, commentsUtil, metrics);
HumanComment comment = createComment(patchset1.id(), "myFile");
when(commentsUtil.determineCommitId(any(), any(), anyShort()))
.thenReturn(Optional.of(dummyObjectId));
- when(patchListCache.get(any(PatchListKey.class), any(Project.NameKey.class)))
- .thenThrow(PatchListNotAvailableException.class);
+ when(diffOperations.listModifiedFiles(
+ any(Project.NameKey.class), any(ObjectId.class), any(ObjectId.class)))
+ .thenThrow(DiffNotAvailableException.class);
ImmutableList<HumanComment> portedComments =
commentPorter.portComments(
changeNotes, patchset2, ImmutableList.of(comment), ImmutableList.of());
@@ -98,11 +96,12 @@
PatchSet patchset2 = createPatchset(PatchSet.id(changeId, 2));
ChangeNotes changeNotes = mockChangeNotes(project, change, patchset1, patchset2);
- CommentPorter commentPorter = new CommentPorter(patchListCache, commentsUtil, metrics);
+ CommentPorter commentPorter = new CommentPorter(diffOperations, commentsUtil, metrics);
HumanComment comment = createComment(patchset1.id(), "myFile");
when(commentsUtil.determineCommitId(any(), any(), anyShort()))
.thenReturn(Optional.of(dummyObjectId));
- when(patchListCache.get(any(PatchListKey.class), any(Project.NameKey.class)))
+ when(diffOperations.listModifiedFiles(
+ any(Project.NameKey.class), any(ObjectId.class), any(ObjectId.class)))
.thenThrow(IllegalStateException.class);
ImmutableList<HumanComment> portedComments =
commentPorter.portComments(
@@ -120,7 +119,7 @@
PatchSet patchset2 = createPatchset(PatchSet.id(changeId, 2));
ChangeNotes changeNotes = mockChangeNotes(project, change, patchset1, patchset2);
- CommentPorter commentPorter = new CommentPorter(patchListCache, commentsUtil, metrics);
+ CommentPorter commentPorter = new CommentPorter(diffOperations, commentsUtil, metrics);
HumanComment comment = createComment(patchset1.id(), "myFile");
when(commentsUtil.determineCommitId(any(), any(), anyShort()))
.thenThrow(IllegalStateException.class);
@@ -140,11 +139,12 @@
PatchSet patchset2 = createPatchset(PatchSet.id(changeId, 2));
ChangeNotes changeNotes = mockChangeNotes(project, change, patchset1, patchset2);
- CommentPorter commentPorter = new CommentPorter(patchListCache, commentsUtil, metrics);
+ CommentPorter commentPorter = new CommentPorter(diffOperations, commentsUtil, metrics);
HumanComment comment = createComment(patchset1.id(), "myFile");
when(commentsUtil.determineCommitId(any(), any(), anyShort()))
.thenReturn(Optional.of(dummyObjectId));
- when(patchListCache.get(any(PatchListKey.class), any(Project.NameKey.class)))
+ when(diffOperations.listModifiedFiles(
+ any(Project.NameKey.class), any(ObjectId.class), any(ObjectId.class)))
.thenThrow(IllegalStateException.class);
ImmutableList<HumanComment> portedComments =
commentPorter.portComments(
@@ -165,17 +165,17 @@
PatchSet patchset3 = createPatchset(PatchSet.id(changeId, 3));
ChangeNotes changeNotes = mockChangeNotes(project, change, patchset1, patchset2, patchset3);
- CommentPorter commentPorter = new CommentPorter(patchListCache, commentsUtil, metrics);
+ CommentPorter commentPorter = new CommentPorter(diffOperations, commentsUtil, metrics);
// Place the comments on different patchsets to have two different diff requests.
HumanComment comment1 = createComment(patchset1.id(), "myFile");
HumanComment comment2 = createComment(patchset2.id(), "myFile");
when(commentsUtil.determineCommitId(any(), any(), anyShort()))
.thenReturn(Optional.of(dummyObjectId));
- PatchList emptyDiff = getEmptyDiff();
// Throw an exception on the first diff request but return an actual value on the second.
- when(patchListCache.get(any(PatchListKey.class), any(Project.NameKey.class)))
+ when(diffOperations.listModifiedFiles(
+ any(Project.NameKey.class), any(ObjectId.class), any(ObjectId.class)))
.thenThrow(IllegalStateException.class)
- .thenReturn(emptyDiff);
+ .thenReturn(ImmutableMap.of());
ImmutableList<HumanComment> portedComments =
commentPorter.portComments(
changeNotes, patchset3, ImmutableList.of(comment1, comment2), ImmutableList.of());
@@ -195,13 +195,13 @@
// Leave out patchset 1 (e.g. reserved for draft patchsets in the past).
ChangeNotes changeNotes = mockChangeNotes(project, change, patchset2);
- CommentPorter commentPorter = new CommentPorter(patchListCache, commentsUtil, metrics);
+ CommentPorter commentPorter = new CommentPorter(diffOperations, commentsUtil, metrics);
HumanComment comment = createComment(patchset1.id(), "myFile");
when(commentsUtil.determineCommitId(any(), any(), anyShort()))
.thenReturn(Optional.of(dummyObjectId));
- PatchList emptyDiff = getEmptyDiff();
- when(patchListCache.get(any(PatchListKey.class), any(Project.NameKey.class)))
- .thenReturn(emptyDiff);
+ when(diffOperations.listModifiedFiles(
+ any(Project.NameKey.class), any(ObjectId.class), any(ObjectId.class)))
+ .thenReturn(ImmutableMap.of());
ImmutableList<HumanComment> portedComments =
commentPorter.portComments(
changeNotes, patchset2, ImmutableList.of(comment), ImmutableList.of());
@@ -260,13 +260,4 @@
private Correspondence<HumanComment, String> hasFilePath() {
return NullAwareCorrespondence.transforming(comment -> comment.key.filename, "hasFilePath");
}
-
- private PatchList getEmptyDiff() {
- return new PatchList(
- dummyObjectId,
- dummyObjectId,
- false,
- ComparisonType.againstOtherPatchSet(),
- new PatchListEntry[0]);
- }
}
diff --git a/polygerrit-ui/app/api/diff.ts b/polygerrit-ui/app/api/diff.ts
index ad83fb8..724141f 100644
--- a/polygerrit-ui/app/api/diff.ts
+++ b/polygerrit-ui/app/api/diff.ts
@@ -406,17 +406,26 @@
): void;
}
-// The current setup requires API users to register GrDiff instances with the
-// cursor, but we do not at this point want to expose the API that GrDiffCursor
-// uses to the public as it is likely to change. So for now, we allow any type
-// and cast. This works fine so long as API users do provide whatever the
-// gr-diff tag creates.
-export type GrDiff = unknown;
+/** An instance of the GrDiff Webcomponent */
+export interface GrDiff extends HTMLElement {
+ /**
+ * Return line number element for reading only,
+ *
+ * This is useful e.g. to determine where on screen certain lines are,
+ * whether they are covered up etc.
+ */
+ getLineNumEls(side: Side): readonly HTMLElement[];
+}
/** A service to interact with the line cursor in gr-diff instances. */
export declare interface GrDiffCursor {
- replaceDiffs(diffs: GrDiff[]): void;
- unregisterDiff(diff: GrDiff): void;
+ // The current setup requires API users to register GrDiff instances with the
+ // cursor, but we do not at this point want to expose the API that GrDiffCursor
+ // uses to the public as it is likely to change. So for now, we allow any type
+ // and cast. This works fine so long as API users do provide whatever the
+ // gr-diff tag creates.
+ replaceDiffs(diffs: unknown[]): void;
+ unregisterDiff(diff: unknown): void;
isAtStart(): boolean;
isAtEnd(): boolean;
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.ts
index 06087ed..8ee6a3f 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.ts
@@ -158,7 +158,7 @@
hidden$="[[isColumnHidden('Owner', visibleChangeTableColumns)]]"
>
<gr-account-link
- highlight-attention
+ highlightAttention
change="[[change]]"
account="[[change.owner]]"
></gr-account-link>
@@ -189,10 +189,10 @@
indexAs="index"
>
<gr-account-link
- hide-avatar=""
- hide-status=""
- first-name
- highlight-attention
+ hideAvatar=""
+ hideStatus=""
+ firstName
+ highlightAttention
change="[[change]]"
account="[[reviewer]]"
></gr-account-link
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog_test.js b/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog_test.ts
similarity index 77%
rename from polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog_test.js
rename to polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog_test.ts
index 9dbcd29..42aed07 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog_test.js
+++ b/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog_test.ts
@@ -17,11 +17,12 @@
import '../../../test/common-test-setup-karma.js';
import './gr-create-commands-dialog.js';
+import {GrCreateCommandsDialog} from './gr-create-commands-dialog.js';
const basicFixture = fixtureFromElement('gr-create-commands-dialog');
suite('gr-create-commands-dialog tests', () => {
- let element;
+ let element: GrCreateCommandsDialog;
setup(() => {
element = basicFixture.instantiate();
@@ -29,12 +30,12 @@
test('_computePushCommand', () => {
element.branch = 'master';
- assert.equal(element._pushCommand,
- 'git push origin HEAD:refs/for/master');
+ assert.equal(element._pushCommand, 'git push origin HEAD:refs/for/master');
element.branch = 'stable-2.15';
- assert.equal(element._pushCommand,
- 'git push origin HEAD:refs/for/stable-2.15');
+ assert.equal(
+ element._pushCommand,
+ 'git push origin HEAD:refs/for/stable-2.15'
+ );
});
});
-
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.ts b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.ts
index ab8e404..516a31e 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.ts
@@ -939,7 +939,7 @@
});
suite('plugin endpoints', () => {
- test('endpoint params', done => {
+ test('endpoint params', async () => {
element.change = createParsedChange();
element.revision = createRevision();
interface MetadataGrEndpointDecorator extends GrEndpointDecorator {
@@ -961,12 +961,10 @@
'http://some/plugins/url.js'
);
getPluginLoader().loadPlugins([]);
- flush(() => {
- assert.strictEqual(hookEl!.plugin, plugin);
- assert.strictEqual(hookEl!.change, element.change);
- assert.strictEqual(hookEl!.revision, element.revision);
- done();
- });
+ await flush();
+ assert.strictEqual(hookEl!.plugin, plugin!);
+ assert.strictEqual(hookEl!.change, element.change);
+ assert.strictEqual(hookEl!.revision, element.revision);
});
});
});
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
index 58cf489..8b37cf0 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
@@ -171,7 +171,7 @@
import {takeUntil} from 'rxjs/operators';
import {aPluginHasRegistered$} from '../../../services/checks/checks-model';
import {Subject} from 'rxjs';
-import {debounce, DelayedTask} from '../../../utils/async-util';
+import {debounce, DelayedTask, throttleWrap} from '../../../utils/async-util';
import {Interaction, Timing} from '../../../constants/reporting';
import {ChangeStates} from '../../shared/gr-change-status/gr-change-status';
import {getRevertCreatedChangeIds} from '../../../utils/message-util';
@@ -603,7 +603,7 @@
/** @override */
connectedCallback() {
super.connectedCallback();
- this._throttledToggleChangeStar = this._throttleWrap(e =>
+ this._throttledToggleChangeStar = throttleWrap(e =>
this._handleToggleChangeStar(e as CustomKeyboardEvent)
);
this._getServerConfig().then(config => {
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.ts b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.ts
index 52ec8af..ea3c01d 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.ts
@@ -31,6 +31,7 @@
RepoName,
} from '../../../types/common';
import {GrDownloadDialog} from './gr-download-dialog';
+import {mockPromise} from '../../../test/test-utils';
const basicFixture = fixtureFromElement('gr-download-dialog');
@@ -168,14 +169,16 @@
);
});
- test('close event', done => {
+ test('close event', async () => {
+ const closeCalled = mockPromise();
element.addEventListener('close', () => {
- done();
+ closeCalled.resolve();
});
const closeButton = element.shadowRoot!.querySelector(
'.closeButtonContainer gr-button'
);
tap(closeButton!);
+ await closeCalled;
});
});
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_html.ts b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_html.ts
index 8b9b80c..be3a0be 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_html.ts
@@ -167,6 +167,30 @@
<span class="separator"></span>
</span>
</template>
+ <div class="fileViewActions">
+ <span class="fileViewActionsLabel">Diff view:</span>
+ <gr-diff-mode-selector
+ id="modeSelect"
+ mode="{{diffViewMode}}"
+ save-on-change="[[!diffPrefsDisabled]]"
+ ></gr-diff-mode-selector>
+ <span
+ id="diffPrefsContainer"
+ class="hideOnEdit"
+ hidden$="[[_computePrefsButtonHidden(diffPrefs, diffPrefsDisabled)]]"
+ hidden=""
+ >
+ <gr-button
+ link=""
+ has-tooltip=""
+ title="Diff preferences"
+ class="prefsButton desktop"
+ on-click="_handlePrefsTap"
+ ><iron-icon icon="gr-icons:settings"></iron-icon
+ ></gr-button>
+ </span>
+ </div>
+ <span class="separator"></span>
<span class="downloadContainer desktop">
<gr-button
link=""
@@ -209,30 +233,6 @@
Bulk actions disabled because there are too many files.
</div>
</template>
- <div class="fileViewActions">
- <span class="separator"></span>
- <span class="fileViewActionsLabel">Diff view:</span>
- <gr-diff-mode-selector
- id="modeSelect"
- mode="{{diffViewMode}}"
- save-on-change="[[!diffPrefsDisabled]]"
- ></gr-diff-mode-selector>
- <span
- id="diffPrefsContainer"
- class="hideOnEdit"
- hidden$="[[_computePrefsButtonHidden(diffPrefs, diffPrefsDisabled)]]"
- hidden=""
- >
- <gr-button
- link=""
- has-tooltip=""
- title="Diff preferences"
- class="prefsButton desktop"
- on-click="_handlePrefsTap"
- ><iron-icon icon="gr-icons:settings"></iron-icon
- ></gr-button>
- </span>
- </div>
</div>
</div>
`;
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.ts b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.ts
index ae9af4a..15bc6bf 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.ts
@@ -599,7 +599,7 @@
resetPlugins();
});
- test('endpoint params', done => {
+ test('endpoint params', async () => {
element.change = {...createParsedChange(), labels: {}};
interface RelatedChangesListGrEndpointDecorator
extends GrEndpointDecorator {
@@ -620,11 +620,9 @@
'http://some/plugins/url1.js'
);
getPluginLoader().loadPlugins([]);
- flush(() => {
- assert.strictEqual(hookEl.plugin, plugin);
- assert.strictEqual(hookEl.change, element.change);
- done();
- });
+ await flush();
+ assert.strictEqual(hookEl!.plugin, plugin!);
+ assert.strictEqual(hookEl!.change, element.change);
});
});
});
diff --git a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.ts b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.ts
index 4b57651..354d360 100644
--- a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_test.ts
@@ -17,7 +17,11 @@
import '../../../test/common-test-setup-karma';
import './gr-reviewer-list';
-import {queryAndAssert, stubRestApi} from '../../../test/test-utils';
+import {
+ mockPromise,
+ queryAndAssert,
+ stubRestApi,
+} from '../../../test/test-utils';
import {GrReviewerList} from './gr-reviewer-list';
import {
createAccountDetailWithId,
@@ -53,12 +57,14 @@
);
});
- test('add reviewer button opens reply dialog', done => {
+ test('add reviewer button opens reply dialog', async () => {
+ const dialogShown = mockPromise();
element.addEventListener('show-reply-dialog', () => {
- done();
+ dialogShown.resolve();
});
- flush();
+ await flush();
tap(queryAndAssert(element, '.addReviewer'));
+ await dialogShown;
});
test('only show remove for removable reviewers', () => {
diff --git a/polygerrit-ui/app/elements/checks/gr-hovercard-run_test.js b/polygerrit-ui/app/elements/checks/gr-hovercard-run_test.ts
similarity index 78%
rename from polygerrit-ui/app/elements/checks/gr-hovercard-run_test.js
rename to polygerrit-ui/app/elements/checks/gr-hovercard-run_test.ts
index 9c77654..80d8e5e 100644
--- a/polygerrit-ui/app/elements/checks/gr-hovercard-run_test.js
+++ b/polygerrit-ui/app/elements/checks/gr-hovercard-run_test.ts
@@ -18,24 +18,25 @@
import '../../test/common-test-setup-karma.js';
import './gr-hovercard-run.js';
import {html} from '@polymer/polymer/lib/utils/html-tag.js';
+import {GrHovercardRun} from './gr-hovercard-run.js';
const basicFixture = fixtureFromTemplate(html`
-<gr-hovercard-run class="hovered"></gr-hovercard-run>
+ <gr-hovercard-run class="hovered"></gr-hovercard-run>
`);
suite('gr-hovercard-run tests', () => {
- let element;
+ let element: GrHovercardRun;
setup(async () => {
- element = basicFixture.instantiate();
+ element = basicFixture.instantiate() as GrHovercardRun;
await flush();
});
teardown(() => {
- element.hide({});
+ element.hide();
});
test('hovercard is shown', () => {
+ assert.equal(element.computeIcon(), '');
});
});
-
diff --git a/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog_test.ts b/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog_test.ts
index fa57a23..2dec8d2 100644
--- a/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog_test.ts
+++ b/polygerrit-ui/app/elements/core/gr-error-dialog/gr-error-dialog_test.ts
@@ -17,7 +17,7 @@
import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
import '../../../test/common-test-setup-karma';
-import {queryAndAssert} from '../../../test/test-utils';
+import {mockPromise, queryAndAssert} from '../../../test/test-utils';
import {GrDialog} from '../../shared/gr-dialog/gr-dialog';
import {GrErrorDialog} from './gr-error-dialog';
@@ -30,10 +30,12 @@
element = basicFixture.instantiate();
});
- test('dismiss tap fires event', done => {
- element.addEventListener('dismiss', () => done());
+ test('dismiss tap fires event', async () => {
+ const dismissCalled = mockPromise();
+ element.addEventListener('dismiss', () => dismissCalled.resolve());
MockInteractions.tap(
(queryAndAssert(element, '#dialog') as GrDialog).$.confirm
);
+ await dismissCalled;
});
});
diff --git a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.ts b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.ts
index 8f9dfe2..8352319 100644
--- a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.ts
+++ b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.ts
@@ -75,6 +75,37 @@
};
}
+export function constructServerErrorMsg({
+ errorText,
+ status,
+ statusText,
+ url,
+ trace,
+ tip,
+}: ErrorMsg) {
+ let err = '';
+ if (tip) {
+ err += `${tip}\n\n`;
+ }
+ err += `Error ${status}`;
+ if (statusText) {
+ err += ` (${statusText})`;
+ }
+ if (errorText || url) {
+ err += ': ';
+ }
+ if (errorText) {
+ err += errorText;
+ }
+ if (url) {
+ err += `\nEndpoint: ${url}`;
+ }
+ if (trace) {
+ err += `\nTrace Id: ${trace}`;
+ }
+ return err;
+}
+
@customElement('gr-error-manager')
export class GrErrorManager extends PolymerElement {
static get template() {
@@ -221,7 +252,7 @@
this._showQuotaExceeded({status, statusText});
} else {
this._showErrorDialog(
- this._constructServerErrorMsg({
+ constructServerErrorMsg({
status,
statusText,
errorText,
@@ -247,7 +278,7 @@
? 'You might have not enough privileges.'
: 'You might have not enough privileges. Sign in and try again.';
this._showErrorDialog(
- this._constructServerErrorMsg({
+ constructServerErrorMsg({
status,
statusText,
errorText,
@@ -266,7 +297,7 @@
const tip = 'Try again later';
const errorText = 'Too many requests from this client';
this._showErrorDialog(
- this._constructServerErrorMsg({
+ constructServerErrorMsg({
status,
statusText,
errorText,
@@ -275,37 +306,6 @@
);
}
- _constructServerErrorMsg({
- errorText,
- status,
- statusText,
- url,
- trace,
- tip,
- }: ErrorMsg) {
- let err = '';
- if (tip) {
- err += `${tip}\n\n`;
- }
- err += `Error ${status}`;
- if (statusText) {
- err += ` (${statusText})`;
- }
- if (errorText || url) {
- err += ': ';
- }
- if (errorText) {
- err += errorText;
- }
- if (url) {
- err += `\nEndpoint: ${url}`;
- }
- if (trace) {
- err += `\nTrace Id: ${trace}`;
- }
- return err;
- }
-
private readonly handleShowAlert = (e: CustomEvent<ShowAlertEventDetail>) => {
this._showAlert(
e.detail.message,
diff --git a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.js b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.js
index fe4d9da..4cf15b4 100644
--- a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.js
+++ b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.js
@@ -18,7 +18,7 @@
import '../../../test/common-test-setup-karma.js';
import './gr-error-manager.js';
import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit.js';
-import {__testOnly_ErrorType} from './gr-error-manager.js';
+import {constructServerErrorMsg, __testOnly_ErrorType} from './gr-error-manager.js';
import {stubRestApi} from '../../../test/test-utils.js';
import {appContext} from '../../../services/app-context.js';
import {createPreferences} from '../../../test/test-data-generators.js';
@@ -132,27 +132,26 @@
});
});
- test('_constructServerErrorMsg', () => {
+ test('constructServerErrorMsg', () => {
const errorText = 'change conflicts';
const status = 409;
const statusText = 'Conflict';
const url = '/my/test/url';
- assert.equal(element._constructServerErrorMsg({status}),
+ assert.equal(constructServerErrorMsg({status}),
'Error 409');
- assert.equal(element._constructServerErrorMsg({status, url}),
+ assert.equal(constructServerErrorMsg({status, url}),
'Error 409: \nEndpoint: /my/test/url');
- assert.equal(element.
- _constructServerErrorMsg({status, statusText, url}),
- 'Error 409 (Conflict): \nEndpoint: /my/test/url');
- assert.equal(element._constructServerErrorMsg({
+ assert.equal(constructServerErrorMsg({status, statusText, url}),
+ 'Error 409 (Conflict): \nEndpoint: /my/test/url');
+ assert.equal(constructServerErrorMsg({
status,
statusText,
errorText,
url,
}), 'Error 409 (Conflict): change conflicts' +
'\nEndpoint: /my/test/url');
- assert.equal(element._constructServerErrorMsg({
+ assert.equal(constructServerErrorMsg({
status,
statusText,
errorText,
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
index dacd8e7..9004517 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
@@ -106,6 +106,7 @@
import {assertIsDefined} from '../../../utils/common-util';
import {toggleClass, getKeyboardEvent} from '../../../utils/dom-util';
import {CursorMoveResult} from '../../../api/core';
+import {throttleWrap} from '../../../utils/async-util';
const ERR_REVIEW_STATUS = 'Couldn’t change file review status.';
const MSG_LOADING_BLAME = 'Loading blame...';
@@ -342,7 +343,7 @@
/** @override */
connectedCallback() {
super.connectedCallback();
- this._throttledToggleFileReviewed = this._throttleWrap(e =>
+ this._throttledToggleFileReviewed = throttleWrap(e =>
this._handleToggleFileReviewed(e as CustomKeyboardEvent)
);
this._getLoggedIn().then(loggedIn => {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.ts b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.ts
index 7c437fd..0b42f9f 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.ts
@@ -69,6 +69,7 @@
import {
CreateCommentEventDetail as CreateCommentEventDetailApi,
RenderPreferences,
+ GrDiff as GrDiffApi,
} from '../../../api/diff';
import {isSafari, toggleClass} from '../../../utils/dom-util';
import {assertIsDefined} from '../../../utils/common-util';
@@ -109,7 +110,7 @@
}
@customElement('gr-diff')
-export class GrDiff extends PolymerElement {
+export class GrDiff extends PolymerElement implements GrDiffApi {
static get template() {
return htmlTemplate;
}
@@ -322,6 +323,12 @@
super.disconnectedCallback();
}
+ getLineNumEls(side: Side): HTMLElement[] {
+ return Array.from(
+ this.root?.querySelectorAll<HTMLElement>(`.lineNum.${side}`) ?? []
+ );
+ }
+
showNoChangeMessage(
loading?: boolean,
prefs?: DiffPreferencesInfo,
diff --git a/polygerrit-ui/app/elements/gr-app-element.ts b/polygerrit-ui/app/elements/gr-app-element.ts
index be9c7c5..c9f0506 100644
--- a/polygerrit-ui/app/elements/gr-app-element.ts
+++ b/polygerrit-ui/app/elements/gr-app-element.ts
@@ -55,7 +55,10 @@
ElementPropertyDeepChange,
ServerInfo,
} from '../types/common';
-import {GrErrorManager} from './core/gr-error-manager/gr-error-manager';
+import {
+ constructServerErrorMsg,
+ GrErrorManager,
+} from './core/gr-error-manager/gr-error-manager';
import {GrOverlay} from './shared/gr-overlay/gr-overlay';
import {GrRegistrationDialog} from './settings/gr-registration-dialog/gr-registration-dialog';
import {
@@ -565,7 +568,15 @@
err.emoji = 'o_O';
if (response) {
response.text().then(text => {
- err.moreInfo = text;
+ const trace =
+ response.headers && response.headers.get('X-Gerrit-Trace');
+ const {status, statusText} = response;
+ err.moreInfo = constructServerErrorMsg({
+ status,
+ statusText,
+ errorText: text,
+ trace,
+ });
this._lastError = err;
});
}
diff --git a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_test.ts b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_test.ts
index f08976f..4891759 100644
--- a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_test.ts
+++ b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_test.ts
@@ -25,7 +25,7 @@
suite('gr-agreements-list tests', () => {
let element: GrAgreementsList;
- setup(done => {
+ setup(async () => {
const agreements: ContributorAgreementInfo[] = [
{
url: 'some url',
@@ -38,9 +38,8 @@
element = basicFixture.instantiate();
- element.loadData().then(() => {
- flush(done);
- });
+ await element.loadData();
+ await flush();
});
test('renders', () => {
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.ts b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.ts
index 9f54cd1..d634483 100644
--- a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.ts
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_test.ts
@@ -125,16 +125,15 @@
},
];
- setup(done => {
+ setup(async () => {
stubRestApi('getConfig').returns(Promise.resolve(config));
stubRestApi('getAccountGroups').returns(Promise.resolve(groups));
stubRestApi('getAccountAgreements').returns(
Promise.resolve(signedAgreements)
);
element = basicFixture.instantiate();
- element.loadData().then(() => {
- flush(done);
- });
+ await element.loadData();
+ await flush();
});
test('renders as expected with signed agreement', () => {
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 5c4b76a..944c3df 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
@@ -16,19 +16,12 @@
*/
import '../gr-account-label/gr-account-label';
-import '../../../styles/shared-styles';
-import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {htmlTemplate} from './gr-account-link_html';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
-import {customElement, property} from '@polymer/decorators';
import {AccountInfo, ChangeInfo} from '../../../types/common';
+import {css, customElement, html, LitElement, property} from 'lit-element';
@customElement('gr-account-link')
-class GrAccountLink extends PolymerElement {
- static get template() {
- return htmlTemplate;
- }
-
+class GrAccountLink extends LitElement {
@property({type: String})
voteableText?: string;
@@ -70,6 +63,45 @@
@property({type: Boolean})
firstName = false;
+ static get styles() {
+ return [
+ css`
+ :host {
+ display: inline-block;
+ vertical-align: top;
+ }
+ a {
+ color: var(--primary-text-color);
+ text-decoration: none;
+ }
+ gr-account-label {
+ --gr-account-label-text-hover-style: {
+ text-decoration: underline;
+ }
+ }
+ `,
+ ];
+ }
+
+ render() {
+ if (!this.account) return;
+ return html`<span>
+ <a href="${this._computeOwnerLink(this.account)}">
+ <gr-account-label
+ .account="${this.account}"
+ .change="${this.change}"
+ ?force-attention=${this.forceAttention}
+ ?highlight-attention=${this.highlightAttention}
+ ?hide-avatar=${this.hideAvatar}
+ ?hide-status=${this.hideStatus}
+ ?first-name=${this.firstName}
+ .voteable-text=${this.voteableText}
+ >
+ </gr-account-label>
+ </a>
+ </span>`;
+ }
+
_computeOwnerLink(account?: AccountInfo) {
if (!account) {
return;
diff --git a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_html.ts b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_html.ts
deleted file mode 100644
index 98a6e77..0000000
--- a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link_html.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * @license
- * Copyright (C) 2020 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.
- */
-import {html} from '@polymer/polymer/lib/utils/html-tag';
-
-export const htmlTemplate = html`
- <style>
- :host {
- display: inline-block;
- vertical-align: top;
- }
- a {
- color: var(--primary-text-color);
- text-decoration: none;
- }
- gr-account-label {
- --gr-account-label-text-hover-style: {
- text-decoration: underline;
- }
- }
- </style>
- <span>
- <a href$="[[_computeOwnerLink(account)]]">
- <gr-account-label
- account="[[account]]"
- change="[[change]]"
- force-attention="[[forceAttention]]"
- highlight-attention="[[highlightAttention]]"
- hide-avatar="[[hideAvatar]]"
- hide-status="[[hideStatus]]"
- first-name="[[firstName]]"
- voteable-text="[[voteableText]]"
- >
- </gr-account-label>
- </a>
- </span>
-`;
diff --git a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert_test.js b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert_test.ts
similarity index 82%
rename from polygerrit-ui/app/elements/shared/gr-alert/gr-alert_test.js
rename to polygerrit-ui/app/elements/shared/gr-alert/gr-alert_test.ts
index 11ec496..cf0c34a 100644
--- a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert_test.ts
@@ -17,8 +17,11 @@
import '../../../test/common-test-setup-karma.js';
import './gr-alert.js';
+import {GrAlert} from './gr-alert.js';
+import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
+
suite('gr-alert tests', () => {
- let element;
+ let element: GrAlert;
setup(() => {
element = document.createElement('gr-alert');
@@ -32,7 +35,7 @@
test('show/hide', () => {
assert.isNull(element.parentNode);
- element.show();
+ element.show('Alert text');
assert.equal(element.parentNode, document.body);
element.updateStyles({'--gr-alert-transition-duration': '0ms'});
element.hide();
@@ -41,11 +44,10 @@
test('action event', () => {
const spy = sinon.spy();
- element.show();
+ element.show('Alert text');
element._actionCallback = spy;
assert.isFalse(spy.called);
- MockInteractions.tap(element.shadowRoot.querySelector('.action'));
+ MockInteractions.tap(element.shadowRoot!.querySelector('.action')!);
assert.isTrue(spy.called);
});
});
-
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_test.js b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_test.ts
similarity index 80%
rename from polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_test.js
rename to polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_test.ts
index dd2b98a..972e02c 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip_test.ts
@@ -15,13 +15,15 @@
* limitations under the License.
*/
-import '../../../test/common-test-setup-karma.js';
-import './gr-linked-chip.js';
+import '../../../test/common-test-setup-karma';
+import './gr-linked-chip';
+import {GrLinkedChip} from './gr-linked-chip';
+import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
const basicFixture = fixtureFromElement('gr-linked-chip');
suite('gr-linked-chip tests', () => {
- let element;
+ let element: GrLinkedChip;
setup(() => {
element = basicFixture.instantiate();
@@ -35,4 +37,3 @@
assert.isTrue(spy.called);
});
});
-
diff --git a/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command_test.js b/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command_test.ts
similarity index 78%
rename from polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command_test.js
rename to polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command_test.ts
index de9f243..1a7d2cd 100644
--- a/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command_test.ts
@@ -17,25 +17,26 @@
import '../../../test/common-test-setup-karma.js';
import './gr-shell-command.js';
+import {GrShellCommand} from './gr-shell-command.js';
const basicFixture = fixtureFromElement('gr-shell-command');
suite('gr-shell-command tests', () => {
- let element;
+ let element: GrShellCommand;
setup(() => {
element = basicFixture.instantiate();
- element.text = `git fetch http://gerrit@localhost:8080/a/test-project
+ element.command = `git fetch http://gerrit@localhost:8080/a/test-project
refs/changes/05/5/1 && git checkout FETCH_HEAD`;
flush();
});
test('focusOnCopy', () => {
- const focusStub = sinon.stub(element.shadowRoot
- .querySelector('gr-copy-clipboard'),
- 'focusOnCopy');
+ const focusStub = sinon.stub(
+ element.shadowRoot!.querySelector('gr-copy-clipboard')!,
+ 'focusOnCopy'
+ );
element.focusOnCopy();
assert.isTrue(focusStub.called);
});
});
-
diff --git a/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts b/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts
index 555a256..3d5a208 100644
--- a/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts
+++ b/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts
@@ -120,8 +120,6 @@
const V_KEY_TIMEOUT_MS = 1000;
-const THROTTLE_INTERVAL_MS = 500;
-
/**
* Enum for all shortcut sections, where that shortcut should be applied to.
*/
@@ -675,8 +673,6 @@
if (!bindings) {
return null;
}
- // TODO(TS): should check base on length to differentiate two
- // cases
if (bindings[0] === SPECIAL_SHORTCUT.GO_KEY) {
return bindings
.slice(1)
@@ -851,13 +847,6 @@
return getKeyboardEvent(e);
}
- // TODO(TS): maybe remove, no reference in the code base
- getRootTarget(e: CustomKeyboardEvent) {
- // TODO(TS): worth checking if we can limit this to EventApi only
- // dom currently returns DomNativeApi|EventApi
- return (dom(getKeyboardEvent(e)) as EventApi).rootTarget;
- }
-
bindShortcut(shortcut: Shortcut, ...bindings: string[]) {
shortcutManager.bindShortcut(shortcut, ...bindings);
}
@@ -868,20 +857,6 @@
return desc && shortcut ? `${desc} (shortcut: ${shortcut})` : '';
}
- _throttleWrap(fn: (e: Event) => void) {
- let lastCall: number | undefined;
- return (e: Event) => {
- if (
- lastCall !== undefined &&
- Date.now() - lastCall < THROTTLE_INTERVAL_MS
- ) {
- return;
- }
- lastCall = Date.now();
- fn(e);
- };
- }
-
_addOwnKeyBindings(shortcut: Shortcut, handler: string) {
const bindings = shortcutManager.getBindingsForShortcut(shortcut);
if (!bindings) {
@@ -1128,8 +1103,6 @@
modifierPressed(event: CustomKeyboardEvent): boolean;
addKeyboardShortcutDirectoryListener(listener: ShortcutListener): void;
removeKeyboardShortcutDirectoryListener(listener: ShortcutListener): void;
- // TODO(TS): Remove underscore. Apparently not a private method.
- _throttleWrap(eventListener: EventListener): EventListener;
}
export function _testOnly_getShortcutManagerInstance() {
diff --git a/polygerrit-ui/app/services/checks/checks-model.ts b/polygerrit-ui/app/services/checks/checks-model.ts
index 5d3da42..22c2381 100644
--- a/polygerrit-ui/app/services/checks/checks-model.ts
+++ b/polygerrit-ui/app/services/checks/checks-model.ts
@@ -261,10 +261,13 @@
// Must only be used by the checks service or whatever is in control of this
// model.
-export function updateStateSetProvider(pluginName: string) {
+export function updateStateSetProvider(
+ pluginName: string,
+ patchset: ChecksPatchset
+) {
const nextState = {...privateState$.getValue()};
- nextState.pluginStateLatest = {...nextState.pluginStateLatest};
- nextState.pluginStateLatest[pluginName] = {
+ const pluginState = getPluginState(nextState, patchset);
+ pluginState[pluginName] = {
pluginName,
loading: false,
runs: [],
diff --git a/polygerrit-ui/app/services/checks/checks-service.ts b/polygerrit-ui/app/services/checks/checks-service.ts
index e1d435b..d683514 100644
--- a/polygerrit-ui/app/services/checks/checks-service.ts
+++ b/polygerrit-ui/app/services/checks/checks-service.ts
@@ -118,7 +118,8 @@
) {
this.providers[pluginName] = provider;
this.reloadSubjects[pluginName] = new BehaviorSubject<void>(undefined);
- updateStateSetProvider(pluginName);
+ updateStateSetProvider(pluginName, ChecksPatchset.LATEST);
+ updateStateSetProvider(pluginName, ChecksPatchset.SELECTED);
this.initFetchingOfData(pluginName, config, ChecksPatchset.LATEST);
this.initFetchingOfData(pluginName, config, ChecksPatchset.SELECTED);
}
diff --git a/polygerrit-ui/app/services/flags/flags_test.js b/polygerrit-ui/app/services/flags/flags_test.ts
similarity index 85%
rename from polygerrit-ui/app/services/flags/flags_test.js
rename to polygerrit-ui/app/services/flags/flags_test.ts
index 33508af..8827368 100644
--- a/polygerrit-ui/app/services/flags/flags_test.js
+++ b/polygerrit-ui/app/services/flags/flags_test.ts
@@ -15,12 +15,12 @@
* limitations under the License.
*/
-import '../../test/common-test-setup-karma.js';
-import {FlagsServiceImplementation} from './flags_impl.js';
+import '../../test/common-test-setup-karma';
+import {FlagsServiceImplementation} from './flags_impl';
suite('flags tests', () => {
- let originalEnabledExperiments;
- let flags;
+ let originalEnabledExperiments: string[];
+ let flags: FlagsServiceImplementation;
suiteSetup(() => {
originalEnabledExperiments = window.ENABLED_EXPERIMENTS;
@@ -41,4 +41,3 @@
assert.deepEqual(flags.enabledExperiments, ['a']);
});
});
-
diff --git a/polygerrit-ui/app/utils/account-util_test.js b/polygerrit-ui/app/utils/account-util_test.ts
similarity index 75%
rename from polygerrit-ui/app/utils/account-util_test.js
rename to polygerrit-ui/app/utils/account-util_test.ts
index 0628f2d..835cd6d 100644
--- a/polygerrit-ui/app/utils/account-util_test.js
+++ b/polygerrit-ui/app/utils/account-util_test.ts
@@ -15,13 +15,12 @@
* limitations under the License.
*/
-import '../test/common-test-setup-karma.js';
-import {isServiceUser, removeServiceUsers} from './account-util.js';
-import {AccountTag} from '../constants/constants.js';
+import '../test/common-test-setup-karma';
+import {isServiceUser, removeServiceUsers} from './account-util';
+import {AccountTag} from '../constants/constants';
const EMPTY = {};
const ERNIE = {name: 'Ernie'};
-const KERMIT = {name: 'Kermit', tags: ['FROG']};
const SERVY = {name: 'Servy', tags: [AccountTag.SERVICE_USER]};
const BOTTY = {name: 'Botty', tags: [AccountTag.SERVICE_USER]};
@@ -30,17 +29,17 @@
assert.isFalse(isServiceUser());
assert.isFalse(isServiceUser(EMPTY));
assert.isFalse(isServiceUser(ERNIE));
- assert.isFalse(isServiceUser(KERMIT));
assert.isTrue(isServiceUser(SERVY));
assert.isTrue(isServiceUser(BOTTY));
});
test('removeServiceUsers', () => {
assert.sameMembers(removeServiceUsers([]), []);
- assert.sameMembers(removeServiceUsers([EMPTY, ERNIE, KERMIT]),
- [EMPTY, ERNIE, KERMIT]);
+ assert.sameMembers(removeServiceUsers([EMPTY, ERNIE]), [EMPTY, ERNIE]);
assert.sameMembers(removeServiceUsers([SERVY, BOTTY]), []);
- assert.sameMembers(removeServiceUsers([EMPTY, SERVY, ERNIE, BOTTY, KERMIT]),
- [EMPTY, ERNIE, KERMIT]);
+ assert.sameMembers(removeServiceUsers([EMPTY, SERVY, ERNIE, BOTTY]), [
+ EMPTY,
+ ERNIE,
+ ]);
});
});
diff --git a/polygerrit-ui/app/utils/async-util.ts b/polygerrit-ui/app/utils/async-util.ts
index 2b36fee..c82f5e4 100644
--- a/polygerrit-ui/app/utils/async-util.ts
+++ b/polygerrit-ui/app/utils/async-util.ts
@@ -110,3 +110,23 @@
existingTask?.cancel();
return new DelayedTask(callback, waitMs);
}
+
+const THROTTLE_INTERVAL_MS = 500;
+
+/**
+ * Ensure only one call is made within THROTTLE_INTERVAL_MS and any call within
+ * this interval is ignored
+ */
+export function throttleWrap(fn: (e: Event) => void) {
+ let lastCall: number | undefined;
+ return (e: Event) => {
+ if (
+ lastCall !== undefined &&
+ Date.now() - lastCall < THROTTLE_INTERVAL_MS
+ ) {
+ return;
+ }
+ lastCall = Date.now();
+ fn(e);
+ };
+}
diff --git a/polygerrit-ui/app/utils/safe-types-util_test.js b/polygerrit-ui/app/utils/safe-types-util_test.ts
similarity index 83%
rename from polygerrit-ui/app/utils/safe-types-util_test.js
rename to polygerrit-ui/app/utils/safe-types-util_test.ts
index e3968d0..03253e0 100644
--- a/polygerrit-ui/app/utils/safe-types-util_test.js
+++ b/polygerrit-ui/app/utils/safe-types-util_test.ts
@@ -15,12 +15,12 @@
* limitations under the License.
*/
-import '../test/common-test-setup-karma.js';
-import {safeTypesBridge, _testOnly_SafeUrl} from './safe-types-util.js';
+import '../test/common-test-setup-karma';
+import {safeTypesBridge, _testOnly_SafeUrl} from './safe-types-util';
suite('safe-types-util tests', () => {
test('SafeUrl accepts valid urls', () => {
- function accepts(url) {
+ function accepts(url: string) {
const safeUrl = new _testOnly_SafeUrl(url);
assert.isOk(safeUrl);
assert.equal(url, safeUrl.toString());
@@ -35,8 +35,10 @@
});
test('SafeUrl rejects invalid urls', () => {
- function rejects(url) {
- assert.throws(() => { new _testOnly_SafeUrl(url); });
+ function rejects(url: string) {
+ assert.throws(() => {
+ new _testOnly_SafeUrl(url);
+ });
}
rejects('javascript://alert("evil");');
rejects('ftp:example.com');
@@ -44,13 +46,14 @@
});
suite('safeTypesBridge', () => {
- function acceptsString(value, type) {
- assert.equal(safeTypesBridge(value, type),
- value);
+ function acceptsString(value: string, type: string) {
+ assert.equal(safeTypesBridge(value, type), value);
}
- function rejects(value, type) {
- assert.throws(() => { safeTypesBridge(value, type); });
+ function rejects(value: unknown, type: string) {
+ assert.throws(() => {
+ safeTypesBridge(value, type);
+ });
}
test('accepts valid URL strings', () => {