Merge "Clarify error message about FORGE_SERVER permission."
diff --git a/Documentation/rest-api-plugins.txt b/Documentation/rest-api-plugins.txt
index 0f687bf..938d101 100644
--- a/Documentation/rest-api-plugins.txt
+++ b/Documentation/rest-api-plugins.txt
@@ -47,6 +47,7 @@
"delete-project": {
"id": "delete-project",
"index_url": "plugins/delete-project/",
+ "filename": "delete-project.jar",
"version": "2.9-SNAPSHOT"
}
}
@@ -73,11 +74,13 @@
"delete-project": {
"id": "delete-project",
"index_url": "plugins/delete-project/",
+ "filename": "delete-project.jar",
"version": "2.9-SNAPSHOT"
},
"reviewers-by-blame": {
"id": "reviewers-by-blame",
"index_url": "plugins/reviewers-by-blame/",
+ "filename": "reviewers-by-blame.jar",
"version": "2.9-SNAPSHOT",
"disabled": true
}
@@ -105,6 +108,7 @@
"delete-project": {
"id": "delete-project",
"index_url": "plugins/delete-project/",
+ "filename": "delete-project.jar",
"version": "2.9-SNAPSHOT"
}
}
@@ -134,6 +138,7 @@
"delete-project": {
"id": "delete-project",
"index_url": "plugins/delete-project/",
+ "filename": "delete-project.jar",
"version": "2.9-SNAPSHOT"
}
}
@@ -168,11 +173,13 @@
"some-plugin": {
"id": "some-plugin",
"index_url": "plugins/some-plugin/",
+ "filename": "some-plugin.jar",
"version": "2.9-SNAPSHOT"
},
"some-other-plugin": {
"id": "some-other-plugin",
"index_url": "plugins/some-other-plugin/",
+ "filename": "some-other-plugin.jar",
"version": "2.9-SNAPSHOT"
}
}
@@ -200,6 +207,7 @@
"reviewers-by-blame": {
"id": "reviewers-by-blame",
"index_url": "plugins/reviewers-by-blame/",
+ "filename": "reviewers-by-blame.jar",
"version": "2.9-SNAPSHOT",
"disabled": true
}
@@ -229,6 +237,7 @@
"delete-project": {
"id": "delete-project",
"index_url": "plugins/delete-project/",
+ "filename": "delete-project.jar",
"version": "2.9-SNAPSHOT"
}
}
@@ -429,6 +438,7 @@
|`id` ||The ID of the plugin.
|`version` ||The version of the plugin.
|`index_url`|optional|URL of the plugin's default page.
+|`filename` |optional|The plugin's filename.
|`disabled` |not set if `false`|Whether the plugin is disabled.
|=======================
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/plugin/PluginIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/plugin/PluginIT.java
index 3e1b2cb..0fa09af 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/plugin/PluginIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/plugin/PluginIT.java
@@ -68,6 +68,7 @@
assertThat(info.id).isEqualTo(name);
assertThat(info.version).isEqualTo(pluginVersion(plugin));
assertThat(info.indexUrl).isEqualTo(String.format("plugins/%s/", name));
+ assertThat(info.filename).isEqualTo(plugin);
assertThat(info.disabled).isNull();
}
assertPlugins(list().get(), PLUGINS);
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/PluginInfo.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/PluginInfo.java
index bcb957e..0df6235 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/PluginInfo.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/common/PluginInfo.java
@@ -18,12 +18,14 @@
public final String id;
public final String version;
public final String indexUrl;
+ public final String filename;
public final Boolean disabled;
- public PluginInfo(String id, String version, String indexUrl, Boolean disabled) {
+ public PluginInfo(String id, String version, String indexUrl, String filename, Boolean disabled) {
this.id = id;
this.version = version;
this.indexUrl = indexUrl;
+ this.filename = filename;
this.disabled = disabled;
}
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/BaseInit.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/BaseInit.java
index 49fd1f9..f750fdb 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/BaseInit.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/BaseInit.java
@@ -73,6 +73,7 @@
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import java.util.Set;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -387,14 +388,25 @@
schemaUpdater.update(
new UpdateUI() {
@Override
- public void message(String msg) {
- System.err.println(msg);
+ public void message(String message) {
+ System.err.println(message);
System.err.flush();
}
@Override
- public boolean yesno(boolean def, String msg) {
- return ui.yesno(def, msg);
+ public boolean yesno(boolean defaultValue, String message) {
+ return ui.yesno(defaultValue, message);
+ }
+
+ @Override
+ public void waitForUser() {
+ ui.waitForUser();
+ }
+
+ @Override
+ public String readString(
+ String defaultValue, Set<String> allowedValues, String message) {
+ return ui.readString(defaultValue, allowedValues, message);
}
@Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/IncludingGroupMembership.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/IncludingGroupMembership.java
index 70801c3..165cbb6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/IncludingGroupMembership.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/IncludingGroupMembership.java
@@ -40,13 +40,16 @@
IncludingGroupMembership create(IdentifiedUser user);
}
+ private final GroupCache groupCache;
private final GroupIncludeCache includeCache;
private final IdentifiedUser user;
private final Map<AccountGroup.UUID, Boolean> memberOf;
private Set<AccountGroup.UUID> knownGroups;
@Inject
- IncludingGroupMembership(GroupIncludeCache includeCache, @Assisted IdentifiedUser user) {
+ IncludingGroupMembership(
+ GroupCache groupCache, GroupIncludeCache includeCache, @Assisted IdentifiedUser user) {
+ this.groupCache = groupCache;
this.includeCache = includeCache;
this.user = user;
@@ -88,6 +91,10 @@
}
memberOf.put(id, false);
+ AccountGroup group = groupCache.get(id);
+ if (group == null) {
+ continue;
+ }
if (search(includeCache.subgroupsOf(id))) {
memberOf.put(id, true);
return true;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/plugins/PluginsImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/plugins/PluginsImpl.java
index 75fb350..a955abe 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/plugins/PluginsImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/plugins/PluginsImpl.java
@@ -66,7 +66,7 @@
list.setMatchPrefix(this.getPrefix());
list.setMatchSubstring(this.getSubstring());
list.setMatchRegex(this.getRegex());
- return list.apply();
+ return list.apply(TopLevelResource.INSTANCE);
}
};
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ListPlugins.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ListPlugins.java
index 0e514d6..97d728d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ListPlugins.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ListPlugins.java
@@ -15,11 +15,8 @@
package com.google.gerrit.server.plugins;
import static java.util.Comparator.comparing;
-import static java.util.stream.Collectors.toList;
-import com.google.common.base.Strings;
import com.google.common.collect.Streams;
-import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.extensions.common.PluginInfo;
@@ -27,16 +24,12 @@
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.extensions.restapi.TopLevelResource;
import com.google.gerrit.extensions.restapi.Url;
-import com.google.gerrit.server.OutputFormat;
-import com.google.gson.reflect.TypeToken;
import com.google.inject.Inject;
-import java.io.PrintWriter;
-import java.util.List;
import java.util.Locale;
-import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.kohsuke.args4j.Option;
@@ -52,10 +45,6 @@
private String matchSubstring;
private String matchRegex;
- @Deprecated
- @Option(name = "--format", usage = "(deprecated) output format")
- private OutputFormat format = OutputFormat.TEXT;
-
@Option(
name = "--all",
aliases = {"-a"},
@@ -115,29 +104,8 @@
this.pluginLoader = pluginLoader;
}
- public OutputFormat getFormat() {
- return format;
- }
-
- public ListPlugins setFormat(OutputFormat fmt) {
- this.format = fmt;
- return this;
- }
-
@Override
- public Object apply(TopLevelResource resource) throws BadRequestException {
- format = OutputFormat.JSON;
- return display(null);
- }
-
- public SortedMap<String, PluginInfo> apply() throws BadRequestException {
- format = OutputFormat.JSON;
- return display(null);
- }
-
- public SortedMap<String, PluginInfo> display(@Nullable PrintWriter stdout)
- throws BadRequestException {
- SortedMap<String, PluginInfo> output = new TreeMap<>();
+ public SortedMap<String, PluginInfo> apply(TopLevelResource resource) throws BadRequestException {
Stream<Plugin> s = Streams.stream(pluginLoader.getPlugins(all));
if (matchPrefix != null) {
checkMatchOptions(matchSubstring == null && matchRegex == null);
@@ -158,38 +126,7 @@
if (limit > 0) {
s = s.limit(limit);
}
- List<Plugin> plugins = s.collect(toList());
-
- if (!format.isJson()) {
- stdout.format("%-30s %-10s %-8s %s\n", "Name", "Version", "Status", "File");
- stdout.print(
- "-------------------------------------------------------------------------------\n");
- }
-
- for (Plugin p : plugins) {
- PluginInfo info = toPluginInfo(p);
- if (format.isJson()) {
- output.put(p.getName(), info);
- } else {
- stdout.format(
- "%-30s %-10s %-8s %s\n",
- p.getName(),
- Strings.nullToEmpty(info.version),
- p.isDisabled() ? "DISABLED" : "ENABLED",
- p.getSrcFile().getFileName());
- }
- }
-
- if (stdout == null) {
- return output;
- } else if (format.isJson()) {
- format
- .newGson()
- .toJson(output, new TypeToken<Map<String, PluginInfo>>() {}.getType(), stdout);
- stdout.print('\n');
- }
- stdout.flush();
- return null;
+ return new TreeMap<>(s.collect(Collectors.toMap(p -> p.getName(), p -> toPluginInfo(p))));
}
private void checkMatchOptions(boolean cond) throws BadRequestException {
@@ -202,13 +139,20 @@
String id;
String version;
String indexUrl;
+ String filename;
Boolean disabled;
id = Url.encode(p.getName());
version = p.getVersion();
disabled = p.isDisabled() ? true : null;
- indexUrl = p.getSrcFile() != null ? String.format("plugins/%s/", p.getName()) : null;
+ if (p.getSrcFile() != null) {
+ indexUrl = String.format("plugins/%s/", p.getName());
+ filename = p.getSrcFile().getFileName().toString();
+ } else {
+ indexUrl = null;
+ filename = null;
+ }
- return new PluginInfo(id, version, indexUrl, disabled);
+ return new PluginInfo(id, version, indexUrl, filename, disabled);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIsVisibleToPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIsVisibleToPredicate.java
index 15fd190..e262881 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIsVisibleToPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIsVisibleToPredicate.java
@@ -30,7 +30,7 @@
public class ChangeIsVisibleToPredicate extends IsVisibleToPredicate<ChangeData> {
protected final Provider<ReviewDb> db;
protected final ChangeNotes.Factory notesFactory;
- protected final ChangeControl.GenericFactory changeControl;
+ protected final ChangeControl.GenericFactory changeControlFactory;
protected final CurrentUser user;
protected final PermissionBackend permissionBackend;
@@ -43,7 +43,7 @@
super(ChangeQueryBuilder.FIELD_VISIBLETO, describe(user));
this.db = db;
this.notesFactory = notesFactory;
- this.changeControl = changeControlFactory;
+ this.changeControlFactory = changeControlFactory;
this.user = user;
this.permissionBackend = permissionBackend;
}
@@ -53,19 +53,20 @@
if (cd.fastIsVisibleTo(user)) {
return true;
}
- Change change;
+ Change change = cd.change();
+ if (change == null) {
+ return false;
+ }
+
+ ChangeControl changeControl;
+ ChangeNotes notes = notesFactory.createFromIndexedChange(change);
try {
- change = cd.change();
- if (change == null) {
- return false;
- }
+ changeControl = changeControlFactory.controlFor(notes, user);
} catch (NoSuchChangeException e) {
// Ignored
return false;
}
- ChangeNotes notes = notesFactory.createFromIndexedChange(change);
- ChangeControl cc = changeControl.controlFor(notes, user);
boolean visible;
try {
visible =
@@ -78,10 +79,9 @@
throw new OrmException("unable to check permissions", e);
}
if (visible) {
- cd.cacheVisibleTo(cc);
+ cd.cacheVisibleTo(changeControl);
return true;
}
-
return false;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/JdbcAccountPatchReviewStore.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/JdbcAccountPatchReviewStore.java
index 5a3e76d..70fbf5c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/JdbcAccountPatchReviewStore.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/JdbcAccountPatchReviewStore.java
@@ -41,6 +41,12 @@
public abstract class JdbcAccountPatchReviewStore
implements AccountPatchReviewStore, LifecycleListener {
+ private static final String ACCOUNT_PATCH_REVIEW_DB = "accountPatchReviewDb";
+ private static final String H2_DB = "h2";
+ private static final String MARIADB = "mariadb";
+ private static final String MYSQL = "mysql";
+ private static final String POSTGRESQL = "postgresql";
+ private static final String URL = "url";
private static final Logger log = LoggerFactory.getLogger(JdbcAccountPatchReviewStore.class);
public static class Module extends LifecycleModule {
@@ -52,20 +58,20 @@
@Override
protected void configure() {
- String url = cfg.getString("accountPatchReviewDb", null, "url");
- if (url == null || url.contains("h2")) {
+ String url = cfg.getString(ACCOUNT_PATCH_REVIEW_DB, null, URL);
+ if (url == null || url.contains(H2_DB)) {
DynamicItem.bind(binder(), AccountPatchReviewStore.class)
.to(H2AccountPatchReviewStore.class);
listener().to(H2AccountPatchReviewStore.class);
- } else if (url.contains("postgresql")) {
+ } else if (url.contains(POSTGRESQL)) {
DynamicItem.bind(binder(), AccountPatchReviewStore.class)
.to(PostgresqlAccountPatchReviewStore.class);
listener().to(PostgresqlAccountPatchReviewStore.class);
- } else if (url.contains("mysql")) {
+ } else if (url.contains(MYSQL)) {
DynamicItem.bind(binder(), AccountPatchReviewStore.class)
.to(MysqlAccountPatchReviewStore.class);
listener().to(MysqlAccountPatchReviewStore.class);
- } else if (url.contains("mariadb")) {
+ } else if (url.contains(MARIADB)) {
DynamicItem.bind(binder(), AccountPatchReviewStore.class)
.to(MariaDBAccountPatchReviewStore.class);
listener().to(MariaDBAccountPatchReviewStore.class);
@@ -80,19 +86,21 @@
public static JdbcAccountPatchReviewStore createAccountPatchReviewStore(
Config cfg, SitePaths sitePaths) {
- String url = cfg.getString("accountPatchReviewDb", null, "url");
- if (url == null || url.contains("h2")) {
+ String url = cfg.getString(ACCOUNT_PATCH_REVIEW_DB, null, URL);
+ if (url == null || url.contains(H2_DB)) {
return new H2AccountPatchReviewStore(cfg, sitePaths);
- } else if (url.contains("postgresql")) {
- return new PostgresqlAccountPatchReviewStore(cfg, sitePaths);
- } else if (url.contains("mysql")) {
- return new MysqlAccountPatchReviewStore(cfg, sitePaths);
- } else if (url.contains("mariadb")) {
- return new MariaDBAccountPatchReviewStore(cfg, sitePaths);
- } else {
- throw new IllegalArgumentException(
- "unsupported driver type for account patch reviews db: " + url);
}
+ if (url.contains(POSTGRESQL)) {
+ return new PostgresqlAccountPatchReviewStore(cfg, sitePaths);
+ }
+ if (url.contains(MYSQL)) {
+ return new MysqlAccountPatchReviewStore(cfg, sitePaths);
+ }
+ if (url.contains(MARIADB)) {
+ return new MariaDBAccountPatchReviewStore(cfg, sitePaths);
+ }
+ throw new IllegalArgumentException(
+ "unsupported driver type for account patch reviews db: " + url);
}
protected JdbcAccountPatchReviewStore(Config cfg, SitePaths sitePaths) {
@@ -104,7 +112,7 @@
}
private static String getUrl(@GerritServerConfig Config cfg, SitePaths sitePaths) {
- String url = cfg.getString("accountPatchReviewDb", null, "url");
+ String url = cfg.getString(ACCOUNT_PATCH_REVIEW_DB, null, URL);
if (url == null) {
return H2.createUrl(sitePaths.db_dir.resolve("account_patch_reviews"));
}
@@ -113,13 +121,13 @@
protected static DataSource createDataSource(String url) {
BasicDataSource datasource = new BasicDataSource();
- if (url.contains("postgresql")) {
+ if (url.contains(POSTGRESQL)) {
datasource.setDriverClassName("org.postgresql.Driver");
- } else if (url.contains("h2")) {
+ } else if (url.contains(H2_DB)) {
datasource.setDriverClassName("org.h2.Driver");
- } else if (url.contains("mysql")) {
+ } else if (url.contains(MYSQL)) {
datasource.setDriverClassName("com.mysql.jdbc.Driver");
- } else if (url.contains("mariadb")) {
+ } else if (url.contains(MARIADB)) {
datasource.setDriverClassName("org.mariadb.jdbc.Driver");
}
datasource.setUrl(url);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/UpdateUI.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/UpdateUI.java
index b43aaa6..0c02607 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/UpdateUI.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/UpdateUI.java
@@ -17,11 +17,24 @@
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.StatementExecutor;
import java.util.List;
+import java.util.Set;
public interface UpdateUI {
- void message(String msg);
- boolean yesno(boolean def, String msg);
+ void message(String message);
+
+ /** Requests the user to answer a yes/no question. */
+ boolean yesno(boolean defaultValue, String message);
+
+ /** Prints a message asking the user to let us know when it's safe to continue. */
+ void waitForUser();
+
+ /**
+ * Prompts the user for a string, suggesting a default.
+ *
+ * @return the chosen string from the list of allowed values.
+ */
+ String readString(String defaultValue, Set<String> allowedValues, String message);
boolean isBatch();
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java
index d9fc7e5..5b86f46 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java
@@ -34,9 +34,9 @@
import com.google.gerrit.testutil.InMemoryDatabase;
import com.google.gerrit.testutil.InMemoryH2Type;
import com.google.gerrit.testutil.InMemoryRepositoryManager;
+import com.google.gerrit.testutil.TestUpdateUI;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.SchemaFactory;
-import com.google.gwtorm.server.StatementExecutor;
import com.google.inject.Guice;
import com.google.inject.Key;
import com.google.inject.ProvisionException;
@@ -45,7 +45,6 @@
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.List;
import java.util.UUID;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.PersonIdent;
@@ -133,28 +132,7 @@
}
}
- u.update(
- new UpdateUI() {
- @Override
- public void message(String msg) {}
-
- @Override
- public boolean yesno(boolean def, String msg) {
- return def;
- }
-
- @Override
- public boolean isBatch() {
- return true;
- }
-
- @Override
- public void pruneSchema(StatementExecutor e, List<String> pruneList) throws OrmException {
- for (String sql : pruneList) {
- e.execute(sql);
- }
- }
- });
+ u.update(new TestUpdateUI());
db.assertSchemaVersion();
final SystemConfig sc = db.getSystemConfig();
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/TestUpdateUI.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/TestUpdateUI.java
index 644f8e2..d4acbcb 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/testutil/TestUpdateUI.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/TestUpdateUI.java
@@ -18,21 +18,34 @@
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.StatementExecutor;
import java.util.List;
+import java.util.Set;
public class TestUpdateUI implements UpdateUI {
@Override
- public void message(String msg) {}
+ public void message(String message) {}
@Override
- public boolean yesno(boolean def, String msg) {
- return false;
+ public boolean yesno(boolean defaultValue, String message) {
+ return defaultValue;
+ }
+
+ @Override
+ public void waitForUser() {}
+
+ @Override
+ public String readString(String defaultValue, Set<String> allowedValues, String message) {
+ return defaultValue;
}
@Override
public boolean isBatch() {
- return false;
+ return true;
}
@Override
- public void pruneSchema(StatementExecutor e, List<String> pruneList) throws OrmException {}
+ public void pruneSchema(StatementExecutor e, List<String> pruneList) throws OrmException {
+ for (String sql : pruneList) {
+ e.execute(sql);
+ }
+ }
}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginLsCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginLsCommand.java
index 78c9526..0fdd105 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginLsCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/PluginLsCommand.java
@@ -16,25 +16,68 @@
import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER_OR_SLAVE;
+import com.google.common.base.Strings;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
+import com.google.gerrit.extensions.common.PluginInfo;
+import com.google.gerrit.extensions.restapi.TopLevelResource;
+import com.google.gerrit.server.OutputFormat;
import com.google.gerrit.server.plugins.ListPlugins;
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
+import com.google.gson.reflect.TypeToken;
import com.google.inject.Inject;
+import java.util.Map;
+import org.kohsuke.args4j.Option;
@RequiresCapability(GlobalCapability.VIEW_PLUGINS)
@CommandMetaData(name = "ls", description = "List the installed plugins", runsAt = MASTER_OR_SLAVE)
final class PluginLsCommand extends SshCommand {
- @Inject private ListPlugins impl;
+ @Inject private ListPlugins list;
+
+ @Option(
+ name = "--all",
+ aliases = {"-a"},
+ usage = "List all plugins, including disabled plugins"
+ )
+ private boolean all;
+
+ @Option(name = "--format", usage = "output format")
+ private OutputFormat format = OutputFormat.TEXT;
@Override
public void run() throws Exception {
- impl.display(stdout);
+ list.setAll(all);
+ Map<String, PluginInfo> output = list.apply(TopLevelResource.INSTANCE);
+
+ if (format.isJson()) {
+ format
+ .newGson()
+ .toJson(output, new TypeToken<Map<String, PluginInfo>>() {}.getType(), stdout);
+ stdout.print('\n');
+ } else {
+ stdout.format("%-30s %-10s %-8s %s\n", "Name", "Version", "Status", "File");
+ stdout.print(
+ "-------------------------------------------------------------------------------\n");
+ for (Map.Entry<String, PluginInfo> p : output.entrySet()) {
+ PluginInfo info = p.getValue();
+ stdout.format(
+ "%-30s %-10s %-8s %s\n",
+ p.getKey(),
+ Strings.nullToEmpty(info.version),
+ status(info.disabled),
+ Strings.nullToEmpty(info.filename));
+ }
+ }
+ stdout.flush();
+ }
+
+ private String status(Boolean disabled) {
+ return disabled != null && disabled.booleanValue() ? "DISABLED" : "ENABLED";
}
@Override
protected void parseCommandLine() throws UnloggedFailure {
- parseCommandLine(impl);
+ parseCommandLine(this);
}
}
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.js b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.js
index 3e6d16b..276a925 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.js
+++ b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.js
@@ -50,6 +50,10 @@
observer: '_computeGroupName',
},
_groupName: String,
+ _groupOwner: {
+ type: Boolean,
+ value: false,
+ },
_filteredLinks: Array,
_showDownload: {
type: Boolean,
@@ -123,16 +127,19 @@
name: this._groupName,
view: 'gr-group',
url: `/admin/groups/${this.encodeURL(this._groupId, true)}`,
- children: [
- {
- name: 'Audit Log',
- detailType: 'audit-log',
- view: 'gr-group-audit-log',
- url: `/admin/groups/${this.encodeURL(this._groupId, true)}` +
- ',audit-log',
- },
- ],
+ children: [],
};
+ if (this._groupOwner) {
+ linkCopy.subsection.children.push(
+ {
+ name: 'Audit Log',
+ detailType: 'audit-log',
+ view: 'gr-group-audit-log',
+ url: `/admin/groups/${this.encodeURL(this._groupId, true)}` +
+ ',audit-log',
+ }
+ );
+ }
}
filteredLinks.push(linkCopy);
}
@@ -203,6 +210,13 @@
this.$.restAPI.getGroupConfig(groupId).then(group => {
this._groupName = group.name;
this.reload();
+ this.$.restAPI.getIsGroupOwner(group.name).then(
+ configs => {
+ if (configs.hasOwnProperty(group.name)) {
+ this._groupOwner = true;
+ this.reload();
+ }
+ });
});
},
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.html b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.html
index b347890..6129e9b 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.html
@@ -90,10 +90,12 @@
setup(done => {
const pluginHost = fixture('plugin-host');
pluginHost.config = {
- js_resource_paths: [],
- html_resource_paths: [
- new URL('test/plugin.html', window.location.href).toString(),
- ],
+ plugin: {
+ js_resource_paths: [],
+ html_resource_paths: [
+ new URL('test/plugin.html', window.location.href).toString(),
+ ],
+ },
};
element = fixture('element');
const importSpy = sandbox.spy(element.$.externalStyle, '_import');
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message.html b/polygerrit-ui/app/elements/change/gr-message/gr-message.html
index 78f59db..cbbe828 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message.html
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message.html
@@ -14,9 +14,8 @@
limitations under the License.
-->
-<link rel="import" href="../../../behaviors/gr-anonymous-name-behavior/gr-anonymous-name-behavior.html">
<link rel="import" href="../../../bower_components/polymer/polymer.html">
-<link rel="import" href="../../shared/gr-account-link/gr-account-link.html">
+<link rel="import" href="../../shared/gr-account-label/gr-account-label.html">
<link rel="import" href="../../shared/gr-button/gr-button.html">
<link rel="import" href="../../shared/gr-date-formatter/gr-date-formatter.html">
<link rel="import" href="../../shared/gr-formatted-text/gr-formatted-text.html">
@@ -135,6 +134,11 @@
.negativeVote {
box-shadow: inset 0 4.4em #ffd4d4;
}
+ gr-account-label {
+ --gr-account-label-text-style: {
+ font-weight: bold;
+ };
+ }
</style>
<div class$="[[_computeClass(_expanded, showAvatar, message)]]">
<gr-avatar account="[[author]]" image-size="100"></gr-avatar>
@@ -144,7 +148,10 @@
<span class="name">[[message.real_author.name]]</span>
on behalf of
</span>
- <span class="name">[[_authorOrAnon(author)]]</span>
+ <gr-account-label
+ account="[[author]]"
+ show-anonymous
+ hide-avatar></gr-account-label>
</div>
<template is="dom-if" if="[[message.message]]">
<div class="content">
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message.js b/polygerrit-ui/app/elements/change/gr-message/gr-message.js
index 2593869..e6a761a 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message.js
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message.js
@@ -90,10 +90,6 @@
},
},
- behaviors: [
- Gerrit.AnonymousNameBehavior,
- ],
-
observers: [
'_updateExpandedClass(message.expanded)',
],
@@ -235,16 +231,6 @@
this.fire('reply', {message: this.message});
},
- _authorOrAnon(author) {
- if (author && author.name) {
- return author.name;
- } else if (author && author.email) {
- return author.email;
- }
-
- return this.getAnonymousName(this.config);
- },
-
_projectNameChanged(name) {
this.$.restAPI.getProjectConfig(name).then(config => {
this._commentLinks = config.commentlinks;
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message_test.html b/polygerrit-ui/app/elements/change/gr-message/gr-message_test.html
index cfeb9cd..aa18c4e 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message_test.html
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message_test.html
@@ -65,37 +65,6 @@
MockInteractions.tap(element.$$('.replyContainer gr-button'));
});
- test('reviewer update', () => {
- const author = {
- _account_id: 1115495,
- name: 'Andrew Bonventre',
- email: 'andybons@chromium.org',
- };
- const reviewer = {
- _account_id: 123456,
- name: 'Foo Bar',
- email: 'barbar@chromium.org',
- };
- element.message = {
- id: 0xDEADBEEF,
- author,
- reviewer,
- date: '2016-01-12 20:24:49.448000000',
- type: 'REVIEWER_UPDATE',
- updates: [
- {
- message: 'Added to CC:',
- reviewers: [reviewer],
- },
- ],
- };
- flushAsynchronousOperations();
- const content = element.$$('.contentContainer');
- assert.isOk(content);
- assert.strictEqual(element.$$('gr-account-chip').account, reviewer);
- assert.equal(author.name, element.$$('.author > .name').textContent);
- });
-
test('autogenerated prefix hiding', () => {
element.message = {
tag: 'autogenerated:gerrit:test',
@@ -211,27 +180,5 @@
};
assert.isOk(Polymer.dom(element.root).querySelector('.positiveVote'));
});
-
- test('test for Anonymous Coward user and replace with Anonymous', () => {
- element.config = {
- user: {
- anonymous_coward_name: 'Anonymous Coward',
- },
- };
- element.account = {};
- assert.deepEqual(
- element._authorOrAnon(element.account), 'Anonymous');
- });
-
- test('test for anonymous_coward_name', () => {
- element.config = {
- user: {
- anonymous_coward_name: 'TestAnon',
- },
- };
- element.account = {};
- assert.deepEqual(
- element._authorOrAnon(element.account, element.config), 'TestAnon');
- });
});
</script>
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog-it_test.html b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog-it_test.html
index e76a9e5..babd95c 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog-it_test.html
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog-it_test.html
@@ -132,10 +132,12 @@
test('lgtm plugin', done => {
const pluginHost = fixture('plugin-host');
pluginHost.config = {
- js_resource_paths: [],
- html_resource_paths: [
- new URL('test/plugin.html', window.location.href).toString(),
- ],
+ plugin: {
+ js_resource_paths: [],
+ html_resource_paths: [
+ new URL('test/plugin.html', window.location.href).toString(),
+ ],
+ },
};
element = fixture('basic');
setupElement(element);
diff --git a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
index 3fc2c22..3083789 100644
--- a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
+++ b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
@@ -184,6 +184,7 @@
return this._getUrlFor({
view: Gerrit.Nav.View.CHANGE,
changeNum: change._number,
+ project: change.project,
patchNum: opt_patchNum,
basePatchNum: opt_basePatchNum,
});
@@ -215,9 +216,9 @@
},
/**
- * @param {!number} change The change object.
- * @param {!string} projectName The name of the project.
- * @param {!string} path The file path.
+ * @param {number} changeNum
+ * @param {string} project The name of the project.
+ * @param {string} path The file path.
* @param {number=} opt_patchNum
* @param {number|string=} opt_basePatchNum The string 'PARENT' can be
* used for none.
@@ -225,7 +226,7 @@
* @param {boolean=} opt_leftSide
* @return {string}
*/
- getUrlForDiffById(changeNum, projectName, path, opt_patchNum,
+ getUrlForDiffById(changeNum, project, path, opt_patchNum,
opt_basePatchNum, opt_lineNum, opt_leftSide) {
if (opt_basePatchNum === PARENT_PATCHNUM) {
opt_basePatchNum = undefined;
@@ -235,7 +236,7 @@
return this._getUrlFor({
view: Gerrit.Nav.View.DIFF,
changeNum,
- projectName,
+ project,
path,
patchNum: opt_patchNum,
basePatchNum: opt_basePatchNum,
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
index 2908f85..440f44b 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
@@ -153,6 +153,9 @@
-webkit-user-select: text;
user-select: text;
}
+ .editLoaded .hideOnEdit {
+ display: none;
+ }
@media screen and (max-width: 50em) {
header {
padding: .5em var(--default-horizontal-margin);
@@ -200,6 +203,7 @@
}
</style>
<gr-fixed-panel
+ class$="[[_computeContainerClass(_editLoaded)]]"
floating-disabled="[[_panelFloatingDisabled]]"
keep-on-scroll
ready-for-measure="[[!_loading]]">
@@ -210,10 +214,10 @@
<span>[[_change.subject]]</span>
<span class="dash">—</span>
<input id="reviewed"
- class="reviewed"
- type="checkbox"
- on-change="_handleReviewedChange"
- hidden$="[[!_loggedIn]]" hidden>
+ class="reviewed hideOnEdit"
+ type="checkbox"
+ on-change="_handleReviewedChange"
+ hidden$="[[!_loggedIn]]" hidden>
<div class="jumpToFileContainer desktop">
<gr-button link class="dropdown-trigger" id="trigger" on-tap="_showDropdownTapHandler">
<span>[[_computeFileDisplayName(_path)]]</span>
@@ -231,9 +235,9 @@
as="path"
initial-count="75">
<a href$="[[_computeDiffURL(_change, _patchRange.*, path)]]"
- selected$="[[_computeFileSelected(path, _path)]]"
- data-key-nav$="[[_computeKeyNav(path, _path, _fileList)]]"
- on-tap="_handleFileTap">[[_computeFileDisplayName(path)]]</a>
+ selected$="[[_computeFileSelected(path, _path)]]"
+ data-key-nav$="[[_computeKeyNav(path, _path, _fileList)]]"
+ on-tap="_handleFileTap">[[_computeFileDisplayName(path)]]</a>
</template>
</div>
</iron-dropdown>
@@ -277,7 +281,7 @@
<span class="download desktop">
<span class="separator">/</span>
<a class="downloadLink"
- href$="[[_computeDownloadLink(_changeNum, _patchRange, _path)]]">
+ href$="[[_computeDownloadLink(_changeNum, _patchRange, _path)]]">
Download
</a>
</span>
@@ -306,7 +310,7 @@
</div>
<div class="fileNav mobile">
<a class="mobileNavLink"
- href$="[[_computeNavLinkURL(_change, _path, _fileList, -1, 1)]]">
+ href$="[[_computeNavLinkURL(_change, _path, _fileList, -1, 1)]]">
<</a>
<div class="fullFileName mobile">[[_computeFileDisplayName(_path)]]
</div>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
index 0f6a07d..c12f700 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
@@ -113,6 +113,10 @@
type: Boolean,
value: () => { return window.PANEL_FLOATING_DISABLED; },
},
+ _editLoaded: {
+ type: Boolean,
+ computed: '_computeEditLoaded(_patchRange.*)',
+ },
},
behaviors: [
@@ -205,6 +209,7 @@
},
_setReviewed(reviewed) {
+ if (this._editLoaded) { return; }
this.$.reviewed.checked = reviewed;
this._saveReviewedState(reviewed).catch(err => {
this.fire('show-alert', {message: ERR_REVIEW_STATUS});
@@ -767,5 +772,20 @@
return 'noOverflow';
}
},
+
+ /**
+ * @param {!Object} patchRangeRecord
+ */
+ _computeEditLoaded(patchRangeRecord) {
+ const patchRange = patchRangeRecord.base || {};
+ return this.patchNumEquals(patchRange.patchNum, this.EDIT_NAME);
+ },
+
+ /**
+ * @param {boolean} editLoaded
+ */
+ _computeContainerClass(editLoaded) {
+ return editLoaded ? 'editLoaded' : '';
+ },
});
})();
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html
index 8ff75c1..49e82d4 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html
@@ -494,6 +494,17 @@
});
});
+ test('file review status with edit loaded', () => {
+ const saveReviewedStub = sandbox.stub(element, '_saveReviewedState');
+
+ element._patchRange = {patchNum: element.EDIT_NAME};
+ flushAsynchronousOperations();
+
+ assert.isTrue(element._editLoaded);
+ element._setReviewed();
+ assert.isFalse(saveReviewedStub.called);
+ });
+
test('hash is determined from params', done => {
stub('gr-rest-api-interface', {
getDiffComments() { return Promise.resolve({}); },
@@ -746,5 +757,34 @@
assert.isFalse(upgradeStub.called);
});
});
+
+ test('_computeEditLoaded', () => {
+ const callCompute = range => element._computeEditLoaded({base: range});
+ assert.isFalse(callCompute({}));
+ assert.isFalse(callCompute({basePatchNum: 'PARENT', patchNum: 1}));
+ assert.isFalse(callCompute({basePatchNum: 'edit', patchNum: 1}));
+ assert.isTrue(callCompute({basePatchNum: 1, patchNum: 'edit'}));
+ });
+
+ suite('editLoaded behavior', () => {
+ setup(() => {
+ element._loggedIn = true;
+ });
+
+ const isVisible = el => {
+ assert.ok(el);
+ return getComputedStyle(el).getPropertyValue('display') !== 'none';
+ };
+
+ test('reviewed checkbox', () => {
+ element._patchRange = {patchNum: '1'};
+ // Reviewed checkbox should be shown.
+ assert.isTrue(isVisible(element.$.reviewed));
+ element.set('_patchRange.patchNum', element.EDIT_NAME);
+ flushAsynchronousOperations();
+
+ assert.isFalse(isVisible(element.$.reviewed));
+ });
+ });
});
</script>
diff --git a/polygerrit-ui/app/elements/gr-app.html b/polygerrit-ui/app/elements/gr-app.html
index 07ecb8d..defbe8a 100644
--- a/polygerrit-ui/app/elements/gr-app.html
+++ b/polygerrit-ui/app/elements/gr-app.html
@@ -206,7 +206,7 @@
<gr-reporting id="reporting"></gr-reporting>
<gr-router id="router"></gr-router>
<gr-plugin-host id="plugins"
- config="[[_serverConfig.plugin]]">
+ config="[[_serverConfig]]">
</gr-plugin-host>
<gr-external-style id="externalStyle" name="app-theme"></gr-external-style>
</template>
diff --git a/polygerrit-ui/app/elements/gr-app_test.html b/polygerrit-ui/app/elements/gr-app_test.html
index 905c5c4..3712ffa 100644
--- a/polygerrit-ui/app/elements/gr-app_test.html
+++ b/polygerrit-ui/app/elements/gr-app_test.html
@@ -50,7 +50,7 @@
getConfig() {
return Promise.resolve({
gerrit: {web_uis: ['GWT', 'POLYGERRIT']},
- plugin: {js_resource_paths: []},
+ plugin: {},
});
},
getPreferences() { return Promise.resolve({my: []}); },
@@ -100,11 +100,9 @@
});
});
- test('passes config to gr-plugin-host', done => {
- element.$.restAPI.getConfig.lastCall.returnValue.then(config => {
- const pluginConfig = config.plugin;
- assert.deepEqual(element.$.plugins.config, pluginConfig);
- done();
+ test('passes config to gr-plugin-host', () => {
+ return element.$.restAPI.getConfig.lastCall.returnValue.then(config => {
+ assert.deepEqual(element.$.plugins.config, config);
});
});
});
diff --git a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.js b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.js
index 03b6d56..1ce8620 100644
--- a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.js
+++ b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.js
@@ -29,8 +29,9 @@
],
_configChanged(config) {
- const jsPlugins = config.js_resource_paths || [];
- const htmlPlugins = config.html_resource_paths || [];
+ const plugins = config.plugin;
+ const jsPlugins = plugins.js_resource_paths || [];
+ const htmlPlugins = plugins.html_resource_paths || [];
const defaultTheme = config.default_theme;
if (defaultTheme) {
// Make theme first to be first to load.
diff --git a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host_test.html b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host_test.html
index 2cacede..27adbe1 100644
--- a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host_test.html
+++ b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host_test.html
@@ -48,15 +48,17 @@
test('counts plugins', () => {
sandbox.stub(Gerrit, '_setPluginsCount');
element.config = {
- html_resource_paths: ['foo/bar', 'baz'],
- js_resource_paths: ['42'],
+ plugin: {
+ html_resource_paths: ['foo/bar', 'baz'],
+ js_resource_paths: ['42'],
+ },
};
assert.isTrue(Gerrit._setPluginsCount.calledWith(3));
});
test('imports relative html plugins from config', () => {
element.config = {
- html_resource_paths: ['foo/bar', 'baz'],
+ plugin: {html_resource_paths: ['foo/bar', 'baz']},
};
assert.isTrue(element.importHref.calledWith(
'/foo/bar', Gerrit._pluginInstalled, Gerrit._pluginInstalled, true));
@@ -67,8 +69,7 @@
test('imports relative html plugins from config with a base url', () => {
sandbox.stub(element, 'getBaseUrl').returns('/the-base');
element.config = {
- html_resource_paths: ['foo/bar', 'baz'],
- };
+ plugin: {html_resource_paths: ['foo/bar', 'baz']}};
assert.isTrue(element.importHref.calledWith(
'/the-base/foo/bar', Gerrit._pluginInstalled, Gerrit._pluginInstalled,
true));
@@ -79,10 +80,12 @@
test('imports absolute html plugins from config', () => {
element.config = {
- html_resource_paths: [
- 'http://example.com/foo/bar',
- 'https://example.com/baz',
- ],
+ plugin: {
+ html_resource_paths: [
+ 'http://example.com/foo/bar',
+ 'https://example.com/baz',
+ ],
+ },
};
assert.isTrue(element.importHref.calledWith(
'http://example.com/foo/bar', Gerrit._pluginInstalled,
@@ -93,17 +96,13 @@
});
test('adds js plugins from config to the body', () => {
- element.config = {
- js_resource_paths: ['foo/bar', 'baz'],
- };
+ element.config = {plugin: {js_resource_paths: ['foo/bar', 'baz']}};
assert.isTrue(document.body.appendChild.calledTwice);
});
test('imports relative js plugins from config', () => {
sandbox.stub(element, '_createScriptTag');
- element.config = {
- js_resource_paths: ['foo/bar', 'baz'],
- };
+ element.config = {plugin: {js_resource_paths: ['foo/bar', 'baz']}};
assert.isTrue(element._createScriptTag.calledWith('/foo/bar'));
assert.isTrue(element._createScriptTag.calledWith('/baz'));
});
@@ -111,9 +110,7 @@
test('imports relative html plugins from config with a base url', () => {
sandbox.stub(element, '_createScriptTag');
sandbox.stub(element, 'getBaseUrl').returns('/the-base');
- element.config = {
- js_resource_paths: ['foo/bar', 'baz'],
- };
+ element.config = {plugin: {js_resource_paths: ['foo/bar', 'baz']}};
assert.isTrue(element._createScriptTag.calledWith('/the-base/foo/bar'));
assert.isTrue(element._createScriptTag.calledWith('/the-base/baz'));
});
@@ -121,10 +118,12 @@
test('imports absolute html plugins from config', () => {
sandbox.stub(element, '_createScriptTag');
element.config = {
- js_resource_paths: [
- 'http://example.com/foo/bar',
- 'https://example.com/baz',
- ],
+ plugin: {
+ js_resource_paths: [
+ 'http://example.com/foo/bar',
+ 'https://example.com/baz',
+ ],
+ },
};
assert.isTrue(element._createScriptTag.calledWith(
'http://example.com/foo/bar'));
@@ -135,7 +134,9 @@
test('default theme is loaded with html plugins', () => {
element.config = {
default_theme: '/oof',
- html_resource_paths: ['some'],
+ plugin: {
+ html_resource_paths: ['some'],
+ },
};
assert.isTrue(element.importHref.calledWith(
'/oof', Gerrit._pluginInstalled, Gerrit._pluginInstalled, true));
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.html b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.html
index a93198c..3811a91 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.html
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.html
@@ -14,8 +14,11 @@
limitations under the License.
-->
+<link rel="import" href="../../../behaviors/gr-anonymous-name-behavior/gr-anonymous-name-behavior.html">
<link rel="import" href="../../../bower_components/polymer/polymer.html">
+<link rel="import" href="../../../behaviors/gr-tooltip-behavior/gr-tooltip-behavior.html">
<link rel="import" href="../gr-avatar/gr-avatar.html">
+<link rel="import" href="../gr-rest-api-interface/gr-rest-api-interface.html">
<link rel="import" href="../../../styles/shared-styles.html">
<dom-module id="gr-account-label">
@@ -33,15 +36,20 @@
margin-right: .15em;
vertical-align: -.25em;
}
+ .text {
+ @apply(--gr-account-label-text-style);
+ }
.text:hover {
@apply(--gr-account-label-text-hover-style);
}
</style>
- <span title$="[[_computeAccountTitle(account)]]">
- <gr-avatar account="[[account]]"
- image-size="[[avatarImageSize]]"></gr-avatar>
+ <span>
+ <template is="dom-if" if="[[!hideAvatar]]">
+ <gr-avatar account="[[account]]"
+ image-size="[[avatarImageSize]]"></gr-avatar>
+ </template>
<span class="text">
- <span>[[account.name]]</span>
+ <span>[[_computeName(account, _serverConfig, showAnonymous)]]</span>
<span hidden$="[[!_computeShowEmail(showEmail, account)]]">
[[_computeEmailStr(account)]]
</span>
@@ -50,6 +58,7 @@
</template>
</span>
</span>
+ <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
</template>
<script src="../../../scripts/util.js"></script>
<script src="gr-account-label.js"></script>
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.js b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.js
index 9ebef82..0071e15 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.js
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.js
@@ -27,6 +27,50 @@
type: Boolean,
value: false,
},
+ title: {
+ type: String,
+ reflectToAttribute: true,
+ computed: '_computeAccountTitle(account)',
+ },
+ hasTooltip: {
+ type: Boolean,
+ reflectToAttribute: true,
+ computed: '_computeHasTooltip(account)',
+ },
+ hideAvatar: {
+ type: Boolean,
+ value: false,
+ },
+ showAnonymous: {
+ type: Boolean,
+ value: false,
+ },
+ _serverConfig: {
+ type: Object,
+ value: null,
+ },
+ },
+
+ behaviors: [
+ Gerrit.AnonymousNameBehavior,
+ Gerrit.TooltipBehavior,
+ ],
+
+ ready() {
+ if (this.showAnonymous) {
+ this.$.restAPI.getConfig()
+ .then(config => { this._serverConfig = config; });
+ }
+ },
+
+ _computeName(account, config, showAnonymous) {
+ if (account && account.name) {
+ return account.name;
+ }
+ if (showAnonymous) {
+ return this.getAnonymousName(config);
+ }
+ return '';
},
_computeAccountTitle(account) {
@@ -54,5 +98,10 @@
}
return account.email;
},
+
+ _computeHasTooltip(account) {
+ // If an account has loaded to fire this method, then set to true.
+ return !!account;
+ },
});
})();
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.html b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.html
index 3b1e1de..7095be3 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.html
@@ -89,5 +89,40 @@
element._computeEmailStr({name: 'test', email: 'test'}), '(test)');
assert.equal(element._computeEmailStr({email: 'test'}, ''), 'test');
});
+
+ suite('_computeName', () => {
+ test('not showing anonymous', () => {
+ const account = {name: 'Wyatt'};
+ assert.deepEqual(element._computeName(account, null, false), 'Wyatt');
+ });
+
+ test('showing anonymous but no config', () => {
+ const account = {};
+ assert.deepEqual(element._computeName(account, null, true),
+ 'Anonymous');
+ });
+
+ test('test for Anonymous Coward user and replace with Anonymous', () => {
+ const config = {
+ user: {
+ anonymous_coward_name: 'Anonymous Coward',
+ },
+ };
+ const account = {};
+ assert.deepEqual(element._computeName(account, config, true),
+ 'Anonymous');
+ });
+
+ test('test for anonymous_coward_name', () => {
+ const config = {
+ user: {
+ anonymous_coward_name: 'TestAnon',
+ },
+ };
+ const account = {};
+ assert.deepEqual(element._computeName(account, config, true),
+ 'TestAnon');
+ });
+ });
});
</script>
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
index a631c2f..d1b9417 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
@@ -67,12 +67,16 @@
const base = Gerrit.BaseUrlBehavior.getBaseUrl();
this._url = new URL(opt_url);
- if (!this._url.pathname.startsWith(base + '/plugins')) {
+ const pathname = this._url.pathname.replace(base, '');
+ // Site theme is server from predefined path.
+ if (pathname === '/static/gerrit-theme.html') {
+ this._name = 'gerrit-theme';
+ } else if (!pathname.startsWith('/plugins')) {
console.warn('Plugin not being loaded from /plugins base path:',
this._url.href, '— Unable to determine name.');
return;
}
- this._name = this._url.pathname.replace(base, '').split('/')[2];
+ this._name = pathname.split('/')[2];
}
Plugin._sharedAPIElement = document.createElement('gr-js-api-interface');
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
index 5ddd0fe..6e780ab 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
@@ -94,10 +94,12 @@
* Doesn't do error checking. Supports cancel condition. Performs auth.
* Validates auth expiry errors.
* @param {string} url
- * @param {function(response, error)} opt_errFn
- * @param {function()} opt_cancelCondition
- * @param {Object=} opt_params URL params, key-value hash.
- * @param {Object=} opt_options Fetch options.
+ * @param {?function(?Response, string=)=} opt_errFn
+ * passed as null sometimes.
+ * @param {?function()=} opt_cancelCondition
+ * passed as null sometimes.
+ * @param {?Object=} opt_params URL params, key-value hash.
+ * @param {?Object=} opt_options Fetch options.
*/
_fetchRawJSON(url, opt_errFn, opt_cancelCondition, opt_params,
opt_options) {
@@ -119,7 +121,7 @@
return;
}
if (opt_errFn) {
- opt_errFn.call(null, null, err);
+ opt_errFn.call(undefined, null, err);
} else {
this.fire('network-error', {error: err});
}
@@ -132,10 +134,12 @@
* Returns a Promise that resolves to a parsed response.
* Same as {@link _fetchRawJSON}, plus error handling.
* @param {string} url
- * @param {function(response, error)} opt_errFn
- * @param {function()} opt_cancelCondition
- * @param {Object=} opt_params URL params, key-value hash.
- * @param {Object=} opt_options Fetch options.
+ * @param {?function(?Response, string=)=} opt_errFn
+ * passed as null sometimes.
+ * @param {?function()=} opt_cancelCondition
+ * passed as null sometimes.
+ * @param {?Object=} opt_params URL params, key-value hash.
+ * @param {?Object=} opt_options Fetch options.
*/
fetchJSON(url, opt_errFn, opt_cancelCondition, opt_params, opt_options) {
return this._fetchRawJSON(
@@ -156,6 +160,11 @@
});
},
+ /**
+ * @param {string} url
+ * @param {?Object=} opt_params URL params, key-value hash.
+ * @return {string}
+ */
_urlWithParams(url, opt_params) {
if (!opt_params) { return this.getBaseUrl() + url; }
@@ -172,6 +181,10 @@
return this.getBaseUrl() + url + '?' + params.join('&');
},
+ /**
+ * @param {!Object} response
+ * @return {?}
+ */
getResponseObject(response) {
return response.text().then(text => {
let result;
@@ -204,6 +217,11 @@
opt_errFn, opt_ctx);
},
+ /**
+ * @param {?Object} config
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {?=} opt_ctx
+ */
createProject(config, opt_errFn, opt_ctx) {
if (!config.name) { return ''; }
const encodeName = encodeURIComponent(config.name);
@@ -211,6 +229,11 @@
opt_ctx);
},
+ /**
+ * @param {?Object} config
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {?=} opt_ctx
+ */
createGroup(config, opt_errFn, opt_ctx) {
if (!config.name) { return ''; }
const encodeName = encodeURIComponent(config.name);
@@ -223,6 +246,12 @@
return this._fetchSharedCacheURL('/groups/' + encodeName + '/detail');
},
+ /**
+ * @param {string} project
+ * @param {string} ref
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {?=} opt_ctx
+ */
deleteProjectBranches(project, ref, opt_errFn, opt_ctx) {
if (!project || !ref) {
return '';
@@ -234,6 +263,12 @@
opt_errFn, opt_ctx);
},
+ /**
+ * @param {string} project
+ * @param {string} ref
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {?=} opt_ctx
+ */
deleteProjectTags(project, ref, opt_errFn, opt_ctx) {
if (!project || !ref) {
return '';
@@ -245,6 +280,13 @@
opt_errFn, opt_ctx);
},
+ /**
+ * @param {string} name
+ * @param {string} branch
+ * @param {string} revision
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {?=} opt_ctx
+ */
createProjectBranch(name, branch, revision, opt_errFn, opt_ctx) {
if (!name || !branch || !revision) { return ''; }
const encodeName = encodeURIComponent(name);
@@ -254,6 +296,13 @@
revision, opt_errFn, opt_ctx);
},
+ /**
+ * @param {string} name
+ * @param {string} tag
+ * @param {string} revision
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {?=} opt_ctx
+ */
createProjectTag(name, tag, revision, opt_errFn, opt_ctx) {
if (!name || !tag || !revision) { return ''; }
const encodeName = encodeURIComponent(name);
@@ -324,6 +373,11 @@
});
},
+ /**
+ * @param {?Object} prefs
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {?=} opt_ctx
+ */
savePreferences(prefs, opt_errFn, opt_ctx) {
// Note (Issue 5142): normalize the download scheme with lower case before
// saving.
@@ -335,6 +389,11 @@
opt_ctx);
},
+ /**
+ * @param {?Object} prefs
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {?=} opt_ctx
+ */
saveDiffPreferences(prefs, opt_errFn, opt_ctx) {
// Invalidate the cache.
this._cache['/accounts/self/preferences.diff'] = undefined;
@@ -354,16 +413,31 @@
return this._fetchSharedCacheURL('/accounts/self/emails');
},
+ /**
+ * @param {string} email
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {?=} opt_ctx
+ */
addAccountEmail(email, opt_errFn, opt_ctx) {
return this.send('PUT', '/accounts/self/emails/' +
encodeURIComponent(email), null, opt_errFn, opt_ctx);
},
+ /**
+ * @param {string} email
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {?=} opt_ctx
+ */
deleteAccountEmail(email, opt_errFn, opt_ctx) {
return this.send('DELETE', '/accounts/self/emails/' +
encodeURIComponent(email), null, opt_errFn, opt_ctx);
},
+ /**
+ * @param {string} email
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {?=} opt_ctx
+ */
setPreferredAccountEmail(email, opt_errFn, opt_ctx) {
return this.send('PUT', '/accounts/self/emails/' +
encodeURIComponent(email) + '/preferred', null,
@@ -384,6 +458,11 @@
});
},
+ /**
+ * @param {string} name
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {?=} opt_ctx
+ */
setAccountName(name, opt_errFn, opt_ctx) {
return this.send('PUT', '/accounts/self/name', {name}, opt_errFn,
opt_ctx).then(response => {
@@ -401,6 +480,11 @@
});
},
+ /**
+ * @param {string} status
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {?=} opt_ctx
+ */
setAccountStatus(status, opt_errFn, opt_ctx) {
return this.send('PUT', '/accounts/self/status', {status},
opt_errFn, opt_ctx).then(response => {
@@ -426,6 +510,9 @@
return this._fetchSharedCacheURL('/accounts/self/agreements');
},
+ /**
+ * @param {string=} opt_params
+ */
getAccountCapabilities(opt_params) {
let queryString = '';
if (opt_params) {
@@ -500,6 +587,11 @@
return this._fetchSharedCacheURL('/accounts/self/watched.projects');
},
+ /**
+ * @param {string} projects
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {?=} opt_ctx
+ */
saveWatchedProjects(projects, opt_errFn, opt_ctx) {
return this.send('POST', '/accounts/self/watched.projects', projects,
opt_errFn, opt_ctx)
@@ -508,11 +600,20 @@
});
},
+ /**
+ * @param {string} projects
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {?=} opt_ctx
+ */
deleteWatchedProjects(projects, opt_errFn, opt_ctx) {
return this.send('POST', '/accounts/self/watched.projects:delete',
projects, opt_errFn, opt_ctx);
},
+ /**
+ * @param {string} url
+ * @param {function(?Response, string=)=} opt_errFn
+ */
_fetchSharedCacheURL(url, opt_errFn) {
if (this._sharedFetchPromises[url]) {
return this._sharedFetchPromises[url];
@@ -540,13 +641,13 @@
},
/**
- * @param {!number} opt_changesPerPage
- * @param {!string|Array<string>} opt_query A query or an array of queries.
- * @param {!number} opt_offset
- * @param {!Object} opt_options
- * @return {Array<Object>|Array<Array<Object>>} If opt_query is an array,
- * fetchJSON will return an array of arrays of changeInfos. If it is
- * unspecified or a string, fetchJSON will return an array of
+ * @param {number=} opt_changesPerPage
+ * @param {string|!Array<string>=} opt_query A query or an array of queries.
+ * @param {number|string=} opt_offset
+ * @param {!Object=} opt_options
+ * @return {?Array<!Object>|?Array<!Array<!Object>>} If opt_query is an
+ * array, fetchJSON will return an array of arrays of changeInfos. If it
+ * is unspecified or a string, fetchJSON will return an array of
* changeInfos.
*/
getChanges(opt_changesPerPage, opt_query, opt_offset, opt_options) {
@@ -587,7 +688,7 @@
/**
* Inserts a change into _projectLookup iff it has a valid structure.
- * @param {!Object} change
+ * @param {?{ _number: (number|string) }} change
*/
_maybeInsertInLookup(change) {
if (change && change.project && change._number) {
@@ -595,17 +696,31 @@
}
},
+ /**
+ * TODO (beckysiegel) this needs to be rewritten with the optional param
+ * at the end.
+ *
+ * @param {number|string} changeNum
+ * @param {?number|string=} opt_patchNum passed as null sometimes.
+ * @param {?=} endpoint
+ * @return {!Promise<string>}
+ */
getChangeActionURL(changeNum, opt_patchNum, endpoint) {
return this._changeBaseURL(changeNum, opt_patchNum)
.then(url => url + endpoint);
},
+ /**
+ * @param {number|string} changeNum
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {function()=} opt_cancelCondition
+ */
getChangeDetail(changeNum, opt_errFn, opt_cancelCondition) {
const options = this.listChangesOptionsToHex(
+ this.ListChangesOption.ALL_COMMITS,
this.ListChangesOption.ALL_REVISIONS,
this.ListChangesOption.CHANGE_ACTIONS,
this.ListChangesOption.CURRENT_ACTIONS,
- this.ListChangesOption.CURRENT_COMMIT,
this.ListChangesOption.DOWNLOAD_COMMANDS,
this.ListChangesOption.SUBMITTABLE,
this.ListChangesOption.WEB_LINKS
@@ -615,6 +730,11 @@
.then(GrReviewerUpdatesParser.parse);
},
+ /**
+ * @param {number|string} changeNum
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {function()=} opt_cancelCondition
+ */
getDiffChangeDetail(changeNum, opt_errFn, opt_cancelCondition) {
const params = this.listChangesOptionsToHex(
this.ListChangesOption.ALL_REVISIONS
@@ -623,6 +743,11 @@
opt_cancelCondition);
},
+ /**
+ * @param {number|string} changeNum
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {function()=} opt_cancelCondition
+ */
_getChangeDetail(changeNum, params, opt_errFn,
opt_cancelCondition) {
return this.getChangeActionURL(changeNum, null, '/detail').then(url => {
@@ -651,10 +776,18 @@
});
},
+ /**
+ * @param {number|string} changeNum
+ * @param {number|string} patchNum
+ */
getChangeCommitInfo(changeNum, patchNum) {
return this._getChangeURLAndFetch(changeNum, '/commit?links', patchNum);
},
+ /**
+ * @param {number|string} changeNum
+ * @param {!Promise<?Object>} patchRange
+ */
getChangeFiles(changeNum, patchRange) {
let endpoint = '/files';
if (patchRange.basePatchNum !== 'PARENT') {
@@ -669,12 +802,22 @@
this._normalizeChangeFilesResponse.bind(this));
},
+ /**
+ * The closure compiler doesn't realize this.specialFilePathCompare is
+ * valid.
+ * @suppress {checkTypes}
+ */
getChangeFilePathsAsSpeciallySortedArray(changeNum, patchRange) {
return this.getChangeFiles(changeNum, patchRange).then(files => {
return Object.keys(files).sort(this.specialFilePathCompare);
});
},
+ /**
+ * The closure compiler doesn't realize this.specialFilePathCompare is
+ * valid.
+ * @suppress {checkTypes}
+ */
_normalizeChangeFilesResponse(response) {
if (!response) { return []; }
const paths = Object.keys(response).sort(this.specialFilePathCompare);
@@ -702,6 +845,11 @@
});
},
+ /**
+ * @param {number|string} changeNum
+ * @param {string} inputVal
+ * @param {function(?Response, string=)=} opt_errFn
+ */
getChangeSuggestedReviewers(changeNum, inputVal, opt_errFn) {
const params = {n: 10};
if (inputVal) { params.q = inputVal; }
@@ -720,6 +868,12 @@
return filter;
},
+ /**
+ * @param {string} filter
+ * @param {number} groupsPerPage
+ * @param {number=} opt_offset
+ * @return {!Promise<?Object>}
+ */
getGroups(filter, groupsPerPage, opt_offset) {
const offset = opt_offset || 0;
@@ -729,6 +883,12 @@
);
},
+ /**
+ * @param {string} filter
+ * @param {number} projectsPerPage
+ * @param {number=} opt_offset
+ * @return {!Promise<?Object>}
+ */
getProjects(filter, projectsPerPage, opt_offset) {
const offset = opt_offset || 0;
@@ -743,6 +903,13 @@
'PUT', `/projects/${encodeURIComponent(project)}/HEAD`, {ref});
},
+ /**
+ * @param {string} filter
+ * @param {string} project
+ * @param {number} projectsBranchesPerPage
+ * @param {number=} opt_offset
+ * @return {!Promise<?Object>}
+ */
getProjectBranches(filter, project, projectsBranchesPerPage, opt_offset) {
const offset = opt_offset || 0;
@@ -753,6 +920,13 @@
);
},
+ /**
+ * @param {string} filter
+ * @param {string} project
+ * @param {number} projectsTagsPerPage
+ * @param {number=} opt_offset
+ * @return {!Promise<?Object>}
+ */
getProjectTags(filter, project, projectsTagsPerPage, opt_offset) {
const offset = opt_offset || 0;
@@ -763,6 +937,12 @@
);
},
+ /**
+ * @param {string} filter
+ * @param {number} pluginsPerPage
+ * @param {number=} opt_offset
+ * @return {!Promise<?Object>}
+ */
getPlugins(filter, pluginsPerPage, opt_offset) {
const offset = opt_offset || 0;
@@ -772,12 +952,24 @@
);
},
+ /**
+ * @param {string} inputVal
+ * @param {number} opt_n
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {?=} opt_ctx
+ */
getSuggestedGroups(inputVal, opt_n, opt_errFn, opt_ctx) {
const params = {s: inputVal};
if (opt_n) { params.n = opt_n; }
return this.fetchJSON('/groups/', opt_errFn, opt_ctx, params);
},
+ /**
+ * @param {string} inputVal
+ * @param {number} opt_n
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {?=} opt_ctx
+ */
getSuggestedProjects(inputVal, opt_n, opt_errFn, opt_ctx) {
const params = {
m: inputVal,
@@ -788,6 +980,12 @@
return this.fetchJSON('/projects/', opt_errFn, opt_ctx, params);
},
+ /**
+ * @param {string} inputVal
+ * @param {number} opt_n
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {?=} opt_ctx
+ */
getSuggestedAccounts(inputVal, opt_n, opt_errFn, opt_ctx) {
if (!inputVal) {
return Promise.resolve([]);
@@ -880,6 +1078,14 @@
return this._getChangeURLAndFetch(changeNum, '/files?reviewed', patchNum);
},
+ /**
+ * @param {number|string} changeNum
+ * @param {number|string} patchNum
+ * @param {string} path
+ * @param {boolean} reviewed
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {?=} opt_ctx
+ */
saveFileReviewed(changeNum, patchNum, path, reviewed, opt_errFn, opt_ctx) {
const method = reviewed ? 'PUT' : 'DELETE';
const e = `/files/${encodeURIComponent(path)}/reviewed`;
@@ -887,6 +1093,13 @@
opt_errFn, opt_ctx);
},
+ /**
+ * @param {number|string} changeNum
+ * @param {number|string} patchNum
+ * @param {!Object} review
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {?=} opt_ctx
+ */
saveChangeReview(changeNum, patchNum, review, opt_errFn, opt_ctx) {
const promises = [
this.awaitPendingDiffDrafts(),
@@ -963,12 +1176,23 @@
return this.send(method, url);
},
+ /**
+ * @param {string} method
+ * @param {string} url
+ * @param {?string|number|Object=} opt_body passed as null sometimes
+ * and also apparently a number. TODO (beckysiegel) remove need for
+ * number at least.
+ * @param {?function(?Response, string=)=} opt_errFn
+ * passed as null sometimes.
+ * @param {?=} opt_ctx
+ * @param {?string=} opt_contentType
+ */
send(method, url, opt_body, opt_errFn, opt_ctx, opt_contentType) {
const options = {method};
if (opt_body) {
- options.headers = new Headers({
- 'Content-Type': opt_contentType || 'application/json',
- });
+ options.headers = new Headers();
+ options.headers.set(
+ 'Content-Type', opt_contentType || 'application/json');
if (typeof opt_body !== 'string') {
opt_body = JSON.stringify(opt_body);
}
@@ -994,6 +1218,14 @@
});
},
+ /**
+ * @param {number|string} changeNum
+ * @param {number|string} basePatchNum
+ * @param {number|string} patchNum
+ * @param {string} path
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {function()=} opt_cancelCondition
+ */
getDiff(changeNum, basePatchNum, patchNum, path,
opt_errFn, opt_cancelCondition) {
const params = {
@@ -1010,6 +1242,12 @@
opt_errFn, opt_cancelCondition, params);
},
+ /**
+ * @param {number|string} changeNum
+ * @param {number|string=} opt_basePatchNum
+ * @param {number|string=} opt_patchNum
+ * @param {string=} opt_path
+ */
getDiffComments(changeNum, opt_basePatchNum, opt_patchNum, opt_path) {
return this._getDiffComments(changeNum, '/comments', opt_basePatchNum,
opt_patchNum, opt_path);
@@ -1026,10 +1264,10 @@
* empty object.
*
* @param {number|string} changeNum
- * @param {number|string} opt_basePatchNum
- * @param {number|string} opt_patchNum
- * @param {string} opt_path
- * @return {Promise<Object>}
+ * @param {number|string=} opt_basePatchNum
+ * @param {number|string=} opt_patchNum
+ * @param {string=} opt_path
+ * @return {!Promise<?Object>}
*/
getDiffDrafts(changeNum, opt_basePatchNum, opt_patchNum, opt_path) {
return this.getLoggedIn().then(loggedIn => {
@@ -1062,17 +1300,24 @@
return comments;
},
+ /**
+ * @param {number|string} changeNum
+ * @param {string} endpoint
+ * @param {number|string=} opt_basePatchNum
+ * @param {number|string=} opt_patchNum
+ * @param {string=} opt_path
+ */
_getDiffComments(changeNum, endpoint, opt_basePatchNum,
opt_patchNum, opt_path) {
/**
* Fetches the comments for a given patchNum.
* Helper function to make promises more legible.
*
- * @param {string|number} patchNum
+ * @param {string|number=} opt_patchNum
* @return {!Object} Diff comments response.
*/
- const fetchComments = patchNum => {
- return this._getChangeURLAndFetch(changeNum, endpoint, patchNum);
+ const fetchComments = opt_patchNum => {
+ return this._getChangeURLAndFetch(changeNum, endpoint, opt_patchNum);
};
if (!opt_basePatchNum && !opt_patchNum && !opt_path) {
@@ -1122,6 +1367,11 @@
});
},
+ /**
+ * @param {number|string} changeNum
+ * @param {string} endpoint
+ * @param {number|string=} opt_patchNum
+ */
_getDiffCommentsFetchURL(changeNum, endpoint, opt_patchNum) {
return this._changeBaseURL(changeNum, opt_patchNum)
.then(url => url + endpoint);
@@ -1144,8 +1394,8 @@
},
/**
- * @returns {Promise} A promise that resolves when all pending diff draft
- * sends have resolved.
+ * @returns {!Promise<undefined>} A promise that resolves when all pending
+ * diff draft sends have resolved.
*/
awaitPendingDiffDrafts() {
return Promise.all(this._pendingRequests[Requests.SEND_DIFF_DRAFT] || [])
@@ -1192,6 +1442,12 @@
});
},
+ /**
+ * @param {string} changeId
+ * @param {string|number} patchNum
+ * @param {string} path
+ * @param {number=} opt_parentIndex
+ */
getChangeFileContents(changeId, patchNum, path, opt_parentIndex) {
const parent = typeof opt_parentIndex === 'number' ?
'?parent=' + opt_parentIndex : '';
@@ -1244,8 +1500,8 @@
},
/**
- * @param {string} changeNum
- * @param {number|string=} opt_patchNum
+ * @param {number|string} changeNum
+ * @param {?number|string=} opt_patchNum passed as null sometimes.
* @param {string=} opt_project
* @return {!Promise<string>}
*/
@@ -1264,12 +1520,22 @@
});
},
+ /**
+ * @suppress {checkTypes}
+ * Resulted in error: Promise.prototype.then does not match formal
+ * parameter.
+ */
setChangeTopic(changeNum, topic) {
const p = {topic};
return this.getChangeURLAndSend(changeNum, 'PUT', null, '/topic', p)
.then(this.getResponseObject);
},
+ /**
+ * @suppress {checkTypes}
+ * Resulted in error: Promise.prototype.then does not match formal
+ * parameter.
+ */
setChangeHashtag(changeNum, hashtag) {
return this.getChangeURLAndSend(changeNum, 'POST', null, '/hashtags',
hashtag).then(this.getResponseObject);
@@ -1279,6 +1545,11 @@
return this.send('DELETE', '/accounts/self/password.http');
},
+ /**
+ * @suppress {checkTypes}
+ * Resulted in error: Promise.prototype.then does not match formal
+ * parameter.
+ */
generateAccountHttpPassword() {
return this.send('PUT', '/accounts/self/password.http', {generate: true})
.then(this.getResponseObject);
@@ -1344,6 +1615,10 @@
});
},
+ /**
+ * @param {number|string} changeNum
+ * @param {number|string=} opt_message
+ */
startWorkInProgress(changeNum, opt_message) {
const payload = {};
if (opt_message) {
@@ -1357,11 +1632,21 @@
});
},
+ /**
+ * @param {number|string} changeNum
+ * @param {number|string=} opt_body
+ * @param {function(?Response, string=)=} opt_errFn
+ */
startReview(changeNum, opt_body, opt_errFn) {
return this.getChangeURLAndSend(changeNum, 'POST', null, '/ready',
opt_body, opt_errFn);
},
+ /**
+ * @suppress {checkTypes}
+ * Resulted in error: Promise.prototype.then does not match formal
+ * parameter.
+ */
deleteComment(changeNum, patchNum, commentID, reason) {
const endpoint = `/comments/${commentID}/delete`;
const payload = {reason};
@@ -1372,8 +1657,8 @@
/**
* Given a changeNum, gets the change.
*
- * @param {string} changeNum
- * @return {Promise<Object>} The change
+ * @param {number|string} changeNum
+ * @return {!Promise<?Object>} The change
*/
getChange(changeNum) {
// Cannot use _changeBaseURL, as this function is used by _projectLookup.
@@ -1382,7 +1667,7 @@
/**
* @param {string|number} changeNum
- * @param {string} project
+ * @param {string=} project
*/
setInProjectLookup(changeNum, project) {
if (this._projectLookup[changeNum] &&
@@ -1399,7 +1684,7 @@
* _projectLookup with the project for that change, and returns the project.
*
* @param {string|number} changeNum
- * @return {Promise<string>}
+ * @return {!Promise<string|undefined>}
*/
_getFromProjectLookup(changeNum) {
const project = this._projectLookup[changeNum];
@@ -1413,18 +1698,21 @@
/**
* Alias for _changeBaseURL.then(send).
- *
+ * @TODO(beckysiegel) clean up comments
* @param {string|number} changeNum
* @param {string} method
- * @param {string} endpoint
- * @param {string|number=} opt_patchNum
- * @param {!Object=} opt_payload
- * @param {function(?Response, string)=} opt_errFn
+ * @param {?string|number} patchNum gets passed as null.
+ * @param {?string} endpoint gets passed as null.
+ * @param {?Object|number|string=} opt_payload gets passed as null, string,
+ * Object, or number.
+ * @param {function(?Response, string=)=} opt_errFn
+ * @param {?=} opt_ctx
+ * @param {?=} opt_contentType
* @return {!Promise<!Object>}
*/
- getChangeURLAndSend(changeNum, method, opt_patchNum, endpoint, opt_payload,
+ getChangeURLAndSend(changeNum, method, patchNum, endpoint, opt_payload,
opt_errFn, opt_ctx, opt_contentType) {
- return this._changeBaseURL(changeNum, opt_patchNum).then(url => {
+ return this._changeBaseURL(changeNum, patchNum).then(url => {
return this.send(method, url + endpoint, opt_payload, opt_errFn,
opt_ctx, opt_contentType);
});
@@ -1432,13 +1720,13 @@
/**
* Alias for _changeBaseURL.then(fetchJSON).
- *
+ * @TODO(beckysiegel) clean up comments
* @param {string|number} changeNum
* @param {string} endpoint
- * @param {string|number=} opt_patchNum
- * @param {function(?Response, string)=} opt_errFn
- * @param {!function()=} opt_cancelCondition
- * @param {!Object=} opt_params
+ * @param {?string|number=} opt_patchNum gets passed as null.
+ * @param {?function(?Response, string=)=} opt_errFn gets passed as null.
+ * @param {?function()=} opt_cancelCondition gets passed as null.
+ * @param {?Object=} opt_params gets passed as null.
* @param {!Object=} opt_options
* @return {!Promise<!Object>}
*/