Merge "Exclude unneeded ref prefixes when getting refs"
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 3dcee80..618621b 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -1319,17 +1319,6 @@
+
The default is false.
-[[change.largeChange]]change.largeChange::
-+
-Number of changed lines from which on a change is considered as a large
-change. The number of changed lines of a change is the sum of the lines
-that were inserted and deleted in the change.
-+
-The specified value is used to visualize the change sizes in the Web UI
-in change tables and user dashboards.
-+
-By default 500.
-
[[change.maxComments]]change.maxComments::
+
Maximum number of comments (regular plus robot) allowed per change. Additional
@@ -3423,9 +3412,9 @@
[[experiments]]
=== Section experiments
-This section covers experimental new features. Gerrit's frontend uses experiments
-to research new behavior. Once the research is done, the experimental feature
-either stays and the experimentation flag gets removed, or the feature as a whole
+This section covers experimental new features. Gerrit uses experiments
+to research new behavior in frontend and core backend. Once the research is done, the experimental
+feature either stays and the experimentation flag gets removed, or the feature as a whole
gets removed
[[experiments.enabled]]experiments.enabled::
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 9876b53..096b068 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -14,10 +14,11 @@
'POST /changes/'
--
-The change input link:#change-input[ChangeInput] entity must be provided in the
-request body. It is not allowed to create changes on refs/tags/* or Gerrit
-internal refs such as refs/changes/*, refs/meta/external-ids/*, refs/users/*,
-etc.. and the request would fail with `400 Bad Request` in this case.
+The change input link:#change-input[ChangeInput] entity must be
+provided in the request body. It is not allowed to create changes
+under `refs/tags/` or Gerrit internal ref namespaces such as
+`refs/changes/`, `refs/meta/external-ids/`, and `refs/users/`. The
+request would fail with `400 Bad Request` in this case.
To create a change the calling user must be allowed to
link:access-control.html#category_push_review[upload to code review].
diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt
index a62ed47..9764c8a 100644
--- a/Documentation/rest-api-config.txt
+++ b/Documentation/rest-api-config.txt
@@ -1552,9 +1552,6 @@
|`allow_blame` |not set if `false`|
link:config-gerrit.html#change.allowBlame[Whether blame on side by side diff is
allowed].
-|`large_change` ||
-link:config-gerrit.html#change.largeChange[Number of changed lines from
-which on a change is considered as a large change].
|`reply_label` ||
link:config-gerrit.html#change.replyTooltip[Label name for the reply
button].
diff --git a/java/com/google/gerrit/acceptance/GerritServer.java b/java/com/google/gerrit/acceptance/GerritServer.java
index b02dc87..f2cc9d1 100644
--- a/java/com/google/gerrit/acceptance/GerritServer.java
+++ b/java/com/google/gerrit/acceptance/GerritServer.java
@@ -50,6 +50,7 @@
import com.google.gerrit.server.config.GerritRuntime;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePath;
+import com.google.gerrit.server.experiments.ConfigExperimentFeatures;
import com.google.gerrit.server.git.receive.AsyncReceiveCommits;
import com.google.gerrit.server.schema.JdbcAccountPatchReviewStore;
import com.google.gerrit.server.ssh.NoSshModule;
@@ -437,7 +438,8 @@
protected void configure() {
bind(GerritRuntime.class).toInstance(GerritRuntime.DAEMON);
}
- }));
+ },
+ new ConfigExperimentFeatures.Module()));
daemon.addAdditionalSysModuleForTesting(
new ReindexProjectsAtStartup.Module(), new ReindexGroupsAtStartup.Module());
daemon.start();
diff --git a/java/com/google/gerrit/entities/RefNames.java b/java/com/google/gerrit/entities/RefNames.java
index 4272960..2263aba 100644
--- a/java/com/google/gerrit/entities/RefNames.java
+++ b/java/com/google/gerrit/entities/RefNames.java
@@ -180,16 +180,6 @@
return ref.startsWith(REFS_CHANGES);
}
- /** True if the provided ref is in {@code refs/changes/../meta}. */
- public static boolean isRefsMetaChanges(String ref) {
- return ref.startsWith(REFS_CHANGES) && ref.endsWith(META_SUFFIX);
- }
-
- /** True if the provided ref is in {@code refs/changes/../robot-comments}. */
- public static boolean isRobotCommentMetaRef(String ref) {
- return ref.startsWith(REFS_CHANGES) && ref.endsWith(ROBOT_COMMENTS_SUFFIX);
- }
-
public static String refsGroups(AccountGroup.UUID groupUuid) {
return REFS_GROUPS + shardUuid(groupUuid.get());
}
diff --git a/java/com/google/gerrit/extensions/common/ChangeConfigInfo.java b/java/com/google/gerrit/extensions/common/ChangeConfigInfo.java
index a441bfd..b387017 100644
--- a/java/com/google/gerrit/extensions/common/ChangeConfigInfo.java
+++ b/java/com/google/gerrit/extensions/common/ChangeConfigInfo.java
@@ -19,7 +19,6 @@
public Boolean allowBlame;
public Boolean showAssigneeInChangesTable;
public Boolean disablePrivateChanges;
- public int largeChange;
public String replyLabel;
public String replyTooltip;
public int updateDelay;
diff --git a/java/com/google/gerrit/httpd/raw/IndexHtmlUtil.java b/java/com/google/gerrit/httpd/raw/IndexHtmlUtil.java
index 46dde41..8d52f5a 100644
--- a/java/com/google/gerrit/httpd/raw/IndexHtmlUtil.java
+++ b/java/com/google/gerrit/httpd/raw/IndexHtmlUtil.java
@@ -20,7 +20,6 @@
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.UsedAt;
@@ -31,6 +30,7 @@
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.json.OutputFormat;
+import com.google.gerrit.server.experiments.ExperimentFeatures;
import com.google.gson.Gson;
import com.google.template.soy.data.SanitizedContent;
import java.net.URI;
@@ -38,21 +38,15 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
-import org.eclipse.jgit.lib.Config;
/** Helper for generating parts of {@code index.html}. */
@UsedAt(Project.GOOGLE)
public class IndexHtmlUtil {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- static final ImmutableSet<String> DEFAULT_EXPERIMENTS =
- ImmutableSet.of(
- "UiFeature__patchset_comments", "UiFeature__patchset_choice_for_comment_links");
-
private static final Gson GSON = OutputFormat.JSON_COMPACT.newGson();
/**
* Returns both static and dynamic parameters of {@code index.html}. The result is to be used when
@@ -60,7 +54,7 @@
*/
public static ImmutableMap<String, Object> templateData(
GerritApi gerritApi,
- Config gerritServerConfig,
+ ExperimentFeatures experimentFeatures,
String canonicalURL,
String cdnPath,
String faviconPath,
@@ -73,14 +67,8 @@
staticTemplateData(
canonicalURL, cdnPath, faviconPath, urlParameterMap, urlInScriptTagOrdainer))
.putAll(dynamicTemplateData(gerritApi, requestedURL));
+ Set<String> enabledExperiments = experimentFeatures.getEnabledExperimentFeatures();
- Set<String> enabledExperiments = new HashSet<>();
- Arrays.stream(gerritServerConfig.getStringList("experiments", null, "enabled"))
- .forEach(enabledExperiments::add);
- DEFAULT_EXPERIMENTS.forEach(enabledExperiments::add);
- Arrays.stream(gerritServerConfig.getStringList("experiments", null, "disabled"))
- .forEach(enabledExperiments::remove);
- experimentData(urlParameterMap).forEach(enabledExperiments::add);
if (!enabledExperiments.isEmpty()) {
data.put("enabledExperiments", serializeObject(GSON, enabledExperiments).toString());
}
diff --git a/java/com/google/gerrit/httpd/raw/IndexServlet.java b/java/com/google/gerrit/httpd/raw/IndexServlet.java
index b2bdf7c..3f2c202 100644
--- a/java/com/google/gerrit/httpd/raw/IndexServlet.java
+++ b/java/com/google/gerrit/httpd/raw/IndexServlet.java
@@ -22,6 +22,7 @@
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.api.GerritApi;
import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.server.experiments.ExperimentFeatures;
import com.google.template.soy.SoyFileSet;
import com.google.template.soy.data.SanitizedContent;
import com.google.template.soy.data.UnsafeSanitizedContentOrdainer;
@@ -34,7 +35,6 @@
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.eclipse.jgit.lib.Config;
public class IndexServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@@ -43,7 +43,7 @@
@Nullable private final String cdnPath;
@Nullable private final String faviconPath;
private final GerritApi gerritApi;
- private final Config gerritServerConfig;
+ private final ExperimentFeatures experimentFeatures;
private final SoySauce soySauce;
private final Function<String, SanitizedContent> urlOrdainer;
@@ -52,12 +52,12 @@
@Nullable String cdnPath,
@Nullable String faviconPath,
GerritApi gerritApi,
- Config gerritServerConfig) {
+ ExperimentFeatures experimentFeatures) {
this.canonicalUrl = canonicalUrl;
this.cdnPath = cdnPath;
this.faviconPath = faviconPath;
this.gerritApi = gerritApi;
- this.gerritServerConfig = gerritServerConfig;
+ this.experimentFeatures = experimentFeatures;
this.soySauce =
SoyFileSet.builder()
.add(Resources.getResource("com/google/gerrit/httpd/raw/PolyGerritIndexHtml.soy"))
@@ -79,7 +79,7 @@
ImmutableMap<String, Object> templateData =
IndexHtmlUtil.templateData(
gerritApi,
- gerritServerConfig,
+ experimentFeatures,
canonicalUrl,
cdnPath,
faviconPath,
diff --git a/java/com/google/gerrit/httpd/raw/StaticModule.java b/java/com/google/gerrit/httpd/raw/StaticModule.java
index 66e107b..cac716f 100644
--- a/java/com/google/gerrit/httpd/raw/StaticModule.java
+++ b/java/com/google/gerrit/httpd/raw/StaticModule.java
@@ -30,6 +30,7 @@
import com.google.gerrit.server.config.GerritOptions;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths;
+import com.google.gerrit.server.experiments.ExperimentFeatures;
import com.google.inject.Inject;
import com.google.inject.Key;
import com.google.inject.Provides;
@@ -221,11 +222,12 @@
HttpServlet getPolyGerritUiIndexServlet(
@CanonicalWebUrl @Nullable String canonicalUrl,
@GerritServerConfig Config cfg,
- GerritApi gerritApi) {
+ GerritApi gerritApi,
+ ExperimentFeatures experimentFeatures) {
String cdnPath =
options.useDevCdn() ? options.devCdn() : cfg.getString("gerrit", null, "cdnPath");
String faviconPath = cfg.getString("gerrit", null, "faviconPath");
- return new IndexServlet(canonicalUrl, cdnPath, faviconPath, gerritApi, cfg);
+ return new IndexServlet(canonicalUrl, cdnPath, faviconPath, gerritApi, experimentFeatures);
}
@Provides
diff --git a/java/com/google/gerrit/pgm/util/SiteProgram.java b/java/com/google/gerrit/pgm/util/SiteProgram.java
index 98558fb..c3be0a4 100644
--- a/java/com/google/gerrit/pgm/util/SiteProgram.java
+++ b/java/com/google/gerrit/pgm/util/SiteProgram.java
@@ -28,6 +28,7 @@
import com.google.gerrit.server.config.GerritRuntime;
import com.google.gerrit.server.config.GerritServerConfigModule;
import com.google.gerrit.server.config.SitePath;
+import com.google.gerrit.server.experiments.ConfigExperimentFeatures;
import com.google.gerrit.server.git.GitRepositoryManagerModule;
import com.google.gerrit.server.git.SystemReaderInstaller;
import com.google.gerrit.server.schema.SchemaModule;
@@ -128,6 +129,9 @@
modules.add(new SchemaModule());
modules.add(cfgInjector.getInstance(GitRepositoryManagerModule.class));
+ // The only implementation of experiments is available in all programs that can use
+ // gerrit.config
+ modules.add(new ConfigExperimentFeatures.Module());
try {
return Guice.createInjector(
diff --git a/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java b/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
index 36d48033..573f2f5 100644
--- a/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
+++ b/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
@@ -106,7 +106,7 @@
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevWalk;
-class RevisionApiImpl implements RevisionApi {
+class RevisionApiImpl extends RevisionApi.NotImplemented {
interface Factory {
RevisionApiImpl create(RevisionResource r);
}
@@ -687,11 +687,6 @@
}
@Override
- public String etag() throws RestApiException {
- return revisionActions.getETag(revision);
- }
-
- @Override
public BinaryResult getArchive(ArchiveFormat format) throws RestApiException {
GetArchive getArchive = getArchiveProvider.get();
getArchive.setFormat(format != null ? format.name().toLowerCase(Locale.US) : null);
diff --git a/java/com/google/gerrit/server/change/FileInfoJsonNewImpl.java b/java/com/google/gerrit/server/change/FileInfoJsonNewImpl.java
index ed046826..0d3dcff 100644
--- a/java/com/google/gerrit/server/change/FileInfoJsonNewImpl.java
+++ b/java/com/google/gerrit/server/change/FileInfoJsonNewImpl.java
@@ -89,8 +89,8 @@
FileDiffOutput fileDiff = fileDiffs.get(path);
FileInfo fileInfo = new FileInfo();
fileInfo.status =
- fileDiff.changeType().get() != Patch.ChangeType.MODIFIED
- ? fileDiff.changeType().get().getCode()
+ fileDiff.changeType() != Patch.ChangeType.MODIFIED
+ ? fileDiff.changeType().getCode()
: null;
fileInfo.oldPath = fileDiff.oldPath().orElse(null);
fileInfo.sizeDelta = fileDiff.sizeDelta();
diff --git a/java/com/google/gerrit/server/experiments/ConfigExperimentFeatures.java b/java/com/google/gerrit/server/experiments/ConfigExperimentFeatures.java
new file mode 100644
index 0000000..f526935
--- /dev/null
+++ b/java/com/google/gerrit/server/experiments/ConfigExperimentFeatures.java
@@ -0,0 +1,63 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.experiments;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.inject.AbstractModule;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import org.eclipse.jgit.lib.Config;
+
+/**
+ * An implementation of {@link ExperimentFeatures} that uses gerrit.config to evaluate the status of
+ * the feature.
+ */
+@Singleton
+public class ConfigExperimentFeatures implements ExperimentFeatures {
+
+ public static class Module extends AbstractModule {
+ @Override
+ protected void configure() {
+ bind(ExperimentFeatures.class).to(ConfigExperimentFeatures.class);
+ }
+ }
+
+ private ImmutableSet<String> enabledExperimentFeatures;
+
+ @Inject
+ public ConfigExperimentFeatures(@GerritServerConfig Config gerritServerConfig) {
+ Set<String> enabledExperiments = new HashSet<>();
+ Arrays.stream(gerritServerConfig.getStringList("experiments", null, "enabled"))
+ .forEach(enabledExperiments::add);
+ ExperimentFeaturesConstants.DEFAULT_ENABLED_FEATURES.forEach(enabledExperiments::add);
+ Arrays.stream(gerritServerConfig.getStringList("experiments", null, "disabled"))
+ .forEach(enabledExperiments::remove);
+ enabledExperimentFeatures = ImmutableSet.copyOf(enabledExperiments);
+ }
+
+ @Override
+ public boolean isFeatureEnabled(String featureFlag) {
+ return getEnabledExperimentFeatures().contains(featureFlag);
+ }
+
+ @Override
+ public ImmutableSet<String> getEnabledExperimentFeatures() {
+ return enabledExperimentFeatures;
+ }
+}
diff --git a/java/com/google/gerrit/server/experiments/ExperimentFeatures.java b/java/com/google/gerrit/server/experiments/ExperimentFeatures.java
new file mode 100644
index 0000000..dc9148a
--- /dev/null
+++ b/java/com/google/gerrit/server/experiments/ExperimentFeatures.java
@@ -0,0 +1,44 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.experiments;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Features that can be enabled/disabled on Gerrit (e. g. experiments to research new behavior in
+ * the current release).
+ *
+ * <p>It may depend on the implementation if the result is decided on the per-request basis or not,
+ * so the outcomes should not be persisted in {@link com.google.inject.Singleton}.
+ */
+public interface ExperimentFeatures {
+
+ /**
+ * Given the name of the feature, returns if it is enabled on the Gerrit server.
+ *
+ * <p>Depending on the implementation, it can be more efficient than filtering the results of
+ * {@link ExperimentFeatures#getEnabledExperimentFeatures}.
+ *
+ * @param featureFlag the name of the feature to test.
+ * @return if the feature is enabled.
+ */
+ boolean isFeatureEnabled(String featureFlag);
+
+ /**
+ * Returns the names of the features that are enabled on Gerrit instance (either by default or via
+ * gerrit.config).
+ */
+ ImmutableSet<String> getEnabledExperimentFeatures();
+}
diff --git a/java/com/google/gerrit/server/experiments/ExperimentFeaturesConstants.java b/java/com/google/gerrit/server/experiments/ExperimentFeaturesConstants.java
new file mode 100644
index 0000000..af49438
--- /dev/null
+++ b/java/com/google/gerrit/server/experiments/ExperimentFeaturesConstants.java
@@ -0,0 +1,28 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.experiments;
+
+import com.google.common.collect.ImmutableSet;
+
+/** Constants for Gerrit {@link ExperimentFeatures} */
+public class ExperimentFeaturesConstants {
+
+ /** Features that are known experiments and can be referenced in the code. */
+ public static String UI_FEATURE_PATCHSET_COMMENTS = "UiFeature__patchset_comments";
+
+ /** Features, enabled by default in the current release. */
+ public static final ImmutableSet<String> DEFAULT_ENABLED_FEATURES =
+ ImmutableSet.of(UI_FEATURE_PATCHSET_COMMENTS);
+}
diff --git a/java/com/google/gerrit/server/git/SearchingChangeCacheImpl.java b/java/com/google/gerrit/server/git/SearchingChangeCacheImpl.java
index c3d4777..fed6541 100644
--- a/java/com/google/gerrit/server/git/SearchingChangeCacheImpl.java
+++ b/java/com/google/gerrit/server/git/SearchingChangeCacheImpl.java
@@ -17,12 +17,10 @@
import com.google.auto.value.AutoValue;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
-import com.google.common.collect.ImmutableList;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.UsedAt;
import com.google.gerrit.entities.Change;
-import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.extensions.events.GitReferenceUpdatedListener;
@@ -44,7 +42,6 @@
import com.google.inject.name.Named;
import com.google.inject.util.Providers;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
@@ -99,10 +96,6 @@
@Nullable
abstract ReviewerSet reviewers();
-
- abstract Collection<PatchSet> patchSets();
-
- abstract ImmutableList<byte[]> refStates();
}
private final LoadingCache<Project.NameKey, List<CachedChange>> cache;
@@ -132,8 +125,6 @@
for (CachedChange cc : cached) {
ChangeData cd = changeDataFactory.create(cc.change());
cd.setReviewers(cc.reviewers());
- cd.setPatchSets(cc.patchSets());
- cd.setRefStates(cc.refStates());
cds.add(cd);
}
return Collections.unmodifiableList(cds);
@@ -169,17 +160,12 @@
List<ChangeData> cds =
queryProvider
.get()
- .setRequestedFields(
- ChangeField.CHANGE,
- ChangeField.REVIEWER,
- ChangeField.REF_STATE,
- ChangeField.PATCH_SET)
+ .setRequestedFields(ChangeField.CHANGE, ChangeField.REVIEWER)
.byProject(key);
List<CachedChange> result = new ArrayList<>(cds.size());
for (ChangeData cd : cds) {
result.add(
- new AutoValue_SearchingChangeCacheImpl_CachedChange(
- cd.change(), cd.reviewers(), cd.patchSets(), cd.getRefStates()));
+ new AutoValue_SearchingChangeCacheImpl_CachedChange(cd.change(), cd.reviewers()));
}
return Collections.unmodifiableList(result);
}
diff --git a/java/com/google/gerrit/server/mail/send/MailSoySauceProvider.java b/java/com/google/gerrit/server/mail/send/MailSoySauceProvider.java
index 1b58057..aade30f 100644
--- a/java/com/google/gerrit/server/mail/send/MailSoySauceProvider.java
+++ b/java/com/google/gerrit/server/mail/send/MailSoySauceProvider.java
@@ -113,6 +113,11 @@
private void addTemplate(SoyFileSet.Builder builder, String resourcePath, String name)
throws ProvisionException {
+ if (!resourcePath.endsWith("/")) {
+ resourcePath += "/";
+ }
+ String logicalPath = resourcePath + name;
+
// Load as a file in the mail templates directory if present.
Path tmpl = site.mail_dir.resolve(name);
if (Files.isRegularFile(tmpl)) {
@@ -125,14 +130,11 @@
throw new ProvisionException(
"Failed to read template file " + tmpl.toAbsolutePath().toString(), err);
}
- builder.add(content, tmpl.toAbsolutePath().toString());
+ builder.add(content, logicalPath);
return;
}
// Otherwise load the template as a resource.
- if (!resourcePath.endsWith("/")) {
- resourcePath += "/";
- }
- builder.add(Resources.getResource(resourcePath + name));
+ builder.add(Resources.getResource(logicalPath), logicalPath);
}
}
diff --git a/java/com/google/gerrit/server/patch/AutoMerger.java b/java/com/google/gerrit/server/patch/AutoMerger.java
index 2e0214c..fe915c5 100644
--- a/java/com/google/gerrit/server/patch/AutoMerger.java
+++ b/java/com/google/gerrit/server/patch/AutoMerger.java
@@ -67,6 +67,8 @@
* is that these refs should never be deleted.
*/
public class AutoMerger {
+ public static final String AUTO_MERGE_MSG_PREFIX = "Auto-merge of ";
+
@UsedAt(UsedAt.Project.GOOGLE)
public static boolean cacheAutomerge(Config cfg) {
return cfg.getBoolean("change", null, "cacheAutomerge", true);
@@ -198,7 +200,7 @@
cb.setAuthor(ident);
cb.setCommitter(ident);
cb.setTreeId(tree);
- cb.setMessage("Auto-merge of " + merge.name() + '\n');
+ cb.setMessage(AUTO_MERGE_MSG_PREFIX + merge.name() + '\n');
for (RevCommit p : merge.getParents()) {
cb.addParentId(p);
}
diff --git a/java/com/google/gerrit/server/patch/DiffOperations.java b/java/com/google/gerrit/server/patch/DiffOperations.java
index 1d8438e..8b90531 100644
--- a/java/com/google/gerrit/server/patch/DiffOperations.java
+++ b/java/com/google/gerrit/server/patch/DiffOperations.java
@@ -17,6 +17,7 @@
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Patch;
import com.google.gerrit.entities.Project;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import java.util.Map;
import org.eclipse.jgit.lib.ObjectId;
@@ -73,34 +74,47 @@
/**
* Returns the diff for a single file between a patchset commit against its parent or the
* auto-merge commit. For deleted files, the {@code fileName} parameter should contain the old
- * name of the file.
+ * name of the file. This method will return {@link FileDiffOutput#empty(String)} if the requested
+ * file identified by {@code fileName} has unchanged content or does not exist at both commits.
*
* @param project a project name representing a git repository.
* @param newCommit 20 bytes SHA-1 of the new commit used in the diff.
* @param parentNum integer specifying which parent to use as base. If null, the only parent will
* be used or the auto-merge if {@code newCommit} is a merge commit.
* @param fileName the file name for which the diff should be evaluated.
+ * @param whitespace preference controlling whitespace effect in diff computation.
* @return the diff for the single file between the two commits.
* @throws DiffNotAvailableException if an internal error occurred in Git while evaluating the
* diff, or if an exception happened while parsing the base commit.
*/
FileDiffOutput getModifiedFileAgainstParent(
- Project.NameKey project, ObjectId newCommit, @Nullable Integer parentNum, String fileName)
+ Project.NameKey project,
+ ObjectId newCommit,
+ @Nullable Integer parentNum,
+ String fileName,
+ @Nullable DiffPreferencesInfo.Whitespace whitespace)
throws DiffNotAvailableException;
/**
* Returns the diff for a single file between two patchset commits. For deleted files, the {@code
- * fileName} parameter should contain the old name of the file.
+ * fileName} parameter should contain the old name of the file. This method will return {@link
+ * FileDiffOutput#empty(String)} if the requested file identified by {@code fileName} has
+ * unchanged content or does not exist at both commits.
*
* @param project a project name representing a git repository.
* @param oldCommit 20 bytes SHA-1 of the old commit used in the diff.
* @param newCommit 20 bytes SHA-1 of the new commit used in the diff.
* @param fileName the file name for which the diff should be evaluated.
+ * @param whitespace preference controlling whitespace effect in diff computation.
* @return the diff for the single file between the two commits.
* @throws DiffNotAvailableException if an internal error occurred in Git while evaluating the
* diff.
*/
FileDiffOutput getModifiedFile(
- Project.NameKey project, ObjectId oldCommit, ObjectId newCommit, String fileName)
+ Project.NameKey project,
+ ObjectId oldCommit,
+ ObjectId newCommit,
+ String fileName,
+ @Nullable DiffPreferencesInfo.Whitespace whitespace)
throws DiffNotAvailableException;
}
diff --git a/java/com/google/gerrit/server/patch/DiffOperationsImpl.java b/java/com/google/gerrit/server/patch/DiffOperationsImpl.java
index 2d98d42..16bd135 100644
--- a/java/com/google/gerrit/server/patch/DiffOperationsImpl.java
+++ b/java/com/google/gerrit/server/patch/DiffOperationsImpl.java
@@ -25,6 +25,7 @@
import com.google.gerrit.entities.Patch;
import com.google.gerrit.entities.Patch.ChangeType;
import com.google.gerrit.entities.Project;
+import com.google.gerrit.extensions.client.DiffPreferencesInfo;
import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.server.patch.diff.ModifiedFilesCache;
@@ -55,6 +56,7 @@
private static final int RENAME_SCORE = 60;
private static final DiffAlgorithm DEFAULT_DIFF_ALGORITHM = DiffAlgorithm.HISTOGRAM;
+ private static final Whitespace DEFAULT_WHITESPACE = Whitespace.IGNORE_NONE;
private final ModifiedFilesCache modifiedFilesCache;
private final FileDiffCache fileDiffCache;
@@ -112,13 +114,18 @@
@Override
public FileDiffOutput getModifiedFileAgainstParent(
- Project.NameKey project, ObjectId newCommit, @Nullable Integer parent, String fileName)
+ Project.NameKey project,
+ ObjectId newCommit,
+ @Nullable Integer parent,
+ String fileName,
+ @Nullable DiffPreferencesInfo.Whitespace whitespace)
throws DiffNotAvailableException {
try {
DiffParameters diffParams = computeDiffParameters(project, newCommit, parent);
FileDiffCacheKey key =
- createFileDiffCacheKey(project, diffParams.baseCommit(), newCommit, fileName);
- return getModifiedFilesForKeys(ImmutableList.of(key)).get(fileName);
+ createFileDiffCacheKey(project, diffParams.baseCommit(), newCommit, fileName, whitespace);
+ Map<String, FileDiffOutput> result = getModifiedFilesForKeys(ImmutableList.of(key));
+ return result.containsKey(fileName) ? result.get(fileName) : FileDiffOutput.empty(fileName);
} catch (IOException e) {
throw new DiffNotAvailableException(
"Failed to evaluate the parent/base commit for commit " + newCommit, e);
@@ -127,10 +134,16 @@
@Override
public FileDiffOutput getModifiedFile(
- Project.NameKey project, ObjectId oldCommit, ObjectId newCommit, String fileName)
+ Project.NameKey project,
+ ObjectId oldCommit,
+ ObjectId newCommit,
+ String fileName,
+ @Nullable DiffPreferencesInfo.Whitespace whitespace)
throws DiffNotAvailableException {
- FileDiffCacheKey key = createFileDiffCacheKey(project, oldCommit, newCommit, fileName);
- return getModifiedFilesForKeys(ImmutableList.of(key)).get(fileName);
+ FileDiffCacheKey key =
+ createFileDiffCacheKey(project, oldCommit, newCommit, fileName, whitespace);
+ Map<String, FileDiffOutput> result = getModifiedFilesForKeys(ImmutableList.of(key));
+ return result.containsKey(fileName) ? result.get(fileName) : FileDiffOutput.empty(fileName);
}
private Map<String, FileDiffOutput> getModifiedFiles(
@@ -144,10 +157,14 @@
modifiedFilesCache.get(createModifiedFilesKey(project, oldCommit, newCommit));
List<FileDiffCacheKey> fileCacheKeys = new ArrayList<>();
- fileCacheKeys.add(createFileDiffCacheKey(project, oldCommit, newCommit, COMMIT_MSG));
+ fileCacheKeys.add(
+ createFileDiffCacheKey(
+ project, oldCommit, newCommit, COMMIT_MSG, /* whitespace= */ null));
if (cmp.isAgainstAutoMerge() || isMergeAgainstParent(cmp, project, newCommit)) {
- fileCacheKeys.add(createFileDiffCacheKey(project, oldCommit, newCommit, MERGE_LIST));
+ fileCacheKeys.add(
+ createFileDiffCacheKey(
+ project, oldCommit, newCommit, MERGE_LIST, /*whitespace = */ null));
}
if (diffParams.skipFiles() == null) {
@@ -160,7 +177,8 @@
newCommit,
entity.newPath().isPresent()
? entity.newPath().get()
- : entity.oldPath().get()))
+ : entity.oldPath().get(),
+ /* whitespace= */ null))
.forEach(fileCacheKeys::add);
}
return getModifiedFilesForKeys(fileCacheKeys);
@@ -178,7 +196,7 @@
if (fileDiffOutput.isEmpty() || allDueToRebase(fileDiffOutput)) {
continue;
}
- if (fileDiffOutput.changeType().get() == Patch.ChangeType.DELETED) {
+ if (fileDiffOutput.changeType() == ChangeType.DELETED) {
files.put(fileDiffOutput.oldPath().get(), fileDiffOutput);
} else {
files.put(fileDiffOutput.newPath().get(), fileDiffOutput);
@@ -189,8 +207,8 @@
private static boolean allDueToRebase(FileDiffOutput fileDiffOutput) {
return fileDiffOutput.allEditsDueToRebase()
- && (!(fileDiffOutput.changeType().get() == ChangeType.RENAMED
- || fileDiffOutput.changeType().get() == ChangeType.COPIED));
+ && (!(fileDiffOutput.changeType() == ChangeType.RENAMED
+ || fileDiffOutput.changeType() == ChangeType.COPIED));
}
private boolean isMergeAgainstParent(ComparisonType cmp, Project.NameKey project, ObjectId commit)
@@ -209,7 +227,12 @@
}
private static FileDiffCacheKey createFileDiffCacheKey(
- Project.NameKey project, ObjectId aCommit, ObjectId bCommit, String newPath) {
+ Project.NameKey project,
+ ObjectId aCommit,
+ ObjectId bCommit,
+ String newPath,
+ @Nullable Whitespace whitespace) {
+ whitespace = whitespace == null ? DEFAULT_WHITESPACE : whitespace;
return FileDiffCacheKey.builder()
.project(project)
.oldCommit(aCommit)
@@ -217,7 +240,7 @@
.newFilePath(newPath)
.renameScore(RENAME_SCORE)
.diffAlgorithm(DEFAULT_DIFF_ALGORITHM)
- .whitespace(Whitespace.IGNORE_NONE)
+ .whitespace(whitespace)
.build();
}
diff --git a/java/com/google/gerrit/server/patch/filediff/FileDiffCacheImpl.java b/java/com/google/gerrit/server/patch/filediff/FileDiffCacheImpl.java
index d945da3..63f311b 100644
--- a/java/com/google/gerrit/server/patch/filediff/FileDiffCacheImpl.java
+++ b/java/com/google/gerrit/server/patch/filediff/FileDiffCacheImpl.java
@@ -31,6 +31,7 @@
import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.patch.AutoMerger;
import com.google.gerrit.server.patch.ComparisonType;
import com.google.gerrit.server.patch.DiffNotAvailableException;
import com.google.gerrit.server.patch.DiffUtil;
@@ -184,7 +185,8 @@
return result.build();
}
- private ComparisonType getComparisonType(RevWalk rw, ObjectId oldCommitId, ObjectId newCommitId)
+ private ComparisonType getComparisonType(
+ RevWalk rw, ObjectReader reader, ObjectId oldCommitId, ObjectId newCommitId)
throws IOException {
RevCommit oldCommit = DiffUtil.getRevCommit(rw, oldCommitId);
RevCommit newCommit = DiffUtil.getRevCommit(rw, newCommitId);
@@ -193,7 +195,16 @@
return ComparisonType.againstParent(i + 1);
}
}
- if (newCommit.getParentCount() > 0) {
+ // TODO(ghareeb): it's not trivial to distinguish if diff with old commit is against another
+ // patchset or auto-merge. Looking at the commit message of old commit gives a strong
+ // signal that we are diffing against auto-merge, though not 100% accurate (e.g. if old commit
+ // has the auto-merge prefix in the commit message). A better resolution would be to move the
+ // COMMIT_MSG and MERGE_LIST evaluations outside of the diff cache. For more details, see
+ // discussion in
+ // https://gerrit-review.googlesource.com/c/gerrit/+/280519/6..18/java/com/google/gerrit/server/patch/FileDiffCache.java#b540
+ Text oldCommitMsgTxt = Text.forCommit(reader, oldCommit);
+ if (oldCommitMsgTxt.size() > 0
+ && oldCommitMsgTxt.getString(0).startsWith(AutoMerger.AUTO_MERGE_MSG_PREFIX)) {
return ComparisonType.againstAutoMerge();
}
return ComparisonType.againstOtherPatchSet();
@@ -206,7 +217,8 @@
FileDiffCacheKey key, ObjectReader reader, RevWalk rw, MagicPath magicPath) {
try {
RawTextComparator cmp = comparatorFor(key.whitespace());
- ComparisonType comparisonType = getComparisonType(rw, key.oldCommit(), key.newCommit());
+ ComparisonType comparisonType =
+ getComparisonType(rw, reader, key.oldCommit(), key.newCommit());
RevCommit aCommit =
comparisonType.isAgainstParentOrAutoMerge()
? null
@@ -288,7 +300,7 @@
return FileDiffOutput.builder()
.oldPath(FileHeaderUtil.getOldPath(fileHeader))
.newPath(FileHeaderUtil.getNewPath(fileHeader))
- .changeType(Optional.of(changeType))
+ .changeType(changeType)
.patchType(Optional.of(FileHeaderUtil.getPatchType(fileHeader)))
.headerLines(FileHeaderUtil.getHeaderLines(fileHeader))
.edits(
@@ -342,7 +354,7 @@
GitFileDiff mainGitDiff = allDiffs.mainDiff().gitDiff();
Long oldSize =
- mainGitDiff.oldPath().isPresent()
+ mainGitDiff.oldMode().isPresent() && mainGitDiff.oldPath().isPresent()
? new FileSizeEvaluator(reader, aTree)
.compute(
mainGitDiff.oldId(),
@@ -350,7 +362,7 @@
mainGitDiff.oldPath().get())
: 0;
Long newSize =
- mainGitDiff.newPath().isPresent()
+ mainGitDiff.newMode().isPresent() && mainGitDiff.newPath().isPresent()
? new FileSizeEvaluator(reader, bTree)
.compute(
mainGitDiff.newId(),
diff --git a/java/com/google/gerrit/server/patch/filediff/FileDiffOutput.java b/java/com/google/gerrit/server/patch/filediff/FileDiffOutput.java
index 46ce28b..3348033 100644
--- a/java/com/google/gerrit/server/patch/filediff/FileDiffOutput.java
+++ b/java/com/google/gerrit/server/patch/filediff/FileDiffOutput.java
@@ -47,7 +47,7 @@
public abstract Optional<String> newPath();
/** The change type of the underlying file, e.g. added, deleted, renamed, etc... */
- public abstract Optional<Patch.ChangeType> changeType();
+ public abstract Patch.ChangeType changeType();
/** The patch type of the underlying file, e.g. unified, binary , etc... */
public abstract Optional<Patch.PatchType> patchType();
@@ -95,10 +95,11 @@
}
/** Returns an entity representing an unchanged file between two commits. */
- static FileDiffOutput empty(String filePath) {
+ public static FileDiffOutput empty(String filePath) {
return builder()
.oldPath(Optional.empty())
.newPath(Optional.of(filePath))
+ .changeType(ChangeType.MODIFIED)
.headerLines(ImmutableList.of())
.edits(ImmutableList.of())
.size(0)
@@ -123,9 +124,7 @@
if (newPath().isPresent()) {
result += stringSize(newPath().get());
}
- if (changeType().isPresent()) {
- result += 4;
- }
+ result += 4; // changeType
if (patchType().isPresent()) {
result += 4;
}
@@ -145,7 +144,7 @@
public abstract Builder newPath(Optional<String> value);
- public abstract Builder changeType(Optional<ChangeType> value);
+ public abstract Builder changeType(ChangeType value);
public abstract Builder patchType(Optional<PatchType> value);
@@ -169,9 +168,6 @@
private static final FieldDescriptor NEW_PATH_DESCRIPTOR =
FileDiffOutputProto.getDescriptor().findFieldByNumber(2);
- private static final FieldDescriptor CHANGE_TYPE_DESCRIPTOR =
- FileDiffOutputProto.getDescriptor().findFieldByNumber(3);
-
private static final FieldDescriptor PATCH_TYPE_DESCRIPTOR =
FileDiffOutputProto.getDescriptor().findFieldByNumber(4);
@@ -182,6 +178,7 @@
.setSize(fileDiff.size())
.setSizeDelta(fileDiff.sizeDelta())
.addAllHeaderLines(fileDiff.headerLines())
+ .setChangeType(fileDiff.changeType().name())
.addAllEdits(
fileDiff.edits().stream()
.map(
@@ -206,10 +203,6 @@
builder.setNewPath(fileDiff.newPath().get());
}
- if (fileDiff.changeType().isPresent()) {
- builder.setChangeType(fileDiff.changeType().get().name());
- }
-
if (fileDiff.patchType().isPresent()) {
builder.setPatchType(fileDiff.patchType().get().name());
}
@@ -225,6 +218,7 @@
.size(proto.getSize())
.sizeDelta(proto.getSizeDelta())
.headerLines(proto.getHeaderLinesList().stream().collect(ImmutableList.toImmutableList()))
+ .changeType(ChangeType.valueOf(proto.getChangeType()))
.edits(
proto.getEditsList().stream()
.map(
@@ -244,9 +238,6 @@
if (proto.hasField(NEW_PATH_DESCRIPTOR)) {
builder.newPath(Optional.of(proto.getNewPath()));
}
- if (proto.hasField(CHANGE_TYPE_DESCRIPTOR)) {
- builder.changeType(Optional.of(Patch.ChangeType.valueOf(proto.getChangeType())));
- }
if (proto.hasField(PATCH_TYPE_DESCRIPTOR)) {
builder.patchType(Optional.of(Patch.PatchType.valueOf(proto.getPatchType())));
}
diff --git a/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiff.java b/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiff.java
index 81c0e5d..a01d447 100644
--- a/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiff.java
+++ b/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiff.java
@@ -77,7 +77,7 @@
.fileHeader(FileHeaderUtil.toString(fileHeader))
.oldPath(FileHeaderUtil.getOldPath(fileHeader))
.newPath(FileHeaderUtil.getNewPath(fileHeader))
- .changeType(Optional.of(FileHeaderUtil.getChangeType(fileHeader)))
+ .changeType(FileHeaderUtil.getChangeType(fileHeader))
.patchType(Optional.of(FileHeaderUtil.getPatchType(fileHeader)))
.oldMode(Optional.of(mapFileMode(diffEntry.getOldMode())))
.newMode(Optional.of(mapFileMode(diffEntry.getNewMode())))
@@ -96,6 +96,7 @@
.oldId(oldId)
.newId(newId)
.newPath(Optional.of(newFilePath))
+ .changeType(ChangeType.MODIFIED)
.edits(ImmutableList.of())
.fileHeader("")
.build();
@@ -126,7 +127,7 @@
public abstract Optional<Patch.FileMode> newMode();
/** The change type associated with the file. */
- public abstract Optional<ChangeType> changeType();
+ public abstract ChangeType changeType();
/** The patch type associated with the file. */
public abstract Optional<PatchType> patchType();
@@ -150,9 +151,7 @@
if (newPath().isPresent()) {
result += stringSize(newPath().get());
}
- if (changeType().isPresent()) {
- result += 4;
- }
+ result += 4;
if (patchType().isPresent()) {
result += 4;
}
@@ -188,7 +187,7 @@
public abstract Builder newMode(Optional<Patch.FileMode> value);
- public abstract Builder changeType(Optional<ChangeType> value);
+ public abstract Builder changeType(ChangeType value);
public abstract Builder patchType(Optional<PatchType> value);
@@ -223,7 +222,8 @@
GitFileDiffProto.newBuilder()
.setFileHeader(gitFileDiff.fileHeader())
.setOldId(idConverter.toByteString(gitFileDiff.oldId().toObjectId()))
- .setNewId(idConverter.toByteString(gitFileDiff.newId().toObjectId()));
+ .setNewId(idConverter.toByteString(gitFileDiff.newId().toObjectId()))
+ .setChangeType(gitFileDiff.changeType().name());
gitFileDiff
.edits()
.forEach(
@@ -246,9 +246,6 @@
if (gitFileDiff.newMode().isPresent()) {
builder.setNewMode(gitFileDiff.newMode().get().name());
}
- if (gitFileDiff.changeType().isPresent()) {
- builder.setChangeType(gitFileDiff.changeType().get().name());
- }
if (gitFileDiff.patchType().isPresent()) {
builder.setPatchType(gitFileDiff.patchType().get().name());
}
@@ -267,7 +264,8 @@
.collect(toImmutableList()))
.fileHeader(proto.getFileHeader())
.oldId(AbbreviatedObjectId.fromObjectId(idConverter.fromByteString(proto.getOldId())))
- .newId(AbbreviatedObjectId.fromObjectId(idConverter.fromByteString(proto.getNewId())));
+ .newId(AbbreviatedObjectId.fromObjectId(idConverter.fromByteString(proto.getNewId())))
+ .changeType(ChangeType.valueOf(proto.getChangeType()));
if (proto.hasField(OLD_PATH_DESCRIPTOR)) {
builder.oldPath(Optional.of(proto.getOldPath()));
@@ -281,9 +279,6 @@
if (proto.hasField(NEW_MODE_DESCRIPTOR)) {
builder.newMode(Optional.of(Patch.FileMode.valueOf(proto.getNewMode())));
}
- if (proto.hasField(CHANGE_TYPE_DESCRIPTOR)) {
- builder.changeType(Optional.of(Patch.ChangeType.valueOf(proto.getChangeType())));
- }
if (proto.hasField(PATCH_TYPE_DESCRIPTOR)) {
builder.patchType(Optional.of(Patch.PatchType.valueOf(proto.getPatchType())));
}
diff --git a/java/com/google/gerrit/server/permissions/DefaultRefFilter.java b/java/com/google/gerrit/server/permissions/DefaultRefFilter.java
index 88f91be..5092e12 100644
--- a/java/com/google/gerrit/server/permissions/DefaultRefFilter.java
+++ b/java/com/google/gerrit/server/permissions/DefaultRefFilter.java
@@ -50,9 +50,7 @@
import java.util.stream.Collectors;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.ObjectIdRef;
import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.Ref.Storage;
import org.eclipse.jgit.lib.Repository;
class DefaultRefFilter {
@@ -129,15 +127,6 @@
"Project state %s permits read = %s",
projectState.getProject().getState(), projectState.statePermitsRead());
- // If we anyway always return all available (most recent) changes in the change index and cache,
- // we shouldn't care about refs/changes.
- if (opts.returnMostRecentRefChanges()) {
- refs =
- refs.stream()
- .filter(r -> !RefNames.isRefsChanges(r.getName()))
- .collect(Collectors.toList());
- }
-
// See if we can get away with a single, cheap ref evaluation.
if (refs.size() == 1) {
String refName = Iterables.getOnlyElement(refs).getName();
@@ -145,7 +134,7 @@
logger.atFinest().log("Filter out metadata ref %s", refName);
return ImmutableList.of();
}
- if (RefNames.isRefsChanges(refName) && !opts.returnMostRecentRefChanges()) {
+ if (RefNames.isRefsChanges(refName)) {
boolean isChangeRefVisisble = canSeeSingleChangeRef(refName);
if (isChangeRefVisisble) {
logger.atFinest().log("Change ref %s is visible", refName);
@@ -188,46 +177,10 @@
}
}
- if (opts.returnMostRecentRefChanges()) {
- visibleChangesCache.cachedVisibleChanges().keySet().stream()
- .forEach(c -> addAllChangeAndPatchsetRefs(visibleRefs, c));
- }
-
logger.atFinest().log("visible refs = %s", visibleRefs);
return visibleRefs;
}
- private void addAllChangeAndPatchsetRefs(Collection<Ref> refs, Change.Id changeId) {
- try {
- refs.add(
- new ObjectIdRef.PeeledNonTag(
- Storage.PACKED,
- RefNames.changeMetaRef(changeId),
- visibleChangesCache.getMetaId(changeId)));
- visibleChangesCache
- .getPatchSets(changeId)
- .forEach(
- p ->
- refs.add(
- new ObjectIdRef.PeeledNonTag(
- Storage.PACKED, RefNames.patchSetRef(p.id()), p.commitId())));
- if (visibleChangesCache.getRobotCommentsMetaId(changeId) != null) {
- refs.add(
- new ObjectIdRef.PeeledNonTag(
- Storage.PACKED,
- RefNames.robotCommentsRef(changeId),
- visibleChangesCache.getRobotCommentsMetaId(changeId)));
- }
- } catch (PermissionBackendException ex) {
- // this can't happen since the changes are all already in the cache, so we don't need to
- // perform permission checks at all to get those changes.
- throw new IllegalStateException(
- "this shouldn't happen since all permission checks should have been "
- + "done previously, exception: %s",
- ex);
- }
- }
-
/**
* Filters refs by visibility. Returns tags where visibility can't be trivially computed
* separately for later rev-walk-based visibility computation. Tags where visibility is trivial to
@@ -366,7 +319,7 @@
try {
// Default to READ_PRIVATE_CHANGES as there is no special permission for reading edits.
permissionBackendForProject
- .ref(visibleChangesCache.getChange(id).getDest().branch())
+ .ref(visibleChangesCache.getBranchNameKey(id).branch())
.check(RefPermission.READ_PRIVATE_CHANGES);
logger.atFinest().log("Foreign change edit ref is visible: %s", name);
return true;
diff --git a/java/com/google/gerrit/server/permissions/PermissionBackend.java b/java/com/google/gerrit/server/permissions/PermissionBackend.java
index 6b50228..27c6793 100644
--- a/java/com/google/gerrit/server/permissions/PermissionBackend.java
+++ b/java/com/google/gerrit/server/permissions/PermissionBackend.java
@@ -330,13 +330,6 @@
public abstract boolean filterMeta();
/**
- * Return all of the visible change refs that are available in the change index (which are the
- * most recent changes), even if they are not part of the List<Ref> passed. This allows the
- * caller not to send all the refs/changes.
- */
- public abstract boolean returnMostRecentRefChanges();
-
- /**
* Select only refs with names matching prefixes per {@link
* org.eclipse.jgit.lib.RefDatabase#getRefsByPrefix}.
*/
@@ -347,7 +340,6 @@
public static Builder builder() {
return new AutoValue_PermissionBackend_RefFilterOptions.Builder()
.setFilterMeta(false)
- .setReturnMostRecentRefChanges(false)
.setPrefixes(Collections.singletonList(""));
}
@@ -355,8 +347,6 @@
public abstract static class Builder {
public abstract Builder setFilterMeta(boolean val);
- public abstract Builder setReturnMostRecentRefChanges(boolean val);
-
public abstract Builder setPrefixes(List<String> prefixes);
public abstract RefFilterOptions build();
diff --git a/java/com/google/gerrit/server/permissions/VisibleChangesCache.java b/java/com/google/gerrit/server/permissions/VisibleChangesCache.java
index 926dde6..2e47576 100644
--- a/java/com/google/gerrit/server/permissions/VisibleChangesCache.java
+++ b/java/com/google/gerrit/server/permissions/VisibleChangesCache.java
@@ -16,18 +16,14 @@
import static com.google.common.collect.ImmutableList.toImmutableList;
-import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Multimap;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
+import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.entities.Change;
-import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.Project;
-import com.google.gerrit.entities.RefNames;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.restapi.AuthException;
-import com.google.gerrit.index.RefState;
import com.google.gerrit.server.git.SearchingChangeCacheImpl;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.notedb.ChangeNotes.Factory.ChangeNotesResult;
@@ -36,10 +32,8 @@
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import java.io.IOException;
-import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
-import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
/**
@@ -59,10 +53,7 @@
private final PermissionBackend.ForProject permissionBackendForProject;
private final Repository repository;
- private Map<Change.Id, Change> visibleChanges;
- private Map<Change.Id, ObjectId> metaIds = new HashMap<>();
- private Map<Change.Id, ObjectId> robotCommentsMetaIds = new HashMap<>();
- private Multimap<Change.Id, PatchSet> patchSets = HashMultimap.create();
+ private Map<Change.Id, BranchNameKey> visibleChanges;
@Inject
VisibleChangesCache(
@@ -92,7 +83,7 @@
* Returns the visible changes in the repository {@code repo}. If not cached, computes the visible
* changes and caches them.
*/
- public Map<Change.Id, Change> cachedVisibleChanges() throws PermissionBackendException {
+ public Map<Change.Id, BranchNameKey> cachedVisibleChanges() throws PermissionBackendException {
if (visibleChanges == null) {
if (changeCache == null) {
visibleChangesByScan();
@@ -105,46 +96,15 @@
}
/**
- * Returns the change for {@code changeId}. If not cached, computes *all* visible changes and
- * caches them before returning this specific change. If not visible or not found, returns null.
+ * Returns the {@code BranchNameKey} for {@code changeId}. If not cached, computes *all* visible
+ * changes and caches them before returning this specific change. If not visible or not found,
+ * returns {@code null}.
*/
@Nullable
- public Change getChange(Change.Id changeId) throws PermissionBackendException {
+ public BranchNameKey getBranchNameKey(Change.Id changeId) throws PermissionBackendException {
return cachedVisibleChanges().get(changeId);
}
- /**
- * Returns the change's meta id for {@code changeId}. If not cached, computes *all* visible
- * changes and caches them before returning this specific meta id. If not visible or not found,
- * returns null.
- */
- @Nullable
- public ObjectId getMetaId(Change.Id changeId) throws PermissionBackendException {
- cachedVisibleChanges();
- return metaIds.get(changeId);
- }
-
- /**
- * Returns the change's robot comment meta id for {@code changeId}. If not cached, computes *all*
- * visible changes and caches them before returning this specific robot comments meta id. If not
- * visible, not found or there are no robot comments on this change, returns null.
- */
- @Nullable
- public ObjectId getRobotCommentsMetaId(Change.Id changeId) throws PermissionBackendException {
- cachedVisibleChanges();
- return robotCommentsMetaIds.get(changeId);
- }
-
- /**
- * Returns the change's patch-sets for {@code changeId}. If not cached, computes *all* visible
- * changes and caches them before returning this collection of patch-sets. If not visible or not
- * found, returns an empty collection.
- */
- public Collection<PatchSet> getPatchSets(Change.Id changeId) throws PermissionBackendException {
- cachedVisibleChanges();
- return patchSets.get(changeId);
- }
-
private void visibleChangesBySearch() throws PermissionBackendException {
visibleChanges = new HashMap<>();
Project.NameKey project = projectState.getNameKey();
@@ -155,20 +115,7 @@
}
try {
permissionBackendForProject.change(cd).check(ChangePermission.READ);
- visibleChanges.put(cd.getId(), cd.change());
- Collection<RefState> refStates = RefState.parseStates(cd.getRefStates()).values();
- for (RefState refState : refStates) {
- if (RefNames.isRobotCommentMetaRef(refState.ref())) {
- if (!refState.id().equals(ObjectId.zeroId())) {
- robotCommentsMetaIds.put(cd.getId(), refState.id());
- }
- }
- if (RefNames.isRefsMetaChanges(refState.ref())) {
- metaIds.put(cd.getId(), refState.id());
- }
- }
- cd.patchSets().stream().forEach(ps -> patchSets.put(cd.getId(), ps));
-
+ visibleChanges.put(cd.getId(), cd.change().getDest());
} catch (AuthException e) {
// Do nothing.
}
@@ -194,14 +141,7 @@
for (ChangeNotesResult notesResult : changes) {
ChangeNotes notes = toNotes(notesResult);
if (notes != null) {
- visibleChanges.put(notes.getChangeId(), notes.getChange());
- metaIds.put(notes.getChangeId(), notes.getMetaId());
- if (notes.getRobotCommentNotes() != null
- && notes.getRobotCommentNotes().getMetaId() != null) {
- robotCommentsMetaIds.put(notes.getChangeId(), notes.getRobotCommentNotes().getMetaId());
- }
- notes.getPatchSets().values().stream()
- .forEach(ps -> patchSets.put(notes.getChangeId(), ps));
+ visibleChanges.put(notes.getChangeId(), notes.getChange().getDest());
}
}
}
diff --git a/java/com/google/gerrit/server/restapi/change/GetRevisionActions.java b/java/com/google/gerrit/server/restapi/change/GetRevisionActions.java
index c4da3b6..527129c 100644
--- a/java/com/google/gerrit/server/restapi/change/GetRevisionActions.java
+++ b/java/com/google/gerrit/server/restapi/change/GetRevisionActions.java
@@ -14,67 +14,26 @@
package com.google.gerrit.server.restapi.change;
-import com.google.common.hash.Hasher;
-import com.google.common.hash.Hashing;
-import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.common.ActionInfo;
-import com.google.gerrit.extensions.restapi.ETagView;
import com.google.gerrit.extensions.restapi.Response;
-import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.server.change.ActionJson;
-import com.google.gerrit.server.change.ChangeResource;
import com.google.gerrit.server.change.RevisionResource;
-import com.google.gerrit.server.config.GerritServerConfig;
-import com.google.gerrit.server.permissions.PermissionBackendException;
-import com.google.gerrit.server.query.change.ChangeData;
-import com.google.gerrit.server.submit.ChangeSet;
-import com.google.gerrit.server.submit.MergeSuperSet;
import com.google.inject.Inject;
-import com.google.inject.Provider;
import com.google.inject.Singleton;
-import java.io.IOException;
import java.util.Map;
-import org.eclipse.jgit.lib.Config;
@Singleton
-public class GetRevisionActions implements ETagView<RevisionResource> {
+public class GetRevisionActions implements RestReadView<RevisionResource> {
private final ActionJson delegate;
- private final Config config;
- private final Provider<MergeSuperSet> mergeSuperSet;
- private final ChangeResource.Factory changeResourceFactory;
@Inject
- GetRevisionActions(
- ActionJson delegate,
- Provider<MergeSuperSet> mergeSuperSet,
- ChangeResource.Factory changeResourceFactory,
- @GerritServerConfig Config config) {
+ GetRevisionActions(ActionJson delegate) {
this.delegate = delegate;
- this.mergeSuperSet = mergeSuperSet;
- this.changeResourceFactory = changeResourceFactory;
- this.config = config;
}
@Override
public Response<Map<String, ActionInfo>> apply(RevisionResource rsrc) {
return Response.withMustRevalidate(delegate.format(rsrc));
}
-
- @Override
- public String getETag(RevisionResource rsrc) {
- Hasher h = Hashing.murmur3_128().newHasher();
- CurrentUser user = rsrc.getUser();
- try {
- rsrc.getChangeResource().prepareETag(h, user);
- h.putBoolean(MergeSuperSet.wholeTopicEnabled(config));
- ChangeSet cs = mergeSuperSet.get().completeChangeSet(rsrc.getChange(), user);
- for (ChangeData cd : cs.changes()) {
- changeResourceFactory.create(cd.notes(), user).prepareETag(h, user);
- }
- h.putBoolean(cs.furtherHiddenChanges());
- } catch (IOException | PermissionBackendException e) {
- throw new StorageException(e);
- }
- return h.hash().toString();
- }
}
diff --git a/java/com/google/gerrit/server/restapi/config/GetServerInfo.java b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
index 780c60a..5459ede 100644
--- a/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
+++ b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
@@ -222,7 +222,6 @@
info.showAssigneeInChangesTable =
toBoolean(
config.getBoolean("change", "showAssigneeInChangesTable", false) && hasAssigneeInIndex);
- info.largeChange = config.getInt("change", "largeChange", 500);
info.replyTooltip =
Optional.ofNullable(config.getString("change", null, "replyTooltip"))
.orElse("Reply and score")
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/BUILD b/javatests/com/google/gerrit/acceptance/api/revision/BUILD
index 3bfe2f0..517b041 100644
--- a/javatests/com/google/gerrit/acceptance/api/revision/BUILD
+++ b/javatests/com/google/gerrit/acceptance/api/revision/BUILD
@@ -4,4 +4,12 @@
srcs = [f],
group = f[:f.index(".")],
labels = ["api"],
+ deps = [":revision-diff-it"],
) for f in glob(["*IT.java"])]
+
+# This is needed because RevisionDiffIT has subclasses that depend on it
+java_library(
+ name = "revision-diff-it",
+ srcs = ["RevisionDiffIT.java"],
+ deps = ["//java/com/google/gerrit/acceptance:lib"],
+)
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java
index b298497..68bb66c 100644
--- a/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java
@@ -42,7 +42,6 @@
import com.google.gerrit.extensions.common.FileInfo;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.BinaryResult;
-import com.google.gerrit.testing.ConfigSuite;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -55,7 +54,6 @@
import java.util.function.Function;
import java.util.stream.IntStream;
import javax.imageio.ImageIO;
-import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -66,7 +64,8 @@
public class RevisionDiffIT extends AbstractDaemonTest {
// @RunWith(Parameterized.class) can't be used as AbstractDaemonTest is annotated with another
// runner. Using different configs is a workaround to achieve the same.
- private static final String TEST_PARAMETER_MARKER = "test_only_parameter";
+ protected static final String TEST_PARAMETER_MARKER = "test_only_parameter";
+
private static final String CURRENT = "current";
private static final String FILE_NAME = "some_file.txt";
private static final String FILE_NAME2 = "another_file.txt";
@@ -83,20 +82,6 @@
private String changeId;
private String initialPatchSetId;
- @ConfigSuite.Config
- public static Config intralineConfig() {
- Config config = new Config();
- config.setBoolean(TEST_PARAMETER_MARKER, null, "intraline", true);
- return config;
- }
-
- @ConfigSuite.Config
- public static Config newDiffCacheConfig() {
- Config config = new Config();
- config.setBoolean("cache", "diff_cache", "useNewDiffCache", true);
- return config;
- }
-
@Before
public void setUp() throws Exception {
// Reduce flakiness of tests. (If tests aren't fast enough, we would use a fall-back
@@ -105,7 +90,7 @@
baseConfig.setString("cache", "diff_intraline", "timeout", "1 minute");
intraline = baseConfig.getBoolean(TEST_PARAMETER_MARKER, "intraline", false);
- useNewDiffCache = baseConfig.getBoolean("cache", "diff_cache", "useNewDiffCache", true);
+ useNewDiffCache = baseConfig.getBoolean("cache", "diff_cache", "useNewDiffCache", false);
ObjectId headCommit = testRepo.getRepository().resolve("HEAD");
commit1 =
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIntralineIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIntralineIT.java
new file mode 100644
index 0000000..ff4ac8e
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIntralineIT.java
@@ -0,0 +1,28 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.acceptance.api.revision;
+
+import com.google.gerrit.testing.ConfigSuite;
+import org.eclipse.jgit.lib.Config;
+
+/** Runs the {@link RevisionDiffIT} tests with the intraline config enabled. */
+public class RevisionDiffIntralineIT extends RevisionDiffIT {
+ @ConfigSuite.Default
+ public static Config intralineConfig() {
+ Config config = new Config();
+ config.setBoolean(TEST_PARAMETER_MARKER, null, "intraline", true);
+ return config;
+ }
+}
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
index 0d92c60..67e62dd 100644
--- a/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
@@ -88,15 +88,12 @@
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.BinaryResult;
-import com.google.gerrit.extensions.restapi.ETagView;
import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.extensions.webui.PatchSetWebLink;
-import com.google.gerrit.server.change.RevisionResource;
import com.google.gerrit.server.query.change.ChangeData;
-import com.google.gerrit.server.restapi.change.GetRevisionActions;
import com.google.gerrit.testing.FakeEmailSender;
import com.google.inject.Inject;
import java.io.ByteArrayOutputStream;
@@ -122,7 +119,6 @@
import org.junit.Test;
public class RevisionIT extends AbstractDaemonTest {
- @Inject private GetRevisionActions getRevisionActions;
@Inject private ProjectOperations projectOperations;
@Inject private RequestScopeOperations requestScopeOperations;
@Inject private ExtensionRegistry extensionRegistry;
@@ -1828,23 +1824,6 @@
}
@Test
- public void actionsETag() throws Exception {
- PushOneCommit.Result r1 = createChange();
- PushOneCommit.Result r2 = createChange();
-
- String oldETag = checkETag(getRevisionActions, r2, null);
- current(r2).review(ReviewInput.approve());
- oldETag = checkETag(getRevisionActions, r2, oldETag);
-
- // Dependent change is included in ETag.
- current(r1).review(ReviewInput.approve());
- oldETag = checkETag(getRevisionActions, r2, oldETag);
-
- current(r2).submit();
- checkETag(getRevisionActions, r2, oldETag);
- }
-
- @Test
public void deleteVoteOnNonCurrentPatchSet() throws Exception {
PushOneCommit.Result r = createChange(); // patch set 1
gApi.changes().id(r.getChangeId()).revision(r.getCommit().name()).review(ReviewInput.approve());
@@ -2015,13 +1994,6 @@
return gApi.changes().id(r.getChangeId()).current();
}
- private String checkETag(ETagView<RevisionResource> view, PushOneCommit.Result r, String oldETag)
- throws Exception {
- String eTag = view.getETag(parseRevisionResource(r));
- assertThat(eTag).isNotEqualTo(oldETag);
- return eTag;
- }
-
private PushOneCommit.Result createCherryPickableMerge(
String parent1FileName, String parent2FileName) throws Exception {
RevCommit initialCommit = getHead(repo(), "HEAD");
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionNewDiffCacheIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionNewDiffCacheIT.java
new file mode 100644
index 0000000..4b85c30
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/api/revision/RevisionNewDiffCacheIT.java
@@ -0,0 +1,31 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.acceptance.api.revision;
+
+import com.google.gerrit.testing.ConfigSuite;
+import org.eclipse.jgit.lib.Config;
+
+/**
+ * Runs the {@link RevisionDiffIT} tests with the new diff cache. This is temporary until the new
+ * diff cache is fully deployed. The new diff cache will become the default in the future.
+ */
+public class RevisionNewDiffCacheIT extends RevisionDiffIT {
+ @ConfigSuite.Default
+ public static Config newDiffCacheConfig() {
+ Config config = new Config();
+ config.setBoolean("cache", "diff_cache", "useNewDiffCache", true);
+ return config;
+ }
+}
diff --git a/javatests/com/google/gerrit/acceptance/git/RefAdvertisementIT.java b/javatests/com/google/gerrit/acceptance/git/RefAdvertisementIT.java
index 5699a04..b7acbe2 100644
--- a/javatests/com/google/gerrit/acceptance/git/RefAdvertisementIT.java
+++ b/javatests/com/google/gerrit/acceptance/git/RefAdvertisementIT.java
@@ -45,7 +45,6 @@
import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.extensions.api.changes.DraftInput;
-import com.google.gerrit.extensions.api.changes.ReviewInput.RobotCommentInput;
import com.google.gerrit.extensions.api.groups.GroupInput;
import com.google.gerrit.extensions.api.projects.BranchInput;
import com.google.gerrit.extensions.restapi.RestApiException;
@@ -59,7 +58,6 @@
import com.google.gerrit.server.permissions.PermissionBackend.RefFilterOptions;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.testing.ConfigSuite;
-import com.google.gerrit.testing.TestCommentHelper;
import com.google.inject.Inject;
import java.util.ArrayList;
import java.util.Arrays;
@@ -88,7 +86,6 @@
@Inject private PermissionBackend permissionBackend;
@Inject private ProjectOperations projectOperations;
@Inject private RequestScopeOperations requestScopeOperations;
- @Inject private TestCommentHelper testCommentHelper;
private AccountGroup.UUID admins;
private AccountGroup.UUID nonInteractiveUsers;
@@ -1426,258 +1423,6 @@
}
@Test
- public void advertiseMostRecentRefChangesEvenWhenNotInInputWithRefStarPermission()
- throws Exception {
- // admin has refs/* permission.
- requestScopeOperations.setApiUser(admin.id());
-
- try (Repository repo = repoManager.openRepository(project)) {
- PermissionBackend.ForProject forProject = newFilter(project, admin);
- assertThat(
- names(
- forProject.filter(
- // set empty list of refs to filter
- new ArrayList<>(),
- repo,
- RefFilterOptions.builder().setReturnMostRecentRefChanges(true).build())))
- // all the change refs are still returned since returnMostRecentRefChanges = true
- .containsExactlyElementsIn(
- ImmutableList.of(
- psRef1, metaRef1, psRef2, metaRef2, psRef3, metaRef3, psRef4, metaRef4));
- }
- }
-
- @Test
- public void advertiseMostRecentRefChangesEvenWhenNotInInputWithoutRefStarPermission()
- throws Exception {
- projectOperations
- .project(project)
- .forUpdate()
- .add(allow(Permission.READ).ref("refs/heads/master").group(REGISTERED_USERS))
- .update();
-
- // user doesn't have refs/* permission.
- requestScopeOperations.setApiUser(user.id());
-
- try (Repository repo = repoManager.openRepository(project)) {
- PermissionBackend.ForProject forProject = newFilter(project, admin);
- assertThat(
- names(
- forProject.filter(
- // set empty list of refs to filter
- new ArrayList<>(),
- repo,
- RefFilterOptions.builder().setReturnMostRecentRefChanges(true).build())))
- // all the change refs are still returned since returnMostRecentRefChanges = true
- .containsExactlyElementsIn(
- ImmutableList.of(
- psRef1, metaRef1, psRef2, metaRef2, psRef3, metaRef3, psRef4, metaRef4));
- }
- }
-
- @Test
- public void advertiseMostRecentRefChangesOnlyOnceWithRefStarPermission() throws Exception {
- // admin has refs/* permission.
- requestScopeOperations.setApiUser(admin.id());
-
- try (Repository repo = repoManager.openRepository(project)) {
- PermissionBackend.ForProject forProject = newFilter(project, admin);
- assertThat(
- names(
- forProject.filter(
- repo.getRefDatabase().getRefs(),
- repo,
- RefFilterOptions.builder().setReturnMostRecentRefChanges(true).build())))
- // all the change refs are still returned since returnMostRecentRefChanges = true. Make
- // sure they are only returned once.
- .containsExactlyElementsIn(
- ImmutableList.of(
- "HEAD",
- psRef1,
- metaRef1,
- psRef2,
- metaRef2,
- psRef3,
- metaRef3,
- psRef4,
- metaRef4,
- "refs/heads/branch",
- "refs/heads/master",
- "refs/meta/config",
- "refs/tags/branch-tag",
- "refs/tags/master-tag",
- "refs/tags/tree-tag"));
- }
- }
-
- @Test
- public void advertiseMostRecentRefChangesOnlyOnceWithoutRefStarPermission() throws Exception {
- projectOperations
- .project(project)
- .forUpdate()
- .add(allow(Permission.READ).ref("refs/heads/master").group(REGISTERED_USERS))
- .update();
-
- // user doesn't have refs/* permission.
- requestScopeOperations.setApiUser(user.id());
-
- try (Repository repo = repoManager.openRepository(project)) {
- PermissionBackend.ForProject forProject = newFilter(project, admin);
- assertThat(
- names(
- forProject.filter(
- repo.getRefDatabase().getRefs(),
- repo,
- RefFilterOptions.builder().setReturnMostRecentRefChanges(true).build())))
- // all the change refs are still returned since returnMostRecentRefChanges = true. Make
- // sure they are only returned once.
- .containsExactlyElementsIn(
- ImmutableList.of(
- "HEAD",
- psRef1,
- metaRef1,
- psRef2,
- metaRef2,
- psRef3,
- metaRef3,
- psRef4,
- metaRef4,
- "refs/heads/branch",
- "refs/heads/master",
- "refs/meta/config",
- "refs/tags/branch-tag",
- "refs/tags/master-tag",
- "refs/tags/tree-tag"));
- }
- }
-
- @Test
- public void advertiseMostRecentRefChangesWithSingleRequestedRefWithRefStarPermission()
- throws Exception {
- // admin has refs/* permission.
- requestScopeOperations.setApiUser(admin.id());
-
- try (Repository repo = repoManager.openRepository(project)) {
- PermissionBackend.ForProject forProject = newFilter(project, admin);
- assertThat(
- names(
- forProject.filter(
- ImmutableList.of(repo.exactRef("HEAD")),
- repo,
- RefFilterOptions.builder().setReturnMostRecentRefChanges(true).build())))
- // all the change refs are still returned since returnMostRecentRefChanges = true.
- .containsExactlyElementsIn(
- ImmutableList.of(
- "HEAD", psRef1, metaRef1, psRef2, metaRef2, psRef3, metaRef3, psRef4, metaRef4));
- }
- }
-
- @Test
- public void advertiseMostRecentRefChangesWithSingleRefRequetedWithoutRefStarPermission()
- throws Exception {
- projectOperations
- .project(project)
- .forUpdate()
- .add(allow(Permission.READ).ref("refs/heads/master").group(REGISTERED_USERS))
- .update();
-
- // user doesn't have refs/* permission.
- requestScopeOperations.setApiUser(user.id());
-
- try (Repository repo = repoManager.openRepository(project)) {
- PermissionBackend.ForProject forProject = newFilter(project, admin);
- assertThat(
- names(
- forProject.filter(
- ImmutableList.of(repo.exactRef("HEAD")),
- repo,
- RefFilterOptions.builder().setReturnMostRecentRefChanges(true).build())))
- // all the change refs are still returned since returnMostRecentRefChanges = true.
- .containsExactlyElementsIn(
- ImmutableList.of(
- "HEAD", psRef1, metaRef1, psRef2, metaRef2, psRef3, metaRef3, psRef4, metaRef4));
- }
- }
-
- @Test
- public void advertiseMostRecentRefChangesWithRobotCommentRef() throws Exception {
- projectOperations
- .project(project)
- .forUpdate()
- .add(allow(Permission.READ).ref("refs/heads/master").group(REGISTERED_USERS))
- .update();
-
- // user doesn't have refs/* permission.
- requestScopeOperations.setApiUser(user.id());
- RobotCommentInput input = TestCommentHelper.createRobotCommentInput(Patch.COMMIT_MSG);
- testCommentHelper.addRobotComment(cd1.getId(), input);
-
- try (Repository repo = repoManager.openRepository(project)) {
- PermissionBackend.ForProject forProject = newFilter(project, admin);
- assertThat(
- names(
- forProject.filter(
- repo.getRefDatabase().getRefs(),
- repo,
- RefFilterOptions.builder().setReturnMostRecentRefChanges(false).build())))
- .containsExactlyElementsIn(
- ImmutableList.of(
- "HEAD",
- RefNames.changeRefPrefix(cd1.getId()) + "robot-comments",
- psRef1,
- metaRef1,
- psRef2,
- metaRef2,
- psRef3,
- metaRef3,
- psRef4,
- metaRef4,
- "refs/heads/branch",
- "refs/heads/master",
- "refs/meta/config",
- "refs/tags/branch-tag",
- "refs/tags/master-tag",
- "refs/tags/tree-tag"));
- }
- }
-
- @Test
- public void advertiseMostRecentRefChangesWithRobotCommentRefWithReturnMostRecentRefChanges()
- throws Exception {
- projectOperations
- .project(project)
- .forUpdate()
- .add(allow(Permission.READ).ref("refs/heads/master").group(REGISTERED_USERS))
- .update();
-
- // user doesn't have refs/* permission.
- requestScopeOperations.setApiUser(user.id());
- RobotCommentInput input = TestCommentHelper.createRobotCommentInput(Patch.COMMIT_MSG);
- testCommentHelper.addRobotComment(cd1.getId(), input);
-
- try (Repository repo = repoManager.openRepository(project)) {
- PermissionBackend.ForProject forProject = newFilter(project, admin);
- assertThat(
- names(
- forProject.filter(
- ImmutableList.of(),
- repo,
- RefFilterOptions.builder().setReturnMostRecentRefChanges(true).build())))
- .containsExactlyElementsIn(
- ImmutableList.of(
- RefNames.changeRefPrefix(cd1.getId()) + "robot-comments",
- psRef1,
- metaRef1,
- psRef2,
- metaRef2,
- psRef3,
- metaRef3,
- psRef4,
- metaRef4));
- }
- }
-
- @Test
public void fetchSingleChangeWithoutIndexAccess() throws Exception {
PushOneCommit.Result change = createChange();
String patchSetRef = change.getPatchSetId().toRefName();
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/ActionsIT.java b/javatests/com/google/gerrit/acceptance/rest/change/ActionsIT.java
index c6a2819..e35f758 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/ActionsIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/ActionsIT.java
@@ -20,26 +20,20 @@
import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_REVISION;
import static com.google.gerrit.truth.MapSubject.assertThatMap;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.ExtensionRegistry;
import com.google.gerrit.acceptance.ExtensionRegistry.Registration;
import com.google.gerrit.acceptance.PushOneCommit;
-import com.google.gerrit.acceptance.TestProjectInput;
-import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.PatchSet;
-import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.api.changes.ActionVisitor;
import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.client.ListChangesOption;
-import com.google.gerrit.extensions.client.SubmitType;
import com.google.gerrit.extensions.common.ActionInfo;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.RevisionInfo;
import com.google.gerrit.server.change.RevisionJson;
-import com.google.gerrit.server.change.testing.TestChangeETagComputation;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.testing.ConfigSuite;
import com.google.inject.Inject;
@@ -56,7 +50,6 @@
return submitWholeTopicEnabledConfig();
}
- @Inject private RequestScopeOperations requestScopeOperations;
@Inject private RevisionJson.Factory revisionJsonFactory;
@Inject private ExtensionRegistry extensionRegistry;
@@ -68,10 +61,6 @@
return gApi.changes().id(id).get().actions;
}
- protected String getETag(String id) throws Exception {
- return gApi.changes().id(id).current().etag();
- }
-
@Test
public void changeActionOneMergedChangeHasOnlyNormalRevert() throws Exception {
String changeId = createChangeWithTopic().getChangeId();
@@ -138,124 +127,6 @@
}
@Test
- public void revisionActionsETag() throws Exception {
- String parent = createChange().getChangeId();
- String change = createChangeWithTopic().getChangeId();
- approve(change);
- String etag1 = getETag(change);
-
- approve(parent);
- String etag2 = getETag(change);
-
- String changeWithSameTopic = createChangeWithTopic().getChangeId();
- String etag3 = getETag(change);
-
- approve(changeWithSameTopic);
- String etag4 = getETag(change);
-
- if (isSubmitWholeTopicEnabled()) {
- assertThat(ImmutableList.of(etag1, etag2, etag3, etag4)).containsNoDuplicates();
- } else {
- assertThat(etag2).isNotEqualTo(etag1);
- assertThat(etag3).isEqualTo(etag2);
- assertThat(etag4).isEqualTo(etag2);
- }
- }
-
- @Test
- public void revisionActionsAnonymousETag() throws Exception {
- String parent = createChange().getChangeId();
- String change = createChangeWithTopic().getChangeId();
- approve(change);
-
- requestScopeOperations.setApiUserAnonymous();
- String etag1 = getETag(change);
-
- requestScopeOperations.setApiUser(admin.id());
- approve(parent);
-
- requestScopeOperations.setApiUserAnonymous();
- String etag2 = getETag(change);
-
- requestScopeOperations.setApiUser(admin.id());
- String changeWithSameTopic = createChangeWithTopic().getChangeId();
-
- requestScopeOperations.setApiUserAnonymous();
- String etag3 = getETag(change);
-
- requestScopeOperations.setApiUser(admin.id());
- approve(changeWithSameTopic);
-
- requestScopeOperations.setApiUserAnonymous();
- String etag4 = getETag(change);
-
- if (isSubmitWholeTopicEnabled()) {
- assertThat(ImmutableList.of(etag1, etag2, etag3, etag4)).containsNoDuplicates();
- } else {
- assertThat(etag2).isNotEqualTo(etag1);
- assertThat(etag3).isEqualTo(etag2);
- assertThat(etag4).isEqualTo(etag2);
- }
- }
-
- @Test
- @TestProjectInput(submitType = SubmitType.CHERRY_PICK)
- public void revisionActionsAnonymousETagCherryPickStrategy() throws Exception {
- String parent = createChange().getChangeId();
- String change = createChange().getChangeId();
- approve(change);
-
- requestScopeOperations.setApiUserAnonymous();
- String etag1 = getETag(change);
-
- requestScopeOperations.setApiUser(admin.id());
- approve(parent);
-
- requestScopeOperations.setApiUserAnonymous();
- String etag2 = getETag(change);
- assertThat(etag2).isEqualTo(etag1);
- }
-
- @Test
- public void pluginCanContributeToETagComputation() throws Exception {
- String change = createChange().getChangeId();
- String oldETag = getETag(change);
-
- try (Registration registration =
- extensionRegistry.newRegistration().add(TestChangeETagComputation.withETag("foo"))) {
- assertThat(getETag(change)).isNotEqualTo(oldETag);
- }
-
- assertThat(getETag(change)).isEqualTo(oldETag);
- }
-
- @Test
- public void returningNullFromETagComputationDoesNotBreakGerrit() throws Exception {
- String change = createChange().getChangeId();
- String oldETag = getETag(change);
-
- try (Registration registration =
- extensionRegistry.newRegistration().add(TestChangeETagComputation.withETag(null))) {
- assertThat(getETag(change)).isEqualTo(oldETag);
- }
- }
-
- @Test
- public void throwingExceptionFromETagComputationDoesNotBreakGerrit() throws Exception {
- String change = createChange().getChangeId();
- String oldETag = getETag(change);
-
- try (Registration registration =
- extensionRegistry
- .newRegistration()
- .add(
- TestChangeETagComputation.withException(
- new StorageException("exception during test")))) {
- assertThat(getETag(change)).isEqualTo(oldETag);
- }
- }
-
- @Test
public void revisionActionsTwoChangesInTopic_conflicting() throws Exception {
String changeId = createChangeWithTopic().getChangeId();
approve(changeId);
diff --git a/javatests/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java b/javatests/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java
index cef66654..0a84db4 100644
--- a/javatests/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/config/ServerInfoIT.java
@@ -58,7 +58,6 @@
@GerritConfig(name = "auth.httpPasswordUrl", value = "https://example.com/password")
// change
- @GerritConfig(name = "change.largeChange", value = "300")
@GerritConfig(name = "change.replyTooltip", value = "Publish votes and draft comments")
@GerritConfig(name = "change.replyLabel", value = "Vote")
@GerritConfig(name = "change.updateDelay", value = "50s")
@@ -102,7 +101,6 @@
assertThat(i.auth.httpPasswordUrl).isNull();
// change
- assertThat(i.change.largeChange).isEqualTo(300);
assertThat(i.change.replyTooltip).startsWith("Publish votes and draft comments");
assertThat(i.change.replyLabel).isEqualTo("Vote\u2026");
assertThat(i.change.updateDelay).isEqualTo(50);
@@ -170,7 +168,6 @@
assertThat(i.auth.httpPasswordUrl).isNull();
// change
- assertThat(i.change.largeChange).isEqualTo(500);
assertThat(i.change.replyTooltip).startsWith("Reply and score");
assertThat(i.change.replyLabel).isEqualTo("Reply\u2026");
assertThat(i.change.updateDelay).isEqualTo(300);
diff --git a/javatests/com/google/gerrit/acceptance/server/experiments/BUILD b/javatests/com/google/gerrit/acceptance/server/experiments/BUILD
new file mode 100644
index 0000000..0f01ffa
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/server/experiments/BUILD
@@ -0,0 +1,7 @@
+load("//javatests/com/google/gerrit/acceptance:tests.bzl", "acceptance_tests")
+
+acceptance_tests(
+ srcs = glob(["*IT.java"]),
+ group = "server_experiments",
+ labels = ["server"],
+)
diff --git a/javatests/com/google/gerrit/acceptance/server/experiments/ExperimentFeaturesIT.java b/javatests/com/google/gerrit/acceptance/server/experiments/ExperimentFeaturesIT.java
new file mode 100644
index 0000000..09e6dfe
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/server/experiments/ExperimentFeaturesIT.java
@@ -0,0 +1,77 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.acceptance.server.experiments;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.config.GerritConfig;
+import com.google.gerrit.server.experiments.ExperimentFeatures;
+import com.google.gerrit.server.experiments.ExperimentFeaturesConstants;
+import com.google.inject.Inject;
+import org.junit.Test;
+
+/** Tests for {@link ExperimentFeatures} */
+public class ExperimentFeaturesIT extends AbstractDaemonTest {
+
+ @Inject ExperimentFeatures experimentFeatures;
+
+ @Test
+ public void emptyConfig_defaultFeatures_enabled() {
+ for (String defaultFeature : ExperimentFeaturesConstants.DEFAULT_ENABLED_FEATURES) {
+ assertThat(experimentFeatures.isFeatureEnabled(defaultFeature)).isTrue();
+ }
+
+ assertThat(experimentFeatures.getEnabledExperimentFeatures())
+ .isEqualTo(ExperimentFeaturesConstants.DEFAULT_ENABLED_FEATURES);
+ }
+
+ @Test
+ @GerritConfig(
+ name = "experiments.enabled",
+ values = {"enabledFeature", "enabledThenDisabledFeature"})
+ @GerritConfig(
+ name = "experiments.disabled",
+ values = {"enabledThenDisabledFeature"})
+ public void configOverride_anyFeatureAllowed() {
+ assertThat(experimentFeatures.isFeatureEnabled("enabledFeature")).isTrue();
+ assertThat(experimentFeatures.isFeatureEnabled("enabledThenDisabledFeature")).isFalse();
+ assertThat(experimentFeatures.isFeatureEnabled("unknownFeature")).isFalse();
+ ImmutableSet<String> expectedEnabledFeatures =
+ new ImmutableSet.Builder<String>()
+ .addAll(ExperimentFeaturesConstants.DEFAULT_ENABLED_FEATURES)
+ .add("enabledFeature")
+ .build();
+ assertThat(experimentFeatures.getEnabledExperimentFeatures())
+ .isEqualTo(expectedEnabledFeatures);
+ }
+
+ @Test
+ @GerritConfig(
+ name = "experiments.enabled",
+ values = {"enabledFeature"})
+ @GerritConfig(
+ name = "experiments.disabled",
+ values = {"UiFeature__patchset_comments"})
+ public void configOverride_defaultFeatureDisabled() {
+ assertThat(experimentFeatures.isFeatureEnabled("enabledFeature")).isTrue();
+ assertThat(
+ experimentFeatures.isFeatureEnabled(
+ ExperimentFeaturesConstants.UI_FEATURE_PATCHSET_COMMENTS))
+ .isFalse();
+ assertThat(experimentFeatures.getEnabledExperimentFeatures()).containsExactly("enabledFeature");
+ }
+}
diff --git a/javatests/com/google/gerrit/httpd/raw/IndexServletTest.java b/javatests/com/google/gerrit/httpd/raw/IndexServletTest.java
index ba9475f..634231f 100644
--- a/javatests/com/google/gerrit/httpd/raw/IndexServletTest.java
+++ b/javatests/com/google/gerrit/httpd/raw/IndexServletTest.java
@@ -15,19 +15,24 @@
package com.google.gerrit.httpd.raw;
import static com.google.common.truth.Truth.assertThat;
-import static java.util.stream.Collectors.joining;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import com.google.gerrit.extensions.api.GerritApi;
import com.google.gerrit.extensions.api.accounts.Accounts;
import com.google.gerrit.extensions.api.config.Config;
import com.google.gerrit.extensions.api.config.Server;
import com.google.gerrit.extensions.common.ServerInfo;
import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.server.experiments.ConfigExperimentFeatures;
+import com.google.gerrit.server.experiments.ExperimentFeatures;
+import com.google.gerrit.server.experiments.ExperimentFeaturesConstants;
import com.google.gerrit.util.http.testutil.FakeHttpServletRequest;
import com.google.gerrit.util.http.testutil.FakeHttpServletResponse;
+import java.util.ArrayList;
+import java.util.List;
import org.junit.Test;
public class IndexServletTest {
@@ -55,14 +60,19 @@
String testCdnPath = "bar-cdn";
String testFaviconURL = "zaz-url";
- String disabledDefault = IndexHtmlUtil.DEFAULT_EXPERIMENTS.asList().get(0);
+ // Pick any known experiment enabled by default;
+ String disabledDefault = ExperimentFeaturesConstants.UI_FEATURE_PATCHSET_COMMENTS;
+ assertThat(ExperimentFeaturesConstants.DEFAULT_ENABLED_FEATURES).contains(disabledDefault);
+
org.eclipse.jgit.lib.Config serverConfig = new org.eclipse.jgit.lib.Config();
serverConfig.setStringList(
"experiments", null, "enabled", ImmutableList.of("NewFeature", "DisabledFeature"));
serverConfig.setStringList(
"experiments", null, "disabled", ImmutableList.of("DisabledFeature", disabledDefault));
+ ExperimentFeatures experimentFeatures = new ConfigExperimentFeatures(serverConfig);
IndexServlet servlet =
- new IndexServlet(testCanonicalUrl, testCdnPath, testFaviconURL, gerritApi, serverConfig);
+ new IndexServlet(
+ testCanonicalUrl, testCdnPath, testFaviconURL, gerritApi, experimentFeatures);
FakeHttpServletResponse response = new FakeHttpServletResponse();
@@ -85,14 +95,17 @@
+ "\\x22\\/config\\/server\\/info\\x22: \\x7b\\x22default_theme\\x22:"
+ "\\x22my-default-theme\\x22\\x7d, \\x22\\/config\\/server\\/top-menus\\x22: "
+ "\\x5b\\x5d\\x7d');");
- String enabledDefaults =
- IndexHtmlUtil.DEFAULT_EXPERIMENTS.stream()
+ ImmutableSet<String> enabledDefaults =
+ ExperimentFeaturesConstants.DEFAULT_ENABLED_FEATURES.stream()
.filter(e -> !e.equals(disabledDefault))
- .collect(joining("\\x22,"));
+ .collect(ImmutableSet.toImmutableSet());
+ List<String> expectedEnabled = new ArrayList<>();
+ expectedEnabled.add("NewFeature");
+ expectedEnabled.addAll(enabledDefaults);
assertThat(output)
.contains(
- "window.ENABLED_EXPERIMENTS = JSON.parse('\\x5b\\x22NewFeature\\x22,\\x22"
- + enabledDefaults
+ "window.ENABLED_EXPERIMENTS = JSON.parse('\\x5b\\x22"
+ + String.join("\\x22,", expectedEnabled)
+ "\\x22\\x5d');</script>");
}
}
diff --git a/javatests/com/google/gerrit/server/cache/serialize/entities/FileDiffOutputSerializerTest.java b/javatests/com/google/gerrit/server/cache/serialize/entities/FileDiffOutputSerializerTest.java
index 4307954..44ea55a 100644
--- a/javatests/com/google/gerrit/server/cache/serialize/entities/FileDiffOutputSerializerTest.java
+++ b/javatests/com/google/gerrit/server/cache/serialize/entities/FileDiffOutputSerializerTest.java
@@ -37,7 +37,7 @@
FileDiffOutput.builder()
.oldPath(Optional.of("old_file_path.txt"))
.newPath(Optional.empty())
- .changeType(Optional.of(ChangeType.DELETED))
+ .changeType(ChangeType.DELETED)
.patchType(Optional.of(PatchType.UNIFIED))
.size(23)
.sizeDelta(10)
diff --git a/javatests/com/google/gerrit/server/cache/serialize/entities/GitFileDiffSerializerTest.java b/javatests/com/google/gerrit/server/cache/serialize/entities/GitFileDiffSerializerTest.java
index 8030818..93441a4 100644
--- a/javatests/com/google/gerrit/server/cache/serialize/entities/GitFileDiffSerializerTest.java
+++ b/javatests/com/google/gerrit/server/cache/serialize/entities/GitFileDiffSerializerTest.java
@@ -47,7 +47,7 @@
.newPath(Optional.empty())
.oldId(AbbreviatedObjectId.fromObjectId(OLD_ID))
.newId(AbbreviatedObjectId.fromObjectId(NEW_ID))
- .changeType(Optional.of(ChangeType.DELETED))
+ .changeType(ChangeType.DELETED)
.patchType(Optional.of(PatchType.UNIFIED))
.oldMode(Optional.of(FileMode.REGULAR_FILE))
.newMode(Optional.of(FileMode.REGULAR_FILE))
diff --git a/polygerrit-ui/app/api/admin.ts b/polygerrit-ui/app/api/admin.ts
new file mode 100644
index 0000000..a7b549d
--- /dev/null
+++ b/polygerrit-ui/app/api/admin.ts
@@ -0,0 +1,29 @@
+/**
+ * @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.
+ */
+
+/** Interface for menu link */
+export interface MenuLink {
+ text: string;
+ url: string;
+ capability: string | null;
+}
+
+export interface AdminPluginApi {
+ addMenuLink(text: string, url: string, capability?: string): void;
+
+ getMenuLinks(): MenuLink[];
+}
diff --git a/polygerrit-ui/app/api/annotation.ts b/polygerrit-ui/app/api/annotation.ts
new file mode 100644
index 0000000..c046b4f
--- /dev/null
+++ b/polygerrit-ui/app/api/annotation.ts
@@ -0,0 +1,130 @@
+/**
+ * @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 {CoverageRange, Side} from './diff';
+import {StyleObject} from './styles';
+
+export type AddLayerFunc = (ctx: AnnotationContext) => void;
+
+export type NotifyFunc = (
+ path: string,
+ start: number,
+ end: number,
+ side: Side
+) => void;
+
+export type CoverageProvider = (
+ changeNum: number,
+ path: string,
+ basePatchNum?: number,
+ patchNum?: number,
+ /**
+ * This is a ChangeInfo object as defined here:
+ * https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#change-info
+ * We neither want to repeat it nor add a dependency on it here.
+ */
+ change?: unknown
+) => Promise<Array<CoverageRange>>;
+
+export interface AnnotationContext {
+ /**
+ * Method to add annotations to a content line.
+ *
+ * @param offset The char offset where the update starts.
+ * @param length The number of chars that the update covers.
+ * @param styleObject The style object for the range.
+ * @param side The side of the update. ('left' or 'right')
+ */
+ annotateRange(
+ offset: number,
+ length: number,
+ styleObject: StyleObject,
+ side: string
+ ): void;
+
+ /**
+ * Method to add a CSS class to the line number TD element.
+ *
+ * @param styleObject The style object for the range.
+ * @param side The side of the update. ('left' or 'right')
+ */
+ annotateLineNumber(styleObject: StyleObject, side: string): void;
+}
+
+export interface AnnotationPluginApi {
+ /**
+ * Register a function to call to apply annotations. Plugins should use
+ * GrAnnotationActionsContext.annotateRange and
+ * GrAnnotationActionsContext.annotateLineNumber to apply a CSS class to the
+ * line content or the line number.
+ *
+ * @param addLayerFunc The function
+ * that will be called when the AnnotationLayer is ready to annotate.
+ */
+ addLayer(addLayerFunc: AddLayerFunc): AnnotationPluginApi;
+
+ /**
+ * The specified function will be called with a notify function for the plugin
+ * to call when it has all required data for annotation. Optional.
+ *
+ * @param notifyFunc See doc of the notify function below to see what it does.
+ */
+ addNotifier(notifyFunc: (n: NotifyFunc) => void): AnnotationPluginApi;
+
+ /**
+ * The specified function will be called when a gr-diff component is built,
+ * and feeds the returned coverage data into the diff. Optional.
+ *
+ * Be sure to call this only once and only from one plugin. Multiple coverage
+ * providers are not supported. A second call will just overwrite the
+ * provider of the first call.
+ */
+ setCoverageProvider(coverageProvider: CoverageProvider): AnnotationPluginApi;
+
+ /**
+ * Returns a checkbox HTMLElement that can be used to toggle annotations
+ * on/off. The checkbox will be initially disabled. Plugins should enable it
+ * when data is ready and should add a click handler to toggle CSS on/off.
+ *
+ * Note1: Calling this method from multiple plugins will only work for the
+ * 1st call. It will print an error message for all subsequent calls
+ * and will not invoke their onAttached functions.
+ * Note2: This method will be deprecated and eventually removed when
+ * https://bugs.chromium.org/p/gerrit/issues/detail?id=8077 is
+ * implemented.
+ *
+ * @param checkboxLabel Will be used as the label for the checkbox.
+ * Optional. "Enable" is used if this is not specified.
+ * @param onAttached The function that will be called
+ * when the checkbox is attached to the page.
+ */
+ enableToggleCheckbox(
+ checkboxLabel: string,
+ onAttached: (checkboxEl: Element | null) => void
+ ): AnnotationPluginApi;
+
+ /**
+ * The notify function will call the listeners of all required annotation
+ * layers. Intended to be called by the plugin when all required data for
+ * annotation is available.
+ *
+ * @param path The file path whose listeners should be notified.
+ * @param start The line where the update starts.
+ * @param end The line where the update ends.
+ * @param side The side of the update ('left' or 'right').
+ */
+ notify(path: string, start: number, end: number, side: Side): void;
+}
diff --git a/polygerrit-ui/app/api/attribute-helper.ts b/polygerrit-ui/app/api/attribute-helper.ts
new file mode 100644
index 0000000..cd52259
--- /dev/null
+++ b/polygerrit-ui/app/api/attribute-helper.ts
@@ -0,0 +1,39 @@
+/**
+ * @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.
+ */
+
+export interface AttributeHelperPluginApi {
+ /**
+ * Binds callback to property updates.
+ *
+ * @param name Property name.
+ * @return Unbind function.
+ */
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ bind(name: string, callback: (value: any) => void): () => any;
+
+ /**
+ * Get value of the property from wrapped object. Waits for the property
+ * to be initialized if it isn't defined.
+ */
+ get(name: string): Promise<unknown>;
+
+ /**
+ * Sets value and dispatches event to force notify.
+ */
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ set(name: string, value: any): void;
+}
diff --git a/polygerrit-ui/app/api/change-actions.ts b/polygerrit-ui/app/api/change-actions.ts
new file mode 100644
index 0000000..792f31e
--- /dev/null
+++ b/polygerrit-ui/app/api/change-actions.ts
@@ -0,0 +1,113 @@
+/**
+ * @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 {HttpMethod} from './rest';
+
+export interface ActionInfo {
+ method?: HttpMethod;
+ label?: string;
+ title?: string;
+ enabled?: boolean;
+}
+
+export enum ActionType {
+ CHANGE = 'change',
+ REVISION = 'revision',
+}
+
+export enum ActionPriority {
+ CHANGE = 2,
+ DEFAULT = 0,
+ PRIMARY = 3,
+ REVIEW = -3,
+ REVISION = 1,
+}
+
+export enum ChangeActions {
+ ABANDON = 'abandon',
+ DELETE = '/',
+ DELETE_EDIT = 'deleteEdit',
+ EDIT = 'edit',
+ FOLLOW_UP = 'followup',
+ IGNORE = 'ignore',
+ MOVE = 'move',
+ PRIVATE = 'private',
+ PRIVATE_DELETE = 'private.delete',
+ PUBLISH_EDIT = 'publishEdit',
+ REBASE = 'rebase',
+ REBASE_EDIT = 'rebaseEdit',
+ READY = 'ready',
+ RESTORE = 'restore',
+ REVERT = 'revert',
+ REVERT_SUBMISSION = 'revert_submission',
+ REVIEWED = 'reviewed',
+ STOP_EDIT = 'stopEdit',
+ SUBMIT = 'submit',
+ UNIGNORE = 'unignore',
+ UNREVIEWED = 'unreviewed',
+ WIP = 'wip',
+}
+
+export enum RevisionActions {
+ CHERRYPICK = 'cherrypick',
+ REBASE = 'rebase',
+ SUBMIT = 'submit',
+ DOWNLOAD = 'download',
+}
+
+export type PrimaryActionKey = ChangeActions | RevisionActions;
+
+export interface ChangeActionsPluginApi {
+ addPrimaryActionKey(key: PrimaryActionKey): void;
+
+ removePrimaryActionKey(key: string): void;
+
+ hideQuickApproveAction(): void;
+
+ setActionOverflow(type: ActionType, key: string, overflow: boolean): void;
+
+ setActionPriority(
+ type: ActionType,
+ key: string,
+ priority: ActionPriority
+ ): void;
+
+ setActionHidden(type: ActionType, key: string, hidden: boolean): void;
+
+ add(type: ActionType, label: string): string;
+
+ remove(key: string): void;
+
+ addTapListener(
+ key: string,
+ handler: EventListenerOrEventListenerObject
+ ): void;
+
+ removeTapListener(
+ key: string,
+ handler: EventListenerOrEventListenerObject
+ ): void;
+
+ setLabel(key: string, text: string): void;
+
+ setTitle(key: string, text: string): void;
+
+ setEnabled(key: string, enabled: boolean): void;
+
+ setIcon(key: string, icon: string): void;
+
+ getActionDetails(action: string): ActionInfo | undefined;
+}
diff --git a/polygerrit-ui/app/api/change-metadata.ts b/polygerrit-ui/app/api/change-metadata.ts
new file mode 100644
index 0000000..effe661
--- /dev/null
+++ b/polygerrit-ui/app/api/change-metadata.ts
@@ -0,0 +1,20 @@
+/**
+ * @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.
+ */
+
+export interface ChangeMetadataPluginApi {
+ onLabelsChanged(callback: (value: unknown) => void): ChangeMetadataPluginApi;
+}
diff --git a/polygerrit-ui/app/api/change-reply.ts b/polygerrit-ui/app/api/change-reply.ts
new file mode 100644
index 0000000..37c96ee
--- /dev/null
+++ b/polygerrit-ui/app/api/change-reply.ts
@@ -0,0 +1,39 @@
+/**
+ * @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.
+ */
+export interface LabelsChangedDetail {
+ name: string;
+ value: string;
+}
+export interface ValueChangedDetail {
+ value: string;
+}
+export type ReplyChangedCallback = (text: string) => void;
+export type LabelsChangedCallback = (detail: LabelsChangedDetail) => void;
+
+export interface ChangeReplyPluginApi {
+ getLabelValue(label: string): string;
+
+ setLabelValue(label: string, value: string): void;
+
+ send(includeComments?: boolean): void;
+
+ addReplyTextChangedCallback(handler: ReplyChangedCallback): void;
+
+ addLabelValuesChangedCallback(handler: LabelsChangedCallback): void;
+
+ showMessage(message: string): void;
+}
diff --git a/polygerrit-ui/app/api/checks.ts b/polygerrit-ui/app/api/checks.ts
index 87d7a2a..143fbd1 100644
--- a/polygerrit-ui/app/api/checks.ts
+++ b/polygerrit-ui/app/api/checks.ts
@@ -20,7 +20,7 @@
// Changes to all type and interfaces are expected.
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-export interface GrChecksApiInterface {
+export interface ChecksPluginApi {
/**
* Must only be called once. You cannot register twice. You cannot unregister.
*/
diff --git a/polygerrit-ui/app/api/event-helper.ts b/polygerrit-ui/app/api/event-helper.ts
new file mode 100644
index 0000000..c4a559b
--- /dev/null
+++ b/polygerrit-ui/app/api/event-helper.ts
@@ -0,0 +1,49 @@
+/**
+ * @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.
+ */
+export type UnsubscribeCallback = () => void;
+
+export interface EventHelperPluginApi {
+ /**
+ * Add a callback to arbitrary event.
+ * The callback may return false to prevent event bubbling.
+ */
+ on(event: string, callback: (event: Event) => boolean): UnsubscribeCallback;
+
+ /**
+ * Alias for @see onClick
+ */
+ onTap(callback: (event: Event) => boolean): UnsubscribeCallback;
+
+ /**
+ * Add a callback to element click or touch.
+ * The callback may return false to prevent event bubbling.
+ */
+ onClick(callback: (event: Event) => boolean): UnsubscribeCallback;
+
+ /**
+ * Alias for @see captureClick
+ */
+ captureTap(callback: (event: Event) => boolean): UnsubscribeCallback;
+
+ /**
+ * Add a callback to element click or touch ahead of normal flow.
+ * Callback is installed on parent during capture phase.
+ * https://www.w3.org/TR/DOM-Level-3-Events/#event-flow
+ * The callback may return false to cancel regular event listeners.
+ */
+ captureClick(callback: (event: Event) => boolean): UnsubscribeCallback;
+}
diff --git a/polygerrit-ui/app/api/hook.ts b/polygerrit-ui/app/api/hook.ts
new file mode 100644
index 0000000..179b967
--- /dev/null
+++ b/polygerrit-ui/app/api/hook.ts
@@ -0,0 +1,52 @@
+/**
+ * @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.
+ */
+interface GerritElementExtensions {
+ content?: HTMLElement & {hidden?: boolean};
+ change?: unknown;
+ revision?: unknown;
+ token?: string;
+ repoName?: string;
+ /**
+ * This is a ConfigInfo object as defined here:
+ * https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#config-info
+ * We neither want to repeat it nor add a dependency on it here.
+ */
+ config?: unknown;
+}
+
+export type HookCallback = (el: HTMLElement & GerritElementExtensions) => void;
+
+export interface RegisterOptions {
+ slot?: string;
+ replace: unknown;
+}
+
+export interface HookApi {
+ onAttached(callback: HookCallback): HookApi;
+
+ onDetached(callback: HookCallback): HookApi;
+
+ getAllAttached(): HTMLElement[];
+
+ getLastAttached(): Promise<HTMLElement>;
+
+ getModuleName(): string;
+
+ handleInstanceDetached(instance: HTMLElement): void;
+
+ handleInstanceAttached(instance: HTMLElement): void;
+}
diff --git a/polygerrit-ui/app/api/plugin.ts b/polygerrit-ui/app/api/plugin.ts
new file mode 100644
index 0000000..cd742a2
--- /dev/null
+++ b/polygerrit-ui/app/api/plugin.ts
@@ -0,0 +1,92 @@
+/**
+ * @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 {AdminPluginApi} from './admin';
+import {AnnotationPluginApi} from './annotation';
+import {AttributeHelperPluginApi} from './attribute-helper';
+import {ChangeMetadataPluginApi} from './change-metadata';
+import {ChangeReplyPluginApi} from './change-reply';
+import {ChecksPluginApi} from './checks';
+import {EventHelperPluginApi} from './event-helper';
+import {PopupPluginApi} from './popup';
+import {RepoPluginApi} from './repo';
+import {ReportingPluginApi} from './reporting';
+import {SettingsPluginApi} from './settings';
+import {StylesPluginApi} from './styles';
+import {ThemePluginApi} from './theme';
+import {ChangeActionsPluginApi} from './change-actions';
+import {RestPluginApi} from './rest';
+import {HookApi, RegisterOptions} from './hook';
+
+export enum TargetElement {
+ CHANGE_ACTIONS = 'changeactions',
+ REPLY_DIALOG = 'replydialog',
+}
+
+// Note: for new events, naming convention should be: `a-b`
+export enum EventType {
+ HISTORY = 'history',
+ LABEL_CHANGE = 'labelchange',
+ SHOW_CHANGE = 'showchange',
+ SUBMIT_CHANGE = 'submitchange',
+ SHOW_REVISION_ACTIONS = 'show-revision-actions',
+ COMMIT_MSG_EDIT = 'commitmsgedit',
+ COMMENT = 'comment',
+ REVERT = 'revert',
+ REVERT_SUBMISSION = 'revert_submission',
+ POST_REVERT = 'postrevert',
+ ANNOTATE_DIFF = 'annotatediff',
+ ADMIN_MENU_LINKS = 'admin-menu-links',
+ HIGHLIGHTJS_LOADED = 'highlightjs-loaded',
+}
+
+export interface PluginApi {
+ _url?: URL;
+ admin(): AdminPluginApi;
+ annotationApi(): AnnotationPluginApi;
+ attributeHelper(element: Element): AttributeHelperPluginApi;
+ changeActions(): ChangeActionsPluginApi;
+ changeMetadata(): ChangeMetadataPluginApi;
+ changeReply(): ChangeReplyPluginApi;
+ checks(): ChecksPluginApi;
+ eventHelper(element: Node): EventHelperPluginApi;
+ getPluginName(): string;
+ hook(endpointName: string, opt_options?: RegisterOptions): HookApi;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ on(eventName: EventType, target: any): void;
+ popup(): Promise<PopupPluginApi>;
+ popup(moduleName: string): Promise<PopupPluginApi>;
+ popup(moduleName?: string): Promise<PopupPluginApi | null>;
+ project(): RepoPluginApi;
+ registerCustomComponent(
+ endpointName: string,
+ moduleName?: string,
+ options?: RegisterOptions
+ ): HookApi;
+ registerDynamicCustomComponent(
+ endpointName: string,
+ moduleName?: string,
+ options?: RegisterOptions
+ ): HookApi;
+ registerStyleModule(endpoint: string, moduleName: string): void;
+ reporting(): ReportingPluginApi;
+ restApi(): RestPluginApi;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ screen(screenName: string, moduleName?: string): any;
+ settings(): SettingsPluginApi;
+ styles(): StylesPluginApi;
+ theme(): ThemePluginApi;
+}
diff --git a/polygerrit-ui/app/api/popup.ts b/polygerrit-ui/app/api/popup.ts
new file mode 100644
index 0000000..60772cc
--- /dev/null
+++ b/polygerrit-ui/app/api/popup.ts
@@ -0,0 +1,30 @@
+/**
+ * @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.
+ */
+
+export interface PopupPluginApi {
+ /**
+ * Opens the popup, inserts it into DOM over current UI.
+ * Creates the popup if not previously created. Creates popup content element,
+ * if it was provided with constructor.
+ */
+ open(): Promise<PopupPluginApi>;
+
+ /**
+ * Hides the popup.
+ */
+ close(): void;
+}
diff --git a/polygerrit-ui/app/api/repo.ts b/polygerrit-ui/app/api/repo.ts
new file mode 100644
index 0000000..a626471
--- /dev/null
+++ b/polygerrit-ui/app/api/repo.ts
@@ -0,0 +1,31 @@
+/**
+ * @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.
+ */
+export type RepoCommandCallback = (
+ repo?: string,
+ /**
+ * This is a ConfigInfo object as defined here:
+ * https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#config-info
+ * We neither want to repeat it nor add a dependency on it here.
+ */
+ config?: unknown
+) => boolean;
+
+export interface RepoPluginApi {
+ createCommand(title: string, callback: RepoCommandCallback): RepoPluginApi;
+
+ onTap(callback: (event: Event) => boolean): RepoPluginApi;
+}
diff --git a/polygerrit-ui/app/api/reporting.ts b/polygerrit-ui/app/api/reporting.ts
new file mode 100644
index 0000000..65bdc3f
--- /dev/null
+++ b/polygerrit-ui/app/api/reporting.ts
@@ -0,0 +1,25 @@
+/**
+ * @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.
+ */
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export type EventDetails = any;
+
+export interface ReportingPluginApi {
+ reportInteraction(eventName: string, details?: EventDetails): void;
+
+ reportLifeCycle(eventName: string, details?: EventDetails): void;
+}
diff --git a/polygerrit-ui/app/api/rest.ts b/polygerrit-ui/app/api/rest.ts
new file mode 100644
index 0000000..fd9cada
--- /dev/null
+++ b/polygerrit-ui/app/api/rest.ts
@@ -0,0 +1,106 @@
+/**
+ * @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.
+ */
+export type RequestPayload = string | object;
+
+export enum HttpMethod {
+ HEAD = 'HEAD',
+ POST = 'POST',
+ GET = 'GET',
+ DELETE = 'DELETE',
+ PUT = 'PUT',
+}
+
+export type ErrorCallback = (response?: Response | null, err?: Error) => void;
+
+export interface RestPluginApi {
+ getLoggedIn(): Promise<boolean>;
+
+ getVersion(): Promise<string | undefined>;
+
+ /**
+ * Returns a ServerInfo object as defined here:
+ * https://gerrit-review.googlesource.com/Documentation/rest-api-config.html#server-info
+ * We neither want to repeat it nor add a dependency on it here.
+ */
+ getConfig(): Promise<unknown>;
+
+ invalidateReposCache(): void;
+
+ fetch(
+ method: HttpMethod,
+ url: string,
+ payload?: RequestPayload,
+ errFn?: undefined,
+ contentType?: string
+ ): Promise<Response>;
+
+ fetch(
+ method: HttpMethod,
+ url: string,
+ payload: RequestPayload | undefined,
+ errFn: ErrorCallback,
+ contentType?: string
+ ): Promise<Response | void>;
+
+ fetch(
+ method: HttpMethod,
+ url: string,
+ payload: RequestPayload | undefined,
+ errFn?: ErrorCallback,
+ contentType?: string
+ ): Promise<Response | void>;
+
+ /**
+ * Fetch and return native browser REST API Response.
+ */
+ fetch(
+ method: HttpMethod,
+ url: string,
+ payload?: RequestPayload,
+ errFn?: ErrorCallback,
+ contentType?: string
+ ): Promise<Response | void>;
+
+ /**
+ * Fetch and parse REST API response, if request succeeds.
+ */
+ send(
+ method: HttpMethod,
+ url: string,
+ payload?: RequestPayload,
+ errFn?: ErrorCallback,
+ contentType?: string
+ ): Promise<unknown>;
+
+ get(url: string): Promise<unknown>;
+
+ post(
+ url: string,
+ payload?: RequestPayload,
+ errFn?: ErrorCallback,
+ contentType?: string
+ ): Promise<unknown>;
+
+ put(
+ url: string,
+ payload?: RequestPayload,
+ errFn?: ErrorCallback,
+ contentType?: string
+ ): Promise<unknown>;
+
+ delete(url: string): Promise<Response>;
+}
diff --git a/polygerrit-ui/app/api/settings.ts b/polygerrit-ui/app/api/settings.ts
new file mode 100644
index 0000000..03cf474
--- /dev/null
+++ b/polygerrit-ui/app/api/settings.ts
@@ -0,0 +1,27 @@
+/**
+ * @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 {HookApi} from './hook';
+
+export interface SettingsPluginApi {
+ title(newTitle: string): SettingsPluginApi;
+
+ token(newToken: string): SettingsPluginApi;
+
+ module(newModuleName: string): SettingsPluginApi;
+
+ build(): HookApi;
+}
diff --git a/polygerrit-ui/app/api/styles.ts b/polygerrit-ui/app/api/styles.ts
new file mode 100644
index 0000000..233c3e2
--- /dev/null
+++ b/polygerrit-ui/app/api/styles.ts
@@ -0,0 +1,35 @@
+/**
+ * @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.
+ */
+
+export interface StyleObject {
+ /**
+ * Creates a new unique CSS class and injects it in a root node of the element
+ * if it hasn't been added yet. A root node is an document or is the
+ * associated shadowRoot. This class can be added to any element with the same
+ * root node.
+ */
+ getClassName(element: Element): string;
+
+ /**
+ * Apply shared style to the element.
+ */
+ apply(element: Element): void;
+}
+
+export interface StylesPluginApi {
+ css(ruleStr: string): StyleObject;
+}
diff --git a/polygerrit-ui/app/api/theme.ts b/polygerrit-ui/app/api/theme.ts
new file mode 100644
index 0000000..70ffcb3
--- /dev/null
+++ b/polygerrit-ui/app/api/theme.ts
@@ -0,0 +1,20 @@
+/**
+ * @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.
+ */
+
+export interface ThemePluginApi {
+ setHeaderLogoAndTitle(logoUrl: string, title: string): void;
+}
diff --git a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.ts b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.ts
index 3aeea3b..bc4750f 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.ts
@@ -26,7 +26,6 @@
import {ListViewMixin} from '../../../mixins/gr-list-view-mixin/gr-list-view-mixin';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
import {customElement, property} from '@polymer/decorators';
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
import {
GroupInfo,
AccountInfo,
@@ -35,6 +34,7 @@
} from '../../../types/common';
import {firePageError, fireTitleChange} from '../../../utils/event-util';
import {appContext} from '../../../services/app-context';
+import {ErrorCallback} from '../../../api/rest';
const GROUP_EVENTS = ['ADD_GROUP', 'REMOVE_GROUP'];
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts
index f5602a3..451139c 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts
@@ -30,7 +30,6 @@
import {htmlTemplate} from './gr-group-members_html';
import {getBaseUrl} from '../../../utils/url-util';
import {customElement, property} from '@polymer/decorators';
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
import {
GroupId,
@@ -50,6 +49,7 @@
fireTitleChange,
} from '../../../utils/event-util';
import {appContext} from '../../../services/app-context';
+import {ErrorCallback} from '../../../api/rest';
const SUGGESTIONS_LIMIT = 15;
const SAVING_ERROR_TEXT =
diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts b/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
index 058f86b..6f00445 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
@@ -32,13 +32,13 @@
AutocompleteQuery,
} from '../../shared/gr-autocomplete/gr-autocomplete';
import {GroupId, GroupInfo, GroupName} from '../../../types/common';
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
import {
fireEvent,
firePageError,
fireTitleChange,
} from '../../../utils/event-util';
import {appContext} from '../../../services/app-context';
+import {ErrorCallback} from '../../../api/rest';
const INTERNAL_GROUP_REGEX = /^[\da-f]{40}$/;
diff --git a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.ts b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.ts
index ceb08b6..fc1ceee 100644
--- a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.ts
+++ b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.ts
@@ -26,11 +26,11 @@
ListViewParams,
} from '../../../mixins/gr-list-view-mixin/gr-list-view-mixin';
import {customElement, property} from '@polymer/decorators';
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
import {PluginInfo} from '../../../types/common';
import {firePageError} from '../../../utils/event-util';
import {fireTitleChange} from '../../../utils/event-util';
import {appContext} from '../../../services/app-context';
+import {ErrorCallback} from '../../../api/rest';
interface PluginInfoWithName extends PluginInfo {
name: string;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts
index 9bc0466..14cf234 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts
@@ -29,7 +29,6 @@
import {htmlTemplate} from './gr-repo-commands_html';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
import {customElement, property} from '@polymer/decorators';
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
import {
BranchName,
ConfigInfo,
@@ -44,6 +43,7 @@
fireTitleChange,
} from '../../../utils/event-util';
import {appContext} from '../../../services/app-context';
+import {ErrorCallback} from '../../../api/rest';
const GC_MESSAGE = 'Garbage collection completed successfully.';
const CONFIG_BRANCH = 'refs/meta/config' as BranchName;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.ts b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.ts
index b30d1f4..5f6cd29 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.ts
@@ -24,9 +24,9 @@
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
import {customElement, property} from '@polymer/decorators';
import {RepoName, DashboardId, DashboardInfo} from '../../../types/common';
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
import {firePageError} from '../../../utils/event-util';
import {appContext} from '../../../services/app-context';
+import {ErrorCallback} from '../../../api/rest';
interface DashboardRef {
section: string;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts
index 5325dc7..a486e27 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts
@@ -35,7 +35,6 @@
import {ListViewMixin} from '../../../mixins/gr-list-view-mixin/gr-list-view-mixin';
import {encodeURL} from '../../../utils/url-util';
import {customElement, property} from '@polymer/decorators';
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
import {GrCreatePointerDialog} from '../gr-create-pointer-dialog/gr-create-pointer-dialog';
import {
@@ -51,6 +50,7 @@
import {RepoDetailView} from '../../core/gr-navigation/gr-navigation';
import {firePageError} from '../../../utils/event-util';
import {appContext} from '../../../services/app-context';
+import {ErrorCallback} from '../../../api/rest';
const PGP_START = '-----BEGIN PGP SIGNATURE-----';
diff --git a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
index 3543e3b..bcc6039 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
@@ -30,7 +30,6 @@
import {htmlTemplate} from './gr-repo_html';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
import {customElement, property, observe} from '@polymer/decorators';
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
import {
ConfigInfo,
RepoName,
@@ -47,6 +46,7 @@
import {firePageError, fireTitleChange} from '../../../utils/event-util';
import {appContext} from '../../../services/app-context';
import {WebLinkInfo} from '../../../types/diff';
+import {ErrorCallback} from '../../../api/rest';
const STATES = {
active: {value: ProjectState.ACTIVE, label: 'Active'},
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
index 903afaa..89ca4ef 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
@@ -50,17 +50,9 @@
HttpMethod,
NotifyType,
} from '../../../constants/constants';
-import {
- EventType as PluginEventType,
- TargetElement,
-} from '../../plugins/gr-plugin-types';
+import {EventType as PluginEventType, TargetElement} from '../../../api/plugin';
import {customElement, observe, property} from '@polymer/decorators';
import {
- ActionPriority,
- ActionType,
- ErrorCallback,
-} from '../../../services/gr-rest-api/gr-rest-api';
-import {
AccountInfo,
ActionInfo,
ActionNameToActionInfoMap,
@@ -102,10 +94,7 @@
import {PolymerDeepPropertyChange} from '@polymer/polymer/interfaces';
import {GrButton} from '../../shared/gr-button/gr-button';
import {
- ChangeActions,
GrChangeActionsElement,
- PrimaryActionKey,
- RevisionActions,
UIActionInfo,
} from '../../shared/gr-js-api-interface/gr-change-actions-js-api';
import {fireAlert} from '../../../utils/event-util';
@@ -116,6 +105,14 @@
} from '../../../utils/label-util';
import {CommentThread} from '../../../utils/comment-util';
import {ShowAlertEventDetail} from '../../../types/events';
+import {
+ ActionPriority,
+ ActionType,
+ ChangeActions,
+ PrimaryActionKey,
+ RevisionActions,
+} from '../../../api/change-actions';
+import {ErrorCallback} from '../../../api/rest';
const ERR_BRANCH_EMPTY = 'The destination branch can’t be empty.';
const ERR_COMMIT_EMPTY = 'The commit message can’t be empty.';
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts
index 918e5e4..cd17271 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts
@@ -110,6 +110,10 @@
.metadata-header {
display: flex;
justify-content: space-between;
+ align-items: flex-end;
+ /* The goal is to achieve alignment of the owner account chip and the
+ commit message box. Their top border should be on the same line. */
+ margin-bottom: var(--spacing-s);
}
</style>
<gr-external-style id="externalStyle" name="change-metadata">
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 11f1050..59287b2 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
@@ -61,7 +61,7 @@
import {RestApiService} from '../../../services/gr-rest-api/gr-rest-api';
import {tap} from '@polymer/iron-test-helpers/mock-interactions';
import {GrEditableLabel} from '../../shared/gr-editable-label/gr-editable-label';
-import {PluginApi} from '../../plugins/gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
import {GrEndpointDecorator} from '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator';
import {stubRestApi} from '../../../test/test-utils.js';
import {ParsedChangeInfo} from '../../../types/types';
diff --git a/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.ts b/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.ts
index c03884e..c0e87f3 100644
--- a/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements.ts
@@ -34,7 +34,6 @@
LabelNameToInfoMap,
LabelInfo,
} from '../../../types/common';
-import {hasOwnProperty} from '../../../utils/common-util';
import {PolymerDeepPropertyChange} from '@polymer/polymer/interfaces';
import {appContext} from '../../../services/app-context';
import {KnownExperimentId} from '../../../services/flags/flags';
@@ -51,6 +50,7 @@
}
interface Label {
+ labelName: string;
labelInfo: LabelInfo;
icon: string;
style: string;
@@ -133,22 +133,19 @@
LabelNameToInfoMap
>
) {
- const labels = labelsRecord.base;
- this._optionalLabels = [];
- this._requiredLabels = [];
+ const labels = labelsRecord.base || {};
+ const allLabels: Label[] = [];
- for (const label of Object.keys(labels || {}).sort()) {
- if (!hasOwnProperty(labels, label)) {
- continue;
- }
-
- const labelInfo = labels[label];
- const icon = this._computeLabelIcon(labelInfo);
- const style = this._computeLabelClass(labelInfo);
- const path = labelInfo.optional ? '_optionalLabels' : '_requiredLabels';
-
- this.push(path, {label, icon, style, labelInfo});
+ for (const label of Object.keys(labels).sort()) {
+ allLabels.push({
+ labelName: label,
+ icon: this._computeLabelIcon(labels[label]),
+ style: this._computeLabelClass(labels[label]),
+ labelInfo: labels[label],
+ });
}
+ this._optionalLabels = allLabels.filter(label => label.labelInfo.optional);
+ this._requiredLabels = allLabels.filter(label => !label.labelInfo.optional);
}
/**
diff --git a/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements_html.ts b/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements_html.ts
index 310b8bf..f172ccc 100644
--- a/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements_html.ts
@@ -138,7 +138,7 @@
<gr-limited-text
class="name"
limit="25"
- text="[[item.label]]"
+ text="[[item.labelName]]"
></gr-limited-text>
</div>
<div class="value">
@@ -146,7 +146,7 @@
change="{{change}}"
account="[[account]]"
mutable="[[mutable]]"
- label="[[item.label]]"
+ label="[[item.labelName]]"
label-info="[[item.labelInfo]]"
></gr-label-info>
</div>
@@ -206,7 +206,7 @@
<gr-limited-text
class="name"
limit="25"
- text="[[item.label]]"
+ text="[[item.labelName]]"
></gr-limited-text>
</div>
<div class="value">
@@ -214,7 +214,7 @@
change="{{change}}"
account="[[account]]"
mutable="[[mutable]]"
- label="[[item.label]]"
+ label="[[item.labelName]]"
label-info="[[item.labelInfo]]"
></gr-label-info>
</div>
diff --git a/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements_test.js b/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements_test.js
index c2fc72d..fda8cb2 100644
--- a/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements_test.js
+++ b/polygerrit-ui/app/elements/change/gr-change-requirements/gr-change-requirements_test.js
@@ -75,7 +75,7 @@
assert.equal(element._optionalLabels.length, 1);
assert.equal(element._requiredLabels.length, 1);
- assert.equal(element._optionalLabels[0].label, 'opt_test');
+ assert.equal(element._optionalLabels[0].labelName, 'opt_test');
assert.equal(element._optionalLabels[0].icon, 'gr-icons:schedule');
assert.equal(element._optionalLabels[0].style, '');
assert.ok(element._optionalLabels[0].labelInfo);
diff --git a/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts b/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts
index 88481a4..021d7c4 100644
--- a/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts
@@ -47,6 +47,8 @@
isResolved,
isUnresolved,
getFirstComment,
+ isRobotThread,
+ hasHumanReply,
} from '../../../utils/comment-util';
import {pluralize} from '../../../utils/string-util';
import {AccountInfo} from '../../../types/common';
@@ -77,8 +79,9 @@
color: var(--chip-color);
cursor: pointer;
display: inline-block;
- padding: var(--spacing-xxs) var(--spacing-s) var(--spacing-xxs)
+ padding: var(--spacing-xxs) var(--spacing-m) var(--spacing-xxs)
var(--spacing-s);
+ margin-right: var(--spacing-s);
border-radius: 12px;
border: 1px solid gray;
vertical-align: top;
@@ -372,9 +375,11 @@
render() {
this.detailsQuota = DETAILS_QUOTA;
- const countResolvedComments =
- this.commentThreads?.filter(isResolved).length ?? 0;
- const unresolvedThreads = this.commentThreads?.filter(isUnresolved) ?? [];
+ const commentThreads =
+ this.commentThreads?.filter(t => !isRobotThread(t) || hasHumanReply(t)) ??
+ [];
+ const countResolvedComments = commentThreads.filter(isResolved).length;
+ const unresolvedThreads = commentThreads.filter(isUnresolved);
const countUnresolvedComments = unresolvedThreads.length;
const unresolvedAuthors = this.getAccounts(unresolvedThreads);
const draftCount = this.changeComments?.computeDraftCount() ?? 0;
@@ -406,15 +411,13 @@
!!countUnresolvedComments}
>
No Comments</gr-summary-chip
- >
- <gr-summary-chip
+ ><gr-summary-chip
styleType=${SummaryChipStyles.WARNING}
icon="edit"
?hidden=${!draftCount}
>
${pluralize(draftCount, 'draft')}</gr-summary-chip
- >
- <gr-summary-chip
+ ><gr-summary-chip
styleType=${SummaryChipStyles.WARNING}
icon="message"
?hidden=${!countUnresolvedComments}
@@ -428,8 +431,7 @@
></gr-avatar>`
)}
${countUnresolvedComments} unresolved</gr-summary-chip
- >
- <gr-summary-chip
+ ><gr-summary-chip
styleType=${SummaryChipStyles.CHECK}
icon="markChatRead"
?hidden=${!countResolvedComments}
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 5afcafc..61006f9 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
@@ -78,7 +78,7 @@
PatchSet,
} from '../../../utils/patch-set-util';
import {changeStatuses, changeStatusString} from '../../../utils/change-util';
-import {EventType as PluginEventType} from '../../plugins/gr-plugin-types';
+import {EventType as PluginEventType} from '../../../api/plugin';
import {customElement, property, observe} from '@polymer/decorators';
import {GrApplyFixDialog} from '../../diff/gr-apply-fix-dialog/gr-apply-fix-dialog';
import {GrFileListHeader} from '../gr-file-list-header/gr-file-list-header';
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts
index 3c37ec7..81aff90 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts
@@ -65,7 +65,7 @@
margin-left: var(--spacing-s);
}
#replyBtn {
- margin-bottom: var(--spacing-l);
+ margin-bottom: var(--spacing-m);
}
gr-change-star {
margin-left: var(--spacing-s);
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
index b9e925c..99e5356 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
@@ -33,7 +33,7 @@
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader';
import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit';
-import {EventType, PluginApi} from '../../plugins/gr-plugin-types';
+import {EventType, PluginApi} from '../../../api/plugin';
import 'lodash/lodash';
import {
diff --git a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.ts b/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.ts
index f8cd42c..a966186 100644
--- a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.ts
+++ b/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores.ts
@@ -32,11 +32,12 @@
} from '../../../types/common';
import {
GrLabelScoreRow,
+ Label,
LabelValuesMap,
} from '../gr-label-score-row/gr-label-score-row';
import {PolymerDeepPropertyChange} from '@polymer/polymer/interfaces';
+import {appContext} from '../../../services/app-context';
-type Labels = {[label: string]: number};
@customElement('gr-label-scores')
export class GrLabelScores extends GestureEventListeners(
LegacyElementMixin(PolymerElement)
@@ -46,7 +47,7 @@
}
@property({type: Array, computed: '_computeLabels(change.labels.*, account)'})
- _labels?: Labels;
+ _labels: Label[] = [];
@property({type: Object, observer: '_computeColumns'})
permittedLabels?: LabelNameToValueMap;
@@ -60,6 +61,8 @@
@property({type: Object})
_labelValues?: LabelValuesMap;
+ private readonly reporting = appContext.reportingService;
+
getLabelValues(includeDefaults = true): LabelNameToValuesMap {
const labels: LabelNameToValuesMap = {};
if (this.shadowRoot === null || !this.change) {
@@ -69,23 +72,14 @@
const selectorEl = this.shadowRoot.querySelector(
`gr-label-score-row[name="${label}"]`
) as null | GrLabelScoreRow;
- if (!selectorEl) {
- continue;
- }
-
- // The user may have not voted on this label.
- if (!selectorEl.selectedItem) {
- continue;
- }
+ if (!selectorEl?.selectedItem) continue;
const selectedVal =
typeof selectorEl.selectedValue === 'string'
? Number(selectorEl.selectedValue)
: selectorEl.selectedValue;
- if (selectedVal === undefined) {
- continue;
- }
+ if (selectedVal === undefined) continue;
const defValNum = this._getDefaultValue(this.change.labels, label);
if (includeDefaults || selectedVal !== defValNum) {
@@ -99,14 +93,18 @@
labels: LabelNameToInfoMap,
labelName: string,
numberValue?: number
- ) {
+ ): string {
const detailedInfo = labels[labelName] as DetailedLabelInfo;
- for (const labelValue of Object.keys(detailedInfo.values)) {
- if (Number(labelValue) === numberValue) {
- return labelValue;
+ if (detailedInfo.values) {
+ for (const labelValue of Object.keys(detailedInfo.values)) {
+ if (Number(labelValue) === numberValue) {
+ return labelValue;
+ }
}
}
- return numberValue;
+ const stringVal = `${numberValue}`;
+ this.reporting.reportExecution('label-value-not-found', {value: stringVal});
+ return stringVal;
}
_getDefaultValue(labels?: LabelNameToInfoMap, labelName?: string) {
@@ -119,7 +117,7 @@
labels: LabelNameToInfoMap | undefined,
labelName: string,
account?: AccountInfo
- ) {
+ ): string | null {
if (!labels) return null;
const votes = labels[labelName] as DetailedLabelInfo;
if (votes.all && votes.all.length > 0) {
@@ -144,16 +142,10 @@
LabelNameToInfoMap
>,
account?: AccountInfo
- ) {
- // Polymer 2: check for undefined
- if ([labelRecord, account].includes(undefined)) {
- return undefined;
- }
-
+ ): Label[] {
+ if (!account) return [];
+ if (!labelRecord?.base) return [];
const labelsObj = labelRecord.base;
- if (!labelsObj) {
- return [];
- }
return Object.keys(labelsObj)
.sort()
.map(key => {
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
index e5396c3..36764f3 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
@@ -46,9 +46,8 @@
import {accountKey, removeServiceUsers} from '../../../utils/account-util';
import {getDisplayName} from '../../../utils/display-name-util';
import {IronA11yAnnouncer} from '@polymer/iron-a11y-announcer/iron-a11y-announcer';
-import {TargetElement} from '../../plugins/gr-plugin-types';
+import {TargetElement} from '../../../api/plugin';
import {customElement, observe, property} from '@polymer/decorators';
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
import {FixIronA11yAnnouncer} from '../../../types/types';
import {
AccountAddition,
@@ -110,6 +109,7 @@
import {isUnresolved} from '../../../utils/comment-util';
import {pluralize} from '../../../utils/string-util';
import {fireAlert, fireEvent, fireServerError} from '../../../utils/event-util';
+import {ErrorCallback} from '../../../api/rest';
const STORAGE_DEBOUNCE_INTERVAL_MS = 400;
@@ -137,7 +137,7 @@
};
const ButtonTooltips = {
- SAVE: 'Save but do not send notification or change review state',
+ SAVE: 'Send changes and comments as work in progress but do not start review',
START_REVIEW: 'Mark as ready for review and send reply',
SEND: 'Send reply',
DISABLED_COMMENT_EDITING: 'Save draft comments to enable send',
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts
index 1235512..79569bc 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts
@@ -577,7 +577,7 @@
has-tooltip=""
title="[[_saveTooltip]]"
on-click="_saveClickHandler"
- >Save</gr-button
+ >Send As WIP</gr-button
>
</template>
<gr-button
diff --git a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.ts b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.ts
index 7cea964..22b2e43 100644
--- a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.ts
@@ -34,9 +34,10 @@
import {
CommentThread,
isDraft,
- UIRobot,
isUnresolved,
isDraftThread,
+ isRobotThread,
+ hasHumanReply,
} from '../../../utils/comment-util';
import {pluralize} from '../../../utils/string-util';
import {fireThreadListModifiedEvent} from '../../../utils/event-util';
@@ -136,8 +137,12 @@
_computeResolvedCommentsMessage(
threads: CommentThread[],
displayedThreads: CommentThread[],
- unresolvedOnly: boolean
+ unresolvedOnly: boolean,
+ onlyShowRobotCommentsWithHumanReply: boolean
) {
+ if (onlyShowRobotCommentsWithHumanReply) {
+ threads = this.filterRobotThreadsWithoutHumanReply(threads) ?? [];
+ }
if (unresolvedOnly && threads.length && !displayedThreads.length) {
return `Show ${pluralize(threads.length, 'resolved comment')}`;
}
@@ -401,15 +406,9 @@
const lastComment = comments.length
? comments[comments.length - 1]
: undefined;
- let hasRobotComment = false;
- let hasHumanReplyToRobotComment = false;
- comments.forEach(comment => {
- if ((comment as UIRobot).robot_id) {
- hasRobotComment = true;
- } else if (hasRobotComment) {
- hasHumanReplyToRobotComment = true;
- }
- });
+ const hasRobotComment = isRobotThread(thread);
+ const hasHumanReplyToRobotComment =
+ hasRobotComment && hasHumanReply(thread);
let updated = undefined;
if (lastComment) {
if (isDraft(lastComment)) updated = lastComment.__date;
@@ -472,15 +471,21 @@
}
_countUnresolved(threads?: CommentThread[]) {
- return threads?.filter(isUnresolved).length ?? 0;
+ return (
+ this.filterRobotThreadsWithoutHumanReply(threads)?.filter(isUnresolved)
+ .length ?? 0
+ );
}
_countAllThreads(threads?: CommentThread[]) {
- return threads?.length ?? 0;
+ return this.filterRobotThreadsWithoutHumanReply(threads)?.length ?? 0;
}
_countDrafts(threads?: CommentThread[]) {
- return threads?.filter(isDraftThread).length ?? 0;
+ return (
+ this.filterRobotThreadsWithoutHumanReply(threads)?.filter(isDraftThread)
+ .length ?? 0
+ );
}
/**
@@ -489,6 +494,10 @@
_onTapUnresolvedToggle(e: Event) {
e.preventDefault();
}
+
+ filterRobotThreadsWithoutHumanReply(threads?: CommentThread[]) {
+ return threads?.filter(t => !isRobotThread(t) || hasHumanReply(t));
+ }
}
declare global {
diff --git a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_html.ts b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_html.ts
index 28e8da8..8a52555 100644
--- a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_html.ts
@@ -150,7 +150,7 @@
link
on-click="_handleResolvedCommentsMessageClick">
[[_computeResolvedCommentsMessage(threads, _displayedThreads,
- unresolvedOnly)]]
+ unresolvedOnly, onlyShowRobotCommentsWithHumanReply)]]
</gr-button>
</template>
</span>
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_html.ts b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_html.ts
index e8a1512..cf7d3ae 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_html.ts
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_html.ts
@@ -79,6 +79,7 @@
flex-grow: 1;
margin: 0 var(--spacing-m);
max-width: 500px;
+ min-width: 150px;
}
gr-dropdown,
.browse {
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
index e9637af..f6f4395 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
@@ -32,7 +32,6 @@
} from '../../core/gr-navigation/gr-navigation';
import {computeTruncatedPath} from '../../../utils/path-list-util';
import {customElement, property} from '@polymer/decorators';
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
import {
ChangeInfo,
PatchSetNum,
@@ -45,6 +44,7 @@
import {HttpMethod, NotifyType} from '../../../constants/constants';
import {fireAlert, fireTitleChange} from '../../../utils/event-util';
import {appContext} from '../../../services/app-context';
+import {ErrorCallback} from '../../../api/rest';
const RESTORED_MESSAGE = 'Content restored from a previous edit.';
const SAVING_MESSAGE = 'Saving changes...';
diff --git a/polygerrit-ui/app/elements/plugins/gr-admin-api/gr-admin-api.ts b/polygerrit-ui/app/elements/plugins/gr-admin-api/gr-admin-api.ts
index 1332118..897be67 100644
--- a/polygerrit-ui/app/elements/plugins/gr-admin-api/gr-admin-api.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-admin-api/gr-admin-api.ts
@@ -14,27 +14,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-import {PluginApi} from '../gr-plugin-types';
-
-/** Interface for menu link */
-export interface MenuLink {
- text: string;
- url: string;
- capability: string | null;
-}
+import {EventType, PluginApi} from '../../../api/plugin';
+import {AdminPluginApi, MenuLink} from '../../../api/admin';
/**
* GrAdminApi class.
*
* Defines common methods to register / retrieve menu links.
*/
-export class GrAdminApi {
+export class GrAdminApi implements AdminPluginApi {
// TODO(TS): maybe define as enum if its a limited set
private menuLinks: MenuLink[] = [];
constructor(private readonly plugin: PluginApi) {
- this.plugin.on('admin-menu-links', this);
+ this.plugin.on(EventType.ADMIN_MENU_LINKS, this);
}
addMenuLink(text: string, url: string, capability?: string) {
diff --git a/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper.ts b/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper.ts
index 0641b49..e0b4ee9 100644
--- a/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper.ts
@@ -14,8 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import {AttributeHelperPluginApi} from '../../../api/attribute-helper';
-export class GrAttributeHelper {
+export class GrAttributeHelper implements AttributeHelperPluginApi {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private readonly _promises = new Map<string, Promise<any>>();
diff --git a/polygerrit-ui/app/elements/plugins/gr-change-metadata-api/gr-change-metadata-api.ts b/polygerrit-ui/app/elements/plugins/gr-change-metadata-api/gr-change-metadata-api.ts
index 322d32e..3a61bce 100644
--- a/polygerrit-ui/app/elements/plugins/gr-change-metadata-api/gr-change-metadata-api.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-change-metadata-api/gr-change-metadata-api.ts
@@ -14,9 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {HookApi, PluginApi} from '../gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
+import {ChangeMetadataPluginApi} from '../../../api/change-metadata';
+import {HookApi} from '../../../api/hook';
-export class GrChangeMetadataApi {
+export class GrChangeMetadataApi implements ChangeMetadataPluginApi {
private _hook: HookApi | null;
public plugin: PluginApi;
diff --git a/polygerrit-ui/app/elements/plugins/gr-checks-api/gr-checks-api.ts b/polygerrit-ui/app/elements/plugins/gr-checks-api/gr-checks-api.ts
index 82c1087..404fc71 100644
--- a/polygerrit-ui/app/elements/plugins/gr-checks-api/gr-checks-api.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-checks-api/gr-checks-api.ts
@@ -14,11 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {PluginApi} from '../gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
import {
ChecksApiConfig,
ChecksProvider,
- GrChecksApiInterface,
+ ChecksPluginApi,
} from '../../../api/checks';
import {appContext} from '../../../services/app-context';
@@ -38,7 +38,7 @@
* Plugins normally just call register() once at startup and then wait for
* fetch() being called on the provider interface.
*/
-export class GrChecksApi implements GrChecksApiInterface {
+export class GrChecksApi implements ChecksPluginApi {
private state = State.NOT_REGISTERED;
private readonly checksService = appContext.checksService;
diff --git a/polygerrit-ui/app/elements/plugins/gr-checks-api/gr-checks-api_test.ts b/polygerrit-ui/app/elements/plugins/gr-checks-api/gr-checks-api_test.ts
index 45cbb47..3ab3efb 100644
--- a/polygerrit-ui/app/elements/plugins/gr-checks-api/gr-checks-api_test.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-checks-api/gr-checks-api_test.ts
@@ -18,13 +18,13 @@
import '../../../test/common-test-setup-karma.js';
import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit.js';
-import {GrChecksApi} from './gr-checks-api';
-import {PluginApi} from '../gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
+import {ChecksPluginApi} from '../../../api/checks';
const gerritPluginApi = _testOnly_initGerritPluginApi();
suite('gr-settings-api tests', () => {
- let checksApi: GrChecksApi | undefined;
+ let checksApi: ChecksPluginApi | undefined;
setup(() => {
let pluginApi: PluginApi | undefined = undefined;
diff --git a/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks.ts b/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks.ts
index dd76be4..d2568ad 100644
--- a/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks.ts
@@ -15,7 +15,8 @@
* limitations under the License.
*/
import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {HookApi, HookCallback, PluginApi} from '../gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
+import {HookApi, HookCallback} from '../../../api/hook';
export class GrDomHooksManager {
private _hooks: Record<string, GrDomHook>;
diff --git a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.ts b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.ts
index 12863fd..423cff9 100644
--- a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.ts
@@ -24,7 +24,8 @@
} from '../../shared/gr-js-api-interface/gr-plugin-endpoints';
import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader';
import {customElement, property} from '@polymer/decorators';
-import {HookApi, PluginApi} from '../gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
+import {HookApi} from '../../../api/hook';
const INIT_PROPERTIES_TIMEOUT_MS = 10000;
diff --git a/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.ts b/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.ts
index 5a4d2ae..4b34d56 100644
--- a/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.ts
@@ -14,13 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import {
+ EventHelperPluginApi,
+ UnsubscribeCallback,
+} from '../../../api/event-helper';
export interface ListenOptions {
event?: string;
capture?: boolean;
}
-export class GrEventHelper {
+export class GrEventHelper implements EventHelperPluginApi {
constructor(readonly element: HTMLElement) {}
/**
@@ -50,7 +54,7 @@
* Alias for @see captureClick
*/
captureTap(callback: (event: Event) => boolean) {
- this.captureClick(callback);
+ return this.captureClick(callback);
}
/**
@@ -68,7 +72,7 @@
container: HTMLElement,
callback: (event: Event) => boolean,
options?: ListenOptions | null
- ) {
+ ): UnsubscribeCallback {
const capture = options?.capture;
const event = options?.event || 'click';
const handler = (e: Event) => {
diff --git a/polygerrit-ui/app/elements/plugins/gr-plugin-types.ts b/polygerrit-ui/app/elements/plugins/gr-plugin-types.ts
deleted file mode 100644
index 2cd0f78..0000000
--- a/polygerrit-ui/app/elements/plugins/gr-plugin-types.ts
+++ /dev/null
@@ -1,105 +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 {GrAttributeHelper} from './gr-attribute-helper/gr-attribute-helper';
-import {GrPluginRestApi} from '../shared/gr-js-api-interface/gr-plugin-rest-api';
-import {GrEventHelper} from './gr-event-helper/gr-event-helper';
-import {GrPopupInterface} from './gr-popup-interface/gr-popup-interface';
-import {ConfigInfo} from '../../types/common';
-import {GrChecksApi} from './gr-checks-api/gr-checks-api';
-
-interface GerritElementExtensions {
- content?: HTMLElement & {hidden?: boolean};
- change?: unknown;
- revision?: unknown;
- token?: string;
- repoName?: string;
- config?: ConfigInfo;
-}
-export type HookCallback = (el: HTMLElement & GerritElementExtensions) => void;
-
-export interface HookApi {
- onAttached(callback: HookCallback): HookApi;
- onDetached(callback: HookCallback): HookApi;
- getAllAttached(): HTMLElement[];
- getLastAttached(): Promise<HTMLElement>;
- getModuleName(): string;
- handleInstanceDetached(instance: HTMLElement): void;
- handleInstanceAttached(instance: HTMLElement): void;
-}
-
-export enum TargetElement {
- CHANGE_ACTIONS = 'changeactions',
- REPLY_DIALOG = 'replydialog',
-}
-
-// Note: for new events, naming convention should be: `a-b`
-export enum EventType {
- HISTORY = 'history',
- LABEL_CHANGE = 'labelchange',
- SHOW_CHANGE = 'showchange',
- SUBMIT_CHANGE = 'submitchange',
- SHOW_REVISION_ACTIONS = 'show-revision-actions',
- COMMIT_MSG_EDIT = 'commitmsgedit',
- COMMENT = 'comment',
- REVERT = 'revert',
- REVERT_SUBMISSION = 'revert_submission',
- POST_REVERT = 'postrevert',
- ANNOTATE_DIFF = 'annotatediff',
- ADMIN_MENU_LINKS = 'admin-menu-links',
- HIGHLIGHTJS_LOADED = 'highlightjs-loaded',
-}
-
-export interface RegisterOptions {
- slot?: string;
- replace: unknown;
-}
-
-export interface PanelInfo {
- body: Element;
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- p: {[key: string]: any};
- onUnload: () => void;
-}
-
-export interface SettingsInfo {
- body: Element;
- token?: string;
- onUnload: () => void;
- setTitle: () => void;
- setWindowTitle: () => void;
- show: () => void;
-}
-
-export interface PluginApi {
- _url?: URL;
- popup(): Promise<GrPopupInterface>;
- popup(moduleName: string): Promise<GrPopupInterface>;
- popup(moduleName?: string): Promise<GrPopupInterface | null>;
- hook(endpointName: string, opt_options?: RegisterOptions): HookApi;
- getPluginName(): string;
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- on(eventName: string, target: any): void;
- attributeHelper(element: Element): GrAttributeHelper;
- checks(): GrChecksApi;
- restApi(): GrPluginRestApi;
- eventHelper(element: Node): GrEventHelper;
- registerDynamicCustomComponent(
- endpointName: string,
- moduleName?: string,
- options?: RegisterOptions
- ): HookApi;
-}
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.ts b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.ts
index d45c263..07d11ec 100644
--- a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.ts
@@ -17,7 +17,8 @@
import './gr-plugin-popup';
import {dom, flush} from '@polymer/polymer/lib/legacy/polymer.dom';
import {GrPluginPopup} from './gr-plugin-popup';
-import {PluginApi} from '../gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
+import {PopupPluginApi} from '../../../api/popup';
interface CustomPolymerPluginEl extends HTMLElement {
plugin: PluginApi;
@@ -29,7 +30,7 @@
* opt_moduleName is a name of custom element that will be automatically
* inserted on popup opening.
*/
-export class GrPopupInterface {
+export class GrPopupInterface implements PopupPluginApi {
private _openingPromise: Promise<GrPopupInterface> | null = null;
private _popup: GrPluginPopup | null = null;
@@ -50,7 +51,7 @@
* Creates the popup if not previously created. Creates popup content element,
* if it was provided with constructor.
*/
- open(): Promise<GrPopupInterface> {
+ open(): Promise<PopupPluginApi> {
if (!this._openingPromise) {
this._openingPromise = this.plugin
.hook('plugin-overlay')
diff --git a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.ts b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.ts
index 701a560..e42ca08 100644
--- a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.ts
@@ -16,9 +16,9 @@
*/
import './gr-plugin-repo-command';
import {ConfigInfo} from '../../../types/common';
-import {HookApi, PluginApi} from '../gr-plugin-types';
-
-type RepoCommandCallback = (repo?: string, config?: ConfigInfo) => boolean;
+import {PluginApi} from '../../../api/plugin';
+import {RepoCommandCallback, RepoPluginApi} from '../../../api/repo';
+import {HookApi} from '../../../api/hook';
/**
* Parameters provided on repo-command endpoint
@@ -28,7 +28,7 @@
config: ConfigInfo;
}
-export class GrRepoApi {
+export class GrRepoApi implements RepoPluginApi {
private _hook?: HookApi;
constructor(readonly plugin: PluginApi) {}
@@ -45,7 +45,7 @@
createCommand(title: string, callback: RepoCommandCallback) {
if (this._hook) {
console.warn('Already set up.');
- return this._hook;
+ return this;
}
this._hook = this._createHook(title);
this._hook.onAttached(element => {
diff --git a/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.ts b/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.ts
index c7f1ecd..4bdd40e 100644
--- a/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.ts
@@ -16,9 +16,10 @@
*/
import '../../settings/gr-settings-view/gr-settings-item';
import '../../settings/gr-settings-view/gr-settings-menu-item';
-import {PluginApi} from '../gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
+import {SettingsPluginApi} from '../../../api/settings';
-export class GrSettingsApi {
+export class GrSettingsApi implements SettingsPluginApi {
private _token: string;
private _title = '(no title)';
diff --git a/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api.ts b/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api.ts
index 5c57208..a91b8d3 100644
--- a/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api.ts
@@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import {StyleObject, StylesPluginApi} from '../../../api/styles';
/**
* @fileoverview We should consider dropping support for this API:
@@ -30,7 +31,7 @@
};
}
-export class GrStyleObject {
+export class GrStyleObject implements StyleObject {
private className = '';
constructor(private readonly rulesStr: string) {
@@ -66,7 +67,6 @@
/**
* Apply shared style to the element.
- *
*/
apply(element: Element) {
element.classList.add(this.getClassName(element));
@@ -76,7 +76,7 @@
/**
* TODO(TS): move to util
*/
-export class GrStylesApi {
+export class GrStylesApi implements StylesPluginApi {
/**
* Creates a new GrStyleObject with specified style properties.
*/
diff --git a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.ts b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.ts
index 821e4bf..894ec6c 100644
--- a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.ts
@@ -16,12 +16,13 @@
*/
import './gr-custom-plugin-header';
import {GrCustomPluginHeader} from './gr-custom-plugin-header';
-import {PluginApi} from '../gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
+import {ThemePluginApi} from '../../../api/theme';
/**
* Defines api for theme, can be used to set header logo and title.
*/
-export class GrThemeApi {
+export class GrThemeApi implements ThemePluginApi {
constructor(private readonly plugin: PluginApi) {}
setHeaderLogoAndTitle(logoUrl: string, title: string) {
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
index cb64001..6ee82c9 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
@@ -326,6 +326,10 @@
return this.restApiService.getLoggedIn();
}
+ _getUnresolvedLabel(unresolved?: boolean) {
+ return unresolved ? 'Unresolved' : 'Resolved';
+ }
+
@observe('comments.*')
_commentsChanged() {
this._orderedComments = sortComments(this.comments);
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_html.ts b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_html.ts
index ba541be..1a89a79 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_html.ts
@@ -132,7 +132,7 @@
id="commentInfoContainer"
hidden$="[[_hideActions(_showActions, _lastComment)]]"
>
- <span id="unresolvedLabel" hidden$="[[!unresolved]]">Unresolved</span>
+ <span id="unresolvedLabel">[[_getUnresolvedLabel(unresolved)]]</span>
<div id="actions">
<gr-button
id="replyBtn"
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.ts b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.ts
index e1c6bff..f2df89d 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.ts
@@ -836,7 +836,7 @@
element.unresolved = false;
const label = element.shadowRoot?.querySelector('#unresolvedLabel');
assert.isOk(label);
- assert.isTrue(label!.hasAttribute('hidden'));
+ assert.isFalse(label!.hasAttribute('hidden'));
element.unresolved = true;
assert.isFalse(label!.hasAttribute('hidden'));
});
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_html.ts b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_html.ts
index 6605394..374cc62 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-editable-content/gr-editable-content_html.ts
@@ -32,13 +32,13 @@
padding: var(--spacing-m);
}
:host([collapsed]) .viewer,
- .viewer[collapsed] {
+ .viewer.new-change-summary-true[collapsed] {
max-height: var(--collapsed-max-height, 300px);
overflow: hidden;
}
.editor.new-change-summary-true iron-autogrow-textarea,
.viewer.new-change-summary-true {
- min-height: 160px;
+ min-height: 100px;
}
.editor iron-autogrow-textarea {
background-color: var(--view-background-color);
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context.ts
index a493e51..6a4da7b 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context.ts
@@ -19,6 +19,7 @@
import {GrStyleObject} from '../../plugins/gr-styles-api/gr-styles-api';
import {GrDiffLine} from '../../diff/gr-diff/gr-diff-line';
import {appContext} from '../../../services/app-context';
+import {AnnotationContext} from '../../../api/annotation';
/**
* Used to create a context for GrAnnotationActionsInterface.
@@ -32,7 +33,7 @@
* @param changeNum The Gerrit change number.
* @param patchNum The Gerrit patch number.
*/
-export class GrAnnotationActionsContext {
+export class GrAnnotationActionsContext implements AnnotationContext {
private _contentEl: HTMLElement;
private _lineNumberEl: HTMLElement;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api.ts
index f160807..4abc6e1 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api.ts
@@ -16,34 +16,18 @@
*/
import {GrAnnotationActionsContext} from './gr-annotation-actions-context';
import {GrDiffLine} from '../../diff/gr-diff/gr-diff-line';
-import {
- CoverageRange,
- DiffLayer,
- DiffLayerListener,
-} from '../../../types/types';
+import {DiffLayer, DiffLayerListener} from '../../../types/types';
import {Side} from '../../../constants/constants';
-import {PluginApi} from '../../plugins/gr-plugin-types';
-import {ChangeInfo, NumericChangeId} from '../../../types/common';
+import {EventType, PluginApi} from '../../../api/plugin';
import {appContext} from '../../../services/app-context';
+import {
+ AddLayerFunc,
+ AnnotationPluginApi,
+ CoverageProvider,
+ NotifyFunc,
+} from '../../../api/annotation';
-type AddLayerFunc = (ctx: GrAnnotationActionsContext) => void;
-
-type NotifyFunc = (
- path: string,
- start: number,
- end: number,
- side: Side
-) => void;
-
-export type CoverageProvider = (
- changeNum: NumericChangeId,
- path: string,
- basePatchNum?: number,
- patchNum?: number,
- change?: ChangeInfo
-) => Promise<Array<CoverageRange>>;
-
-export class GrAnnotationActionsInterface {
+export class GrAnnotationActionsInterface implements AnnotationPluginApi {
// Collect all annotation layers instantiated by getLayer. Will be used when
// notifying their listeners in the notify function.
private annotationLayers: AnnotationLayer[] = [];
@@ -57,7 +41,7 @@
constructor(private readonly plugin: PluginApi) {
// Return this instance when there is an annotatediff event.
- plugin.on('annotatediff', this);
+ plugin.on(EventType.ANNOTATE_DIFF, this);
}
/**
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.ts
index 9ae2900..2f2b5ce 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.ts
@@ -14,47 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {
- ActionType,
- ActionPriority,
-} from '../../../services/gr-rest-api/gr-rest-api';
-import {PluginApi, TargetElement} from '../../plugins/gr-plugin-types';
+import {PluginApi, TargetElement} from '../../../api/plugin';
import {ActionInfo, RequireProperties} from '../../../types/common';
import {appContext} from '../../../services/app-context';
-
-export enum ChangeActions {
- ABANDON = 'abandon',
- DELETE = '/',
- DELETE_EDIT = 'deleteEdit',
- EDIT = 'edit',
- FOLLOW_UP = 'followup',
- IGNORE = 'ignore',
- MOVE = 'move',
- PRIVATE = 'private',
- PRIVATE_DELETE = 'private.delete',
- PUBLISH_EDIT = 'publishEdit',
- REBASE = 'rebase',
- REBASE_EDIT = 'rebaseEdit',
- READY = 'ready',
- RESTORE = 'restore',
- REVERT = 'revert',
- REVERT_SUBMISSION = 'revert_submission',
- REVIEWED = 'reviewed',
- STOP_EDIT = 'stopEdit',
- SUBMIT = 'submit',
- UNIGNORE = 'unignore',
- UNREVIEWED = 'unreviewed',
- WIP = 'wip',
-}
-
-export enum RevisionActions {
- CHERRYPICK = 'cherrypick',
- REBASE = 'rebase',
- SUBMIT = 'submit',
- DOWNLOAD = 'download',
-}
-
-export type PrimaryActionKey = ChangeActions | RevisionActions;
+import {
+ ActionPriority,
+ ActionType,
+ ChangeActions,
+ ChangeActionsPluginApi,
+ PrimaryActionKey,
+ RevisionActions,
+} from '../../../api/change-actions';
export interface UIActionInfo extends RequireProperties<ActionInfo, 'label'> {
__key: string;
@@ -89,7 +59,7 @@
getActionDetails(actionName: string): ActionInfo | undefined;
}
-export class GrChangeActionsInterface {
+export class GrChangeActionsInterface implements ChangeActionsPluginApi {
private _el?: GrChangeActionsElement;
RevisionActions = RevisionActions;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api.ts
index 74130af..effebe1 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api.ts
@@ -16,25 +16,20 @@
*/
import {GrReplyDialog} from '../../../services/gr-rest-api/gr-rest-api';
-import {PluginApi, TargetElement} from '../../plugins/gr-plugin-types';
+import {PluginApi, TargetElement} from '../../../api/plugin';
import {JsApiService} from './gr-js-api-types';
-
-// TODO(TS): maybe move interfaces\types to other files when convertion complete
-interface LabelsChangedDetail {
- name: string;
- value: string;
-}
-interface ValueChangedDetail {
- value: string;
-}
-
-type ReplyChangedCallback = (text: string) => void;
-type LabelsChangedCallback = (detail: LabelsChangedDetail) => void;
+import {
+ ChangeReplyPluginApi,
+ LabelsChangedCallback,
+ LabelsChangedDetail,
+ ReplyChangedCallback,
+ ValueChangedDetail,
+} from '../../../api/change-reply';
/**
* GrChangeReplyInterface, provides a set of handy methods on reply dialog.
*/
-export class GrChangeReplyInterface {
+export class GrChangeReplyInterface implements ChangeReplyPluginApi {
constructor(
readonly plugin: PluginApi,
readonly sharedApiElement: JsApiService
@@ -46,7 +41,7 @@
) as unknown) as GrReplyDialog;
}
- getLabelValue(label: string) {
+ getLabelValue(label: string): string {
return this._el.getLabelValue(label);
}
@@ -100,6 +95,6 @@
}
showMessage(message: string) {
- return this._el.setPluginMessage(message);
+ this._el.setPluginMessage(message);
}
}
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit.ts
index 32a9238..27bc591 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit.ts
@@ -26,7 +26,7 @@
} from './gr-plugin-loader';
import {send} from './gr-api-utils';
import {appContext} from '../../../services/app-context';
-import {PluginApi} from '../../plugins/gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
import {HttpMethod} from '../../../constants/constants';
import {RequestPayload} from '../../../types/common';
import {
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.ts
index 412165d..830fb92 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.ts
@@ -23,16 +23,17 @@
RevisionInfo,
} from '../../../types/common';
import {GrAnnotationActionsInterface} from './gr-annotation-actions-js-api';
-import {GrAdminApi, MenuLink} from '../../plugins/gr-admin-api/gr-admin-api';
+import {GrAdminApi} from '../../plugins/gr-admin-api/gr-admin-api';
import {
JsApiService,
EventCallback,
ShowChangeDetail,
ShowRevisionActionsDetail,
} from './gr-js-api-types';
-import {EventType, TargetElement} from '../../plugins/gr-plugin-types';
+import {EventType, TargetElement} from '../../../api/plugin';
import {DiffLayer, HighlightJS, ParsedChangeInfo} from '../../../types/types';
import {appContext} from '../../../services/app-context';
+import {MenuLink} from '../../../api/admin';
const elements: {[key: string]: HTMLElement} = {};
const eventCallbacks: {[key: string]: EventCallback[]} = {};
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.js
index 47b6006..6a8a0dd 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.js
@@ -19,7 +19,7 @@
import './gr-js-api-interface.js';
import {GrPopupInterface} from '../../plugins/gr-popup-interface/gr-popup-interface.js';
import {GrSettingsApi} from '../../plugins/gr-settings-api/gr-settings-api.js';
-import {EventType} from '../../plugins/gr-plugin-types.js';
+import {EventType} from '../../../api/plugin.js';
import {PLUGIN_LOADING_TIMEOUT_MS} from './gr-api-utils.js';
import {getPluginLoader} from './gr-plugin-loader.js';
import {_testOnly_initGerritPluginApi} from './gr-gerrit.js';
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-types.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-types.ts
index 37db662..0b28c5e 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-types.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-types.ts
@@ -21,10 +21,10 @@
ReviewInput,
RevisionInfo,
} from '../../../types/common';
-import {EventType, TargetElement} from '../../plugins/gr-plugin-types';
+import {EventType, TargetElement} from '../../../api/plugin';
import {DiffLayer, ParsedChangeInfo} from '../../../types/types';
import {GrAnnotationActionsInterface} from './gr-annotation-actions-js-api';
-import {MenuLink} from '../../plugins/gr-admin-api/gr-admin-api';
+import {MenuLink} from '../../../api/admin';
export interface ShowChangeDetail {
change: ChangeInfo;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context.ts
index d4a2bd6..21e4876 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context.ts
@@ -17,20 +17,18 @@
import {RevisionInfo, ChangeInfo, RequestPayload} from '../../../types/common';
import {ShowAlertEventDetail} from '../../../types/events';
-import {PluginApi} from '../../plugins/gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
import {UIActionInfo} from './gr-change-actions-js-api';
import {windowLocationReload} from '../../../utils/dom-util';
-
-interface GrPopupInterface {
- close(): void;
-}
+import {PopupPluginApi} from '../../../api/popup';
+import {GrPopupInterface} from '../../plugins/gr-popup-interface/gr-popup-interface';
interface ButtonCallBacks {
onclick: (event: Event) => boolean;
}
export class GrPluginActionContext {
- private _popups: GrPopupInterface[] = [];
+ private _popups: PopupPluginApi[] = [];
constructor(
public readonly plugin: PluginApi,
@@ -41,7 +39,7 @@
popup(element: Node) {
this.plugin.popup().then(popApi => {
- const popupEl = popApi._getElement();
+ const popupEl = (popApi as GrPopupInterface)._getElement();
if (!popupEl) {
throw new Error('Popup element not found');
}
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints.ts
index da19e5b..2752c74 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints.ts
@@ -16,8 +16,9 @@
*/
import {importHref} from '../../../scripts/import-href';
-import {HookApi, PluginApi} from '../../plugins/gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
import {notUndefined} from '../../../types/types';
+import {HookApi} from '../../../api/hook';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type Callback = (value: any) => void;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader.ts
index aacef0e..8c0fce26 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader.ts
@@ -24,7 +24,7 @@
import {Plugin} from './gr-public-js-api';
import {getBaseUrl} from '../../../utils/url-util';
import {getPluginEndpoints} from './gr-plugin-endpoints';
-import {PluginApi} from '../../plugins/gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
import {ReportingService} from '../../../services/gr-reporting/gr-reporting';
import {hasOwnProperty} from '../../../utils/common-util';
import {ShowAlertEventDetail} from '../../../types/events';
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api.ts
index e640ba1..cd35d4e 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api.ts
@@ -14,10 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
import {HttpMethod} from '../../../constants/constants';
import {RequestPayload} from '../../../types/common';
import {appContext} from '../../../services/app-context';
+import {ErrorCallback, RestPluginApi} from '../../../api/rest';
async function getErrorMessage(response: Response): Promise<string> {
const text = await response.text();
@@ -33,7 +33,7 @@
}
}
-export class GrPluginRestApi {
+export class GrPluginRestApi implements RestPluginApi {
private readonly restApi = appContext.restApiService;
constructor(private readonly prefix = '') {}
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.ts
index f21ddc6..45ffdcd9 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.ts
@@ -32,20 +32,28 @@
import {GrStylesApi} from '../../plugins/gr-styles-api/gr-styles-api';
import {getPluginEndpoints} from './gr-plugin-endpoints';
-import {PRELOADED_PROTOCOL, getPluginNameFromUrl, send} from './gr-api-utils';
+import {getPluginNameFromUrl, PRELOADED_PROTOCOL, send} from './gr-api-utils';
import {GrReportingJsApi} from './gr-reporting-js-api';
-import {
- EventType,
- HookApi,
- PluginApi,
- RegisterOptions,
- TargetElement,
-} from '../../plugins/gr-plugin-types';
+import {EventType, PluginApi, TargetElement} from '../../../api/plugin';
import {RequestPayload} from '../../../types/common';
import {HttpMethod} from '../../../constants/constants';
import {GrChangeActions} from '../../change/gr-change-actions/gr-change-actions';
import {GrChecksApi} from '../../plugins/gr-checks-api/gr-checks-api';
import {appContext} from '../../../services/app-context';
+import {AdminPluginApi} from '../../../api/admin';
+import {AnnotationPluginApi} from '../../../api/annotation';
+import {StylesPluginApi} from '../../../api/styles';
+import {ThemePluginApi} from '../../../api/theme';
+import {EventHelperPluginApi} from '../../../api/event-helper';
+import {PopupPluginApi} from '../../../api/popup';
+import {SettingsPluginApi} from '../../../api/settings';
+import {ReportingPluginApi} from '../../../api/reporting';
+import {ChangeActionsPluginApi} from '../../../api/change-actions';
+import {ChangeMetadataPluginApi} from '../../../api/change-metadata';
+import {RepoPluginApi} from '../../../api/repo';
+import {ChangeReplyPluginApi} from '../../../api/change-reply';
+import {RestPluginApi} from '../../../api/rest';
+import {HookApi, RegisterOptions} from '../../../api/hook';
/**
* Plugin-provided custom components can affect content in extension
@@ -232,11 +240,11 @@
});
}
- annotationApi() {
+ annotationApi(): AnnotationPluginApi {
return new GrAnnotationActionsInterface(this);
}
- changeActions() {
+ changeActions(): ChangeActionsPluginApi {
return new GrChangeActionsInterface(
this,
(this.jsApi.getElement(
@@ -245,7 +253,7 @@
);
}
- changeReply() {
+ changeReply(): ChangeReplyPluginApi {
return new GrChangeReplyInterface(this, this.jsApi);
}
@@ -253,42 +261,35 @@
return new GrChecksApi(this);
}
- reporting() {
+ reporting(): ReportingPluginApi {
return new GrReportingJsApi(this);
}
- theme() {
+ theme(): ThemePluginApi {
return new GrThemeApi(this);
}
- project() {
+ project(): RepoPluginApi {
return new GrRepoApi(this);
}
- changeMetadata() {
+ changeMetadata(): ChangeMetadataPluginApi {
return new GrChangeMetadataApi(this);
}
- admin() {
+ admin(): AdminPluginApi {
return new GrAdminApi(this);
}
- settings() {
+ settings(): SettingsPluginApi {
return new GrSettingsApi(this);
}
- styles() {
+ styles(): StylesPluginApi {
return new GrStylesApi();
}
- /**
- * To make REST requests for plugin-provided endpoints, use
- *
- * @example
- * const pluginRestApi = plugin.restApi(plugin.url());
- * @param prefix url for subsequent .get(), .post() etc requests.
- */
- restApi(prefix?: string) {
+ restApi(prefix?: string): RestPluginApi {
return new GrPluginRestApi(prefix);
}
@@ -296,15 +297,15 @@
return new GrAttributeHelper(element);
}
- eventHelper(element: HTMLElement) {
+ eventHelper(element: HTMLElement): EventHelperPluginApi {
return new GrEventHelper(element);
}
- popup(): Promise<GrPopupInterface>;
+ popup(): Promise<PopupPluginApi>;
- popup(moduleName: string): Promise<GrPopupInterface>;
+ popup(moduleName: string): Promise<PopupPluginApi>;
- popup(moduleName?: string): Promise<GrPopupInterface | null> {
+ popup(moduleName?: string): Promise<PopupPluginApi | null> {
if (moduleName !== undefined && typeof moduleName !== 'string') {
console.error('.popup(element) deprecated, use .popup(moduleName)!');
return Promise.resolve(null);
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-reporting-js-api.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-reporting-js-api.ts
index 87b320c4..d4b51a8 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-reporting-js-api.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-reporting-js-api.ts
@@ -16,26 +16,26 @@
*/
import {appContext} from '../../../services/app-context';
-import {EventDetails} from '../../../services/gr-reporting/gr-reporting';
-import {PluginApi} from '../../plugins/gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
+import {EventDetails, ReportingPluginApi} from '../../../api/reporting';
/**
* Defines all methods that will be exported to plugin from reporting service.
*/
-export class GrReportingJsApi {
+export class GrReportingJsApi implements ReportingPluginApi {
private readonly reporting = appContext.reportingService;
constructor(private readonly plugin: PluginApi) {}
reportInteraction(eventName: string, details?: EventDetails) {
- return this.reporting.reportInteraction(
+ this.reporting.reportInteraction(
`${this.plugin.getPluginName()}-${eventName}`,
details
);
}
reportLifeCycle(eventName: string, details?: EventDetails) {
- return this.reporting.reportLifeCycle(
+ this.reporting.reportLifeCycle(
`${this.plugin.getPluginName()}-${eventName}`,
details
);
diff --git a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts
index 70f68ae..60a07a4 100644
--- a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts
+++ b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts
@@ -223,7 +223,7 @@
if (
!labelInfo ||
!isDetailedLabelInfo(labelInfo) ||
- !labelInfo.values[score]
+ !labelInfo.values?.[score]
) {
return '';
}
diff --git a/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.ts b/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.ts
index 329cc7e..655acde 100644
--- a/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.ts
+++ b/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.ts
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import '../gr-js-api-interface/gr-js-api-interface';
-import {EventType} from '../../plugins/gr-plugin-types';
+import {EventType} from '../../../api/plugin';
import {HighlightJS} from '../../../types/types';
import {appContext} from '../../../services/app-context';
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts
index 84d84b1..6e17c75 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts
@@ -139,7 +139,6 @@
} from '../../../types/diff';
import {
CancelConditionCallback,
- ErrorCallback,
GetDiffCommentsOutput,
GetDiffRobotCommentsOutput,
RestApiService,
@@ -155,6 +154,7 @@
} from '../../../constants/constants';
import {firePageError, fireServerError} from '../../../utils/event-util';
import {ParsedChangeInfo} from '../../../types/types';
+import {ErrorCallback} from '../../../api/rest';
const MAX_PROJECT_RESULTS = 25;
// This value is somewhat arbitrary and not based on research or calculations.
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper.ts b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper.ts
index 710445c..fa2a28e 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper.ts
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper.ts
@@ -15,10 +15,7 @@
* limitations under the License.
*/
import {getBaseUrl} from '../../../../utils/url-util';
-import {
- CancelConditionCallback,
- ErrorCallback,
-} from '../../../../services/gr-rest-api/gr-rest-api';
+import {CancelConditionCallback} from '../../../../services/gr-rest-api/gr-rest-api';
import {
AuthRequestInit,
AuthService,
@@ -33,6 +30,7 @@
import {RpcLogEventDetail} from '../../../../types/events';
import {fireNetworkError, fireServerError} from '../../../../utils/event-util';
import {FetchRequest} from '../../../../types/types';
+import {ErrorCallback} from '../../../../api/rest';
export const JSON_PREFIX = ")]}'";
diff --git a/polygerrit-ui/app/services/flags/flags.ts b/polygerrit-ui/app/services/flags/flags.ts
index 891716b..f96afaa 100644
--- a/polygerrit-ui/app/services/flags/flags.ts
+++ b/polygerrit-ui/app/services/flags/flags.ts
@@ -30,4 +30,5 @@
CI_REBOOT_CHECKS = 'UiFeature__ci_reboot_checks',
NEW_CHANGE_SUMMARY_UI = 'UiFeature__new_change_summary_ui',
PORTING_COMMENTS = 'UiFeature__porting_comments',
+ NEW_IMAGE_DIFF_UI = 'UiFeature__new_image_diff_ui',
}
diff --git a/polygerrit-ui/app/services/gr-reporting/gr-reporting.ts b/polygerrit-ui/app/services/gr-reporting/gr-reporting.ts
index 7035f26..4ca983a 100644
--- a/polygerrit-ui/app/services/gr-reporting/gr-reporting.ts
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting.ts
@@ -16,13 +16,10 @@
*/
import {NumericChangeId} from '../../types/common';
+import {EventDetails} from '../../api/reporting';
export type EventValue = string | number | {error?: Error};
-// TODO(dmfilippov): TS-fix-any use more specific type instead if possible
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-export type EventDetails = any;
-
export interface Timer {
reset(): this;
end(): this;
diff --git a/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts b/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts
index 657a3f4..f80cb75 100644
--- a/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts
@@ -16,14 +16,10 @@
*/
import {AppContext} from '../app-context';
import {FlagsService} from '../flags/flags';
-import {
- EventDetails,
- EventValue,
- ReportingService,
- Timer,
-} from './gr-reporting';
+import {EventValue, ReportingService, Timer} from './gr-reporting';
import {hasOwnProperty} from '../../utils/common-util';
import {NumericChangeId} from '../../types/common';
+import {EventDetails} from '../../api/reporting';
// Latency reporting constants.
diff --git a/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts b/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts
index 2b42a6b..484ce45 100644
--- a/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts
@@ -14,7 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {EventDetails, ReportingService, Timer} from './gr-reporting';
+import {ReportingService, Timer} from './gr-reporting';
+import {EventDetails} from '../../api/reporting';
export class MockTimer implements Timer {
end(): this {
diff --git a/polygerrit-ui/app/services/gr-rest-api/gr-rest-api.ts b/polygerrit-ui/app/services/gr-rest-api/gr-rest-api.ts
index 6fec5f0..4742e65 100644
--- a/polygerrit-ui/app/services/gr-rest-api/gr-rest-api.ts
+++ b/polygerrit-ui/app/services/gr-rest-api/gr-rest-api.ts
@@ -17,88 +17,88 @@
import {HttpMethod} from '../../constants/constants';
import {
+ AccountCapabilityInfo,
AccountDetailInfo,
AccountExternalIdInfo,
+ AccountId,
AccountInfo,
- NumericChangeId,
- ServerInfo,
- ProjectInfo,
- AccountCapabilityInfo,
- SuggestedReviewerInfo,
- GroupNameToGroupInfoMap,
- ParsedJSON,
- PatchSetNum,
- RequestPayload,
- PreferencesInput,
- EditPreferencesInfo,
- DiffPreferenceInput,
- SshKeyInfo,
- RepoName,
- BranchName,
- BranchInput,
- TagInput,
- GpgKeysInput,
- GpgKeyId,
- GpgKeyInfo,
- PreferencesInfo,
- EmailInfo,
- ProjectAccessInfo,
- CapabilityInfoMap,
- ProjectAccessInput,
- ChangeInfo,
- ProjectInfoWithName,
- GroupId,
- GroupInfo,
- GroupOptionsInput,
+ ActionNameToActionInfoMap,
+ Base64FileContent,
+ BlameInfo,
BranchInfo,
- ConfigInfo,
- ReviewInput,
- EditInfo,
+ BranchInput,
+ BranchName,
+ CapabilityInfoMap,
ChangeId,
- DashboardInfo,
- ProjectAccessInfoMap,
- IncludedInInfo,
- RobotCommentInfo,
+ ChangeInfo,
+ ChangeMessageId,
CommentInfo,
- PathToCommentsInfoMap,
- PathToRobotCommentsInfoMap,
CommentInput,
- GroupInput,
- PluginInfo,
- DocResult,
+ CommitInfo,
+ ConfigInfo,
+ ConfigInput,
ContributorAgreementInfo,
ContributorAgreementInput,
- Password,
- ProjectWatchInfo,
- NameToProjectInfoMap,
- ProjectInput,
- AccountId,
- ChangeMessageId,
- GroupAuditEventInfo,
- EncodedGroupId,
- Base64FileContent,
- UrlEncodedCommentId,
- TagInfo,
- GitRef,
- ConfigInput,
- RelatedChangesInfo,
- SubmittedTogetherInfo,
- EmailAddress,
- FixId,
- FilePathToDiffInfoMap,
- BlameInfo,
- PatchRange,
- ImagesForDiff,
- ActionNameToActionInfoMap,
- RevisionId,
- GroupName,
DashboardId,
- HashtagsInput,
- Hashtag,
+ DashboardInfo,
+ DiffPreferenceInput,
+ DocResult,
+ EditInfo,
+ EditPreferencesInfo,
+ EmailAddress,
+ EmailInfo,
+ EncodedGroupId,
FileNameToFileInfoMap,
- TopMenuEntryInfo,
+ FilePathToDiffInfoMap,
+ FixId,
+ GitRef,
+ GpgKeyId,
+ GpgKeyInfo,
+ GpgKeysInput,
+ GroupAuditEventInfo,
+ GroupId,
+ GroupInfo,
+ GroupInput,
+ GroupName,
+ GroupNameToGroupInfoMap,
+ GroupOptionsInput,
+ Hashtag,
+ HashtagsInput,
+ ImagesForDiff,
+ IncludedInInfo,
MergeableInfo,
- CommitInfo,
+ NameToProjectInfoMap,
+ NumericChangeId,
+ ParsedJSON,
+ Password,
+ PatchRange,
+ PatchSetNum,
+ PathToCommentsInfoMap,
+ PathToRobotCommentsInfoMap,
+ PluginInfo,
+ PreferencesInfo,
+ PreferencesInput,
+ ProjectAccessInfo,
+ ProjectAccessInfoMap,
+ ProjectAccessInput,
+ ProjectInfo,
+ ProjectInfoWithName,
+ ProjectInput,
+ ProjectWatchInfo,
+ RelatedChangesInfo,
+ RepoName,
+ RequestPayload,
+ ReviewInput,
+ RevisionId,
+ RobotCommentInfo,
+ ServerInfo,
+ SshKeyInfo,
+ SubmittedTogetherInfo,
+ SuggestedReviewerInfo,
+ TagInfo,
+ TagInput,
+ TopMenuEntryInfo,
+ UrlEncodedCommentId,
} from '../../types/common';
import {
DiffInfo,
@@ -106,8 +106,8 @@
IgnoreWhitespaceType,
} from '../../types/diff';
import {ParsedChangeInfo} from '../../types/types';
+import {ErrorCallback} from '../../api/rest';
-export type ErrorCallback = (response?: Response | null, err?: Error) => void;
export type CancelConditionCallback = () => boolean;
// TODO(TS): remove when GrReplyDialog converted to typescript
@@ -118,21 +118,6 @@
setPluginMessage(message: string): void;
}
-// Copied from gr-change-actions.js
-export enum ActionType {
- CHANGE = 'change',
- REVISION = 'revision',
-}
-
-// Copied from gr-change-actions.js
-export enum ActionPriority {
- CHANGE = 2,
- DEFAULT = 0,
- PRIMARY = 3,
- REVIEW = -3,
- REVISION = 1,
-}
-
export interface GetDiffCommentsOutput {
baseComments: CommentInfo[];
comments: CommentInfo[];
diff --git a/polygerrit-ui/app/types/common.ts b/polygerrit-ui/app/types/common.ts
index 5f196b1..8f5518a 100644
--- a/polygerrit-ui/app/types/common.ts
+++ b/polygerrit-ui/app/types/common.ts
@@ -198,7 +198,7 @@
// This is not set when the change has no reviewers.
all?: ApprovalInfo[];
// Docs claim that 'values' is optional, but it is actually always set.
- values: LabelValueToDescriptionMap; // A map of all values that are allowed for this label
+ values?: LabelValueToDescriptionMap; // A map of all values that are allowed for this label
default_value?: number;
}
diff --git a/polygerrit-ui/app/utils/admin-nav-util.ts b/polygerrit-ui/app/utils/admin-nav-util.ts
index b144313..275f9e6 100644
--- a/polygerrit-ui/app/utils/admin-nav-util.ts
+++ b/polygerrit-ui/app/utils/admin-nav-util.ts
@@ -25,9 +25,9 @@
AccountDetailInfo,
AccountCapabilityInfo,
} from '../types/common';
-import {MenuLink} from '../elements/plugins/gr-admin-api/gr-admin-api';
import {hasOwnProperty} from './common-util';
import {GerritView} from '../services/router/router-model';
+import {MenuLink} from '../api/admin';
const ADMIN_LINKS: NavLink[] = [
{
diff --git a/polygerrit-ui/app/utils/comment-util.ts b/polygerrit-ui/app/utils/comment-util.ts
index d7e7595..0c4a3c6 100644
--- a/polygerrit-ui/app/utils/comment-util.ts
+++ b/polygerrit-ui/app/utils/comment-util.ts
@@ -177,6 +177,10 @@
return thread?.comments?.[0];
}
+export function countComments(thread?: CommentThread) {
+ return thread?.comments?.length ?? 0;
+}
+
export function isUnresolved(thread?: CommentThread): boolean {
return !isResolved(thread);
}
@@ -189,6 +193,14 @@
return isDraft(getLastComment(thread));
}
+export function isRobotThread(thread?: CommentThread): boolean {
+ return isRobot(getFirstComment(thread));
+}
+
+export function hasHumanReply(thread?: CommentThread): boolean {
+ return countComments(thread) > 1 && !isRobot(getLastComment(thread));
+}
+
/**
* Whether the given comment should be included in the base side of the
* given patch range.
diff --git a/polygerrit-ui/app/utils/label-util.ts b/polygerrit-ui/app/utils/label-util.ts
index fc83d77..60ac4d8 100644
--- a/polygerrit-ui/app/utils/label-util.ts
+++ b/polygerrit-ui/app/utils/label-util.ts
@@ -27,7 +27,7 @@
export const CODE_REVIEW = 'Code-Review';
export function getVotingRange(label?: LabelInfo): VotingRangeInfo | undefined {
- if (!label || !isDetailedLabelInfo(label)) return undefined;
+ if (!label || !isDetailedLabelInfo(label) || !label.values) return undefined;
const values = Object.keys(label.values).map(v => Number(v));
values.sort((a, b) => a - b);
if (!values.length) return undefined;
diff --git a/resources/com/google/gerrit/httpd/raw/PolyGerritIndexHtml.soy b/resources/com/google/gerrit/httpd/raw/PolyGerritIndexHtml.soy
index 31ea7d2..93584c6 100644
--- a/resources/com/google/gerrit/httpd/raw/PolyGerritIndexHtml.soy
+++ b/resources/com/google/gerrit/httpd/raw/PolyGerritIndexHtml.soy
@@ -16,7 +16,7 @@
{namespace com.google.gerrit.httpd.raw}
-{template .Index}
+{template Index}
{@param canonicalPath: ?}
{@param staticResourcePath: ?}
{@param gerritInitialData: /** {string} map of REST endpoint to response for startup. */ ?}
diff --git a/resources/com/google/gerrit/server/mail/Abandoned.soy b/resources/com/google/gerrit/server/mail/Abandoned.soy
index d5aac0e..b57f00a 100644
--- a/resources/com/google/gerrit/server/mail/Abandoned.soy
+++ b/resources/com/google/gerrit/server/mail/Abandoned.soy
@@ -20,7 +20,7 @@
* The .Abandoned template will determine the contents of the email related to a
* change being abandoned.
*/
-{template .Abandoned kind="text"}
+{template Abandoned kind="text"}
{@param change: ?}
{@param coverLetter: ?}
{@param email: ?}
diff --git a/resources/com/google/gerrit/server/mail/AbandonedHtml.soy b/resources/com/google/gerrit/server/mail/AbandonedHtml.soy
index 9ad996e..9f80241 100644
--- a/resources/com/google/gerrit/server/mail/AbandonedHtml.soy
+++ b/resources/com/google/gerrit/server/mail/AbandonedHtml.soy
@@ -16,7 +16,9 @@
{namespace com.google.gerrit.server.mail.template}
-{template .AbandonedHtml}
+import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
+
+{template AbandonedHtml}
{@param coverLetter: ?}
{@param email: ?}
{@param fromName: ?}
@@ -26,7 +28,7 @@
{if $email.changeUrl}
<p>
- {call .ViewChangeButton data="all" /}
+ {call mailTemplate.ViewChangeButton data="all" /}
</p>
{/if}
diff --git a/resources/com/google/gerrit/server/mail/AddKey.soy b/resources/com/google/gerrit/server/mail/AddKey.soy
index 8b609cf..c77ab56 100644
--- a/resources/com/google/gerrit/server/mail/AddKey.soy
+++ b/resources/com/google/gerrit/server/mail/AddKey.soy
@@ -16,11 +16,13 @@
{namespace com.google.gerrit.server.mail.template}
+import * as mailTemplate from 'com/google/gerrit/server/mail/NoReplyFooter.soy';
+
/**
* The .AddKey template will determine the contents of the email related to
* adding a new SSH or GPG key to an account.
*/
-{template .AddKey kind="text"}
+{template AddKey kind="text"}
{@param email: ?}
One or more new {$email.keyType} keys have been added to Gerrit Code Review at
{sp}{$email.gerritHost}:
@@ -64,5 +66,5 @@
browser window instead.
{\n}
- {call .NoReplyFooter /}
+ {call mailTemplate.NoReplyFooter /}
{/template}
diff --git a/resources/com/google/gerrit/server/mail/AddKeyHtml.soy b/resources/com/google/gerrit/server/mail/AddKeyHtml.soy
index ed4f435..3987684 100644
--- a/resources/com/google/gerrit/server/mail/AddKeyHtml.soy
+++ b/resources/com/google/gerrit/server/mail/AddKeyHtml.soy
@@ -16,7 +16,9 @@
{namespace com.google.gerrit.server.mail.template}
-{template .AddKeyHtml}
+import * as mailTemplate from 'com/google/gerrit/server/mail/NoReplyFooterHtml.soy';
+
+{template AddKeyHtml}
{@param email: ?}
<p>
One or more new {$email.keyType} keys have been added to Gerrit Code Review
@@ -57,5 +59,5 @@
{/if}.
</p>
- {call .NoReplyFooterHtml /}
+ {call mailTemplate.NoReplyFooterHtml /}
{/template}
diff --git a/resources/com/google/gerrit/server/mail/AddToAttentionSet.soy b/resources/com/google/gerrit/server/mail/AddToAttentionSet.soy
index 5ea41b2..64c1ad3 100644
--- a/resources/com/google/gerrit/server/mail/AddToAttentionSet.soy
+++ b/resources/com/google/gerrit/server/mail/AddToAttentionSet.soy
@@ -20,7 +20,7 @@
* The .AddToAttentionSet template will determine the contents of the email related to a
* user being added to the attention set.
*/
-{template .AddToAttentionSet kind="text"}
+{template AddToAttentionSet kind="text"}
{@param change: ?}
{@param coverLetter: ?}
{@param email: ?}
diff --git a/resources/com/google/gerrit/server/mail/AddToAttentionSetHtml.soy b/resources/com/google/gerrit/server/mail/AddToAttentionSetHtml.soy
index bac180a..04d759e 100644
--- a/resources/com/google/gerrit/server/mail/AddToAttentionSetHtml.soy
+++ b/resources/com/google/gerrit/server/mail/AddToAttentionSetHtml.soy
@@ -16,7 +16,9 @@
{namespace com.google.gerrit.server.mail.template}
-{template .AddToAttentionSetHtml}
+import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
+
+{template AddToAttentionSetHtml}
{@param coverLetter: ?}
{@param email: ?}
{@param fromName: ?}
@@ -33,11 +35,11 @@
{if $email.changeUrl}
<p>
- {call .ViewChangeButton data="all" /}
+ {call mailTemplate.ViewChangeButton data="all" /}
</p>
{/if}
{if $coverLetter}
<div style="white-space:pre-wrap">{$coverLetter}</div>
{/if}
-{/template}
\ No newline at end of file
+{/template}
diff --git a/resources/com/google/gerrit/server/mail/ChangeFooter.soy b/resources/com/google/gerrit/server/mail/ChangeFooter.soy
index a8170ca..236b171 100644
--- a/resources/com/google/gerrit/server/mail/ChangeFooter.soy
+++ b/resources/com/google/gerrit/server/mail/ChangeFooter.soy
@@ -20,7 +20,7 @@
* The .ChangeFooter template will determine the contents of the footer text
* that will be appended to ALL emails related to changes.
*/
-{template .ChangeFooter kind="text"}
+{template ChangeFooter kind="text"}
{@param email: ?}
--{sp}
{\n}
diff --git a/resources/com/google/gerrit/server/mail/ChangeFooterHtml.soy b/resources/com/google/gerrit/server/mail/ChangeFooterHtml.soy
index b619c53..28442ee 100644
--- a/resources/com/google/gerrit/server/mail/ChangeFooterHtml.soy
+++ b/resources/com/google/gerrit/server/mail/ChangeFooterHtml.soy
@@ -16,7 +16,7 @@
{namespace com.google.gerrit.server.mail.template}
-{template .ChangeFooterHtml}
+{template ChangeFooterHtml}
{@param change: ?}
{@param email: ?}
{if $email.changeUrl or $email.settingsUrl}
diff --git a/resources/com/google/gerrit/server/mail/ChangeHeader.soy b/resources/com/google/gerrit/server/mail/ChangeHeader.soy
index fde69f1..7a2da65 100644
--- a/resources/com/google/gerrit/server/mail/ChangeHeader.soy
+++ b/resources/com/google/gerrit/server/mail/ChangeHeader.soy
@@ -16,7 +16,7 @@
{namespace com.google.gerrit.server.mail.template}
-{template .ChangeHeader kind="text"}
+{template ChangeHeader kind="text"}
{@param attentionSet: ?}
{if $attentionSet}
Attention is currently required from:{sp}
diff --git a/resources/com/google/gerrit/server/mail/ChangeHeaderHtml.soy b/resources/com/google/gerrit/server/mail/ChangeHeaderHtml.soy
index ea12455..a1bcd8f 100644
--- a/resources/com/google/gerrit/server/mail/ChangeHeaderHtml.soy
+++ b/resources/com/google/gerrit/server/mail/ChangeHeaderHtml.soy
@@ -17,7 +17,7 @@
{namespace com.google.gerrit.server.mail.template}
-{template .ChangeHeaderHtml}
+{template ChangeHeaderHtml}
{@param attentionSet: ?}
{if $attentionSet}
<p> Attention is currently required from:{sp}
diff --git a/resources/com/google/gerrit/server/mail/ChangeSubject.soy b/resources/com/google/gerrit/server/mail/ChangeSubject.soy
index 7fcd213..12422ed 100644
--- a/resources/com/google/gerrit/server/mail/ChangeSubject.soy
+++ b/resources/com/google/gerrit/server/mail/ChangeSubject.soy
@@ -20,7 +20,7 @@
* The .ChangeSubject template will determine the contents of the email subject
* line for ALL emails related to changes.
*/
-{template .ChangeSubject kind="text"}
+{template ChangeSubject kind="text"}
{@param branch: ?}
{@param change: ?}
{@param shortProjectName: ?}
diff --git a/resources/com/google/gerrit/server/mail/Comment.soy b/resources/com/google/gerrit/server/mail/Comment.soy
index 893ef6f..973b369 100644
--- a/resources/com/google/gerrit/server/mail/Comment.soy
+++ b/resources/com/google/gerrit/server/mail/Comment.soy
@@ -20,7 +20,7 @@
* The .Comment template will determine the contents of the email related to a
* user submitting comments on changes.
*/
-{template .Comment kind="text"}
+{template Comment kind="text"}
{@param change: ?}
{@param coverLetter: ?}
{@param email: ?}
diff --git a/resources/com/google/gerrit/server/mail/CommentFooter.soy b/resources/com/google/gerrit/server/mail/CommentFooter.soy
index 3998438..3c111f7 100644
--- a/resources/com/google/gerrit/server/mail/CommentFooter.soy
+++ b/resources/com/google/gerrit/server/mail/CommentFooter.soy
@@ -21,5 +21,5 @@
* that will be appended to emails related to a user submitting comments on
* changes.
*/
-{template .CommentFooter kind="text"}
+{template CommentFooter kind="text"}
{/template}
diff --git a/resources/com/google/gerrit/server/mail/CommentFooterHtml.soy b/resources/com/google/gerrit/server/mail/CommentFooterHtml.soy
index 033c1b1..ce8a933 100644
--- a/resources/com/google/gerrit/server/mail/CommentFooterHtml.soy
+++ b/resources/com/google/gerrit/server/mail/CommentFooterHtml.soy
@@ -16,5 +16,5 @@
{namespace com.google.gerrit.server.mail.template}
-{template .CommentFooterHtml}
+{template CommentFooterHtml}
{/template}
diff --git a/resources/com/google/gerrit/server/mail/CommentHtml.soy b/resources/com/google/gerrit/server/mail/CommentHtml.soy
index 21fee18..b3924c3 100644
--- a/resources/com/google/gerrit/server/mail/CommentHtml.soy
+++ b/resources/com/google/gerrit/server/mail/CommentHtml.soy
@@ -16,7 +16,9 @@
{namespace com.google.gerrit.server.mail.template}
-{template .CommentHtml}
+import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
+
+{template CommentHtml}
{@param commentFiles: ?}
{@param commentCount: ?}
{@param email: ?}
@@ -71,7 +73,9 @@
{/let}
{if $patchSetCommentBlocks}
- {call .WikiFormat}{param content: $patchSetCommentBlocks /}{/call}
+ {call mailTemplate.WikiFormat}
+ {param content: $patchSetCommentBlocks /}
+ {/call}
{/if}
{if length($labels) > 0}
@@ -97,7 +101,7 @@
{if $email.changeUrl}
<p>
- {call .ViewChangeButton data="all" /}
+ {call mailTemplate.ViewChangeButton data="all" /}
</p>
{/if}
@@ -146,11 +150,13 @@
{if length($comment.lines) > 1}
<p>
<blockquote style="{$blockquoteStyle}">
- {call .Pre}{param content kind="html"}
- {for $line in $comment.lines}
- {$line}{\n}
- {/for}
- {/param}{/call}
+ {call mailTemplate.Pre}
+ {param content kind="html"}
+ {for $line in $comment.lines}
+ {$line}{\n}
+ {/for}
+ {/param}
+ {/call}
</blockquote>
</p>
{/if}
@@ -163,7 +169,9 @@
</p>
{/if}
- {call .WikiFormat}{param content: $comment.messageBlocks /}{/call}
+ {call mailTemplate.WikiFormat}
+ {param content: $comment.messageBlocks /}
+ {/call}
</li>
{/for}
</ul>
diff --git a/resources/com/google/gerrit/server/mail/DeleteKey.soy b/resources/com/google/gerrit/server/mail/DeleteKey.soy
index 30548c8..ffc12dc 100644
--- a/resources/com/google/gerrit/server/mail/DeleteKey.soy
+++ b/resources/com/google/gerrit/server/mail/DeleteKey.soy
@@ -20,7 +20,7 @@
* The .DeleteKey template will determine the contents of the email related to
* deleting a SSH or GPG key.
*/
-{template .DeleteKey kind="text"}
+{template DeleteKey kind="text"}
{@param email: ?}
One or more {$email.keyType} keys have been deleted on Gerrit Code Review at
{sp}{$email.gerritHost}:
diff --git a/resources/com/google/gerrit/server/mail/DeleteKeyHtml.soy b/resources/com/google/gerrit/server/mail/DeleteKeyHtml.soy
index 1ab3955..4ce5246 100644
--- a/resources/com/google/gerrit/server/mail/DeleteKeyHtml.soy
+++ b/resources/com/google/gerrit/server/mail/DeleteKeyHtml.soy
@@ -16,7 +16,7 @@
{namespace com.google.gerrit.server.mail.template}
-{template .DeleteKeyHtml}
+{template DeleteKeyHtml}
{@param email: ?}
<p>
One or more {$email.keyType} keys have been deleted on Gerrit Code Review
diff --git a/resources/com/google/gerrit/server/mail/DeleteReviewer.soy b/resources/com/google/gerrit/server/mail/DeleteReviewer.soy
index 3310249..a9ba802 100644
--- a/resources/com/google/gerrit/server/mail/DeleteReviewer.soy
+++ b/resources/com/google/gerrit/server/mail/DeleteReviewer.soy
@@ -20,7 +20,7 @@
* The .DeleteReviewer template will determine the contents of the email related
* to removal of a reviewer (and the reviewer's votes) from reviews.
*/
-{template .DeleteReviewer kind="text"}
+{template DeleteReviewer kind="text"}
{@param change: ?}
{@param coverLetter: ?}
{@param email: ?}
diff --git a/resources/com/google/gerrit/server/mail/DeleteReviewerHtml.soy b/resources/com/google/gerrit/server/mail/DeleteReviewerHtml.soy
index 54720fe..685ca4c 100644
--- a/resources/com/google/gerrit/server/mail/DeleteReviewerHtml.soy
+++ b/resources/com/google/gerrit/server/mail/DeleteReviewerHtml.soy
@@ -16,7 +16,9 @@
{namespace com.google.gerrit.server.mail.template}
-{template .DeleteReviewerHtml}
+import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
+
+{template DeleteReviewerHtml}
{@param email: ?}
{@param fromName: ?}
<p>
@@ -35,7 +37,7 @@
{if $email.changeUrl}
<p>
- {call .ViewChangeButton data="all" /}
+ {call mailTemplate.ViewChangeButton data="all" /}
</p>
{/if}
{/template}
diff --git a/resources/com/google/gerrit/server/mail/DeleteVote.soy b/resources/com/google/gerrit/server/mail/DeleteVote.soy
index 0ee5454..74790f7 100644
--- a/resources/com/google/gerrit/server/mail/DeleteVote.soy
+++ b/resources/com/google/gerrit/server/mail/DeleteVote.soy
@@ -20,7 +20,7 @@
* The .DeleteVote template will determine the contents of the email related
* to removing votes on changes.
*/
-{template .DeleteVote kind="text"}
+{template DeleteVote kind="text"}
{@param change: ?}
{@param coverLetter: ?}
{@param email: ?}
diff --git a/resources/com/google/gerrit/server/mail/DeleteVoteHtml.soy b/resources/com/google/gerrit/server/mail/DeleteVoteHtml.soy
index 3a82927..dd3b423 100644
--- a/resources/com/google/gerrit/server/mail/DeleteVoteHtml.soy
+++ b/resources/com/google/gerrit/server/mail/DeleteVoteHtml.soy
@@ -16,7 +16,9 @@
{namespace com.google.gerrit.server.mail.template}
-{template .DeleteVoteHtml}
+import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
+
+{template DeleteVoteHtml}
{@param coverLetter: ?}
{@param email: ?}
{@param fromName: ?}
@@ -26,7 +28,7 @@
{if $email.changeUrl}
<p>
- {call .ViewChangeButton data="all" /}
+ {call mailTemplate.ViewChangeButton data="all" /}
</p>
{/if}
diff --git a/resources/com/google/gerrit/server/mail/Footer.soy b/resources/com/google/gerrit/server/mail/Footer.soy
index 7483cd9..6ce0d3b 100644
--- a/resources/com/google/gerrit/server/mail/Footer.soy
+++ b/resources/com/google/gerrit/server/mail/Footer.soy
@@ -21,7 +21,7 @@
* appended to the end of all outgoing emails after the ChangeFooter and
* CommentFooter.
*/
-{template .Footer kind="text"}
+{template Footer kind="text"}
{@param footers: ?}
{for $footer in $footers}
{$footer}{\n}
diff --git a/resources/com/google/gerrit/server/mail/FooterHtml.soy b/resources/com/google/gerrit/server/mail/FooterHtml.soy
index ce934d3..c89dea7 100644
--- a/resources/com/google/gerrit/server/mail/FooterHtml.soy
+++ b/resources/com/google/gerrit/server/mail/FooterHtml.soy
@@ -16,7 +16,7 @@
{namespace com.google.gerrit.server.mail.template}
-{template .FooterHtml}
+{template FooterHtml}
{@param footers: ?}
{\n}
{\n}
diff --git a/resources/com/google/gerrit/server/mail/HttpPasswordUpdate.soy b/resources/com/google/gerrit/server/mail/HttpPasswordUpdate.soy
index 38e679e..08daa932 100644
--- a/resources/com/google/gerrit/server/mail/HttpPasswordUpdate.soy
+++ b/resources/com/google/gerrit/server/mail/HttpPasswordUpdate.soy
@@ -20,7 +20,7 @@
* The .HttpPasswordUpdate template will determine the contents of the email related to
* adding, changing or deleting the HTTP password.
*/
-{template .HttpPasswordUpdate kind="text"}
+{template HttpPasswordUpdate kind="text"}
{@param email: ?}
The HTTP password was {$email.operation} on Gerrit Code Review at
{sp}{$email.gerritHost}.
diff --git a/resources/com/google/gerrit/server/mail/HttpPasswordUpdateHtml.soy b/resources/com/google/gerrit/server/mail/HttpPasswordUpdateHtml.soy
index 3c4594c..e28aaaa 100644
--- a/resources/com/google/gerrit/server/mail/HttpPasswordUpdateHtml.soy
+++ b/resources/com/google/gerrit/server/mail/HttpPasswordUpdateHtml.soy
@@ -16,7 +16,7 @@
{namespace com.google.gerrit.server.mail.template}
-{template .HttpPasswordUpdateHtml}
+{template HttpPasswordUpdateHtml}
{@param email: ?}
<p>
The HTTP password was {$email.operation} on Gerrit Code Review
diff --git a/resources/com/google/gerrit/server/mail/InboundEmailRejection.soy b/resources/com/google/gerrit/server/mail/InboundEmailRejection.soy
index 16c5c8d..378785a 100644
--- a/resources/com/google/gerrit/server/mail/InboundEmailRejection.soy
+++ b/resources/com/google/gerrit/server/mail/InboundEmailRejection.soy
@@ -16,7 +16,9 @@
{namespace com.google.gerrit.server.mail.template}
-{template .InboundEmailRejectionFooter kind="text"}
+import * as noReplyFooter from 'com/google/gerrit/server/mail/NoReplyFooter.soy';
+
+{template InboundEmailRejectionFooter kind="text"}
{\n}
{\n}
Thus, no actions were taken by Gerrit in response to this email,
@@ -24,7 +26,7 @@
{\n}
This email was sent in response to an email coming from this address.
In case you did not send Gerrit an email, feel free to ignore this.
- {call .NoReplyFooter /}
+ {call noReplyFooter.NoReplyFooter /}
{/template}
/**
@@ -32,39 +34,39 @@
* to warning users of error in inbound emails
*/
-{template .InboundEmailRejection_PARSING_ERROR kind="text"}
+{template InboundEmailRejection_PARSING_ERROR kind="text"}
Gerrit Code Review was unable to parse your email.{\n}
This might be because your email did not quote Gerrit's email,
because you are using an unsupported email client,
or because of a bug.
- {call .InboundEmailRejectionFooter /}
+ {call InboundEmailRejectionFooter /}
{/template}
-{template .InboundEmailRejection_UNKNOWN_ACCOUNT kind="text"}
+{template InboundEmailRejection_UNKNOWN_ACCOUNT kind="text"}
Gerrit Code Review was unable to match your email to an account.{\n}
This may happen if several accounts are linked to this email address.
- {call .InboundEmailRejectionFooter /}
+ {call InboundEmailRejectionFooter /}
{/template}
-{template .InboundEmailRejection_INACTIVE_ACCOUNT kind="text"}
+{template InboundEmailRejection_INACTIVE_ACCOUNT kind="text"}
Your account on this Gerrit Code Review instance is marked as inactive,
so your email has been ignored. {\n}
If you think this is an error, please contact your Gerrit instance administrator.
{\n}{\n}
This email was sent in response to an email coming from this address.
In case you did not send Gerrit an email, feel free to ignore this.
- {call .NoReplyFooter /}
+ {call noReplyFooter.NoReplyFooter /}
{/template}
-{template .InboundEmailRejection_INTERNAL_EXCEPTION kind="text"}
+{template InboundEmailRejection_INTERNAL_EXCEPTION kind="text"}
Gerrit Code Review encountered an internal exception and was unable to fulfil your request.
{\n}
This might be caused by an ongoing maintenance or a data corruption.
- {call .InboundEmailRejectionFooter /}
+ {call InboundEmailRejectionFooter /}
{/template}
-{template .InboundEmailRejection_COMMENT_REJECTED kind="text"}
+{template InboundEmailRejection_COMMENT_REJECTED kind="text"}
Gerrit Code Review rejected one or more comments because they did not pass validation, or
because the maximum number of comments per change would be exceeded.
- {call .InboundEmailRejectionFooter /}
+ {call InboundEmailRejectionFooter /}
{/template}
diff --git a/resources/com/google/gerrit/server/mail/InboundEmailRejectionHtml.soy b/resources/com/google/gerrit/server/mail/InboundEmailRejectionHtml.soy
index 8762e10..f0b18d2 100644
--- a/resources/com/google/gerrit/server/mail/InboundEmailRejectionHtml.soy
+++ b/resources/com/google/gerrit/server/mail/InboundEmailRejectionHtml.soy
@@ -16,8 +16,11 @@
{namespace com.google.gerrit.server.mail.template}
+import * as noReplyFooter from 'com/google/gerrit/server/mail/NoReplyFooter.soy';
+import * as noReplyFooterHtml from 'com/google/gerrit/server/mail/NoReplyFooterHtml.soy';
-{template .InboundEmailRejectionFooterHtml}
+
+{template InboundEmailRejectionFooterHtml}
<p>
Thus, no actions were taken by Gerrit in response to this email,
and you should use the Gerrit website to continue.
@@ -25,7 +28,7 @@
<p>
In case you did not send Gerrit an email, feel free to ignore this.
</p>
- {call .NoReplyFooterHtml /}
+ {call noReplyFooterHtml.NoReplyFooterHtml /}
{/template}
/**
@@ -33,7 +36,7 @@
* to warning users of error in inbound emails
*/
-{template .InboundEmailRejectionHtml_PARSING_ERROR}
+{template InboundEmailRejectionHtml_PARSING_ERROR}
<p>
Gerrit Code Review was unable to parse your email.
</p>
@@ -42,20 +45,20 @@
because you are using an unsupported email client,
or because of a bug.
</p>
- {call .InboundEmailRejectionFooterHtml /}
+ {call InboundEmailRejectionFooterHtml /}
{/template}
-{template .InboundEmailRejectionHtml_UNKNOWN_ACCOUNT}
+{template InboundEmailRejectionHtml_UNKNOWN_ACCOUNT}
<p>
Gerrit Code Review was unable to match your email to an account.
</p>
<p>
This may happen if several accounts are linked to this email address.
</p>
- {call .InboundEmailRejectionFooterHtml /}
+ {call InboundEmailRejectionFooterHtml /}
{/template}
-{template .InboundEmailRejectionHtml_INACTIVE_ACCOUNT}
+{template InboundEmailRejectionHtml_INACTIVE_ACCOUNT}
<p>
Your account on this Gerrit Code Review instance is marked as inactive,
so your email has been ignored.
@@ -66,23 +69,23 @@
<p>
In case you did not send Gerrit an email, feel free to ignore this.
</p>
- {call .NoReplyFooter /}
+ {call noReplyFooter.NoReplyFooter /}
{/template}
-{template .InboundEmailRejectionHtml_INTERNAL_EXCEPTION}
+{template InboundEmailRejectionHtml_INTERNAL_EXCEPTION}
<p>
Gerrit Code Review encountered an internal exception and was unable to fulfil your request.
</p>
<p>
This might be caused by an ongoing maintenance or a data corruption.
<p>
- {call .InboundEmailRejectionFooterHtml /}
+ {call InboundEmailRejectionFooterHtml /}
{/template}
-{template .InboundEmailRejectionHtml_COMMENT_REJECTED}
+{template InboundEmailRejectionHtml_COMMENT_REJECTED}
<p>
Gerrit Code Review rejected one or more comments because they did not pass validation, or
because the maximum number of comments per change would be exceeded.
</p>
- {call .InboundEmailRejectionFooterHtml /}
+ {call InboundEmailRejectionFooterHtml /}
{/template}
diff --git a/resources/com/google/gerrit/server/mail/Merged.soy b/resources/com/google/gerrit/server/mail/Merged.soy
index 59e73eb..b586851 100644
--- a/resources/com/google/gerrit/server/mail/Merged.soy
+++ b/resources/com/google/gerrit/server/mail/Merged.soy
@@ -21,7 +21,7 @@
* The .Merged template will determine the contents of the email related to
* a change successfully merged to the head.
*/
-{template .Merged kind="text"}
+{template Merged kind="text"}
{@param change: ?}
{@param email: ?}
{@param fromName: ?}
diff --git a/resources/com/google/gerrit/server/mail/MergedHtml.soy b/resources/com/google/gerrit/server/mail/MergedHtml.soy
index ca6451e..53c1645 100644
--- a/resources/com/google/gerrit/server/mail/MergedHtml.soy
+++ b/resources/com/google/gerrit/server/mail/MergedHtml.soy
@@ -16,7 +16,9 @@
{namespace com.google.gerrit.server.mail.template}
-{template .MergedHtml}
+import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
+
+{template MergedHtml}
{@param diffLines: ?}
{@param email: ?}
{@param fromName: ?}
@@ -26,16 +28,20 @@
{if $email.changeUrl}
<p>
- {call .ViewChangeButton data="all" /}
+ {call mailTemplate.ViewChangeButton data="all" /}
</p>
{/if}
<div style="white-space:pre-wrap">{$email.approvals}</div>
- {call .Pre}{param content: $email.changeDetail /}{/call}
+ {call mailTemplate.Pre}
+ {param content: $email.changeDetail /}
+ {/call}
{if $email.includeDiff}
- {call .UnifiedDiff}{param diffLines: $diffLines /}{/call}
+ {call mailTemplate.UnifiedDiff}
+ {param diffLines: $diffLines /}
+ {/call}
{/if}
<div style="white-space:pre-wrap">{$email.stickyApprovalDiff}</div>
{/template}
diff --git a/resources/com/google/gerrit/server/mail/NewChange.soy b/resources/com/google/gerrit/server/mail/NewChange.soy
index fa447e9..fe99ba4 100644
--- a/resources/com/google/gerrit/server/mail/NewChange.soy
+++ b/resources/com/google/gerrit/server/mail/NewChange.soy
@@ -20,7 +20,7 @@
* The .NewChange template will determine the contents of the email related to a
* user submitting a new change for review.
*/
-{template .NewChange kind="text"}
+{template NewChange kind="text"}
{@param change: ?}
{@param email: ?}
{@param ownerName: ?}
diff --git a/resources/com/google/gerrit/server/mail/NewChangeHtml.soy b/resources/com/google/gerrit/server/mail/NewChangeHtml.soy
index e16b213..756d6ce 100644
--- a/resources/com/google/gerrit/server/mail/NewChangeHtml.soy
+++ b/resources/com/google/gerrit/server/mail/NewChangeHtml.soy
@@ -16,7 +16,9 @@
{namespace com.google.gerrit.server.mail.template}
-{template .NewChangeHtml}
+import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
+
+{template NewChangeHtml}
{@param diffLines: ?}
{@param email: ?}
{@param fromName: ?}
@@ -41,20 +43,26 @@
{if $email.changeUrl}
<p>
- {call .ViewChangeButton data="all" /}
+ {call mailTemplate.ViewChangeButton data="all" /}
</p>
{/if}
- {call .Pre}{param content: $email.changeDetail /}{/call}
+ {call mailTemplate.Pre}
+ {param content: $email.changeDetail /}
+ {/call}
{if $email.sshHost}
- {call .Pre}{param content kind="html"}
- git pull ssh:{print '//'}{$email.sshHost}/{$projectName}
- {sp}{$patchSet.refName}
- {/param}{/call}
+ {call mailTemplate.Pre}
+ {param content kind="html"}
+ git pull ssh:{print '//'}{$email.sshHost}/{$projectName}
+ {sp}{$patchSet.refName}
+ {/param}
+ {/call}
{/if}
{if $email.includeDiff}
- {call .UnifiedDiff}{param diffLines: $diffLines /}{/call}
+ {call mailTemplate.UnifiedDiff}
+ {param diffLines: $diffLines /}
+ {/call}
{/if}
{/template}
diff --git a/resources/com/google/gerrit/server/mail/NoReplyFooter.soy b/resources/com/google/gerrit/server/mail/NoReplyFooter.soy
index 1443100..d309e90 100644
--- a/resources/com/google/gerrit/server/mail/NoReplyFooter.soy
+++ b/resources/com/google/gerrit/server/mail/NoReplyFooter.soy
@@ -16,7 +16,7 @@
{namespace com.google.gerrit.server.mail.template}
-{template .NoReplyFooter kind="text"}
+{template NoReplyFooter kind="text"}
{\n}
This is a send-only email address. Replies to this message will not be read
or answered.
diff --git a/resources/com/google/gerrit/server/mail/NoReplyFooterHtml.soy b/resources/com/google/gerrit/server/mail/NoReplyFooterHtml.soy
index 93df527..1baf5ab 100644
--- a/resources/com/google/gerrit/server/mail/NoReplyFooterHtml.soy
+++ b/resources/com/google/gerrit/server/mail/NoReplyFooterHtml.soy
@@ -16,7 +16,7 @@
{namespace com.google.gerrit.server.mail.template}
-{template .NoReplyFooterHtml}
+{template NoReplyFooterHtml}
<p>
This is a send-only email address. Replies to this message will not be read
or answered.
diff --git a/resources/com/google/gerrit/server/mail/Private.soy b/resources/com/google/gerrit/server/mail/Private.soy
index 510f15e..7920c21 100644
--- a/resources/com/google/gerrit/server/mail/Private.soy
+++ b/resources/com/google/gerrit/server/mail/Private.soy
@@ -23,7 +23,7 @@
/**
* Private template to generate "View Change" buttons.
*/
-{template .ViewChangeButton}
+{template ViewChangeButton}
{@param email: ?}
<a href="{$email.changeUrl}">View Change</a>
{/template}
@@ -31,7 +31,7 @@
/**
* Private template to render PRE block with consistent font-sizing.
*/
-{template .Pre}
+{template Pre}
{@param content: ?}
{let $preStyle kind="css"}
font-family: monospace,monospace; // Use this to avoid browsers scaling down
@@ -54,7 +54,7 @@
* This mechanism encodes as little structure as possible in order to depend on
* the Soy autoescape mechanism for all of the content.
*/
-{template .WikiFormat}
+{template WikiFormat}
{@param content: ?}
{let $blockquoteStyle kind="css"}
border-left: 1px solid #aaa;
@@ -72,10 +72,10 @@
<p style="{$pStyle}">{$block.text|changeNewlineToBr}</p>
{elseif $block.type == 'quote'}
<blockquote style="{$blockquoteStyle}">
- {call .WikiFormat}{param content: $block.quotedBlocks /}{/call}
+ {call WikiFormat}{param content: $block.quotedBlocks /}{/call}
</blockquote>
{elseif $block.type == 'pre'}
- {call .Pre}{param content: $block.text /}{/call}
+ {call Pre}{param content: $block.text /}{/call}
{elseif $block.type == 'list'}
<ul>
{for $item in $block.items}
@@ -86,7 +86,7 @@
{/for}
{/template}
-{template .UnifiedDiff}
+{template UnifiedDiff}
{@param diffLines: ?}
{let $addStyle kind="css"}
color: hsl(120, 100%, 40%);
diff --git a/resources/com/google/gerrit/server/mail/RegisterNewEmail.soy b/resources/com/google/gerrit/server/mail/RegisterNewEmail.soy
index ee03de0..bde8152 100644
--- a/resources/com/google/gerrit/server/mail/RegisterNewEmail.soy
+++ b/resources/com/google/gerrit/server/mail/RegisterNewEmail.soy
@@ -20,7 +20,7 @@
* The .RegisterNewEmail template will determine the contents of the email
* related to registering new email accounts.
*/
-{template .RegisterNewEmail kind="text"}
+{template RegisterNewEmail kind="text"}
{@param email: ?}
Welcome to Gerrit Code Review at {$email.gerritHost}.{\n}
diff --git a/resources/com/google/gerrit/server/mail/RegisterNewEmailHtml.soy b/resources/com/google/gerrit/server/mail/RegisterNewEmailHtml.soy
index 033d145..e3ec3a5 100644
--- a/resources/com/google/gerrit/server/mail/RegisterNewEmailHtml.soy
+++ b/resources/com/google/gerrit/server/mail/RegisterNewEmailHtml.soy
@@ -16,7 +16,7 @@
{namespace com.google.gerrit.server.mail.template}
-{template .RegisterNewEmailHtml}
+{template RegisterNewEmailHtml}
{@param email: ?}
<p>
Welcome to Gerrit Code Review at {$email.gerritHost}.
diff --git a/resources/com/google/gerrit/server/mail/RemoveFromAttentionSet.soy b/resources/com/google/gerrit/server/mail/RemoveFromAttentionSet.soy
index f116adb..a329f7b0 100644
--- a/resources/com/google/gerrit/server/mail/RemoveFromAttentionSet.soy
+++ b/resources/com/google/gerrit/server/mail/RemoveFromAttentionSet.soy
@@ -20,7 +20,7 @@
* The .RemoveFromAttentionSet template will determine the contents of the email related to a
* user being added to the attention set.
*/
-{template .RemoveFromAttentionSet kind="text"}
+{template RemoveFromAttentionSet kind="text"}
{@param change: ?}
{@param coverLetter: ?}
{@param email: ?}
diff --git a/resources/com/google/gerrit/server/mail/RemoveFromAttentionSetHtml.soy b/resources/com/google/gerrit/server/mail/RemoveFromAttentionSetHtml.soy
index 55eef13..c1c6185 100644
--- a/resources/com/google/gerrit/server/mail/RemoveFromAttentionSetHtml.soy
+++ b/resources/com/google/gerrit/server/mail/RemoveFromAttentionSetHtml.soy
@@ -16,7 +16,9 @@
{namespace com.google.gerrit.server.mail.template}
-{template .RemoveFromAttentionSetHtml}
+import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
+
+{template RemoveFromAttentionSetHtml}
{@param coverLetter: ?}
{@param email: ?}
{@param fromName: ?}
@@ -33,11 +35,11 @@
{if $email.changeUrl}
<p>
- {call .ViewChangeButton data="all" /}
+ {call mailTemplate.ViewChangeButton data="all" /}
</p>
{/if}
{if $coverLetter}
<div style="white-space:pre-wrap">{$coverLetter}</div>
{/if}
-{/template}
\ No newline at end of file
+{/template}
diff --git a/resources/com/google/gerrit/server/mail/ReplacePatchSet.soy b/resources/com/google/gerrit/server/mail/ReplacePatchSet.soy
index bb84cf1..6dffa6b 100644
--- a/resources/com/google/gerrit/server/mail/ReplacePatchSet.soy
+++ b/resources/com/google/gerrit/server/mail/ReplacePatchSet.soy
@@ -20,7 +20,7 @@
* The .ReplacePatchSet template will determine the contents of the email
* related to a user submitting a new patchset for a change.
*/
-{template .ReplacePatchSet kind="text"}
+{template ReplacePatchSet kind="text"}
{@param change: ?}
{@param email: ?}
{@param fromEmail: ?}
diff --git a/resources/com/google/gerrit/server/mail/ReplacePatchSetHtml.soy b/resources/com/google/gerrit/server/mail/ReplacePatchSetHtml.soy
index 96cba5f..57c6db6 100644
--- a/resources/com/google/gerrit/server/mail/ReplacePatchSetHtml.soy
+++ b/resources/com/google/gerrit/server/mail/ReplacePatchSetHtml.soy
@@ -16,7 +16,9 @@
{namespace com.google.gerrit.server.mail.template}
-{template .ReplacePatchSetHtml}
+import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
+
+{template ReplacePatchSetHtml}
{@param change: ?}
{@param email: ?}
{@param fromName: ?}
@@ -35,16 +37,20 @@
{if $email.changeUrl}
<p>
- {call .ViewChangeButton data="all" /}
+ {call mailTemplate.ViewChangeButton data="all" /}
</p>
{/if}
- {call .Pre}{param content: $email.changeDetail /}{/call}
+ {call mailTemplate.Pre}
+ {param content: $email.changeDetail /}
+ {/call}
{if $email.sshHost}
- {call .Pre}{param content kind="html"}
- git pull ssh:{print '//'}{$email.sshHost}/{$projectName}{sp}
- {$patchSet.refName}
- {/param}{/call}
+ {call mailTemplate.Pre}
+ {param content kind="html"}
+ git pull ssh:{print '//'}{$email.sshHost}/{$projectName}{sp}
+ {$patchSet.refName}
+ {/param}
+ {/call}
{/if}
{/template}
diff --git a/resources/com/google/gerrit/server/mail/Restored.soy b/resources/com/google/gerrit/server/mail/Restored.soy
index 0ec65b30..e09f95f 100644
--- a/resources/com/google/gerrit/server/mail/Restored.soy
+++ b/resources/com/google/gerrit/server/mail/Restored.soy
@@ -20,7 +20,7 @@
* The .Restored template will determine the contents of the email related to a
* change being restored.
*/
-{template .Restored kind="text"}
+{template Restored kind="text"}
{@param change: ?}
{@param coverLetter: ?}
{@param email: ?}
diff --git a/resources/com/google/gerrit/server/mail/RestoredHtml.soy b/resources/com/google/gerrit/server/mail/RestoredHtml.soy
index bcd358f..19c4b99 100644
--- a/resources/com/google/gerrit/server/mail/RestoredHtml.soy
+++ b/resources/com/google/gerrit/server/mail/RestoredHtml.soy
@@ -16,7 +16,9 @@
{namespace com.google.gerrit.server.mail.template}
-{template .RestoredHtml}
+import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
+
+{template RestoredHtml}
{@param email: ?}
{@param fromName: ?}
<p>
@@ -25,7 +27,7 @@
{if $email.changeUrl}
<p>
- {call .ViewChangeButton data="all" /}
+ {call mailTemplate.ViewChangeButton data="all" /}
</p>
{/if}
{/template}
diff --git a/resources/com/google/gerrit/server/mail/Reverted.soy b/resources/com/google/gerrit/server/mail/Reverted.soy
index 32a65c6..bdfd0ad 100644
--- a/resources/com/google/gerrit/server/mail/Reverted.soy
+++ b/resources/com/google/gerrit/server/mail/Reverted.soy
@@ -20,7 +20,7 @@
* The .Reverted template will determine the contents of the email related
* to a change being reverted.
*/
-{template .Reverted kind="text"}
+{template Reverted kind="text"}
{@param change: ?}
{@param coverLetter: ?}
{@param email: ?}
diff --git a/resources/com/google/gerrit/server/mail/RevertedHtml.soy b/resources/com/google/gerrit/server/mail/RevertedHtml.soy
index 69260ad..d7b60df 100644
--- a/resources/com/google/gerrit/server/mail/RevertedHtml.soy
+++ b/resources/com/google/gerrit/server/mail/RevertedHtml.soy
@@ -16,7 +16,9 @@
{namespace com.google.gerrit.server.mail.template}
-{template .RevertedHtml}
+import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
+
+{template RevertedHtml}
{@param email: ?}
{@param fromName: ?}
<p>
@@ -25,7 +27,7 @@
{if $email.changeUrl}
<p>
- {call .ViewChangeButton data="all" /}
+ {call mailTemplate.ViewChangeButton data="all" /}
</p>
{/if}
{/template}
diff --git a/resources/com/google/gerrit/server/mail/SetAssignee.soy b/resources/com/google/gerrit/server/mail/SetAssignee.soy
index 1fdf690..5e83cfb 100644
--- a/resources/com/google/gerrit/server/mail/SetAssignee.soy
+++ b/resources/com/google/gerrit/server/mail/SetAssignee.soy
@@ -20,7 +20,7 @@
* The .SetAssignee template will determine the contents of the email related
* to a user being assigned to a change.
*/
-{template .SetAssignee kind="text"}
+{template SetAssignee kind="text"}
{@param change: ?}
{@param email: ?}
{@param fromName: ?}
diff --git a/resources/com/google/gerrit/server/mail/SetAssigneeHtml.soy b/resources/com/google/gerrit/server/mail/SetAssigneeHtml.soy
index 1826314..4ff6cc1 100644
--- a/resources/com/google/gerrit/server/mail/SetAssigneeHtml.soy
+++ b/resources/com/google/gerrit/server/mail/SetAssigneeHtml.soy
@@ -16,7 +16,9 @@
{namespace com.google.gerrit.server.mail.template}
-{template .SetAssigneeHtml}
+import * as mailTemplate from 'com/google/gerrit/server/mail/Private.soy';
+
+{template SetAssigneeHtml}
{@param diffLines: ?}
{@param email: ?}
{@param fromName: ?}
@@ -29,20 +31,26 @@
{if $email.changeUrl}
<p>
- {call .ViewChangeButton data="all" /}
+ {call mailTemplate.ViewChangeButton data="all" /}
</p>
{/if}
- {call .Pre}{param content: $email.changeDetail /}{/call}
+ {call mailTemplate.Pre}
+ {param content: $email.changeDetail /}
+ {/call}
{if $email.sshHost}
- {call .Pre}{param content kind="html"}
- git pull ssh:{print '//'}{$email.sshHost}/{$projectName}
- {sp}{$patchSet.refName}
- {/param}{/call}
+ {call mailTemplate.Pre}
+ {param content kind="html"}
+ git pull ssh:{print '//'}{$email.sshHost}/{$projectName}
+ {sp}{$patchSet.refName}
+ {/param}
+ {/call}
{/if}
{if $email.includeDiff}
- {call .UnifiedDiff}{param diffLines: $diffLines /}{/call}
+ {call mailTemplate.UnifiedDiff}
+ {param diffLines: $diffLines /}
+ {/call}
{/if}
{/template}
diff --git a/tools/nongoogle.bzl b/tools/nongoogle.bzl
index e8f12c8..3f5ef20 100644
--- a/tools/nongoogle.bzl
+++ b/tools/nongoogle.bzl
@@ -164,8 +164,8 @@
# Keep this version of Soy synchronized with the version used in Gitiles.
maven_jar(
name = "soy",
- artifact = "com.google.template:soy:2019-10-08",
- sha1 = "4518bf8bac2dbbed684849bc209c39c4cb546237",
+ artifact = "com.google.template:soy:2021-02-01",
+ sha1 = "8e833744832ba88059205a1e30e0898f925d8cb5",
)
# Test-only dependencies below.